xref: /vim-8.2.3635/src/cmdhist.c (revision 4490ec4e)
1d7663c22SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2d7663c22SBram Moolenaar  *
3d7663c22SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4d7663c22SBram Moolenaar  *
5d7663c22SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6d7663c22SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7d7663c22SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8d7663c22SBram Moolenaar  */
9d7663c22SBram Moolenaar 
10d7663c22SBram Moolenaar /*
11d7663c22SBram Moolenaar  * cmdhist.c: Functions for the history of the command-line.
12d7663c22SBram Moolenaar  */
13d7663c22SBram Moolenaar 
14d7663c22SBram Moolenaar #include "vim.h"
15d7663c22SBram Moolenaar 
16d7663c22SBram Moolenaar static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
17d7663c22SBram Moolenaar static int	hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1};  // lastused entry
18d7663c22SBram Moolenaar static int	hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
19d7663c22SBram Moolenaar 		    // identifying (unique) number of newest history entry
20d7663c22SBram Moolenaar static int	hislen = 0;		// actual length of history tables
21d7663c22SBram Moolenaar 
22d7663c22SBram Moolenaar /*
23d7663c22SBram Moolenaar  * Return the length of the history tables
24d7663c22SBram Moolenaar  */
25d7663c22SBram Moolenaar     int
get_hislen(void)26d7663c22SBram Moolenaar get_hislen(void)
27d7663c22SBram Moolenaar {
28d7663c22SBram Moolenaar     return hislen;
29d7663c22SBram Moolenaar }
30d7663c22SBram Moolenaar 
31d7663c22SBram Moolenaar /*
32d7663c22SBram Moolenaar  * Return a pointer to a specified history table
33d7663c22SBram Moolenaar  */
34d7663c22SBram Moolenaar     histentry_T *
get_histentry(int hist_type)35d7663c22SBram Moolenaar get_histentry(int hist_type)
36d7663c22SBram Moolenaar {
37d7663c22SBram Moolenaar     return history[hist_type];
38d7663c22SBram Moolenaar }
39d7663c22SBram Moolenaar 
40d7663c22SBram Moolenaar     void
set_histentry(int hist_type,histentry_T * entry)41d7663c22SBram Moolenaar set_histentry(int hist_type, histentry_T *entry)
42d7663c22SBram Moolenaar {
43d7663c22SBram Moolenaar     history[hist_type] = entry;
44d7663c22SBram Moolenaar }
45d7663c22SBram Moolenaar 
46d7663c22SBram Moolenaar     int *
get_hisidx(int hist_type)47d7663c22SBram Moolenaar get_hisidx(int hist_type)
48d7663c22SBram Moolenaar {
49d7663c22SBram Moolenaar     return &hisidx[hist_type];
50d7663c22SBram Moolenaar }
51d7663c22SBram Moolenaar 
52d7663c22SBram Moolenaar     int *
get_hisnum(int hist_type)53d7663c22SBram Moolenaar get_hisnum(int hist_type)
54d7663c22SBram Moolenaar {
55d7663c22SBram Moolenaar     return &hisnum[hist_type];
56d7663c22SBram Moolenaar }
57d7663c22SBram Moolenaar 
58d7663c22SBram Moolenaar /*
59d7663c22SBram Moolenaar  * Translate a history character to the associated type number.
60d7663c22SBram Moolenaar  */
61d7663c22SBram Moolenaar     int
hist_char2type(int c)62d7663c22SBram Moolenaar hist_char2type(int c)
63d7663c22SBram Moolenaar {
64d7663c22SBram Moolenaar     if (c == ':')
65d7663c22SBram Moolenaar 	return HIST_CMD;
66d7663c22SBram Moolenaar     if (c == '=')
67d7663c22SBram Moolenaar 	return HIST_EXPR;
68d7663c22SBram Moolenaar     if (c == '@')
69d7663c22SBram Moolenaar 	return HIST_INPUT;
70d7663c22SBram Moolenaar     if (c == '>')
71d7663c22SBram Moolenaar 	return HIST_DEBUG;
72d7663c22SBram Moolenaar     return HIST_SEARCH;	    // must be '?' or '/'
73d7663c22SBram Moolenaar }
74d7663c22SBram Moolenaar 
75d7663c22SBram Moolenaar /*
76d7663c22SBram Moolenaar  * Table of history names.
77d7663c22SBram Moolenaar  * These names are used in :history and various hist...() functions.
78d7663c22SBram Moolenaar  * It is sufficient to give the significant prefix of a history name.
79d7663c22SBram Moolenaar  */
80d7663c22SBram Moolenaar 
81d7663c22SBram Moolenaar static char *(history_names[]) =
82d7663c22SBram Moolenaar {
83d7663c22SBram Moolenaar     "cmd",
84d7663c22SBram Moolenaar     "search",
85d7663c22SBram Moolenaar     "expr",
86d7663c22SBram Moolenaar     "input",
87d7663c22SBram Moolenaar     "debug",
88d7663c22SBram Moolenaar     NULL
89d7663c22SBram Moolenaar };
90d7663c22SBram Moolenaar 
91d7663c22SBram Moolenaar /*
92d7663c22SBram Moolenaar  * Function given to ExpandGeneric() to obtain the possible first
93d7663c22SBram Moolenaar  * arguments of the ":history command.
94d7663c22SBram Moolenaar  */
95d7663c22SBram Moolenaar     char_u *
get_history_arg(expand_T * xp UNUSED,int idx)96d7663c22SBram Moolenaar get_history_arg(expand_T *xp UNUSED, int idx)
97d7663c22SBram Moolenaar {
98d7663c22SBram Moolenaar     static char_u compl[2] = { NUL, NUL };
99d7663c22SBram Moolenaar     char *short_names = ":=@>?/";
100d7663c22SBram Moolenaar     int short_names_count = (int)STRLEN(short_names);
101eeec2548SK.Takata     int history_name_count = ARRAY_LENGTH(history_names) - 1;
102d7663c22SBram Moolenaar 
103d7663c22SBram Moolenaar     if (idx < short_names_count)
104d7663c22SBram Moolenaar     {
105d7663c22SBram Moolenaar 	compl[0] = (char_u)short_names[idx];
106d7663c22SBram Moolenaar 	return compl;
107d7663c22SBram Moolenaar     }
108d7663c22SBram Moolenaar     if (idx < short_names_count + history_name_count)
109d7663c22SBram Moolenaar 	return (char_u *)history_names[idx - short_names_count];
110d7663c22SBram Moolenaar     if (idx == short_names_count + history_name_count)
111d7663c22SBram Moolenaar 	return (char_u *)"all";
112d7663c22SBram Moolenaar     return NULL;
113d7663c22SBram Moolenaar }
114d7663c22SBram Moolenaar 
115d7663c22SBram Moolenaar /*
116d7663c22SBram Moolenaar  * init_history() - Initialize the command line history.
117d7663c22SBram Moolenaar  * Also used to re-allocate the history when the size changes.
118d7663c22SBram Moolenaar  */
119d7663c22SBram Moolenaar     void
init_history(void)120d7663c22SBram Moolenaar init_history(void)
121d7663c22SBram Moolenaar {
122d7663c22SBram Moolenaar     int		newlen;	    // new length of history table
123d7663c22SBram Moolenaar     histentry_T	*temp;
124d7663c22SBram Moolenaar     int		i;
125d7663c22SBram Moolenaar     int		j;
126d7663c22SBram Moolenaar     int		type;
127d7663c22SBram Moolenaar 
128d7663c22SBram Moolenaar     // If size of history table changed, reallocate it
129d7663c22SBram Moolenaar     newlen = (int)p_hi;
130d7663c22SBram Moolenaar     if (newlen != hislen)			// history length changed
131d7663c22SBram Moolenaar     {
132d7663c22SBram Moolenaar 	for (type = 0; type < HIST_COUNT; ++type)   // adjust the tables
133d7663c22SBram Moolenaar 	{
134d7663c22SBram Moolenaar 	    if (newlen)
135d7663c22SBram Moolenaar 	    {
136d7663c22SBram Moolenaar 		temp = ALLOC_MULT(histentry_T, newlen);
137d7663c22SBram Moolenaar 		if (temp == NULL)   // out of memory!
138d7663c22SBram Moolenaar 		{
139d7663c22SBram Moolenaar 		    if (type == 0)  // first one: just keep the old length
140d7663c22SBram Moolenaar 		    {
141d7663c22SBram Moolenaar 			newlen = hislen;
142d7663c22SBram Moolenaar 			break;
143d7663c22SBram Moolenaar 		    }
144d7663c22SBram Moolenaar 		    // Already changed one table, now we can only have zero
145d7663c22SBram Moolenaar 		    // length for all tables.
146d7663c22SBram Moolenaar 		    newlen = 0;
147d7663c22SBram Moolenaar 		    type = -1;
148d7663c22SBram Moolenaar 		    continue;
149d7663c22SBram Moolenaar 		}
150d7663c22SBram Moolenaar 	    }
151d7663c22SBram Moolenaar 	    else
152d7663c22SBram Moolenaar 		temp = NULL;
153d7663c22SBram Moolenaar 	    if (newlen == 0 || temp != NULL)
154d7663c22SBram Moolenaar 	    {
155d7663c22SBram Moolenaar 		if (hisidx[type] < 0)		// there are no entries yet
156d7663c22SBram Moolenaar 		{
157d7663c22SBram Moolenaar 		    for (i = 0; i < newlen; ++i)
158d7663c22SBram Moolenaar 			clear_hist_entry(&temp[i]);
159d7663c22SBram Moolenaar 		}
160d7663c22SBram Moolenaar 		else if (newlen > hislen)	// array becomes bigger
161d7663c22SBram Moolenaar 		{
162d7663c22SBram Moolenaar 		    for (i = 0; i <= hisidx[type]; ++i)
163d7663c22SBram Moolenaar 			temp[i] = history[type][i];
164d7663c22SBram Moolenaar 		    j = i;
165d7663c22SBram Moolenaar 		    for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
166d7663c22SBram Moolenaar 			clear_hist_entry(&temp[i]);
167d7663c22SBram Moolenaar 		    for ( ; j < hislen; ++i, ++j)
168d7663c22SBram Moolenaar 			temp[i] = history[type][j];
169d7663c22SBram Moolenaar 		}
170d7663c22SBram Moolenaar 		else				// array becomes smaller or 0
171d7663c22SBram Moolenaar 		{
172d7663c22SBram Moolenaar 		    j = hisidx[type];
173d7663c22SBram Moolenaar 		    for (i = newlen - 1; ; --i)
174d7663c22SBram Moolenaar 		    {
175d7663c22SBram Moolenaar 			if (i >= 0)		// copy newest entries
176d7663c22SBram Moolenaar 			    temp[i] = history[type][j];
177d7663c22SBram Moolenaar 			else			// remove older entries
178d7663c22SBram Moolenaar 			    vim_free(history[type][j].hisstr);
179d7663c22SBram Moolenaar 			if (--j < 0)
180d7663c22SBram Moolenaar 			    j = hislen - 1;
181d7663c22SBram Moolenaar 			if (j == hisidx[type])
182d7663c22SBram Moolenaar 			    break;
183d7663c22SBram Moolenaar 		    }
184d7663c22SBram Moolenaar 		    hisidx[type] = newlen - 1;
185d7663c22SBram Moolenaar 		}
186d7663c22SBram Moolenaar 		vim_free(history[type]);
187d7663c22SBram Moolenaar 		history[type] = temp;
188d7663c22SBram Moolenaar 	    }
189d7663c22SBram Moolenaar 	}
190d7663c22SBram Moolenaar 	hislen = newlen;
191d7663c22SBram Moolenaar     }
192d7663c22SBram Moolenaar }
193d7663c22SBram Moolenaar 
194d7663c22SBram Moolenaar     void
clear_hist_entry(histentry_T * hisptr)195d7663c22SBram Moolenaar clear_hist_entry(histentry_T *hisptr)
196d7663c22SBram Moolenaar {
197d7663c22SBram Moolenaar     hisptr->hisnum = 0;
198d7663c22SBram Moolenaar     hisptr->viminfo = FALSE;
199d7663c22SBram Moolenaar     hisptr->hisstr = NULL;
200d7663c22SBram Moolenaar     hisptr->time_set = 0;
201d7663c22SBram Moolenaar }
202d7663c22SBram Moolenaar 
203d7663c22SBram Moolenaar /*
204d7663c22SBram Moolenaar  * Check if command line 'str' is already in history.
205d7663c22SBram Moolenaar  * If 'move_to_front' is TRUE, matching entry is moved to end of history.
206d7663c22SBram Moolenaar  */
207d7663c22SBram Moolenaar     int
in_history(int type,char_u * str,int move_to_front,int sep,int writing)208d7663c22SBram Moolenaar in_history(
209d7663c22SBram Moolenaar     int	    type,
210d7663c22SBram Moolenaar     char_u  *str,
211d7663c22SBram Moolenaar     int	    move_to_front,	// Move the entry to the front if it exists
212d7663c22SBram Moolenaar     int	    sep,
213d7663c22SBram Moolenaar     int	    writing)		// ignore entries read from viminfo
214d7663c22SBram Moolenaar {
215d7663c22SBram Moolenaar     int	    i;
216d7663c22SBram Moolenaar     int	    last_i = -1;
217d7663c22SBram Moolenaar     char_u  *p;
218d7663c22SBram Moolenaar 
219d7663c22SBram Moolenaar     if (hisidx[type] < 0)
220d7663c22SBram Moolenaar 	return FALSE;
221d7663c22SBram Moolenaar     i = hisidx[type];
222d7663c22SBram Moolenaar     do
223d7663c22SBram Moolenaar     {
224d7663c22SBram Moolenaar 	if (history[type][i].hisstr == NULL)
225d7663c22SBram Moolenaar 	    return FALSE;
226d7663c22SBram Moolenaar 
227d7663c22SBram Moolenaar 	// For search history, check that the separator character matches as
228d7663c22SBram Moolenaar 	// well.
229d7663c22SBram Moolenaar 	p = history[type][i].hisstr;
230d7663c22SBram Moolenaar 	if (STRCMP(str, p) == 0
231d7663c22SBram Moolenaar 		&& !(writing && history[type][i].viminfo)
232d7663c22SBram Moolenaar 		&& (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
233d7663c22SBram Moolenaar 	{
234d7663c22SBram Moolenaar 	    if (!move_to_front)
235d7663c22SBram Moolenaar 		return TRUE;
236d7663c22SBram Moolenaar 	    last_i = i;
237d7663c22SBram Moolenaar 	    break;
238d7663c22SBram Moolenaar 	}
239d7663c22SBram Moolenaar 	if (--i < 0)
240d7663c22SBram Moolenaar 	    i = hislen - 1;
241d7663c22SBram Moolenaar     } while (i != hisidx[type]);
242d7663c22SBram Moolenaar 
243d7663c22SBram Moolenaar     if (last_i >= 0)
244d7663c22SBram Moolenaar     {
245d7663c22SBram Moolenaar 	str = history[type][i].hisstr;
246d7663c22SBram Moolenaar 	while (i != hisidx[type])
247d7663c22SBram Moolenaar 	{
248d7663c22SBram Moolenaar 	    if (++i >= hislen)
249d7663c22SBram Moolenaar 		i = 0;
250d7663c22SBram Moolenaar 	    history[type][last_i] = history[type][i];
251d7663c22SBram Moolenaar 	    last_i = i;
252d7663c22SBram Moolenaar 	}
253d7663c22SBram Moolenaar 	history[type][i].hisnum = ++hisnum[type];
254d7663c22SBram Moolenaar 	history[type][i].viminfo = FALSE;
255d7663c22SBram Moolenaar 	history[type][i].hisstr = str;
256d7663c22SBram Moolenaar 	history[type][i].time_set = vim_time();
257d7663c22SBram Moolenaar 	return TRUE;
258d7663c22SBram Moolenaar     }
259d7663c22SBram Moolenaar     return FALSE;
260d7663c22SBram Moolenaar }
261d7663c22SBram Moolenaar 
262d7663c22SBram Moolenaar /*
263d7663c22SBram Moolenaar  * Convert history name (from table above) to its HIST_ equivalent.
264d7663c22SBram Moolenaar  * When "name" is empty, return "cmd" history.
265d7663c22SBram Moolenaar  * Returns -1 for unknown history name.
266d7663c22SBram Moolenaar  */
267d7663c22SBram Moolenaar     static int
get_histtype(char_u * name)268d7663c22SBram Moolenaar get_histtype(char_u *name)
269d7663c22SBram Moolenaar {
270d7663c22SBram Moolenaar     int		i;
271d7663c22SBram Moolenaar     int		len = (int)STRLEN(name);
272d7663c22SBram Moolenaar 
273d7663c22SBram Moolenaar     // No argument: use current history.
274d7663c22SBram Moolenaar     if (len == 0)
275d7663c22SBram Moolenaar 	return hist_char2type(get_cmdline_firstc());
276d7663c22SBram Moolenaar 
277d7663c22SBram Moolenaar     for (i = 0; history_names[i] != NULL; ++i)
278d7663c22SBram Moolenaar 	if (STRNICMP(name, history_names[i], len) == 0)
279d7663c22SBram Moolenaar 	    return i;
280d7663c22SBram Moolenaar 
281d7663c22SBram Moolenaar     if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
282d7663c22SBram Moolenaar 	return hist_char2type(name[0]);
283d7663c22SBram Moolenaar 
284d7663c22SBram Moolenaar     return -1;
285d7663c22SBram Moolenaar }
286d7663c22SBram Moolenaar 
287d7663c22SBram Moolenaar static int	last_maptick = -1;	// last seen maptick
288d7663c22SBram Moolenaar 
289d7663c22SBram Moolenaar /*
290d7663c22SBram Moolenaar  * Add the given string to the given history.  If the string is already in the
291d7663c22SBram Moolenaar  * history then it is moved to the front.  "histype" may be one of he HIST_
292d7663c22SBram Moolenaar  * values.
293d7663c22SBram Moolenaar  */
294d7663c22SBram Moolenaar     void
add_to_history(int histype,char_u * new_entry,int in_map,int sep)295d7663c22SBram Moolenaar add_to_history(
296d7663c22SBram Moolenaar     int		histype,
297d7663c22SBram Moolenaar     char_u	*new_entry,
298d7663c22SBram Moolenaar     int		in_map,		// consider maptick when inside a mapping
299d7663c22SBram Moolenaar     int		sep)		// separator character used (search hist)
300d7663c22SBram Moolenaar {
301d7663c22SBram Moolenaar     histentry_T	*hisptr;
302d7663c22SBram Moolenaar     int		len;
303d7663c22SBram Moolenaar 
304d7663c22SBram Moolenaar     if (hislen == 0)		// no history
305d7663c22SBram Moolenaar 	return;
306d7663c22SBram Moolenaar 
307e1004401SBram Moolenaar     if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) && histype == HIST_SEARCH)
308d7663c22SBram Moolenaar 	return;
309d7663c22SBram Moolenaar 
310d7663c22SBram Moolenaar     // Searches inside the same mapping overwrite each other, so that only
311d7663c22SBram Moolenaar     // the last line is kept.  Be careful not to remove a line that was moved
312d7663c22SBram Moolenaar     // down, only lines that were added.
313d7663c22SBram Moolenaar     if (histype == HIST_SEARCH && in_map)
314d7663c22SBram Moolenaar     {
315d7663c22SBram Moolenaar 	if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0)
316d7663c22SBram Moolenaar 	{
317d7663c22SBram Moolenaar 	    // Current line is from the same mapping, remove it
318d7663c22SBram Moolenaar 	    hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
319d7663c22SBram Moolenaar 	    vim_free(hisptr->hisstr);
320d7663c22SBram Moolenaar 	    clear_hist_entry(hisptr);
321d7663c22SBram Moolenaar 	    --hisnum[histype];
322d7663c22SBram Moolenaar 	    if (--hisidx[HIST_SEARCH] < 0)
323d7663c22SBram Moolenaar 		hisidx[HIST_SEARCH] = hislen - 1;
324d7663c22SBram Moolenaar 	}
325d7663c22SBram Moolenaar 	last_maptick = -1;
326d7663c22SBram Moolenaar     }
327d7663c22SBram Moolenaar     if (!in_history(histype, new_entry, TRUE, sep, FALSE))
328d7663c22SBram Moolenaar     {
329d7663c22SBram Moolenaar 	if (++hisidx[histype] == hislen)
330d7663c22SBram Moolenaar 	    hisidx[histype] = 0;
331d7663c22SBram Moolenaar 	hisptr = &history[histype][hisidx[histype]];
332d7663c22SBram Moolenaar 	vim_free(hisptr->hisstr);
333d7663c22SBram Moolenaar 
334d7663c22SBram Moolenaar 	// Store the separator after the NUL of the string.
335d7663c22SBram Moolenaar 	len = (int)STRLEN(new_entry);
336d7663c22SBram Moolenaar 	hisptr->hisstr = vim_strnsave(new_entry, len + 2);
337d7663c22SBram Moolenaar 	if (hisptr->hisstr != NULL)
338d7663c22SBram Moolenaar 	    hisptr->hisstr[len + 1] = sep;
339d7663c22SBram Moolenaar 
340d7663c22SBram Moolenaar 	hisptr->hisnum = ++hisnum[histype];
341d7663c22SBram Moolenaar 	hisptr->viminfo = FALSE;
342d7663c22SBram Moolenaar 	hisptr->time_set = vim_time();
343d7663c22SBram Moolenaar 	if (histype == HIST_SEARCH && in_map)
344d7663c22SBram Moolenaar 	    last_maptick = maptick;
345d7663c22SBram Moolenaar     }
346d7663c22SBram Moolenaar }
347d7663c22SBram Moolenaar 
348d7663c22SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
349d7663c22SBram Moolenaar 
350d7663c22SBram Moolenaar /*
351d7663c22SBram Moolenaar  * Get identifier of newest history entry.
352d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
353d7663c22SBram Moolenaar  */
354d7663c22SBram Moolenaar     static int
get_history_idx(int histype)355d7663c22SBram Moolenaar get_history_idx(int histype)
356d7663c22SBram Moolenaar {
357d7663c22SBram Moolenaar     if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
358d7663c22SBram Moolenaar 		    || hisidx[histype] < 0)
359d7663c22SBram Moolenaar 	return -1;
360d7663c22SBram Moolenaar 
361d7663c22SBram Moolenaar     return history[histype][hisidx[histype]].hisnum;
362d7663c22SBram Moolenaar }
363d7663c22SBram Moolenaar 
364d7663c22SBram Moolenaar /*
365d7663c22SBram Moolenaar  * Calculate history index from a number:
366d7663c22SBram Moolenaar  *   num > 0: seen as identifying number of a history entry
367d7663c22SBram Moolenaar  *   num < 0: relative position in history wrt newest entry
368d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
369d7663c22SBram Moolenaar  */
370d7663c22SBram Moolenaar     static int
calc_hist_idx(int histype,int num)371d7663c22SBram Moolenaar calc_hist_idx(int histype, int num)
372d7663c22SBram Moolenaar {
373d7663c22SBram Moolenaar     int		i;
374d7663c22SBram Moolenaar     histentry_T	*hist;
375d7663c22SBram Moolenaar     int		wrapped = FALSE;
376d7663c22SBram Moolenaar 
377d7663c22SBram Moolenaar     if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
378d7663c22SBram Moolenaar 		    || (i = hisidx[histype]) < 0 || num == 0)
379d7663c22SBram Moolenaar 	return -1;
380d7663c22SBram Moolenaar 
381d7663c22SBram Moolenaar     hist = history[histype];
382d7663c22SBram Moolenaar     if (num > 0)
383d7663c22SBram Moolenaar     {
384d7663c22SBram Moolenaar 	while (hist[i].hisnum > num)
385d7663c22SBram Moolenaar 	    if (--i < 0)
386d7663c22SBram Moolenaar 	    {
387d7663c22SBram Moolenaar 		if (wrapped)
388d7663c22SBram Moolenaar 		    break;
389d7663c22SBram Moolenaar 		i += hislen;
390d7663c22SBram Moolenaar 		wrapped = TRUE;
391d7663c22SBram Moolenaar 	    }
3928d588cceSBram Moolenaar 	if (i >= 0 && hist[i].hisnum == num && hist[i].hisstr != NULL)
393d7663c22SBram Moolenaar 	    return i;
394d7663c22SBram Moolenaar     }
395d7663c22SBram Moolenaar     else if (-num <= hislen)
396d7663c22SBram Moolenaar     {
397d7663c22SBram Moolenaar 	i += num + 1;
398d7663c22SBram Moolenaar 	if (i < 0)
399d7663c22SBram Moolenaar 	    i += hislen;
400d7663c22SBram Moolenaar 	if (hist[i].hisstr != NULL)
401d7663c22SBram Moolenaar 	    return i;
402d7663c22SBram Moolenaar     }
403d7663c22SBram Moolenaar     return -1;
404d7663c22SBram Moolenaar }
405d7663c22SBram Moolenaar 
406d7663c22SBram Moolenaar /*
407d7663c22SBram Moolenaar  * Get a history entry by its index.
408d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
409d7663c22SBram Moolenaar  */
410d7663c22SBram Moolenaar     static char_u *
get_history_entry(int histype,int idx)411d7663c22SBram Moolenaar get_history_entry(int histype, int idx)
412d7663c22SBram Moolenaar {
413d7663c22SBram Moolenaar     idx = calc_hist_idx(histype, idx);
414d7663c22SBram Moolenaar     if (idx >= 0)
415d7663c22SBram Moolenaar 	return history[histype][idx].hisstr;
416d7663c22SBram Moolenaar     else
417d7663c22SBram Moolenaar 	return (char_u *)"";
418d7663c22SBram Moolenaar }
419d7663c22SBram Moolenaar 
420d7663c22SBram Moolenaar /*
421d7663c22SBram Moolenaar  * Clear all entries of a history.
422d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
423d7663c22SBram Moolenaar  */
424d7663c22SBram Moolenaar     static int
clr_history(int histype)425d7663c22SBram Moolenaar clr_history(int histype)
426d7663c22SBram Moolenaar {
427d7663c22SBram Moolenaar     int		i;
428d7663c22SBram Moolenaar     histentry_T	*hisptr;
429d7663c22SBram Moolenaar 
430d7663c22SBram Moolenaar     if (hislen != 0 && histype >= 0 && histype < HIST_COUNT)
431d7663c22SBram Moolenaar     {
432d7663c22SBram Moolenaar 	hisptr = history[histype];
433d7663c22SBram Moolenaar 	for (i = hislen; i--;)
434d7663c22SBram Moolenaar 	{
435d7663c22SBram Moolenaar 	    vim_free(hisptr->hisstr);
436d7663c22SBram Moolenaar 	    clear_hist_entry(hisptr);
437d7663c22SBram Moolenaar 	    hisptr++;
438d7663c22SBram Moolenaar 	}
439d7663c22SBram Moolenaar 	hisidx[histype] = -1;	// mark history as cleared
440d7663c22SBram Moolenaar 	hisnum[histype] = 0;	// reset identifier counter
441d7663c22SBram Moolenaar 	return OK;
442d7663c22SBram Moolenaar     }
443d7663c22SBram Moolenaar     return FAIL;
444d7663c22SBram Moolenaar }
445d7663c22SBram Moolenaar 
446d7663c22SBram Moolenaar /*
447d7663c22SBram Moolenaar  * Remove all entries matching {str} from a history.
448d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
449d7663c22SBram Moolenaar  */
450d7663c22SBram Moolenaar     static int
del_history_entry(int histype,char_u * str)451d7663c22SBram Moolenaar del_history_entry(int histype, char_u *str)
452d7663c22SBram Moolenaar {
453d7663c22SBram Moolenaar     regmatch_T	regmatch;
454d7663c22SBram Moolenaar     histentry_T	*hisptr;
455d7663c22SBram Moolenaar     int		idx;
456d7663c22SBram Moolenaar     int		i;
457d7663c22SBram Moolenaar     int		last;
458d7663c22SBram Moolenaar     int		found = FALSE;
459d7663c22SBram Moolenaar 
460d7663c22SBram Moolenaar     regmatch.regprog = NULL;
461d7663c22SBram Moolenaar     regmatch.rm_ic = FALSE;	// always match case
462d7663c22SBram Moolenaar     if (hislen != 0
463d7663c22SBram Moolenaar 	    && histype >= 0
464d7663c22SBram Moolenaar 	    && histype < HIST_COUNT
465d7663c22SBram Moolenaar 	    && *str != NUL
466d7663c22SBram Moolenaar 	    && (idx = hisidx[histype]) >= 0
467d7663c22SBram Moolenaar 	    && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING))
468d7663c22SBram Moolenaar 								      != NULL)
469d7663c22SBram Moolenaar     {
470d7663c22SBram Moolenaar 	i = last = idx;
471d7663c22SBram Moolenaar 	do
472d7663c22SBram Moolenaar 	{
473d7663c22SBram Moolenaar 	    hisptr = &history[histype][i];
474d7663c22SBram Moolenaar 	    if (hisptr->hisstr == NULL)
475d7663c22SBram Moolenaar 		break;
476d7663c22SBram Moolenaar 	    if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0))
477d7663c22SBram Moolenaar 	    {
478d7663c22SBram Moolenaar 		found = TRUE;
479d7663c22SBram Moolenaar 		vim_free(hisptr->hisstr);
480d7663c22SBram Moolenaar 		clear_hist_entry(hisptr);
481d7663c22SBram Moolenaar 	    }
482d7663c22SBram Moolenaar 	    else
483d7663c22SBram Moolenaar 	    {
484d7663c22SBram Moolenaar 		if (i != last)
485d7663c22SBram Moolenaar 		{
486d7663c22SBram Moolenaar 		    history[histype][last] = *hisptr;
487d7663c22SBram Moolenaar 		    clear_hist_entry(hisptr);
488d7663c22SBram Moolenaar 		}
489d7663c22SBram Moolenaar 		if (--last < 0)
490d7663c22SBram Moolenaar 		    last += hislen;
491d7663c22SBram Moolenaar 	    }
492d7663c22SBram Moolenaar 	    if (--i < 0)
493d7663c22SBram Moolenaar 		i += hislen;
494d7663c22SBram Moolenaar 	} while (i != idx);
495d7663c22SBram Moolenaar 	if (history[histype][idx].hisstr == NULL)
496d7663c22SBram Moolenaar 	    hisidx[histype] = -1;
497d7663c22SBram Moolenaar     }
498d7663c22SBram Moolenaar     vim_regfree(regmatch.regprog);
499d7663c22SBram Moolenaar     return found;
500d7663c22SBram Moolenaar }
501d7663c22SBram Moolenaar 
502d7663c22SBram Moolenaar /*
503d7663c22SBram Moolenaar  * Remove an indexed entry from a history.
504d7663c22SBram Moolenaar  * "histype" may be one of the HIST_ values.
505d7663c22SBram Moolenaar  */
506d7663c22SBram Moolenaar     static int
del_history_idx(int histype,int idx)507d7663c22SBram Moolenaar del_history_idx(int histype, int idx)
508d7663c22SBram Moolenaar {
509d7663c22SBram Moolenaar     int	    i, j;
510d7663c22SBram Moolenaar 
511d7663c22SBram Moolenaar     i = calc_hist_idx(histype, idx);
512d7663c22SBram Moolenaar     if (i < 0)
513d7663c22SBram Moolenaar 	return FALSE;
514d7663c22SBram Moolenaar     idx = hisidx[histype];
515d7663c22SBram Moolenaar     vim_free(history[histype][i].hisstr);
516d7663c22SBram Moolenaar 
517d7663c22SBram Moolenaar     // When deleting the last added search string in a mapping, reset
518d7663c22SBram Moolenaar     // last_maptick, so that the last added search string isn't deleted again.
519d7663c22SBram Moolenaar     if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
520d7663c22SBram Moolenaar 	last_maptick = -1;
521d7663c22SBram Moolenaar 
522d7663c22SBram Moolenaar     while (i != idx)
523d7663c22SBram Moolenaar     {
524d7663c22SBram Moolenaar 	j = (i + 1) % hislen;
525d7663c22SBram Moolenaar 	history[histype][i] = history[histype][j];
526d7663c22SBram Moolenaar 	i = j;
527d7663c22SBram Moolenaar     }
528d7663c22SBram Moolenaar     clear_hist_entry(&history[histype][i]);
529d7663c22SBram Moolenaar     if (--i < 0)
530d7663c22SBram Moolenaar 	i += hislen;
531d7663c22SBram Moolenaar     hisidx[histype] = i;
532d7663c22SBram Moolenaar     return TRUE;
533d7663c22SBram Moolenaar }
534d7663c22SBram Moolenaar 
535d7663c22SBram Moolenaar /*
536d7663c22SBram Moolenaar  * "histadd()" function
537d7663c22SBram Moolenaar  */
538d7663c22SBram Moolenaar     void
f_histadd(typval_T * argvars UNUSED,typval_T * rettv)539d7663c22SBram Moolenaar f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
540d7663c22SBram Moolenaar {
541d7663c22SBram Moolenaar     int		histype;
542d7663c22SBram Moolenaar     char_u	*str;
543d7663c22SBram Moolenaar     char_u	buf[NUMBUFLEN];
544d7663c22SBram Moolenaar 
545d7663c22SBram Moolenaar     rettv->vval.v_number = FALSE;
546d7663c22SBram Moolenaar     if (check_secure())
547d7663c22SBram Moolenaar 	return;
548*4490ec4eSYegappan Lakshmanan 
549*4490ec4eSYegappan Lakshmanan     if (in_vim9script()
550*4490ec4eSYegappan Lakshmanan 	    && (check_for_string_arg(argvars, 0) == FAIL
551*4490ec4eSYegappan Lakshmanan 		|| check_for_string_arg(argvars, 1) == FAIL))
552*4490ec4eSYegappan Lakshmanan 	return;
553*4490ec4eSYegappan Lakshmanan 
554d7663c22SBram Moolenaar     str = tv_get_string_chk(&argvars[0]);	// NULL on type error
555d7663c22SBram Moolenaar     histype = str != NULL ? get_histtype(str) : -1;
556d7663c22SBram Moolenaar     if (histype >= 0)
557d7663c22SBram Moolenaar     {
558d7663c22SBram Moolenaar 	str = tv_get_string_buf(&argvars[1], buf);
559d7663c22SBram Moolenaar 	if (*str != NUL)
560d7663c22SBram Moolenaar 	{
561d7663c22SBram Moolenaar 	    init_history();
562d7663c22SBram Moolenaar 	    add_to_history(histype, str, FALSE, NUL);
563d7663c22SBram Moolenaar 	    rettv->vval.v_number = TRUE;
564d7663c22SBram Moolenaar 	    return;
565d7663c22SBram Moolenaar 	}
566d7663c22SBram Moolenaar     }
567d7663c22SBram Moolenaar }
568d7663c22SBram Moolenaar 
569d7663c22SBram Moolenaar /*
570d7663c22SBram Moolenaar  * "histdel()" function
571d7663c22SBram Moolenaar  */
572d7663c22SBram Moolenaar     void
f_histdel(typval_T * argvars UNUSED,typval_T * rettv UNUSED)573d7663c22SBram Moolenaar f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
574d7663c22SBram Moolenaar {
575d7663c22SBram Moolenaar     int		n;
576d7663c22SBram Moolenaar     char_u	buf[NUMBUFLEN];
577d7663c22SBram Moolenaar     char_u	*str;
578d7663c22SBram Moolenaar 
5790ad871dcSYegappan Lakshmanan     if (in_vim9script()
5800ad871dcSYegappan Lakshmanan 	    && (check_for_string_arg(argvars, 0) == FAIL
5810ad871dcSYegappan Lakshmanan 		|| check_for_opt_string_or_number_arg(argvars, 1) == FAIL))
5820ad871dcSYegappan Lakshmanan 	return;
5830ad871dcSYegappan Lakshmanan 
584d7663c22SBram Moolenaar     str = tv_get_string_chk(&argvars[0]);	// NULL on type error
585d7663c22SBram Moolenaar     if (str == NULL)
586d7663c22SBram Moolenaar 	n = 0;
587d7663c22SBram Moolenaar     else if (argvars[1].v_type == VAR_UNKNOWN)
588d7663c22SBram Moolenaar 	// only one argument: clear entire history
589d7663c22SBram Moolenaar 	n = clr_history(get_histtype(str));
590d7663c22SBram Moolenaar     else if (argvars[1].v_type == VAR_NUMBER)
591d7663c22SBram Moolenaar 	// index given: remove that entry
592d7663c22SBram Moolenaar 	n = del_history_idx(get_histtype(str),
593d7663c22SBram Moolenaar 					  (int)tv_get_number(&argvars[1]));
594d7663c22SBram Moolenaar     else
595d7663c22SBram Moolenaar 	// string given: remove all matching entries
596d7663c22SBram Moolenaar 	n = del_history_entry(get_histtype(str),
597d7663c22SBram Moolenaar 				      tv_get_string_buf(&argvars[1], buf));
598d7663c22SBram Moolenaar     rettv->vval.v_number = n;
599d7663c22SBram Moolenaar }
600d7663c22SBram Moolenaar 
601d7663c22SBram Moolenaar /*
602d7663c22SBram Moolenaar  * "histget()" function
603d7663c22SBram Moolenaar  */
604d7663c22SBram Moolenaar     void
f_histget(typval_T * argvars UNUSED,typval_T * rettv)605d7663c22SBram Moolenaar f_histget(typval_T *argvars UNUSED, typval_T *rettv)
606d7663c22SBram Moolenaar {
607d7663c22SBram Moolenaar     int		type;
608d7663c22SBram Moolenaar     int		idx;
609d7663c22SBram Moolenaar     char_u	*str;
610d7663c22SBram Moolenaar 
6111a71d31bSYegappan Lakshmanan     if (in_vim9script()
6121a71d31bSYegappan Lakshmanan 	    && (check_for_string_arg(argvars, 0) == FAIL
61383494b4aSYegappan Lakshmanan 		|| check_for_opt_number_arg(argvars, 1) == FAIL))
6141a71d31bSYegappan Lakshmanan 	return;
6151a71d31bSYegappan Lakshmanan 
616d7663c22SBram Moolenaar     str = tv_get_string_chk(&argvars[0]);	// NULL on type error
617d7663c22SBram Moolenaar     if (str == NULL)
618d7663c22SBram Moolenaar 	rettv->vval.v_string = NULL;
619d7663c22SBram Moolenaar     else
620d7663c22SBram Moolenaar     {
621d7663c22SBram Moolenaar 	type = get_histtype(str);
622d7663c22SBram Moolenaar 	if (argvars[1].v_type == VAR_UNKNOWN)
623d7663c22SBram Moolenaar 	    idx = get_history_idx(type);
624d7663c22SBram Moolenaar 	else
625d7663c22SBram Moolenaar 	    idx = (int)tv_get_number_chk(&argvars[1], NULL);
626d7663c22SBram Moolenaar 						    // -1 on type error
627d7663c22SBram Moolenaar 	rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
628d7663c22SBram Moolenaar     }
629d7663c22SBram Moolenaar     rettv->v_type = VAR_STRING;
630d7663c22SBram Moolenaar }
631d7663c22SBram Moolenaar 
632d7663c22SBram Moolenaar /*
633d7663c22SBram Moolenaar  * "histnr()" function
634d7663c22SBram Moolenaar  */
635d7663c22SBram Moolenaar     void
f_histnr(typval_T * argvars UNUSED,typval_T * rettv)636d7663c22SBram Moolenaar f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
637d7663c22SBram Moolenaar {
638d7663c22SBram Moolenaar     int		i;
639*4490ec4eSYegappan Lakshmanan     char_u	*histname;
640d7663c22SBram Moolenaar 
641*4490ec4eSYegappan Lakshmanan     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
642*4490ec4eSYegappan Lakshmanan 	return;
643d7663c22SBram Moolenaar 
644*4490ec4eSYegappan Lakshmanan     histname = tv_get_string_chk(&argvars[0]);
645d7663c22SBram Moolenaar     i = histname == NULL ? HIST_CMD - 1 : get_histtype(histname);
646d7663c22SBram Moolenaar     if (i >= HIST_CMD && i < HIST_COUNT)
647d7663c22SBram Moolenaar 	i = get_history_idx(i);
648d7663c22SBram Moolenaar     else
649d7663c22SBram Moolenaar 	i = -1;
650d7663c22SBram Moolenaar     rettv->vval.v_number = i;
651d7663c22SBram Moolenaar }
652d7663c22SBram Moolenaar #endif // FEAT_EVAL
653d7663c22SBram Moolenaar 
654d7663c22SBram Moolenaar #if defined(FEAT_CRYPT) || defined(PROTO)
655d7663c22SBram Moolenaar /*
656d7663c22SBram Moolenaar  * Very specific function to remove the value in ":set key=val" from the
657d7663c22SBram Moolenaar  * history.
658d7663c22SBram Moolenaar  */
659d7663c22SBram Moolenaar     void
remove_key_from_history(void)660d7663c22SBram Moolenaar remove_key_from_history(void)
661d7663c22SBram Moolenaar {
662d7663c22SBram Moolenaar     char_u	*p;
663d7663c22SBram Moolenaar     int		i;
664d7663c22SBram Moolenaar 
665d7663c22SBram Moolenaar     i = hisidx[HIST_CMD];
666d7663c22SBram Moolenaar     if (i < 0)
667d7663c22SBram Moolenaar 	return;
668d7663c22SBram Moolenaar     p = history[HIST_CMD][i].hisstr;
669d7663c22SBram Moolenaar     if (p != NULL)
670d7663c22SBram Moolenaar 	for ( ; *p; ++p)
671d7663c22SBram Moolenaar 	    if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3]))
672d7663c22SBram Moolenaar 	    {
673d7663c22SBram Moolenaar 		p = vim_strchr(p + 3, '=');
674d7663c22SBram Moolenaar 		if (p == NULL)
675d7663c22SBram Moolenaar 		    break;
676d7663c22SBram Moolenaar 		++p;
677d7663c22SBram Moolenaar 		for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i)
678d7663c22SBram Moolenaar 		    if (p[i] == '\\' && p[i + 1])
679d7663c22SBram Moolenaar 			++i;
680d7663c22SBram Moolenaar 		STRMOVE(p, p + i);
681d7663c22SBram Moolenaar 		--p;
682d7663c22SBram Moolenaar 	    }
683d7663c22SBram Moolenaar }
684d7663c22SBram Moolenaar #endif
685d7663c22SBram Moolenaar 
686d7663c22SBram Moolenaar /*
687d7663c22SBram Moolenaar  * :history command - print a history
688d7663c22SBram Moolenaar  */
689d7663c22SBram Moolenaar     void
ex_history(exarg_T * eap)690d7663c22SBram Moolenaar ex_history(exarg_T *eap)
691d7663c22SBram Moolenaar {
692d7663c22SBram Moolenaar     histentry_T	*hist;
693d7663c22SBram Moolenaar     int		histype1 = HIST_CMD;
694d7663c22SBram Moolenaar     int		histype2 = HIST_CMD;
695d7663c22SBram Moolenaar     int		hisidx1 = 1;
696d7663c22SBram Moolenaar     int		hisidx2 = -1;
697d7663c22SBram Moolenaar     int		idx;
698d7663c22SBram Moolenaar     int		i, j, k;
699d7663c22SBram Moolenaar     char_u	*end;
700d7663c22SBram Moolenaar     char_u	*arg = eap->arg;
701d7663c22SBram Moolenaar 
702d7663c22SBram Moolenaar     if (hislen == 0)
703d7663c22SBram Moolenaar     {
704d7663c22SBram Moolenaar 	msg(_("'history' option is zero"));
705d7663c22SBram Moolenaar 	return;
706d7663c22SBram Moolenaar     }
707d7663c22SBram Moolenaar 
708d7663c22SBram Moolenaar     if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ','))
709d7663c22SBram Moolenaar     {
710d7663c22SBram Moolenaar 	end = arg;
711d7663c22SBram Moolenaar 	while (ASCII_ISALPHA(*end)
712d7663c22SBram Moolenaar 		|| vim_strchr((char_u *)":=@>/?", *end) != NULL)
713d7663c22SBram Moolenaar 	    end++;
714d7663c22SBram Moolenaar 	i = *end;
715d7663c22SBram Moolenaar 	*end = NUL;
716d7663c22SBram Moolenaar 	histype1 = get_histtype(arg);
717d7663c22SBram Moolenaar 	if (histype1 == -1)
718d7663c22SBram Moolenaar 	{
719d7663c22SBram Moolenaar 	    if (STRNICMP(arg, "all", STRLEN(arg)) == 0)
720d7663c22SBram Moolenaar 	    {
721d7663c22SBram Moolenaar 		histype1 = 0;
722d7663c22SBram Moolenaar 		histype2 = HIST_COUNT-1;
723d7663c22SBram Moolenaar 	    }
724d7663c22SBram Moolenaar 	    else
725d7663c22SBram Moolenaar 	    {
726d7663c22SBram Moolenaar 		*end = i;
7272d06bfdeSBram Moolenaar 		semsg(_(e_trailing_arg), arg);
728d7663c22SBram Moolenaar 		return;
729d7663c22SBram Moolenaar 	    }
730d7663c22SBram Moolenaar 	}
731d7663c22SBram Moolenaar 	else
732d7663c22SBram Moolenaar 	    histype2 = histype1;
733d7663c22SBram Moolenaar 	*end = i;
734d7663c22SBram Moolenaar     }
735d7663c22SBram Moolenaar     else
736d7663c22SBram Moolenaar 	end = arg;
737d7663c22SBram Moolenaar     if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL)
738d7663c22SBram Moolenaar     {
7392d06bfdeSBram Moolenaar 	semsg(_(e_trailing_arg), end);
740d7663c22SBram Moolenaar 	return;
741d7663c22SBram Moolenaar     }
742d7663c22SBram Moolenaar 
743d7663c22SBram Moolenaar     for (; !got_int && histype1 <= histype2; ++histype1)
744d7663c22SBram Moolenaar     {
745d7663c22SBram Moolenaar 	STRCPY(IObuff, "\n      #  ");
746d7663c22SBram Moolenaar 	STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
747d7663c22SBram Moolenaar 	msg_puts_title((char *)IObuff);
748d7663c22SBram Moolenaar 	idx = hisidx[histype1];
749d7663c22SBram Moolenaar 	hist = history[histype1];
750d7663c22SBram Moolenaar 	j = hisidx1;
751d7663c22SBram Moolenaar 	k = hisidx2;
752d7663c22SBram Moolenaar 	if (j < 0)
753d7663c22SBram Moolenaar 	    j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
754d7663c22SBram Moolenaar 	if (k < 0)
755d7663c22SBram Moolenaar 	    k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
756d7663c22SBram Moolenaar 	if (idx >= 0 && j <= k)
757d7663c22SBram Moolenaar 	    for (i = idx + 1; !got_int; ++i)
758d7663c22SBram Moolenaar 	    {
759d7663c22SBram Moolenaar 		if (i == hislen)
760d7663c22SBram Moolenaar 		    i = 0;
761d7663c22SBram Moolenaar 		if (hist[i].hisstr != NULL
762d7663c22SBram Moolenaar 			&& hist[i].hisnum >= j && hist[i].hisnum <= k)
763d7663c22SBram Moolenaar 		{
764d7663c22SBram Moolenaar 		    msg_putchar('\n');
765d7663c22SBram Moolenaar 		    sprintf((char *)IObuff, "%c%6d  ", i == idx ? '>' : ' ',
766d7663c22SBram Moolenaar 							      hist[i].hisnum);
767d7663c22SBram Moolenaar 		    if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
768d7663c22SBram Moolenaar 			trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
769d7663c22SBram Moolenaar 			     (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff));
770d7663c22SBram Moolenaar 		    else
771d7663c22SBram Moolenaar 			STRCAT(IObuff, hist[i].hisstr);
772d7663c22SBram Moolenaar 		    msg_outtrans(IObuff);
773d7663c22SBram Moolenaar 		    out_flush();
774d7663c22SBram Moolenaar 		}
775d7663c22SBram Moolenaar 		if (i == idx)
776d7663c22SBram Moolenaar 		    break;
777d7663c22SBram Moolenaar 	    }
778d7663c22SBram Moolenaar     }
779d7663c22SBram Moolenaar }
780