comparison src/ex_getln.c @ 17460:e43f0c0c491c v8.1.1728

patch 8.1.1728: wrong place for command line history viminfo support commit https://github.com/vim/vim/commit/5f32ece459d1f310b1b48b72e07dcd77d3261a76 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 21 21:51:59 2019 +0200 patch 8.1.1728: wrong place for command line history viminfo support Problem: Wrong place for command line history viminfo support. Solution: Move it to viminfo.c.
author Bram Moolenaar <Bram@vim.org>
date Sun, 21 Jul 2019 22:00:05 +0200
parents 9c4ddc78df74
children 77c3f6428b6c
comparison
equal deleted inserted replaced
17459:02dc4260ddbb 17460:e43f0c0c491c
58 static int extra_char = NUL; /* extra character to display when redrawing 58 static int extra_char = NUL; /* extra character to display when redrawing
59 * the command line */ 59 * the command line */
60 static int extra_char_shift; 60 static int extra_char_shift;
61 61
62 #ifdef FEAT_CMDHIST 62 #ifdef FEAT_CMDHIST
63 typedef struct hist_entry
64 {
65 int hisnum; /* identifying number */
66 int viminfo; /* when TRUE hisstr comes from viminfo */
67 char_u *hisstr; /* actual entry, separator char after the NUL */
68 time_t time_set; /* when it was typed, zero if unknown */
69 } histentry_T;
70
71 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL}; 63 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
72 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */ 64 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
73 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0}; 65 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
74 /* identifying (unique) number of newest history entry */ 66 /* identifying (unique) number of newest history entry */
75 static int hislen = 0; /* actual length of history tables */ 67 static int hislen = 0; /* actual length of history tables */
76
77 static int hist_char2type(int c);
78 #endif 68 #endif
79 69
80 #ifdef FEAT_RIGHTLEFT 70 #ifdef FEAT_RIGHTLEFT
81 static int cmd_hkmap = 0; /* Hebrew mapping during command line */ 71 static int cmd_hkmap = 0; /* Hebrew mapping during command line */
82 #endif 72 #endif
113 # endif 103 # endif
114 # if defined(FEAT_EVAL) 104 # if defined(FEAT_EVAL)
115 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); 105 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
116 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); 106 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
117 # endif 107 # endif
118 #endif
119 #ifdef FEAT_CMDHIST
120 static void clear_hist_entry(histentry_T *hisptr);
121 #endif 108 #endif
122 109
123 #ifdef FEAT_CMDWIN 110 #ifdef FEAT_CMDWIN
124 static int open_cmdwin(void); 111 static int open_cmdwin(void);
125 #endif 112 #endif
5871 *********************************/ 5858 *********************************/
5872 5859
5873 /* 5860 /*
5874 * Translate a history character to the associated type number. 5861 * Translate a history character to the associated type number.
5875 */ 5862 */
5876 static int 5863 int
5877 hist_char2type(int c) 5864 hist_char2type(int c)
5878 { 5865 {
5879 if (c == ':') 5866 if (c == ':')
5880 return HIST_CMD; 5867 return HIST_CMD;
5881 if (c == '=') 5868 if (c == '=')
6008 } 5995 }
6009 hislen = newlen; 5996 hislen = newlen;
6010 } 5997 }
6011 } 5998 }
6012 5999
6013 static void 6000 void
6014 clear_hist_entry(histentry_T *hisptr) 6001 clear_hist_entry(histentry_T *hisptr)
6015 { 6002 {
6016 hisptr->hisnum = 0; 6003 hisptr->hisnum = 0;
6017 hisptr->viminfo = FALSE; 6004 hisptr->viminfo = FALSE;
6018 hisptr->hisstr = NULL; 6005 hisptr->hisstr = NULL;
6021 6008
6022 /* 6009 /*
6023 * Check if command line 'str' is already in history. 6010 * Check if command line 'str' is already in history.
6024 * If 'move_to_front' is TRUE, matching entry is moved to end of history. 6011 * If 'move_to_front' is TRUE, matching entry is moved to end of history.
6025 */ 6012 */
6026 static int 6013 int
6027 in_history( 6014 in_history(
6028 int type, 6015 int type,
6029 char_u *str, 6016 char_u *str,
6030 int move_to_front, /* Move the entry to the front if it exists */ 6017 int move_to_front, /* Move the entry to the front if it exists */
6031 int sep, 6018 int sep,
6627 } 6614 }
6628 } 6615 }
6629 #endif 6616 #endif
6630 6617
6631 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO) 6618 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
6632 /* 6619 int
6633 * Buffers for history read from a viminfo file. Only valid while reading. 6620 get_hislen(void)
6634 */ 6621 {
6635 static histentry_T *viminfo_history[HIST_COUNT] = 6622 return hislen;
6636 {NULL, NULL, NULL, NULL, NULL}; 6623 }
6637 static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0}; 6624
6638 static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0}; 6625 histentry_T *
6639 static int viminfo_add_at_front = FALSE; 6626 get_histentry(int hist_type)
6640 6627 {
6641 /* 6628 return history[hist_type];
6642 * Translate a history type number to the associated character. 6629 }
6643 */ 6630
6644 static int
6645 hist_type2char(
6646 int type,
6647 int use_question) /* use '?' instead of '/' */
6648 {
6649 if (type == HIST_CMD)
6650 return ':';
6651 if (type == HIST_SEARCH)
6652 {
6653 if (use_question)
6654 return '?';
6655 else
6656 return '/';
6657 }
6658 if (type == HIST_EXPR)
6659 return '=';
6660 return '@';
6661 }
6662
6663 /*
6664 * Prepare for reading the history from the viminfo file.
6665 * This allocates history arrays to store the read history lines.
6666 */
6667 void 6631 void
6668 prepare_viminfo_history(int asklen, int writing) 6632 set_histentry(int hist_type, histentry_T *entry)
6669 { 6633 {
6670 int i; 6634 history[hist_type] = entry;
6671 int num; 6635 }
6672 int type; 6636
6673 int len; 6637 int *
6674 6638 get_hisidx(int hist_type)
6675 init_history(); 6639 {
6676 viminfo_add_at_front = (asklen != 0 && !writing); 6640 return &hisidx[hist_type];
6677 if (asklen > hislen) 6641 }
6678 asklen = hislen; 6642
6679 6643 int *
6680 for (type = 0; type < HIST_COUNT; ++type) 6644 get_hisnum(int hist_type)
6681 { 6645 {
6682 /* Count the number of empty spaces in the history list. Entries read 6646 return &hisnum[hist_type];
6683 * from viminfo previously are also considered empty. If there are 6647 }
6684 * more spaces available than we request, then fill them up. */ 6648 #endif
6685 for (i = 0, num = 0; i < hislen; i++)
6686 if (history[type][i].hisstr == NULL || history[type][i].viminfo)
6687 num++;
6688 len = asklen;
6689 if (num > len)
6690 len = num;
6691 if (len <= 0)
6692 viminfo_history[type] = NULL;
6693 else
6694 viminfo_history[type] = LALLOC_MULT(histentry_T, len);
6695 if (viminfo_history[type] == NULL)
6696 len = 0;
6697 viminfo_hislen[type] = len;
6698 viminfo_hisidx[type] = 0;
6699 }
6700 }
6701
6702 /*
6703 * Accept a line from the viminfo, store it in the history array when it's
6704 * new.
6705 */
6706 int
6707 read_viminfo_history(vir_T *virp, int writing)
6708 {
6709 int type;
6710 long_u len;
6711 char_u *val;
6712 char_u *p;
6713
6714 type = hist_char2type(virp->vir_line[0]);
6715 if (viminfo_hisidx[type] < viminfo_hislen[type])
6716 {
6717 val = viminfo_readstring(virp, 1, TRUE);
6718 if (val != NULL && *val != NUL)
6719 {
6720 int sep = (*val == ' ' ? NUL : *val);
6721
6722 if (!in_history(type, val + (type == HIST_SEARCH),
6723 viminfo_add_at_front, sep, writing))
6724 {
6725 /* Need to re-allocate to append the separator byte. */
6726 len = STRLEN(val);
6727 p = alloc(len + 2);
6728 if (p != NULL)
6729 {
6730 if (type == HIST_SEARCH)
6731 {
6732 /* Search entry: Move the separator from the first
6733 * column to after the NUL. */
6734 mch_memmove(p, val + 1, (size_t)len);
6735 p[len] = sep;
6736 }
6737 else
6738 {
6739 /* Not a search entry: No separator in the viminfo
6740 * file, add a NUL separator. */
6741 mch_memmove(p, val, (size_t)len + 1);
6742 p[len + 1] = NUL;
6743 }
6744 viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
6745 viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
6746 viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE;
6747 viminfo_history[type][viminfo_hisidx[type]].hisnum = 0;
6748 viminfo_hisidx[type]++;
6749 }
6750 }
6751 }
6752 vim_free(val);
6753 }
6754 return viminfo_readline(virp);
6755 }
6756
6757 /*
6758 * Accept a new style history line from the viminfo, store it in the history
6759 * array when it's new.
6760 */
6761 void
6762 handle_viminfo_history(
6763 garray_T *values,
6764 int writing)
6765 {
6766 int type;
6767 long_u len;
6768 char_u *val;
6769 char_u *p;
6770 bval_T *vp = (bval_T *)values->ga_data;
6771
6772 /* Check the format:
6773 * |{bartype},{histtype},{timestamp},{separator},"text" */
6774 if (values->ga_len < 4
6775 || vp[0].bv_type != BVAL_NR
6776 || vp[1].bv_type != BVAL_NR
6777 || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
6778 || vp[3].bv_type != BVAL_STRING)
6779 return;
6780
6781 type = vp[0].bv_nr;
6782 if (type >= HIST_COUNT)
6783 return;
6784 if (viminfo_hisidx[type] < viminfo_hislen[type])
6785 {
6786 val = vp[3].bv_string;
6787 if (val != NULL && *val != NUL)
6788 {
6789 int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
6790 ? vp[2].bv_nr : NUL;
6791 int idx;
6792 int overwrite = FALSE;
6793
6794 if (!in_history(type, val, viminfo_add_at_front, sep, writing))
6795 {
6796 /* If lines were written by an older Vim we need to avoid
6797 * getting duplicates. See if the entry already exists. */
6798 for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
6799 {
6800 p = viminfo_history[type][idx].hisstr;
6801 if (STRCMP(val, p) == 0
6802 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
6803 {
6804 overwrite = TRUE;
6805 break;
6806 }
6807 }
6808
6809 if (!overwrite)
6810 {
6811 /* Need to re-allocate to append the separator byte. */
6812 len = vp[3].bv_len;
6813 p = alloc(len + 2);
6814 }
6815 else
6816 len = 0; /* for picky compilers */
6817 if (p != NULL)
6818 {
6819 viminfo_history[type][idx].time_set = vp[1].bv_nr;
6820 if (!overwrite)
6821 {
6822 mch_memmove(p, val, (size_t)len + 1);
6823 /* Put the separator after the NUL. */
6824 p[len + 1] = sep;
6825 viminfo_history[type][idx].hisstr = p;
6826 viminfo_history[type][idx].hisnum = 0;
6827 viminfo_history[type][idx].viminfo = TRUE;
6828 viminfo_hisidx[type]++;
6829 }
6830 }
6831 }
6832 }
6833 }
6834 }
6835
6836 /*
6837 * Concatenate history lines from viminfo after the lines typed in this Vim.
6838 */
6839 static void
6840 concat_history(int type)
6841 {
6842 int idx;
6843 int i;
6844
6845 idx = hisidx[type] + viminfo_hisidx[type];
6846 if (idx >= hislen)
6847 idx -= hislen;
6848 else if (idx < 0)
6849 idx = hislen - 1;
6850 if (viminfo_add_at_front)
6851 hisidx[type] = idx;
6852 else
6853 {
6854 if (hisidx[type] == -1)
6855 hisidx[type] = hislen - 1;
6856 do
6857 {
6858 if (history[type][idx].hisstr != NULL
6859 || history[type][idx].viminfo)
6860 break;
6861 if (++idx == hislen)
6862 idx = 0;
6863 } while (idx != hisidx[type]);
6864 if (idx != hisidx[type] && --idx < 0)
6865 idx = hislen - 1;
6866 }
6867 for (i = 0; i < viminfo_hisidx[type]; i++)
6868 {
6869 vim_free(history[type][idx].hisstr);
6870 history[type][idx].hisstr = viminfo_history[type][i].hisstr;
6871 history[type][idx].viminfo = TRUE;
6872 history[type][idx].time_set = viminfo_history[type][i].time_set;
6873 if (--idx < 0)
6874 idx = hislen - 1;
6875 }
6876 idx += 1;
6877 idx %= hislen;
6878 for (i = 0; i < viminfo_hisidx[type]; i++)
6879 {
6880 history[type][idx++].hisnum = ++hisnum[type];
6881 idx %= hislen;
6882 }
6883 }
6884
6885 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
6886 static int
6887 sort_hist(const void *s1, const void *s2)
6888 {
6889 histentry_T *p1 = *(histentry_T **)s1;
6890 histentry_T *p2 = *(histentry_T **)s2;
6891
6892 if (p1->time_set < p2->time_set) return -1;
6893 if (p1->time_set > p2->time_set) return 1;
6894 return 0;
6895 }
6896 #endif
6897
6898 /*
6899 * Merge history lines from viminfo and lines typed in this Vim based on the
6900 * timestamp;
6901 */
6902 static void
6903 merge_history(int type)
6904 {
6905 int max_len;
6906 histentry_T **tot_hist;
6907 histentry_T *new_hist;
6908 int i;
6909 int len;
6910
6911 /* Make one long list with all entries. */
6912 max_len = hislen + viminfo_hisidx[type];
6913 tot_hist = ALLOC_MULT(histentry_T *, max_len);
6914 new_hist = ALLOC_MULT(histentry_T, hislen );
6915 if (tot_hist == NULL || new_hist == NULL)
6916 {
6917 vim_free(tot_hist);
6918 vim_free(new_hist);
6919 return;
6920 }
6921 for (i = 0; i < viminfo_hisidx[type]; i++)
6922 tot_hist[i] = &viminfo_history[type][i];
6923 len = i;
6924 for (i = 0; i < hislen; i++)
6925 if (history[type][i].hisstr != NULL)
6926 tot_hist[len++] = &history[type][i];
6927
6928 /* Sort the list on timestamp. */
6929 qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist);
6930
6931 /* Keep the newest ones. */
6932 for (i = 0; i < hislen; i++)
6933 {
6934 if (i < len)
6935 {
6936 new_hist[i] = *tot_hist[i];
6937 tot_hist[i]->hisstr = NULL;
6938 if (new_hist[i].hisnum == 0)
6939 new_hist[i].hisnum = ++hisnum[type];
6940 }
6941 else
6942 clear_hist_entry(&new_hist[i]);
6943 }
6944 hisidx[type] = (i < len ? i : len) - 1;
6945
6946 /* Free what is not kept. */
6947 for (i = 0; i < viminfo_hisidx[type]; i++)
6948 vim_free(viminfo_history[type][i].hisstr);
6949 for (i = 0; i < hislen; i++)
6950 vim_free(history[type][i].hisstr);
6951 vim_free(history[type]);
6952 history[type] = new_hist;
6953 vim_free(tot_hist);
6954 }
6955
6956 /*
6957 * Finish reading history lines from viminfo. Not used when writing viminfo.
6958 */
6959 void
6960 finish_viminfo_history(vir_T *virp)
6961 {
6962 int type;
6963 int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY;
6964
6965 for (type = 0; type < HIST_COUNT; ++type)
6966 {
6967 if (history[type] == NULL)
6968 continue;
6969
6970 if (merge)
6971 merge_history(type);
6972 else
6973 concat_history(type);
6974
6975 VIM_CLEAR(viminfo_history[type]);
6976 viminfo_hisidx[type] = 0;
6977 }
6978 }
6979
6980 /*
6981 * Write history to viminfo file in "fp".
6982 * When "merge" is TRUE merge history lines with a previously read viminfo
6983 * file, data is in viminfo_history[].
6984 * When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
6985 */
6986 void
6987 write_viminfo_history(FILE *fp, int merge)
6988 {
6989 int i;
6990 int type;
6991 int num_saved;
6992 int round;
6993
6994 init_history();
6995 if (hislen == 0)
6996 return;
6997 for (type = 0; type < HIST_COUNT; ++type)
6998 {
6999 num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
7000 if (num_saved == 0)
7001 continue;
7002 if (num_saved < 0) /* Use default */
7003 num_saved = hislen;
7004 fprintf(fp, _("\n# %s History (newest to oldest):\n"),
7005 type == HIST_CMD ? _("Command Line") :
7006 type == HIST_SEARCH ? _("Search String") :
7007 type == HIST_EXPR ? _("Expression") :
7008 type == HIST_INPUT ? _("Input Line") :
7009 _("Debug Line"));
7010 if (num_saved > hislen)
7011 num_saved = hislen;
7012
7013 /*
7014 * Merge typed and viminfo history:
7015 * round 1: history of typed commands.
7016 * round 2: history from recently read viminfo.
7017 */
7018 for (round = 1; round <= 2; ++round)
7019 {
7020 if (round == 1)
7021 /* start at newest entry, somewhere in the list */
7022 i = hisidx[type];
7023 else if (viminfo_hisidx[type] > 0)
7024 /* start at newest entry, first in the list */
7025 i = 0;
7026 else
7027 /* empty list */
7028 i = -1;
7029 if (i >= 0)
7030 while (num_saved > 0
7031 && !(round == 2 && i >= viminfo_hisidx[type]))
7032 {
7033 char_u *p;
7034 time_t timestamp;
7035 int c = NUL;
7036
7037 if (round == 1)
7038 {
7039 p = history[type][i].hisstr;
7040 timestamp = history[type][i].time_set;
7041 }
7042 else
7043 {
7044 p = viminfo_history[type] == NULL ? NULL
7045 : viminfo_history[type][i].hisstr;
7046 timestamp = viminfo_history[type] == NULL ? 0
7047 : viminfo_history[type][i].time_set;
7048 }
7049
7050 if (p != NULL && (round == 2
7051 || !merge
7052 || !history[type][i].viminfo))
7053 {
7054 --num_saved;
7055 fputc(hist_type2char(type, TRUE), fp);
7056 /* For the search history: put the separator in the
7057 * second column; use a space if there isn't one. */
7058 if (type == HIST_SEARCH)
7059 {
7060 c = p[STRLEN(p) + 1];
7061 putc(c == NUL ? ' ' : c, fp);
7062 }
7063 viminfo_writestring(fp, p);
7064
7065 {
7066 char cbuf[NUMBUFLEN];
7067
7068 /* New style history with a bar line. Format:
7069 * |{bartype},{histtype},{timestamp},{separator},"text" */
7070 if (c == NUL)
7071 cbuf[0] = NUL;
7072 else
7073 sprintf(cbuf, "%d", c);
7074 fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
7075 type, (long)timestamp, cbuf);
7076 barline_writestring(fp, p, LSIZE - 20);
7077 putc('\n', fp);
7078 }
7079 }
7080 if (round == 1)
7081 {
7082 /* Decrement index, loop around and stop when back at
7083 * the start. */
7084 if (--i < 0)
7085 i = hislen - 1;
7086 if (i == hisidx[type])
7087 break;
7088 }
7089 else
7090 {
7091 /* Increment index. Stop at the end in the while. */
7092 ++i;
7093 }
7094 }
7095 }
7096 for (i = 0; i < viminfo_hisidx[type]; ++i)
7097 if (viminfo_history[type] != NULL)
7098 vim_free(viminfo_history[type][i].hisstr);
7099 VIM_CLEAR(viminfo_history[type]);
7100 viminfo_hisidx[type] = 0;
7101 }
7102 }
7103 #endif /* FEAT_VIMINFO */
7104 6649
7105 #if defined(FEAT_CMDWIN) || defined(PROTO) 6650 #if defined(FEAT_CMDWIN) || defined(PROTO)
7106 /* 6651 /*
7107 * Open a window on the current command line and history. Allow editing in 6652 * Open a window on the current command line and history. Allow editing in
7108 * the window. Returns when the window is closed. 6653 * the window. Returns when the window is closed.