comparison src/ex_getln.c @ 17652:9efb4dda9720

patch 8.1.1823: command line history code is spread out commit https://github.com/vim/vim/commit/d7663c22c6c1ff0f86b81371586fbc851d3a3e9e Author: Bram Moolenaar <Bram@vim.org> Date: Tue Aug 6 21:59:57 2019 +0200 patch 8.1.1823: command line history code is spread out Problem: Command line history code is spread out. Solution: Put the code in a new file. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/4779) Also graduate the +cmdline_hist feature.
author Bram Moolenaar <Bram@vim.org>
date Tue, 06 Aug 2019 22:00:08 +0200
parents 1348696d07cd
children 87a8760babec
comparison
equal deleted inserted replaced
17651:826360df7aff 17652:9efb4dda9720
57 57
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
63 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
64 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
65 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
66 /* identifying (unique) number of newest history entry */
67 static int hislen = 0; /* actual length of history tables */
68 #endif
69
70 #ifdef FEAT_RIGHTLEFT 62 #ifdef FEAT_RIGHTLEFT
71 static int cmd_hkmap = 0; /* Hebrew mapping during command line */ 63 static int cmd_hkmap = 0; /* Hebrew mapping during command line */
72 #endif 64 #endif
73 65
74 static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline); 66 static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
96 static int expand_showtail(expand_T *xp); 88 static int expand_showtail(expand_T *xp);
97 #ifdef FEAT_CMDL_COMPL 89 #ifdef FEAT_CMDL_COMPL
98 static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg); 90 static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg);
99 static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]); 91 static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]);
100 static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); 92 static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file);
101 # ifdef FEAT_CMDHIST
102 static char_u *get_history_arg(expand_T *xp, int idx);
103 # endif
104 # if defined(FEAT_EVAL) 93 # if defined(FEAT_EVAL)
105 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); 94 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
106 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); 95 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
107 # endif 96 # endif
108 #endif 97 #endif
842 int c; 831 int c;
843 int i; 832 int i;
844 int j; 833 int j;
845 int gotesc = FALSE; /* TRUE when <ESC> just typed */ 834 int gotesc = FALSE; /* TRUE when <ESC> just typed */
846 int do_abbr; /* when TRUE check for abbr. */ 835 int do_abbr; /* when TRUE check for abbr. */
847 #ifdef FEAT_CMDHIST
848 char_u *lookfor = NULL; /* string to match */ 836 char_u *lookfor = NULL; /* string to match */
849 int hiscnt; /* current history line in use */ 837 int hiscnt; /* current history line in use */
850 int histype; /* history type to be used */ 838 int histype; /* history type to be used */
851 #endif
852 #ifdef FEAT_SEARCH_EXTRA 839 #ifdef FEAT_SEARCH_EXTRA
853 incsearch_state_T is_state; 840 incsearch_state_T is_state;
854 #endif 841 #endif
855 int did_wild_list = FALSE; /* did wild_list() recently */ 842 int did_wild_list = FALSE; /* did wild_list() recently */
856 int wim_index = 0; /* index in wim_flags[] */ 843 int wim_index = 0; /* index in wim_flags[] */
1002 989
1003 /* Trigger CmdlineEnter autocommands. */ 990 /* Trigger CmdlineEnter autocommands. */
1004 cmdline_type = firstc == NUL ? '-' : firstc; 991 cmdline_type = firstc == NUL ? '-' : firstc;
1005 trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER); 992 trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
1006 993
1007 #ifdef FEAT_CMDHIST
1008 init_history(); 994 init_history();
1009 hiscnt = hislen; /* set hiscnt to impossible history value */ 995 hiscnt = get_hislen(); /* set hiscnt to impossible history value */
1010 histype = hist_char2type(firstc); 996 histype = hist_char2type(firstc);
1011 #endif
1012 997
1013 #ifdef FEAT_DIGRAPHS 998 #ifdef FEAT_DIGRAPHS
1014 do_digraph(-1); /* init digraph typeahead */ 999 do_digraph(-1); /* init digraph typeahead */
1015 #endif 1000 #endif
1016 1001
1088 && !break_ctrl_c 1073 && !break_ctrl_c
1089 #endif 1074 #endif
1090 && !global_busy) 1075 && !global_busy)
1091 got_int = FALSE; 1076 got_int = FALSE;
1092 1077
1093 #ifdef FEAT_CMDHIST 1078 // free old command line when finished moving around in the history
1094 /* free old command line when finished moving around in the history 1079 // list
1095 * list */
1096 if (lookfor != NULL 1080 if (lookfor != NULL
1097 && c != K_S_DOWN && c != K_S_UP 1081 && c != K_S_DOWN && c != K_S_UP
1098 && c != K_DOWN && c != K_UP 1082 && c != K_DOWN && c != K_UP
1099 && c != K_PAGEDOWN && c != K_PAGEUP 1083 && c != K_PAGEDOWN && c != K_PAGEUP
1100 && c != K_KPAGEDOWN && c != K_KPAGEUP 1084 && c != K_KPAGEDOWN && c != K_KPAGEUP
1101 && c != K_LEFT && c != K_RIGHT 1085 && c != K_LEFT && c != K_RIGHT
1102 && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N))) 1086 && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N)))
1103 VIM_CLEAR(lookfor); 1087 VIM_CLEAR(lookfor);
1104 #endif
1105 1088
1106 /* 1089 /*
1107 * When there are matching completions to select <S-Tab> works like 1090 * When there are matching completions to select <S-Tab> works like
1108 * CTRL-P (unless 'wc' is <S-Tab>). 1091 * CTRL-P (unless 'wc' is <S-Tab>).
1109 */ 1092 */
2106 if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT, 2089 if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT,
2107 0, firstc != '@') == FAIL) 2090 0, firstc != '@') == FAIL)
2108 break; 2091 break;
2109 goto cmdline_not_changed; 2092 goto cmdline_not_changed;
2110 } 2093 }
2111 #ifdef FEAT_CMDHIST
2112 /* FALLTHROUGH */ 2094 /* FALLTHROUGH */
2113 case K_UP: 2095 case K_UP:
2114 case K_DOWN: 2096 case K_DOWN:
2115 case K_S_UP: 2097 case K_S_UP:
2116 case K_S_DOWN: 2098 case K_S_DOWN:
2117 case K_PAGEUP: 2099 case K_PAGEUP:
2118 case K_KPAGEUP: 2100 case K_KPAGEUP:
2119 case K_PAGEDOWN: 2101 case K_PAGEDOWN:
2120 case K_KPAGEDOWN: 2102 case K_KPAGEDOWN:
2121 if (hislen == 0 || firstc == NUL) /* no history */ 2103 if (get_hislen() == 0 || firstc == NUL) /* no history */
2122 goto cmdline_not_changed; 2104 goto cmdline_not_changed;
2123 2105
2124 i = hiscnt; 2106 i = hiscnt;
2125 2107
2126 /* save current command string so it can be restored later */ 2108 /* save current command string so it can be restored later */
2136 { 2118 {
2137 /* one step backwards */ 2119 /* one step backwards */
2138 if (c == K_UP|| c == K_S_UP || c == Ctrl_P 2120 if (c == K_UP|| c == K_S_UP || c == Ctrl_P
2139 || c == K_PAGEUP || c == K_KPAGEUP) 2121 || c == K_PAGEUP || c == K_KPAGEUP)
2140 { 2122 {
2141 if (hiscnt == hislen) /* first time */ 2123 if (hiscnt == get_hislen()) /* first time */
2142 hiscnt = hisidx[histype]; 2124 hiscnt = *get_hisidx(histype);
2143 else if (hiscnt == 0 && hisidx[histype] != hislen - 1) 2125 else if (hiscnt == 0 && *get_hisidx(histype) != get_hislen() - 1)
2144 hiscnt = hislen - 1; 2126 hiscnt = get_hislen() - 1;
2145 else if (hiscnt != hisidx[histype] + 1) 2127 else if (hiscnt != *get_hisidx(histype) + 1)
2146 --hiscnt; 2128 --hiscnt;
2147 else /* at top of list */ 2129 else /* at top of list */
2148 { 2130 {
2149 hiscnt = i; 2131 hiscnt = i;
2150 break; 2132 break;
2151 } 2133 }
2152 } 2134 }
2153 else /* one step forwards */ 2135 else /* one step forwards */
2154 { 2136 {
2155 /* on last entry, clear the line */ 2137 /* on last entry, clear the line */
2156 if (hiscnt == hisidx[histype]) 2138 if (hiscnt == *get_hisidx(histype))
2157 { 2139 {
2158 hiscnt = hislen; 2140 hiscnt = get_hislen();
2159 break; 2141 break;
2160 } 2142 }
2161 2143
2162 /* not on a history line, nothing to do */ 2144 /* not on a history line, nothing to do */
2163 if (hiscnt == hislen) 2145 if (hiscnt == get_hislen())
2164 break; 2146 break;
2165 if (hiscnt == hislen - 1) /* wrap around */ 2147 if (hiscnt == get_hislen() - 1) /* wrap around */
2166 hiscnt = 0; 2148 hiscnt = 0;
2167 else 2149 else
2168 ++hiscnt; 2150 ++hiscnt;
2169 } 2151 }
2170 if (hiscnt < 0 || history[histype][hiscnt].hisstr == NULL) 2152 if (hiscnt < 0 || get_histentry(histype)[hiscnt].hisstr == NULL)
2171 { 2153 {
2172 hiscnt = i; 2154 hiscnt = i;
2173 break; 2155 break;
2174 } 2156 }
2175 if ((c != K_UP && c != K_DOWN) 2157 if ((c != K_UP && c != K_DOWN)
2176 || hiscnt == i 2158 || hiscnt == i
2177 || STRNCMP(history[histype][hiscnt].hisstr, 2159 || STRNCMP(get_histentry(histype)[hiscnt].hisstr,
2178 lookfor, (size_t)j) == 0) 2160 lookfor, (size_t)j) == 0)
2179 break; 2161 break;
2180 } 2162 }
2181 2163
2182 if (hiscnt != i) /* jumped to other entry */ 2164 if (hiscnt != i) /* jumped to other entry */
2185 int len; 2167 int len;
2186 int old_firstc; 2168 int old_firstc;
2187 2169
2188 VIM_CLEAR(ccline.cmdbuff); 2170 VIM_CLEAR(ccline.cmdbuff);
2189 xpc.xp_context = EXPAND_NOTHING; 2171 xpc.xp_context = EXPAND_NOTHING;
2190 if (hiscnt == hislen) 2172 if (hiscnt == get_hislen())
2191 p = lookfor; /* back to the old one */ 2173 p = lookfor; /* back to the old one */
2192 else 2174 else
2193 p = history[histype][hiscnt].hisstr; 2175 p = get_histentry(histype)[hiscnt].hisstr;
2194 2176
2195 if (histype == HIST_SEARCH 2177 if (histype == HIST_SEARCH
2196 && p != lookfor 2178 && p != lookfor
2197 && (old_firstc = p[STRLEN(p) + 1]) != firstc) 2179 && (old_firstc = p[STRLEN(p) + 1]) != firstc)
2198 { 2180 {
2249 ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); 2231 ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
2250 redrawcmd(); 2232 redrawcmd();
2251 goto cmdline_changed; 2233 goto cmdline_changed;
2252 } 2234 }
2253 beep_flush(); 2235 beep_flush();
2254 #endif
2255 goto cmdline_not_changed; 2236 goto cmdline_not_changed;
2256 2237
2257 #ifdef FEAT_SEARCH_EXTRA 2238 #ifdef FEAT_SEARCH_EXTRA
2258 case Ctrl_G: /* next match */ 2239 case Ctrl_G: /* next match */
2259 case Ctrl_T: /* previous match */ 2240 case Ctrl_T: /* previous match */
2417 if (ccline.cmdbuff != NULL) 2398 if (ccline.cmdbuff != NULL)
2418 { 2399 {
2419 /* 2400 /*
2420 * Put line in history buffer (":" and "=" only when it was typed). 2401 * Put line in history buffer (":" and "=" only when it was typed).
2421 */ 2402 */
2422 #ifdef FEAT_CMDHIST
2423 if (ccline.cmdlen && firstc != NUL 2403 if (ccline.cmdlen && firstc != NUL
2424 && (some_key_typed || histype == HIST_SEARCH)) 2404 && (some_key_typed || histype == HIST_SEARCH))
2425 { 2405 {
2426 add_to_history(histype, ccline.cmdbuff, TRUE, 2406 add_to_history(histype, ccline.cmdbuff, TRUE,
2427 histype == HIST_SEARCH ? firstc : NUL); 2407 histype == HIST_SEARCH ? firstc : NUL);
2429 { 2409 {
2430 vim_free(new_last_cmdline); 2410 vim_free(new_last_cmdline);
2431 new_last_cmdline = vim_strsave(ccline.cmdbuff); 2411 new_last_cmdline = vim_strsave(ccline.cmdbuff);
2432 } 2412 }
2433 } 2413 }
2434 #endif
2435 2414
2436 if (gotesc) 2415 if (gotesc)
2437 abandon_cmdline(); 2416 abandon_cmdline();
2438 } 2417 }
2439 2418
5203 { 5182 {
5204 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE}, 5183 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE},
5205 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE}, 5184 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE},
5206 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE}, 5185 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE},
5207 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE}, 5186 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE},
5208 #ifdef FEAT_CMDHIST
5209 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE}, 5187 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE},
5210 #endif
5211 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE}, 5188 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE},
5212 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE}, 5189 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE},
5213 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE}, 5190 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
5214 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE}, 5191 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
5215 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE}, 5192 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
5869 vim_free(buf); 5846 vim_free(buf);
5870 } 5847 }
5871 5848
5872 #endif 5849 #endif
5873 5850
5874 #if defined(FEAT_CMDHIST) || defined(PROTO)
5875
5876 /*********************************
5877 * Command line history stuff *
5878 *********************************/
5879
5880 /*
5881 * Translate a history character to the associated type number.
5882 */
5883 int
5884 hist_char2type(int c)
5885 {
5886 if (c == ':')
5887 return HIST_CMD;
5888 if (c == '=')
5889 return HIST_EXPR;
5890 if (c == '@')
5891 return HIST_INPUT;
5892 if (c == '>')
5893 return HIST_DEBUG;
5894 return HIST_SEARCH; /* must be '?' or '/' */
5895 }
5896
5897 /*
5898 * Table of history names.
5899 * These names are used in :history and various hist...() functions.
5900 * It is sufficient to give the significant prefix of a history name.
5901 */
5902
5903 static char *(history_names[]) =
5904 {
5905 "cmd",
5906 "search",
5907 "expr",
5908 "input",
5909 "debug",
5910 NULL
5911 };
5912
5913 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
5914 /*
5915 * Function given to ExpandGeneric() to obtain the possible first
5916 * arguments of the ":history command.
5917 */
5918 static char_u *
5919 get_history_arg(expand_T *xp UNUSED, int idx)
5920 {
5921 static char_u compl[2] = { NUL, NUL };
5922 char *short_names = ":=@>?/";
5923 int short_names_count = (int)STRLEN(short_names);
5924 int history_name_count = sizeof(history_names) / sizeof(char *) - 1;
5925
5926 if (idx < short_names_count)
5927 {
5928 compl[0] = (char_u)short_names[idx];
5929 return compl;
5930 }
5931 if (idx < short_names_count + history_name_count)
5932 return (char_u *)history_names[idx - short_names_count];
5933 if (idx == short_names_count + history_name_count)
5934 return (char_u *)"all";
5935 return NULL;
5936 }
5937 #endif
5938
5939 /*
5940 * init_history() - Initialize the command line history.
5941 * Also used to re-allocate the history when the size changes.
5942 */
5943 void
5944 init_history(void)
5945 {
5946 int newlen; /* new length of history table */
5947 histentry_T *temp;
5948 int i;
5949 int j;
5950 int type;
5951
5952 /*
5953 * If size of history table changed, reallocate it
5954 */
5955 newlen = (int)p_hi;
5956 if (newlen != hislen) /* history length changed */
5957 {
5958 for (type = 0; type < HIST_COUNT; ++type) /* adjust the tables */
5959 {
5960 if (newlen)
5961 {
5962 temp = ALLOC_MULT(histentry_T, newlen);
5963 if (temp == NULL) /* out of memory! */
5964 {
5965 if (type == 0) /* first one: just keep the old length */
5966 {
5967 newlen = hislen;
5968 break;
5969 }
5970 /* Already changed one table, now we can only have zero
5971 * length for all tables. */
5972 newlen = 0;
5973 type = -1;
5974 continue;
5975 }
5976 }
5977 else
5978 temp = NULL;
5979 if (newlen == 0 || temp != NULL)
5980 {
5981 if (hisidx[type] < 0) /* there are no entries yet */
5982 {
5983 for (i = 0; i < newlen; ++i)
5984 clear_hist_entry(&temp[i]);
5985 }
5986 else if (newlen > hislen) /* array becomes bigger */
5987 {
5988 for (i = 0; i <= hisidx[type]; ++i)
5989 temp[i] = history[type][i];
5990 j = i;
5991 for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
5992 clear_hist_entry(&temp[i]);
5993 for ( ; j < hislen; ++i, ++j)
5994 temp[i] = history[type][j];
5995 }
5996 else /* array becomes smaller or 0 */
5997 {
5998 j = hisidx[type];
5999 for (i = newlen - 1; ; --i)
6000 {
6001 if (i >= 0) /* copy newest entries */
6002 temp[i] = history[type][j];
6003 else /* remove older entries */
6004 vim_free(history[type][j].hisstr);
6005 if (--j < 0)
6006 j = hislen - 1;
6007 if (j == hisidx[type])
6008 break;
6009 }
6010 hisidx[type] = newlen - 1;
6011 }
6012 vim_free(history[type]);
6013 history[type] = temp;
6014 }
6015 }
6016 hislen = newlen;
6017 }
6018 }
6019
6020 void
6021 clear_hist_entry(histentry_T *hisptr)
6022 {
6023 hisptr->hisnum = 0;
6024 hisptr->viminfo = FALSE;
6025 hisptr->hisstr = NULL;
6026 hisptr->time_set = 0;
6027 }
6028
6029 /*
6030 * Check if command line 'str' is already in history.
6031 * If 'move_to_front' is TRUE, matching entry is moved to end of history.
6032 */
6033 int
6034 in_history(
6035 int type,
6036 char_u *str,
6037 int move_to_front, /* Move the entry to the front if it exists */
6038 int sep,
6039 int writing) /* ignore entries read from viminfo */
6040 {
6041 int i;
6042 int last_i = -1;
6043 char_u *p;
6044
6045 if (hisidx[type] < 0)
6046 return FALSE;
6047 i = hisidx[type];
6048 do
6049 {
6050 if (history[type][i].hisstr == NULL)
6051 return FALSE;
6052
6053 /* For search history, check that the separator character matches as
6054 * well. */
6055 p = history[type][i].hisstr;
6056 if (STRCMP(str, p) == 0
6057 && !(writing && history[type][i].viminfo)
6058 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
6059 {
6060 if (!move_to_front)
6061 return TRUE;
6062 last_i = i;
6063 break;
6064 }
6065 if (--i < 0)
6066 i = hislen - 1;
6067 } while (i != hisidx[type]);
6068
6069 if (last_i >= 0)
6070 {
6071 str = history[type][i].hisstr;
6072 while (i != hisidx[type])
6073 {
6074 if (++i >= hislen)
6075 i = 0;
6076 history[type][last_i] = history[type][i];
6077 last_i = i;
6078 }
6079 history[type][i].hisnum = ++hisnum[type];
6080 history[type][i].viminfo = FALSE;
6081 history[type][i].hisstr = str;
6082 history[type][i].time_set = vim_time();
6083 return TRUE;
6084 }
6085 return FALSE;
6086 }
6087
6088 /*
6089 * Convert history name (from table above) to its HIST_ equivalent.
6090 * When "name" is empty, return "cmd" history.
6091 * Returns -1 for unknown history name.
6092 */
6093 int
6094 get_histtype(char_u *name)
6095 {
6096 int i;
6097 int len = (int)STRLEN(name);
6098
6099 /* No argument: use current history. */
6100 if (len == 0)
6101 return hist_char2type(ccline.cmdfirstc);
6102
6103 for (i = 0; history_names[i] != NULL; ++i)
6104 if (STRNICMP(name, history_names[i], len) == 0)
6105 return i;
6106
6107 if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
6108 return hist_char2type(name[0]);
6109
6110 return -1;
6111 }
6112
6113 static int last_maptick = -1; /* last seen maptick */
6114
6115 /*
6116 * Add the given string to the given history. If the string is already in the
6117 * history then it is moved to the front. "histype" may be one of he HIST_
6118 * values.
6119 */
6120 void
6121 add_to_history(
6122 int histype,
6123 char_u *new_entry,
6124 int in_map, /* consider maptick when inside a mapping */
6125 int sep) /* separator character used (search hist) */
6126 {
6127 histentry_T *hisptr;
6128 int len;
6129
6130 if (hislen == 0) /* no history */
6131 return;
6132
6133 if (cmdmod.keeppatterns && histype == HIST_SEARCH)
6134 return;
6135
6136 /*
6137 * Searches inside the same mapping overwrite each other, so that only
6138 * the last line is kept. Be careful not to remove a line that was moved
6139 * down, only lines that were added.
6140 */
6141 if (histype == HIST_SEARCH && in_map)
6142 {
6143 if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0)
6144 {
6145 /* Current line is from the same mapping, remove it */
6146 hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
6147 vim_free(hisptr->hisstr);
6148 clear_hist_entry(hisptr);
6149 --hisnum[histype];
6150 if (--hisidx[HIST_SEARCH] < 0)
6151 hisidx[HIST_SEARCH] = hislen - 1;
6152 }
6153 last_maptick = -1;
6154 }
6155 if (!in_history(histype, new_entry, TRUE, sep, FALSE))
6156 {
6157 if (++hisidx[histype] == hislen)
6158 hisidx[histype] = 0;
6159 hisptr = &history[histype][hisidx[histype]];
6160 vim_free(hisptr->hisstr);
6161
6162 /* Store the separator after the NUL of the string. */
6163 len = (int)STRLEN(new_entry);
6164 hisptr->hisstr = vim_strnsave(new_entry, len + 2);
6165 if (hisptr->hisstr != NULL)
6166 hisptr->hisstr[len + 1] = sep;
6167
6168 hisptr->hisnum = ++hisnum[histype];
6169 hisptr->viminfo = FALSE;
6170 hisptr->time_set = vim_time();
6171 if (histype == HIST_SEARCH && in_map)
6172 last_maptick = maptick;
6173 }
6174 }
6175
6176 #if defined(FEAT_EVAL) || defined(PROTO)
6177
6178 /*
6179 * Get identifier of newest history entry.
6180 * "histype" may be one of the HIST_ values.
6181 */
6182 int
6183 get_history_idx(int histype)
6184 {
6185 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
6186 || hisidx[histype] < 0)
6187 return -1;
6188
6189 return history[histype][hisidx[histype]].hisnum;
6190 }
6191
6192 /*
6193 * Calculate history index from a number:
6194 * num > 0: seen as identifying number of a history entry
6195 * num < 0: relative position in history wrt newest entry
6196 * "histype" may be one of the HIST_ values.
6197 */
6198 static int
6199 calc_hist_idx(int histype, int num)
6200 {
6201 int i;
6202 histentry_T *hist;
6203 int wrapped = FALSE;
6204
6205 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
6206 || (i = hisidx[histype]) < 0 || num == 0)
6207 return -1;
6208
6209 hist = history[histype];
6210 if (num > 0)
6211 {
6212 while (hist[i].hisnum > num)
6213 if (--i < 0)
6214 {
6215 if (wrapped)
6216 break;
6217 i += hislen;
6218 wrapped = TRUE;
6219 }
6220 if (hist[i].hisnum == num && hist[i].hisstr != NULL)
6221 return i;
6222 }
6223 else if (-num <= hislen)
6224 {
6225 i += num + 1;
6226 if (i < 0)
6227 i += hislen;
6228 if (hist[i].hisstr != NULL)
6229 return i;
6230 }
6231 return -1;
6232 }
6233
6234 /*
6235 * Get a history entry by its index.
6236 * "histype" may be one of the HIST_ values.
6237 */
6238 char_u *
6239 get_history_entry(int histype, int idx)
6240 {
6241 idx = calc_hist_idx(histype, idx);
6242 if (idx >= 0)
6243 return history[histype][idx].hisstr;
6244 else
6245 return (char_u *)"";
6246 }
6247
6248 /*
6249 * Clear all entries of a history.
6250 * "histype" may be one of the HIST_ values.
6251 */
6252 int
6253 clr_history(int histype)
6254 {
6255 int i;
6256 histentry_T *hisptr;
6257
6258 if (hislen != 0 && histype >= 0 && histype < HIST_COUNT)
6259 {
6260 hisptr = history[histype];
6261 for (i = hislen; i--;)
6262 {
6263 vim_free(hisptr->hisstr);
6264 clear_hist_entry(hisptr);
6265 hisptr++;
6266 }
6267 hisidx[histype] = -1; /* mark history as cleared */
6268 hisnum[histype] = 0; /* reset identifier counter */
6269 return OK;
6270 }
6271 return FAIL;
6272 }
6273
6274 /*
6275 * Remove all entries matching {str} from a history.
6276 * "histype" may be one of the HIST_ values.
6277 */
6278 int
6279 del_history_entry(int histype, char_u *str)
6280 {
6281 regmatch_T regmatch;
6282 histentry_T *hisptr;
6283 int idx;
6284 int i;
6285 int last;
6286 int found = FALSE;
6287
6288 regmatch.regprog = NULL;
6289 regmatch.rm_ic = FALSE; /* always match case */
6290 if (hislen != 0
6291 && histype >= 0
6292 && histype < HIST_COUNT
6293 && *str != NUL
6294 && (idx = hisidx[histype]) >= 0
6295 && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING))
6296 != NULL)
6297 {
6298 i = last = idx;
6299 do
6300 {
6301 hisptr = &history[histype][i];
6302 if (hisptr->hisstr == NULL)
6303 break;
6304 if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0))
6305 {
6306 found = TRUE;
6307 vim_free(hisptr->hisstr);
6308 clear_hist_entry(hisptr);
6309 }
6310 else
6311 {
6312 if (i != last)
6313 {
6314 history[histype][last] = *hisptr;
6315 clear_hist_entry(hisptr);
6316 }
6317 if (--last < 0)
6318 last += hislen;
6319 }
6320 if (--i < 0)
6321 i += hislen;
6322 } while (i != idx);
6323 if (history[histype][idx].hisstr == NULL)
6324 hisidx[histype] = -1;
6325 }
6326 vim_regfree(regmatch.regprog);
6327 return found;
6328 }
6329
6330 /*
6331 * Remove an indexed entry from a history.
6332 * "histype" may be one of the HIST_ values.
6333 */
6334 int
6335 del_history_idx(int histype, int idx)
6336 {
6337 int i, j;
6338
6339 i = calc_hist_idx(histype, idx);
6340 if (i < 0)
6341 return FALSE;
6342 idx = hisidx[histype];
6343 vim_free(history[histype][i].hisstr);
6344
6345 /* When deleting the last added search string in a mapping, reset
6346 * last_maptick, so that the last added search string isn't deleted again.
6347 */
6348 if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
6349 last_maptick = -1;
6350
6351 while (i != idx)
6352 {
6353 j = (i + 1) % hislen;
6354 history[histype][i] = history[histype][j];
6355 i = j;
6356 }
6357 clear_hist_entry(&history[histype][i]);
6358 if (--i < 0)
6359 i += hislen;
6360 hisidx[histype] = i;
6361 return TRUE;
6362 }
6363
6364 #endif /* FEAT_EVAL */
6365
6366 #if defined(FEAT_CRYPT) || defined(PROTO)
6367 /*
6368 * Very specific function to remove the value in ":set key=val" from the
6369 * history.
6370 */
6371 void
6372 remove_key_from_history(void)
6373 {
6374 char_u *p;
6375 int i;
6376
6377 i = hisidx[HIST_CMD];
6378 if (i < 0)
6379 return;
6380 p = history[HIST_CMD][i].hisstr;
6381 if (p != NULL)
6382 for ( ; *p; ++p)
6383 if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3]))
6384 {
6385 p = vim_strchr(p + 3, '=');
6386 if (p == NULL)
6387 break;
6388 ++p;
6389 for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i)
6390 if (p[i] == '\\' && p[i + 1])
6391 ++i;
6392 STRMOVE(p, p + i);
6393 --p;
6394 }
6395 }
6396 #endif
6397
6398 #endif /* FEAT_CMDHIST */
6399
6400 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO) 5851 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
6401 /* 5852 /*
6402 * Get pointer to the command line info to use. save_ccline() may clear 5853 * Get pointer to the command line info to use. save_ccline() may clear
6403 * ccline and put the previous value in prev_ccline. 5854 * ccline and put the previous value in prev_ccline.
6404 */ 5855 */
6496 '-'; 5947 '-';
6497 return p->cmdfirstc; 5948 return p->cmdfirstc;
6498 } 5949 }
6499 #endif 5950 #endif
6500 5951
6501 #if defined(FEAT_QUICKFIX) || defined(FEAT_CMDHIST) || defined(PROTO) 5952 /*
5953 * Return the first character of the current command line.
5954 */
5955 int
5956 get_cmdline_firstc(void)
5957 {
5958 return ccline.cmdfirstc;
5959 }
5960
6502 /* 5961 /*
6503 * Get indices "num1,num2" that specify a range within a list (not a range of 5962 * Get indices "num1,num2" that specify a range within a list (not a range of
6504 * text lines in a buffer!) from a string. Used for ":history" and ":clist". 5963 * text lines in a buffer!) from a string. Used for ":history" and ":clist".
6505 * Returns OK if parsed successfully, otherwise FAIL. 5964 * Returns OK if parsed successfully, otherwise FAIL.
6506 */ 5965 */
6534 } 5993 }
6535 else if (first) /* only one number given */ 5994 else if (first) /* only one number given */
6536 *num2 = *num1; 5995 *num2 = *num1;
6537 return OK; 5996 return OK;
6538 } 5997 }
6539 #endif
6540
6541 #if defined(FEAT_CMDHIST) || defined(PROTO)
6542 /*
6543 * :history command - print a history
6544 */
6545 void
6546 ex_history(exarg_T *eap)
6547 {
6548 histentry_T *hist;
6549 int histype1 = HIST_CMD;
6550 int histype2 = HIST_CMD;
6551 int hisidx1 = 1;
6552 int hisidx2 = -1;
6553 int idx;
6554 int i, j, k;
6555 char_u *end;
6556 char_u *arg = eap->arg;
6557
6558 if (hislen == 0)
6559 {
6560 msg(_("'history' option is zero"));
6561 return;
6562 }
6563
6564 if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ','))
6565 {
6566 end = arg;
6567 while (ASCII_ISALPHA(*end)
6568 || vim_strchr((char_u *)":=@>/?", *end) != NULL)
6569 end++;
6570 i = *end;
6571 *end = NUL;
6572 histype1 = get_histtype(arg);
6573 if (histype1 == -1)
6574 {
6575 if (STRNICMP(arg, "all", STRLEN(arg)) == 0)
6576 {
6577 histype1 = 0;
6578 histype2 = HIST_COUNT-1;
6579 }
6580 else
6581 {
6582 *end = i;
6583 emsg(_(e_trailing));
6584 return;
6585 }
6586 }
6587 else
6588 histype2 = histype1;
6589 *end = i;
6590 }
6591 else
6592 end = arg;
6593 if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL)
6594 {
6595 emsg(_(e_trailing));
6596 return;
6597 }
6598
6599 for (; !got_int && histype1 <= histype2; ++histype1)
6600 {
6601 STRCPY(IObuff, "\n # ");
6602 STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
6603 msg_puts_title((char *)IObuff);
6604 idx = hisidx[histype1];
6605 hist = history[histype1];
6606 j = hisidx1;
6607 k = hisidx2;
6608 if (j < 0)
6609 j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
6610 if (k < 0)
6611 k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
6612 if (idx >= 0 && j <= k)
6613 for (i = idx + 1; !got_int; ++i)
6614 {
6615 if (i == hislen)
6616 i = 0;
6617 if (hist[i].hisstr != NULL
6618 && hist[i].hisnum >= j && hist[i].hisnum <= k)
6619 {
6620 msg_putchar('\n');
6621 sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ',
6622 hist[i].hisnum);
6623 if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
6624 trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
6625 (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff));
6626 else
6627 STRCAT(IObuff, hist[i].hisstr);
6628 msg_outtrans(IObuff);
6629 out_flush();
6630 }
6631 if (i == idx)
6632 break;
6633 }
6634 }
6635 }
6636 #endif
6637
6638 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
6639 int
6640 get_hislen(void)
6641 {
6642 return hislen;
6643 }
6644
6645 histentry_T *
6646 get_histentry(int hist_type)
6647 {
6648 return history[hist_type];
6649 }
6650
6651 void
6652 set_histentry(int hist_type, histentry_T *entry)
6653 {
6654 history[hist_type] = entry;
6655 }
6656
6657 int *
6658 get_hisidx(int hist_type)
6659 {
6660 return &hisidx[hist_type];
6661 }
6662
6663 int *
6664 get_hisnum(int hist_type)
6665 {
6666 return &hisnum[hist_type];
6667 }
6668 #endif
6669 5998
6670 #if defined(FEAT_CMDWIN) || defined(PROTO) 5999 #if defined(FEAT_CMDWIN) || defined(PROTO)
6671 /* 6000 /*
6672 * Open a window on the current command line and history. Allow editing in 6001 * Open a window on the current command line and history. Allow editing in
6673 * the window. Returns when the window is closed. 6002 * the window. Returns when the window is closed.
6772 * sets 'textwidth' to 78). */ 6101 * sets 'textwidth' to 78). */
6773 curbuf->b_p_tw = 0; 6102 curbuf->b_p_tw = 0;
6774 6103
6775 /* Fill the buffer with the history. */ 6104 /* Fill the buffer with the history. */
6776 init_history(); 6105 init_history();
6777 if (hislen > 0) 6106 if (get_hislen() > 0)
6778 { 6107 {
6779 i = hisidx[histtype]; 6108 i = *get_hisidx(histtype);
6780 if (i >= 0) 6109 if (i >= 0)
6781 { 6110 {
6782 lnum = 0; 6111 lnum = 0;
6783 do 6112 do
6784 { 6113 {
6785 if (++i == hislen) 6114 if (++i == get_hislen())
6786 i = 0; 6115 i = 0;
6787 if (history[histtype][i].hisstr != NULL) 6116 if (get_histentry(histtype)[i].hisstr != NULL)
6788 ml_append(lnum++, history[histtype][i].hisstr, 6117 ml_append(lnum++, get_histentry(histtype)[i].hisstr,
6789 (colnr_T)0, FALSE); 6118 (colnr_T)0, FALSE);
6790 } 6119 }
6791 while (i != hisidx[histtype]); 6120 while (i != *get_hisidx(histtype));
6792 } 6121 }
6793 } 6122 }
6794 6123
6795 /* Replace the empty last line with the current command-line and put the 6124 /* Replace the empty last line with the current command-line and put the
6796 * cursor there. */ 6125 * cursor there. */