xref: /vim-8.2.3635/src/ex_getln.c (revision a1198124)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * ex_getln.c: Functions for entering and editing an Ex command line.
12  */
13 
14 #include "vim.h"
15 
16 #ifndef MAX
17 # define MAX(x,y) ((x) > (y) ? (x) : (y))
18 #endif
19 
20 // Return value when handling keys in command-line mode.
21 #define CMDLINE_NOT_CHANGED	1
22 #define CMDLINE_CHANGED		2
23 #define GOTO_NORMAL_MODE	3
24 #define PROCESS_NEXT_KEY	4
25 
26 // The current cmdline_info.  It is initialized in getcmdline() and after that
27 // used by other functions.  When invoking getcmdline() recursively it needs
28 // to be saved with save_cmdline() and restored with restore_cmdline().
29 static cmdline_info_T ccline;
30 
31 #ifdef FEAT_EVAL
32 static int	new_cmdpos;	// position set by set_cmdline_pos()
33 #endif
34 
35 static int	extra_char = NUL;  // extra character to display when redrawing
36 				   // the command line
37 static int	extra_char_shift;
38 
39 #ifdef FEAT_RIGHTLEFT
40 static int	cmd_hkmap = 0;	// Hebrew mapping during command line
41 #endif
42 
43 static char_u	*getcmdline_int(int firstc, long count, int indent, int clear_ccline);
44 static int	cmdline_charsize(int idx);
45 static void	set_cmdspos(void);
46 static void	set_cmdspos_cursor(void);
47 static void	correct_cmdspos(int idx, int cells);
48 static void	alloc_cmdbuff(int len);
49 static void	draw_cmdline(int start, int len);
50 static void	save_cmdline(cmdline_info_T *ccp);
51 static void	restore_cmdline(cmdline_info_T *ccp);
52 static int	cmdline_paste(int regname, int literally, int remcr);
53 static void	redrawcmdprompt(void);
54 static int	ccheck_abbr(int);
55 #ifdef FEAT_SEARCH_EXTRA
56 static int	empty_pattern_magic(char_u *pat, size_t len, magic_T magic_val);
57 #endif
58 
59 #ifdef FEAT_CMDWIN
60 static int	open_cmdwin(void);
61 
62 static int	cedit_key INIT(= -1);	// key value of 'cedit' option
63 #endif
64 
65 
66     static void
trigger_cmd_autocmd(int typechar,int evt)67 trigger_cmd_autocmd(int typechar, int evt)
68 {
69     char_u	typestr[2];
70 
71     typestr[0] = typechar;
72     typestr[1] = NUL;
73     apply_autocmds(evt, typestr, typestr, FALSE, curbuf);
74 }
75 
76 /*
77  * Abandon the command line.
78  */
79     static void
abandon_cmdline(void)80 abandon_cmdline(void)
81 {
82     VIM_CLEAR(ccline.cmdbuff);
83     if (msg_scrolled == 0)
84 	compute_cmdrow();
85     msg("");
86     redraw_cmdline = TRUE;
87 }
88 
89 #ifdef FEAT_SEARCH_EXTRA
90 /*
91  * Guess that the pattern matches everything.  Only finds specific cases, such
92  * as a trailing \|, which can happen while typing a pattern.
93  */
94     static int
empty_pattern(char_u * p,int delim)95 empty_pattern(char_u *p, int delim)
96 {
97     size_t	n = STRLEN(p);
98     magic_T	magic_val = MAGIC_ON;
99 
100     if (n > 0)
101 	(void) skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val);
102     else
103 	return TRUE;
104 
105     return empty_pattern_magic(p, n, magic_val);
106 }
107 
108     static int
empty_pattern_magic(char_u * p,size_t len,magic_T magic_val)109 empty_pattern_magic(char_u *p, size_t len, magic_T magic_val)
110 {
111     // remove trailing \v and the like
112     while (len >= 2 && p[len - 2] == '\\'
113                         && vim_strchr((char_u *)"mMvVcCZ", p[len - 1]) != NULL)
114        len -= 2;
115 
116     // true, if the pattern is empty, or the pattern ends with \| and magic is
117     // set (or it ends with '|' and very magic is set)
118     return len == 0 || (len > 1
119 	    && ((p[len - 2] == '\\'
120 				 && p[len - 1] == '|' && magic_val == MAGIC_ON)
121 		|| (p[len - 2] != '\\'
122 			     && p[len - 1] == '|' && magic_val == MAGIC_ALL)));
123 }
124 
125 // Struct to store the viewstate during 'incsearch' highlighting.
126 typedef struct {
127     colnr_T	vs_curswant;
128     colnr_T	vs_leftcol;
129     linenr_T	vs_topline;
130 # ifdef FEAT_DIFF
131     int		vs_topfill;
132 # endif
133     linenr_T	vs_botline;
134     linenr_T	vs_empty_rows;
135 } viewstate_T;
136 
137     static void
save_viewstate(viewstate_T * vs)138 save_viewstate(viewstate_T *vs)
139 {
140     vs->vs_curswant = curwin->w_curswant;
141     vs->vs_leftcol = curwin->w_leftcol;
142     vs->vs_topline = curwin->w_topline;
143 # ifdef FEAT_DIFF
144     vs->vs_topfill = curwin->w_topfill;
145 # endif
146     vs->vs_botline = curwin->w_botline;
147     vs->vs_empty_rows = curwin->w_empty_rows;
148 }
149 
150     static void
restore_viewstate(viewstate_T * vs)151 restore_viewstate(viewstate_T *vs)
152 {
153     curwin->w_curswant = vs->vs_curswant;
154     curwin->w_leftcol = vs->vs_leftcol;
155     curwin->w_topline = vs->vs_topline;
156 # ifdef FEAT_DIFF
157     curwin->w_topfill = vs->vs_topfill;
158 # endif
159     curwin->w_botline = vs->vs_botline;
160     curwin->w_empty_rows = vs->vs_empty_rows;
161 }
162 
163 // Struct to store the state of 'incsearch' highlighting.
164 typedef struct {
165     pos_T	search_start;	// where 'incsearch' starts searching
166     pos_T	save_cursor;
167     int		winid;		// window where this state is valid
168     viewstate_T	init_viewstate;
169     viewstate_T	old_viewstate;
170     pos_T	match_start;
171     pos_T	match_end;
172     int		did_incsearch;
173     int		incsearch_postponed;
174     optmagic_T	magic_overruled_save;
175 } incsearch_state_T;
176 
177     static void
init_incsearch_state(incsearch_state_T * is_state)178 init_incsearch_state(incsearch_state_T *is_state)
179 {
180     is_state->winid = curwin->w_id;
181     is_state->match_start = curwin->w_cursor;
182     is_state->did_incsearch = FALSE;
183     is_state->incsearch_postponed = FALSE;
184     is_state->magic_overruled_save = magic_overruled;
185     CLEAR_POS(&is_state->match_end);
186     is_state->save_cursor = curwin->w_cursor;  // may be restored later
187     is_state->search_start = curwin->w_cursor;
188     save_viewstate(&is_state->init_viewstate);
189     save_viewstate(&is_state->old_viewstate);
190 }
191 
192 /*
193  * First move cursor to end of match, then to the start.  This
194  * moves the whole match onto the screen when 'nowrap' is set.
195  */
196     static void
set_search_match(pos_T * t)197 set_search_match(pos_T *t)
198 {
199     t->lnum += search_match_lines;
200     t->col = search_match_endcol;
201     if (t->lnum > curbuf->b_ml.ml_line_count)
202     {
203 	t->lnum = curbuf->b_ml.ml_line_count;
204 	coladvance((colnr_T)MAXCOL);
205     }
206 }
207 
208 /*
209  * Return TRUE when 'incsearch' highlighting is to be done.
210  * Sets search_first_line and search_last_line to the address range.
211  * May change the last search pattern.
212  */
213     static int
do_incsearch_highlighting(int firstc,int * search_delim,incsearch_state_T * is_state,int * skiplen,int * patlen)214 do_incsearch_highlighting(
215 	int		    firstc,
216 	int		    *search_delim,
217 	incsearch_state_T   *is_state,
218 	int		    *skiplen,
219 	int		    *patlen)
220 {
221     char_u	*cmd;
222     cmdmod_T	dummy_cmdmod;
223     char_u	*p;
224     int		delim_optional = FALSE;
225     int		delim;
226     char_u	*end;
227     char	*dummy;
228     exarg_T	ea;
229     pos_T	save_cursor;
230     int		use_last_pat;
231     int		retval = FALSE;
232     magic_T     magic = 0;
233 
234     *skiplen = 0;
235     *patlen = ccline.cmdlen;
236 
237     if (!p_is || cmd_silent)
238 	return FALSE;
239 
240     // by default search all lines
241     search_first_line = 0;
242     search_last_line = MAXLNUM;
243 
244     if (firstc == '/' || firstc == '?')
245     {
246 	*search_delim = firstc;
247 	return TRUE;
248     }
249     if (firstc != ':')
250 	return FALSE;
251 
252     ++emsg_off;
253     CLEAR_FIELD(ea);
254     ea.line1 = 1;
255     ea.line2 = 1;
256     ea.cmd = ccline.cmdbuff;
257     ea.addr_type = ADDR_LINES;
258 
259     CLEAR_FIELD(dummy_cmdmod);
260     parse_command_modifiers(&ea, &dummy, &dummy_cmdmod, TRUE);
261 
262     cmd = skip_range(ea.cmd, TRUE, NULL);
263     if (vim_strchr((char_u *)"sgvl", *cmd) == NULL)
264 	goto theend;
265 
266     // Skip over "substitute" to find the pattern separator.
267     for (p = cmd; ASCII_ISALPHA(*p); ++p)
268 	;
269     if (*skipwhite(p) == NUL)
270 	goto theend;
271 
272     if (STRNCMP(cmd, "substitute", p - cmd) == 0
273 	    || STRNCMP(cmd, "smagic", p - cmd) == 0
274 	    || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0
275 	    || STRNCMP(cmd, "vglobal", p - cmd) == 0)
276     {
277 	if (*cmd == 's' && cmd[1] == 'm')
278 	    magic_overruled = OPTION_MAGIC_ON;
279 	else if (*cmd == 's' && cmd[1] == 'n')
280 	    magic_overruled = OPTION_MAGIC_OFF;
281     }
282     else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0)
283     {
284 	// skip over ! and flags
285 	if (*p == '!')
286 	    p = skipwhite(p + 1);
287 	while (ASCII_ISALPHA(*(p = skipwhite(p))))
288 	    ++p;
289 	if (*p == NUL)
290 	    goto theend;
291     }
292     else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
293 	|| STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
294 	|| STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0
295 	|| STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0
296 	|| STRNCMP(cmd, "global", p - cmd) == 0)
297     {
298 	// skip over "!"
299 	if (*p == '!')
300 	{
301 	    p++;
302 	    if (*skipwhite(p) == NUL)
303 		goto theend;
304 	}
305 	if (*cmd != 'g')
306 	    delim_optional = TRUE;
307     }
308     else
309 	goto theend;
310 
311     p = skipwhite(p);
312     delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
313     *search_delim = delim;
314     end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic);
315 
316     use_last_pat = end == p && *end == delim;
317 
318     if (end == p && !use_last_pat)
319 	goto theend;
320 
321     // Don't do 'hlsearch' highlighting if the pattern matches everything.
322     if (!use_last_pat)
323     {
324 	char c = *end;
325 	int  empty;
326 
327 	*end = NUL;
328 	empty = empty_pattern_magic(p, STRLEN(p), magic);
329 	*end = c;
330 	if (empty)
331 	    goto theend;
332     }
333 
334     // found a non-empty pattern or //
335     *skiplen = (int)(p - ccline.cmdbuff);
336     *patlen = (int)(end - p);
337 
338     // parse the address range
339     save_cursor = curwin->w_cursor;
340     curwin->w_cursor = is_state->search_start;
341     parse_cmd_address(&ea, &dummy, TRUE);
342     if (ea.addr_count > 0)
343     {
344 	// Allow for reverse match.
345 	if (ea.line2 < ea.line1)
346 	{
347 	    search_first_line = ea.line2;
348 	    search_last_line = ea.line1;
349 	}
350 	else
351 	{
352 	    search_first_line = ea.line1;
353 	    search_last_line = ea.line2;
354 	}
355     }
356     else if (cmd[0] == 's' && cmd[1] != 'o')
357     {
358 	// :s defaults to the current line
359 	search_first_line = curwin->w_cursor.lnum;
360 	search_last_line = curwin->w_cursor.lnum;
361     }
362 
363     curwin->w_cursor = save_cursor;
364     retval = TRUE;
365 theend:
366     --emsg_off;
367     return retval;
368 }
369 
370     static void
finish_incsearch_highlighting(int gotesc,incsearch_state_T * is_state,int call_update_screen)371 finish_incsearch_highlighting(
372 	int gotesc,
373 	incsearch_state_T *is_state,
374 	int call_update_screen)
375 {
376     if (is_state->did_incsearch)
377     {
378 	is_state->did_incsearch = FALSE;
379 	if (gotesc)
380 	    curwin->w_cursor = is_state->save_cursor;
381 	else
382 	{
383 	    if (!EQUAL_POS(is_state->save_cursor, is_state->search_start))
384 	    {
385 		// put the '" mark at the original position
386 		curwin->w_cursor = is_state->save_cursor;
387 		setpcmark();
388 	    }
389 	    curwin->w_cursor = is_state->search_start;
390 	}
391 	restore_viewstate(&is_state->old_viewstate);
392 	highlight_match = FALSE;
393 
394 	// by default search all lines
395 	search_first_line = 0;
396 	search_last_line = MAXLNUM;
397 
398 	magic_overruled = is_state->magic_overruled_save;
399 
400 	validate_cursor();	// needed for TAB
401 	redraw_all_later(SOME_VALID);
402 	if (call_update_screen)
403 	    update_screen(SOME_VALID);
404     }
405 }
406 
407 /*
408  * Do 'incsearch' highlighting if desired.
409  */
410     static void
may_do_incsearch_highlighting(int firstc,long count,incsearch_state_T * is_state)411 may_do_incsearch_highlighting(
412 	int		    firstc,
413 	long		    count,
414 	incsearch_state_T   *is_state)
415 {
416     int		skiplen, patlen;
417     int		found;  // do_search() result
418     pos_T	end_pos;
419 #ifdef FEAT_RELTIME
420     proftime_T	tm;
421     searchit_arg_T sia;
422 #endif
423     int		next_char;
424     int		use_last_pat;
425     int		did_do_incsearch = is_state->did_incsearch;
426     int		search_delim;
427 
428     // Parsing range may already set the last search pattern.
429     // NOTE: must call restore_last_search_pattern() before returning!
430     save_last_search_pattern();
431 
432     if (!do_incsearch_highlighting(firstc, &search_delim, is_state,
433 							    &skiplen, &patlen))
434     {
435 	restore_last_search_pattern();
436 	finish_incsearch_highlighting(FALSE, is_state, TRUE);
437 	if (did_do_incsearch && vpeekc() == NUL)
438 	    // may have skipped a redraw, do it now
439 	    redrawcmd();
440 	return;
441     }
442 
443     // If there is a character waiting, search and redraw later.
444     if (char_avail())
445     {
446 	restore_last_search_pattern();
447 	is_state->incsearch_postponed = TRUE;
448 	return;
449     }
450     is_state->incsearch_postponed = FALSE;
451 
452     if (search_first_line == 0)
453 	// start at the original cursor position
454 	curwin->w_cursor = is_state->search_start;
455     else if (search_first_line > curbuf->b_ml.ml_line_count)
456     {
457 	// start after the last line
458 	curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
459 	curwin->w_cursor.col = MAXCOL;
460     }
461     else
462     {
463 	// start at the first line in the range
464 	curwin->w_cursor.lnum = search_first_line;
465 	curwin->w_cursor.col = 0;
466     }
467 
468     // Use the previous pattern for ":s//".
469     next_char = ccline.cmdbuff[skiplen + patlen];
470     use_last_pat = patlen == 0 && skiplen > 0
471 				   && ccline.cmdbuff[skiplen - 1] == next_char;
472 
473     // If there is no pattern, don't do anything.
474     if (patlen == 0 && !use_last_pat)
475     {
476 	found = 0;
477 	set_no_hlsearch(TRUE); // turn off previous highlight
478 	redraw_all_later(SOME_VALID);
479     }
480     else
481     {
482 	int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
483 
484 	cursor_off();	// so the user knows we're busy
485 	out_flush();
486 	++emsg_off;	// so it doesn't beep if bad expr
487 #ifdef FEAT_RELTIME
488 	// Set the time limit to half a second.
489 	profile_setlimit(500L, &tm);
490 #endif
491 	if (!p_hls)
492 	    search_flags += SEARCH_KEEP;
493 	if (search_first_line != 0)
494 	    search_flags += SEARCH_START;
495 	ccline.cmdbuff[skiplen + patlen] = NUL;
496 #ifdef FEAT_RELTIME
497 	CLEAR_FIELD(sia);
498 	sia.sa_tm = &tm;
499 #endif
500 	found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
501 				 ccline.cmdbuff + skiplen, count, search_flags,
502 #ifdef FEAT_RELTIME
503 		&sia
504 #else
505 		NULL
506 #endif
507 		);
508 	ccline.cmdbuff[skiplen + patlen] = next_char;
509 	--emsg_off;
510 
511 	if (curwin->w_cursor.lnum < search_first_line
512 		|| curwin->w_cursor.lnum > search_last_line)
513 	{
514 	    // match outside of address range
515 	    found = 0;
516 	    curwin->w_cursor = is_state->search_start;
517 	}
518 
519 	// if interrupted while searching, behave like it failed
520 	if (got_int)
521 	{
522 	    (void)vpeekc();	// remove <C-C> from input stream
523 	    got_int = FALSE;	// don't abandon the command line
524 	    found = 0;
525 	}
526 	else if (char_avail())
527 	    // cancelled searching because a char was typed
528 	    is_state->incsearch_postponed = TRUE;
529     }
530     if (found != 0)
531 	highlight_match = TRUE;		// highlight position
532     else
533 	highlight_match = FALSE;	// remove highlight
534 
535     // First restore the old curwin values, so the screen is positioned in the
536     // same way as the actual search command.
537     restore_viewstate(&is_state->old_viewstate);
538     changed_cline_bef_curs();
539     update_topline();
540 
541     if (found != 0)
542     {
543 	pos_T	    save_pos = curwin->w_cursor;
544 
545 	is_state->match_start = curwin->w_cursor;
546 	set_search_match(&curwin->w_cursor);
547 	validate_cursor();
548 	end_pos = curwin->w_cursor;
549 	is_state->match_end = end_pos;
550 	curwin->w_cursor = save_pos;
551     }
552     else
553 	end_pos = curwin->w_cursor; // shutup gcc 4
554 
555     // Disable 'hlsearch' highlighting if the pattern matches everything.
556     // Avoids a flash when typing "foo\|".
557     if (!use_last_pat)
558     {
559 	next_char = ccline.cmdbuff[skiplen + patlen];
560 	ccline.cmdbuff[skiplen + patlen] = NUL;
561 	if (empty_pattern(ccline.cmdbuff + skiplen, search_delim)
562 							       && !no_hlsearch)
563 	{
564 	    redraw_all_later(SOME_VALID);
565 	    set_no_hlsearch(TRUE);
566 	}
567 	ccline.cmdbuff[skiplen + patlen] = next_char;
568     }
569 
570     validate_cursor();
571     // May redraw the status line to show the cursor position.
572     if (p_ru && curwin->w_status_height > 0)
573 	curwin->w_redr_status = TRUE;
574 
575     update_screen(SOME_VALID);
576     highlight_match = FALSE;
577     restore_last_search_pattern();
578 
579     // Leave it at the end to make CTRL-R CTRL-W work.  But not when beyond the
580     // end of the pattern, e.g. for ":s/pat/".
581     if (ccline.cmdbuff[skiplen + patlen] != NUL)
582 	curwin->w_cursor = is_state->search_start;
583     else if (found != 0)
584 	curwin->w_cursor = end_pos;
585 
586     msg_starthere();
587     redrawcmdline();
588     is_state->did_incsearch = TRUE;
589 }
590 
591 /*
592  * May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
593  * or previous match.
594  * Returns FAIL when jumping to cmdline_not_changed;
595  */
596     static int
may_adjust_incsearch_highlighting(int firstc,long count,incsearch_state_T * is_state,int c)597 may_adjust_incsearch_highlighting(
598 	int			firstc,
599 	long			count,
600 	incsearch_state_T	*is_state,
601 	int			c)
602 {
603     int	    skiplen, patlen;
604     pos_T   t;
605     char_u  *pat;
606     int	    search_flags = SEARCH_NOOF;
607     int	    i;
608     int	    save;
609     int	    search_delim;
610 
611     // Parsing range may already set the last search pattern.
612     // NOTE: must call restore_last_search_pattern() before returning!
613     save_last_search_pattern();
614 
615     if (!do_incsearch_highlighting(firstc, &search_delim, is_state,
616 							    &skiplen, &patlen))
617     {
618 	restore_last_search_pattern();
619 	return OK;
620     }
621     if (patlen == 0 && ccline.cmdbuff[skiplen] == NUL)
622     {
623 	restore_last_search_pattern();
624 	return FAIL;
625     }
626 
627     if (search_delim == ccline.cmdbuff[skiplen])
628     {
629 	pat = last_search_pattern();
630 	if (pat == NULL)
631 	{
632 	    restore_last_search_pattern();
633 	    return FAIL;
634 	}
635 	skiplen = 0;
636 	patlen = (int)STRLEN(pat);
637     }
638     else
639 	pat = ccline.cmdbuff + skiplen;
640 
641     cursor_off();
642     out_flush();
643     if (c == Ctrl_G)
644     {
645 	t = is_state->match_end;
646 	if (LT_POS(is_state->match_start, is_state->match_end))
647 	    // Start searching at the end of the match not at the beginning of
648 	    // the next column.
649 	    (void)decl(&t);
650 	search_flags += SEARCH_COL;
651     }
652     else
653 	t = is_state->match_start;
654     if (!p_hls)
655 	search_flags += SEARCH_KEEP;
656     ++emsg_off;
657     save = pat[patlen];
658     pat[patlen] = NUL;
659     i = searchit(curwin, curbuf, &t, NULL,
660 		 c == Ctrl_G ? FORWARD : BACKWARD,
661 		 pat, count, search_flags, RE_SEARCH, NULL);
662     --emsg_off;
663     pat[patlen] = save;
664     if (i)
665     {
666 	is_state->search_start = is_state->match_start;
667 	is_state->match_end = t;
668 	is_state->match_start = t;
669 	if (c == Ctrl_T && firstc != '?')
670 	{
671 	    // Move just before the current match, so that when nv_search
672 	    // finishes the cursor will be put back on the match.
673 	    is_state->search_start = t;
674 	    (void)decl(&is_state->search_start);
675 	}
676 	else if (c == Ctrl_G && firstc == '?')
677 	{
678 	    // Move just after the current match, so that when nv_search
679 	    // finishes the cursor will be put back on the match.
680 	    is_state->search_start = t;
681 	    (void)incl(&is_state->search_start);
682 	}
683 	if (LT_POS(t, is_state->search_start) && c == Ctrl_G)
684 	{
685 	    // wrap around
686 	    is_state->search_start = t;
687 	    if (firstc == '?')
688 		(void)incl(&is_state->search_start);
689 	    else
690 		(void)decl(&is_state->search_start);
691 	}
692 
693 	set_search_match(&is_state->match_end);
694 	curwin->w_cursor = is_state->match_start;
695 	changed_cline_bef_curs();
696 	update_topline();
697 	validate_cursor();
698 	highlight_match = TRUE;
699 	save_viewstate(&is_state->old_viewstate);
700 	update_screen(NOT_VALID);
701 	highlight_match = FALSE;
702 	redrawcmdline();
703 	curwin->w_cursor = is_state->match_end;
704     }
705     else
706 	vim_beep(BO_ERROR);
707     restore_last_search_pattern();
708     return FAIL;
709 }
710 
711 /*
712  * When CTRL-L typed: add character from the match to the pattern.
713  * May set "*c" to the added character.
714  * Return OK when jumping to cmdline_not_changed.
715  */
716     static int
may_add_char_to_search(int firstc,int * c,incsearch_state_T * is_state)717 may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state)
718 {
719     int		skiplen, patlen, search_delim;
720 
721     // Parsing range may already set the last search pattern.
722     // NOTE: must call restore_last_search_pattern() before returning!
723     save_last_search_pattern();
724 
725     if (!do_incsearch_highlighting(firstc, &search_delim, is_state,
726 							    &skiplen, &patlen))
727     {
728 	restore_last_search_pattern();
729 	return FAIL;
730     }
731     restore_last_search_pattern();
732 
733     // Add a character from under the cursor for 'incsearch'.
734     if (is_state->did_incsearch)
735     {
736 	curwin->w_cursor = is_state->match_end;
737 	*c = gchar_cursor();
738 	if (*c != NUL)
739 	{
740 	    // If 'ignorecase' and 'smartcase' are set and the
741 	    // command line has no uppercase characters, convert
742 	    // the character to lowercase.
743 	    if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff + skiplen))
744 		*c = MB_TOLOWER(*c);
745 	    if (*c == search_delim || vim_strchr((char_u *)(
746 			     magic_isset() ? "\\~^$.*[" : "\\^$"), *c) != NULL)
747 	    {
748 		// put a backslash before special characters
749 		stuffcharReadbuff(*c);
750 		*c = '\\';
751 	    }
752 	    // add any composing characters
753 	    if (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
754 	    {
755 		int save_c = *c;
756 
757 		while (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
758 		{
759 		    curwin->w_cursor.col += mb_char2len(*c);
760 		    *c = gchar_cursor();
761 		    stuffcharReadbuff(*c);
762 		}
763 		*c = save_c;
764 	    }
765 	    return FAIL;
766 	}
767     }
768     return OK;
769 }
770 #endif
771 
772 #ifdef FEAT_ARABIC
773 /*
774  * Return TRUE if the command line has an Arabic character at or after "start"
775  * for "len" bytes.
776  */
777     static int
cmdline_has_arabic(int start,int len)778 cmdline_has_arabic(int start, int len)
779 {
780     int	    j;
781     int	    mb_l;
782     int	    u8c;
783     char_u  *p;
784     int	    u8cc[MAX_MCO];
785 
786     if (!enc_utf8)
787 	return FALSE;
788 
789     for (j = start; j < start + len; j += mb_l)
790     {
791 	p = ccline.cmdbuff + j;
792 	u8c = utfc_ptr2char_len(p, u8cc, start + len - j);
793 	mb_l = utfc_ptr2len_len(p, start + len - j);
794 	if (ARABIC_CHAR(u8c))
795 	    return TRUE;
796     }
797     return FALSE;
798 }
799 #endif
800 
801     void
cmdline_init(void)802 cmdline_init(void)
803 {
804     CLEAR_FIELD(ccline);
805 }
806 
807 /*
808  * Handle the backslash key pressed in the command-line mode.  CTRL-\ CTRL-N
809  * goes to Normal mode, CTRL-\ CTRL-G goes to Insert mode when 'insertmode' is
810  * set, CTRL-\ e prompts for an expression.
811  */
812     static int
cmdline_handle_backslash_key(int c,int * gotesc)813 cmdline_handle_backslash_key(int c, int *gotesc)
814 {
815     ++no_mapping;
816     ++allow_keys;
817     c = plain_vgetc();
818     --no_mapping;
819     --allow_keys;
820 
821     // CTRL-\ e doesn't work when obtaining an expression, unless it
822     // is in a mapping.
823     if (c != Ctrl_N && c != Ctrl_G && (c != 'e'
824 		|| (ccline.cmdfirstc == '=' && KeyTyped)
825 #ifdef FEAT_EVAL
826 		|| cmdline_star > 0
827 #endif
828 		))
829     {
830 	vungetc(c);
831 	return PROCESS_NEXT_KEY;
832     }
833 
834 #ifdef FEAT_EVAL
835     if (c == 'e')
836     {
837 	char_u	*p = NULL;
838 	int	len;
839 
840 	/*
841 	 * Replace the command line with the result of an expression.
842 	 * Need to save and restore the current command line, to be
843 	 * able to enter a new one...
844 	 */
845 	if (ccline.cmdpos == ccline.cmdlen)
846 	    new_cmdpos = 99999;	// keep it at the end
847 	else
848 	    new_cmdpos = ccline.cmdpos;
849 
850 	c = get_expr_register();
851 	if (c == '=')
852 	{
853 	    // Need to save and restore ccline.  And set "textwinlock"
854 	    // to avoid nasty things like going to another buffer when
855 	    // evaluating an expression.
856 	    ++textwinlock;
857 	    p = get_expr_line();
858 	    --textwinlock;
859 
860 	    if (p != NULL)
861 	    {
862 		len = (int)STRLEN(p);
863 		if (realloc_cmdbuff(len + 1) == OK)
864 		{
865 		    ccline.cmdlen = len;
866 		    STRCPY(ccline.cmdbuff, p);
867 		    vim_free(p);
868 
869 		    // Restore the cursor or use the position set with
870 		    // set_cmdline_pos().
871 		    if (new_cmdpos > ccline.cmdlen)
872 			ccline.cmdpos = ccline.cmdlen;
873 		    else
874 			ccline.cmdpos = new_cmdpos;
875 
876 		    KeyTyped = FALSE;	// Don't do p_wc completion.
877 		    redrawcmd();
878 		    return CMDLINE_CHANGED;
879 		}
880 		vim_free(p);
881 	    }
882 	}
883 	beep_flush();
884 	got_int = FALSE;	// don't abandon the command line
885 	did_emsg = FALSE;
886 	emsg_on_display = FALSE;
887 	redrawcmd();
888 	return CMDLINE_NOT_CHANGED;
889     }
890 #endif
891 
892     if (c == Ctrl_G && p_im && restart_edit == 0)
893 	restart_edit = 'a';
894     *gotesc = TRUE;	// will free ccline.cmdbuff after putting it
895 			// in history
896     return GOTO_NORMAL_MODE;
897 }
898 
899 /*
900  * Completion for 'wildchar' or 'wildcharm' key.
901  * - hitting <ESC> twice means: abandon command line.
902  * - wildcard expansion is only done when the 'wildchar' key is really
903  *   typed, not when it comes from a macro
904  * Returns CMDLINE_CHANGED if command line is changed or CMDLINE_NOT_CHANGED.
905  */
906     static int
cmdline_wildchar_complete(int c,int escape,int * did_wild_list,int * wim_index_p,expand_T * xp,int * gotesc)907 cmdline_wildchar_complete(
908 	int		c,
909 	int		escape,
910 	int		*did_wild_list,
911 	int		*wim_index_p,
912 	expand_T	*xp,
913 	int		*gotesc)
914 {
915     int		wim_index = *wim_index_p;
916     int		res;
917     int		j;
918     int		options = WILD_NO_BEEP;
919 
920     if (wim_flags[wim_index] & WIM_BUFLASTUSED)
921 	options |= WILD_BUFLASTUSED;
922     if (xp->xp_numfiles > 0)   // typed p_wc at least twice
923     {
924 	// if 'wildmode' contains "list" may still need to list
925 	if (xp->xp_numfiles > 1
926 		&& !*did_wild_list
927 		&& (wim_flags[wim_index] & WIM_LIST))
928 	{
929 	    (void)showmatches(xp, FALSE);
930 	    redrawcmd();
931 	    *did_wild_list = TRUE;
932 	}
933 	if (wim_flags[wim_index] & WIM_LONGEST)
934 	    res = nextwild(xp, WILD_LONGEST, options, escape);
935 	else if (wim_flags[wim_index] & WIM_FULL)
936 	    res = nextwild(xp, WILD_NEXT, options, escape);
937 	else
938 	    res = OK;	    // don't insert 'wildchar' now
939     }
940     else		    // typed p_wc first time
941     {
942 	wim_index = 0;
943 	j = ccline.cmdpos;
944 	// if 'wildmode' first contains "longest", get longest
945 	// common part
946 	if (wim_flags[0] & WIM_LONGEST)
947 	    res = nextwild(xp, WILD_LONGEST, options, escape);
948 	else
949 	    res = nextwild(xp, WILD_EXPAND_KEEP, options, escape);
950 
951 	// if interrupted while completing, behave like it failed
952 	if (got_int)
953 	{
954 	    (void)vpeekc();	// remove <C-C> from input stream
955 	    got_int = FALSE;	// don't abandon the command line
956 	    (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
957 #ifdef FEAT_WILDMENU
958 	    xp->xp_context = EXPAND_NOTHING;
959 #endif
960 	    *wim_index_p = wim_index;
961 	    return CMDLINE_CHANGED;
962 	}
963 
964 	// when more than one match, and 'wildmode' first contains
965 	// "list", or no change and 'wildmode' contains "longest,list",
966 	// list all matches
967 	if (res == OK && xp->xp_numfiles > 1)
968 	{
969 	    // a "longest" that didn't do anything is skipped (but not
970 	    // "list:longest")
971 	    if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
972 		wim_index = 1;
973 	    if ((wim_flags[wim_index] & WIM_LIST)
974 #ifdef FEAT_WILDMENU
975 		    || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
976 #endif
977 	       )
978 	    {
979 		if (!(wim_flags[0] & WIM_LONGEST))
980 		{
981 #ifdef FEAT_WILDMENU
982 		    int p_wmnu_save = p_wmnu;
983 		    p_wmnu = 0;
984 #endif
985 		    // remove match
986 		    nextwild(xp, WILD_PREV, 0, escape);
987 #ifdef FEAT_WILDMENU
988 		    p_wmnu = p_wmnu_save;
989 #endif
990 		}
991 #ifdef FEAT_WILDMENU
992 		(void)showmatches(xp, p_wmnu
993 			&& ((wim_flags[wim_index] & WIM_LIST) == 0));
994 #else
995 		(void)showmatches(xp, FALSE);
996 #endif
997 		redrawcmd();
998 		*did_wild_list = TRUE;
999 		if (wim_flags[wim_index] & WIM_LONGEST)
1000 		    nextwild(xp, WILD_LONGEST, options, escape);
1001 		else if (wim_flags[wim_index] & WIM_FULL)
1002 		    nextwild(xp, WILD_NEXT, options, escape);
1003 	    }
1004 	    else
1005 		vim_beep(BO_WILD);
1006 	}
1007 #ifdef FEAT_WILDMENU
1008 	else if (xp->xp_numfiles == -1)
1009 	    xp->xp_context = EXPAND_NOTHING;
1010 #endif
1011     }
1012     if (wim_index < 3)
1013 	++wim_index;
1014     if (c == ESC)
1015 	*gotesc = TRUE;
1016 
1017     *wim_index_p = wim_index;
1018     return (res == OK) ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED;
1019 }
1020 
1021 /*
1022  * Handle backspace, delete and CTRL-W keys in the command-line mode.
1023  * Returns:
1024  *  CMDLINE_NOT_CHANGED - if the command line is not changed
1025  *  CMDLINE_CHANGED - if the command line is changed
1026  *  GOTO_NORMAL_MODE - go back to normal mode
1027  */
1028     static int
cmdline_erase_chars(int c,int indent,incsearch_state_T * isp)1029 cmdline_erase_chars(
1030 	int c,
1031 	int indent
1032 #ifdef FEAT_SEARCH_EXTRA
1033 	, incsearch_state_T *isp
1034 #endif
1035 	)
1036 {
1037     int		i;
1038     int		j;
1039 
1040     if (c == K_KDEL)
1041 	c = K_DEL;
1042 
1043     /*
1044      * Delete current character is the same as backspace on next
1045      * character, except at end of line.
1046      */
1047     if (c == K_DEL && ccline.cmdpos != ccline.cmdlen)
1048 	++ccline.cmdpos;
1049     if (has_mbyte && c == K_DEL)
1050 	ccline.cmdpos += mb_off_next(ccline.cmdbuff,
1051 		ccline.cmdbuff + ccline.cmdpos);
1052     if (ccline.cmdpos > 0)
1053     {
1054 	char_u *p;
1055 
1056 	j = ccline.cmdpos;
1057 	p = ccline.cmdbuff + j;
1058 	if (has_mbyte)
1059 	{
1060 	    p = mb_prevptr(ccline.cmdbuff, p);
1061 	    if (c == Ctrl_W)
1062 	    {
1063 		while (p > ccline.cmdbuff && vim_isspace(*p))
1064 		    p = mb_prevptr(ccline.cmdbuff, p);
1065 		i = mb_get_class(p);
1066 		while (p > ccline.cmdbuff && mb_get_class(p) == i)
1067 		    p = mb_prevptr(ccline.cmdbuff, p);
1068 		if (mb_get_class(p) != i)
1069 		    p += (*mb_ptr2len)(p);
1070 	    }
1071 	}
1072 	else if (c == Ctrl_W)
1073 	{
1074 	    while (p > ccline.cmdbuff && vim_isspace(p[-1]))
1075 		--p;
1076 	    i = vim_iswordc(p[-1]);
1077 	    while (p > ccline.cmdbuff && !vim_isspace(p[-1])
1078 		    && vim_iswordc(p[-1]) == i)
1079 		--p;
1080 	}
1081 	else
1082 	    --p;
1083 	ccline.cmdpos = (int)(p - ccline.cmdbuff);
1084 	ccline.cmdlen -= j - ccline.cmdpos;
1085 	i = ccline.cmdpos;
1086 	while (i < ccline.cmdlen)
1087 	    ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
1088 
1089 	// Truncate at the end, required for multi-byte chars.
1090 	ccline.cmdbuff[ccline.cmdlen] = NUL;
1091 #ifdef FEAT_SEARCH_EXTRA
1092 	if (ccline.cmdlen == 0)
1093 	{
1094 	    isp->search_start = isp->save_cursor;
1095 	    // save view settings, so that the screen
1096 	    // won't be restored at the wrong position
1097 	    isp->old_viewstate = isp->init_viewstate;
1098 	}
1099 #endif
1100 	redrawcmd();
1101     }
1102     else if (ccline.cmdlen == 0 && c != Ctrl_W
1103 	    && ccline.cmdprompt == NULL && indent == 0)
1104     {
1105 	// In ex and debug mode it doesn't make sense to return.
1106 	if (exmode_active
1107 #ifdef FEAT_EVAL
1108 		|| ccline.cmdfirstc == '>'
1109 #endif
1110 	   )
1111 	    return CMDLINE_NOT_CHANGED;
1112 
1113 	VIM_CLEAR(ccline.cmdbuff);	// no commandline to return
1114 	if (!cmd_silent)
1115 	{
1116 #ifdef FEAT_RIGHTLEFT
1117 	    if (cmdmsg_rl)
1118 		msg_col = Columns;
1119 	    else
1120 #endif
1121 		msg_col = 0;
1122 	    msg_putchar(' ');		// delete ':'
1123 	}
1124 #ifdef FEAT_SEARCH_EXTRA
1125 	if (ccline.cmdlen == 0)
1126 	    isp->search_start = isp->save_cursor;
1127 #endif
1128 	redraw_cmdline = TRUE;
1129 	return GOTO_NORMAL_MODE;
1130     }
1131     return CMDLINE_CHANGED;
1132 }
1133 
1134 /*
1135  * Handle the CTRL-^ key in the command-line mode and toggle the use of the
1136  * language :lmap mappings and/or Input Method.
1137  */
1138     static void
cmdline_toggle_langmap(long * b_im_ptr)1139 cmdline_toggle_langmap(long *b_im_ptr)
1140 {
1141     if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
1142     {
1143 	// ":lmap" mappings exists, toggle use of mappings.
1144 	State ^= LANGMAP;
1145 #ifdef HAVE_INPUT_METHOD
1146 	im_set_active(FALSE);	// Disable input method
1147 #endif
1148 	if (b_im_ptr != NULL)
1149 	{
1150 	    if (State & LANGMAP)
1151 		*b_im_ptr = B_IMODE_LMAP;
1152 	    else
1153 		*b_im_ptr = B_IMODE_NONE;
1154 	}
1155     }
1156 #ifdef HAVE_INPUT_METHOD
1157     else
1158     {
1159 	// There are no ":lmap" mappings, toggle IM.  When
1160 	// 'imdisable' is set don't try getting the status, it's
1161 	// always off.
1162 	if ((p_imdisable && b_im_ptr != NULL)
1163 		? *b_im_ptr == B_IMODE_IM : im_get_status())
1164 	{
1165 	    im_set_active(FALSE);	// Disable input method
1166 	    if (b_im_ptr != NULL)
1167 		*b_im_ptr = B_IMODE_NONE;
1168 	}
1169 	else
1170 	{
1171 	    im_set_active(TRUE);	// Enable input method
1172 	    if (b_im_ptr != NULL)
1173 		*b_im_ptr = B_IMODE_IM;
1174 	}
1175     }
1176 #endif
1177     if (b_im_ptr != NULL)
1178     {
1179 	if (b_im_ptr == &curbuf->b_p_iminsert)
1180 	    set_iminsert_global();
1181 	else
1182 	    set_imsearch_global();
1183     }
1184 #ifdef CURSOR_SHAPE
1185     ui_cursor_shape();	// may show different cursor shape
1186 #endif
1187 #if defined(FEAT_KEYMAP)
1188     // Show/unshow value of 'keymap' in status lines later.
1189     status_redraw_curbuf();
1190 #endif
1191 }
1192 
1193 /*
1194  * Handle the CTRL-R key in the command-line mode and insert the contents of a
1195  * numbered or named register.
1196  */
1197     static int
cmdline_insert_reg(int * gotesc UNUSED)1198 cmdline_insert_reg(int *gotesc UNUSED)
1199 {
1200     int		i;
1201     int		c;
1202 
1203 #ifdef USE_ON_FLY_SCROLL
1204     dont_scroll = TRUE;	// disallow scrolling here
1205 #endif
1206     putcmdline('"', TRUE);
1207     ++no_mapping;
1208     ++allow_keys;
1209     i = c = plain_vgetc();	// CTRL-R <char>
1210     if (i == Ctrl_O)
1211 	i = Ctrl_R;		// CTRL-R CTRL-O == CTRL-R CTRL-R
1212     if (i == Ctrl_R)
1213 	c = plain_vgetc();	// CTRL-R CTRL-R <char>
1214     extra_char = NUL;
1215     --no_mapping;
1216     --allow_keys;
1217 #ifdef FEAT_EVAL
1218     /*
1219      * Insert the result of an expression.
1220      * Need to save the current command line, to be able to enter
1221      * a new one...
1222      */
1223     new_cmdpos = -1;
1224     if (c == '=')
1225     {
1226 	if (ccline.cmdfirstc == '='  // can't do this recursively
1227 		|| cmdline_star > 0) // or when typing a password
1228 	{
1229 	    beep_flush();
1230 	    c = ESC;
1231 	}
1232 	else
1233 	    c = get_expr_register();
1234     }
1235 #endif
1236     if (c != ESC)	    // use ESC to cancel inserting register
1237     {
1238 	cmdline_paste(c, i == Ctrl_R, FALSE);
1239 
1240 #ifdef FEAT_EVAL
1241 	// When there was a serious error abort getting the
1242 	// command line.
1243 	if (aborting())
1244 	{
1245 	    *gotesc = TRUE;  // will free ccline.cmdbuff after
1246 	    // putting it in history
1247 	    return GOTO_NORMAL_MODE;
1248 	}
1249 #endif
1250 	KeyTyped = FALSE;	// Don't do p_wc completion.
1251 #ifdef FEAT_EVAL
1252 	if (new_cmdpos >= 0)
1253 	{
1254 	    // set_cmdline_pos() was used
1255 	    if (new_cmdpos > ccline.cmdlen)
1256 		ccline.cmdpos = ccline.cmdlen;
1257 	    else
1258 		ccline.cmdpos = new_cmdpos;
1259 	}
1260 #endif
1261     }
1262     // remove the double quote
1263     redrawcmd();
1264 
1265     // The text has been stuffed, the command line didn't change yet.
1266     return CMDLINE_NOT_CHANGED;
1267 }
1268 
1269 /*
1270  * Handle the Left and Right mouse clicks in the command-line mode.
1271  */
1272     static void
cmdline_left_right_mouse(int c,int * ignore_drag_release)1273 cmdline_left_right_mouse(int c, int *ignore_drag_release)
1274 {
1275     if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
1276 	*ignore_drag_release = TRUE;
1277     else
1278 	*ignore_drag_release = FALSE;
1279 # ifdef FEAT_GUI
1280     // When GUI is active, also move when 'mouse' is empty
1281     if (!gui.in_use)
1282 # endif
1283 	if (!mouse_has(MOUSE_COMMAND))
1284 	    return;
1285 # ifdef FEAT_CLIPBOARD
1286     if (mouse_row < cmdline_row && clip_star.available)
1287     {
1288 	int	    button, is_click, is_drag;
1289 
1290 	/*
1291 	 * Handle modeless selection.
1292 	 */
1293 	button = get_mouse_button(KEY2TERMCAP1(c),
1294 		&is_click, &is_drag);
1295 	if (mouse_model_popup() && button == MOUSE_LEFT
1296 		&& (mod_mask & MOD_MASK_SHIFT))
1297 	{
1298 	    // Translate shift-left to right button.
1299 	    button = MOUSE_RIGHT;
1300 	    mod_mask &= ~MOD_MASK_SHIFT;
1301 	}
1302 	clip_modeless(button, is_click, is_drag);
1303 	return;
1304     }
1305 # endif
1306 
1307     set_cmdspos();
1308     for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
1309 	    ++ccline.cmdpos)
1310     {
1311 	int	i;
1312 
1313 	i = cmdline_charsize(ccline.cmdpos);
1314 	if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
1315 		&& mouse_col < ccline.cmdspos % Columns + i)
1316 	    break;
1317 	if (has_mbyte)
1318 	{
1319 	    // Count ">" for double-wide char that doesn't fit.
1320 	    correct_cmdspos(ccline.cmdpos, i);
1321 	    ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
1322 		    + ccline.cmdpos) - 1;
1323 	}
1324 	ccline.cmdspos += i;
1325     }
1326 }
1327 
1328 /*
1329  * Handle the Up, Down, Page Up, Page down, CTRL-N and CTRL-P key in the
1330  * command-line mode. The pressed key is in 'c'.
1331  * Returns:
1332  *  CMDLINE_NOT_CHANGED - if the command line is not changed
1333  *  CMDLINE_CHANGED - if the command line is changed
1334  *  GOTO_NORMAL_MODE - go back to normal mode
1335  */
1336     static int
cmdline_browse_history(int c,int firstc,char_u ** curcmdstr,int histype,int * hiscnt_p,expand_T * xp)1337 cmdline_browse_history(
1338 	int	c,
1339 	int	firstc,
1340 	char_u	**curcmdstr,
1341 	int	histype,
1342 	int	*hiscnt_p,
1343 	expand_T *xp)
1344 {
1345     int		i;
1346     int		j;
1347     char_u	*lookfor = *curcmdstr;
1348     int		hiscnt = *hiscnt_p;
1349     int		res;
1350 
1351     if (get_hislen() == 0 || firstc == NUL)	// no history
1352 	return CMDLINE_NOT_CHANGED;
1353 
1354     i = hiscnt;
1355 
1356     // save current command string so it can be restored later
1357     if (lookfor == NULL)
1358     {
1359 	if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL)
1360 	    return CMDLINE_NOT_CHANGED;
1361 	lookfor[ccline.cmdpos] = NUL;
1362     }
1363 
1364     j = (int)STRLEN(lookfor);
1365     for (;;)
1366     {
1367 	// one step backwards
1368 	if (c == K_UP|| c == K_S_UP || c == Ctrl_P
1369 		|| c == K_PAGEUP || c == K_KPAGEUP)
1370 	{
1371 	    if (hiscnt == get_hislen())	// first time
1372 		hiscnt = *get_hisidx(histype);
1373 	    else if (hiscnt == 0 && *get_hisidx(histype)
1374 		    != get_hislen() - 1)
1375 		hiscnt = get_hislen() - 1;
1376 	    else if (hiscnt != *get_hisidx(histype) + 1)
1377 		--hiscnt;
1378 	    else			// at top of list
1379 	    {
1380 		hiscnt = i;
1381 		break;
1382 	    }
1383 	}
1384 	else    // one step forwards
1385 	{
1386 	    // on last entry, clear the line
1387 	    if (hiscnt == *get_hisidx(histype))
1388 	    {
1389 		hiscnt = get_hislen();
1390 		break;
1391 	    }
1392 
1393 	    // not on a history line, nothing to do
1394 	    if (hiscnt == get_hislen())
1395 		break;
1396 	    if (hiscnt == get_hislen() - 1)   // wrap around
1397 		hiscnt = 0;
1398 	    else
1399 		++hiscnt;
1400 	}
1401 	if (hiscnt < 0 || get_histentry(histype)[hiscnt].hisstr
1402 		== NULL)
1403 	{
1404 	    hiscnt = i;
1405 	    break;
1406 	}
1407 	if ((c != K_UP && c != K_DOWN)
1408 		|| hiscnt == i
1409 		|| STRNCMP(get_histentry(histype)[hiscnt].hisstr,
1410 		    lookfor, (size_t)j) == 0)
1411 	    break;
1412     }
1413 
1414     if (hiscnt != i)	// jumped to other entry
1415     {
1416 	char_u	*p;
1417 	int		len;
1418 	int		old_firstc;
1419 
1420 	VIM_CLEAR(ccline.cmdbuff);
1421 	xp->xp_context = EXPAND_NOTHING;
1422 	if (hiscnt == get_hislen())
1423 	    p = lookfor;	// back to the old one
1424 	else
1425 	    p = get_histentry(histype)[hiscnt].hisstr;
1426 
1427 	if (histype == HIST_SEARCH
1428 		&& p != lookfor
1429 		&& (old_firstc = p[STRLEN(p) + 1]) != firstc)
1430 	{
1431 	    // Correct for the separator character used when
1432 	    // adding the history entry vs the one used now.
1433 	    // First loop: count length.
1434 	    // Second loop: copy the characters.
1435 	    for (i = 0; i <= 1; ++i)
1436 	    {
1437 		len = 0;
1438 		for (j = 0; p[j] != NUL; ++j)
1439 		{
1440 		    // Replace old sep with new sep, unless it is
1441 		    // escaped.
1442 		    if (p[j] == old_firstc
1443 			    && (j == 0 || p[j - 1] != '\\'))
1444 		    {
1445 			if (i > 0)
1446 			    ccline.cmdbuff[len] = firstc;
1447 		    }
1448 		    else
1449 		    {
1450 			// Escape new sep, unless it is already
1451 			// escaped.
1452 			if (p[j] == firstc
1453 				&& (j == 0 || p[j - 1] != '\\'))
1454 			{
1455 			    if (i > 0)
1456 				ccline.cmdbuff[len] = '\\';
1457 			    ++len;
1458 			}
1459 			if (i > 0)
1460 			    ccline.cmdbuff[len] = p[j];
1461 		    }
1462 		    ++len;
1463 		}
1464 		if (i == 0)
1465 		{
1466 		    alloc_cmdbuff(len);
1467 		    if (ccline.cmdbuff == NULL)
1468 		    {
1469 			res = GOTO_NORMAL_MODE;
1470 			goto done;
1471 		    }
1472 		}
1473 	    }
1474 	    ccline.cmdbuff[len] = NUL;
1475 	}
1476 	else
1477 	{
1478 	    alloc_cmdbuff((int)STRLEN(p));
1479 	    if (ccline.cmdbuff == NULL)
1480 	    {
1481 		res = GOTO_NORMAL_MODE;
1482 		goto done;
1483 	    }
1484 	    STRCPY(ccline.cmdbuff, p);
1485 	}
1486 
1487 	ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
1488 	redrawcmd();
1489 	res = CMDLINE_CHANGED;
1490 	goto done;
1491     }
1492     beep_flush();
1493     res = CMDLINE_NOT_CHANGED;
1494 
1495 done:
1496     *curcmdstr = lookfor;
1497     *hiscnt_p = hiscnt;
1498     return res;
1499 }
1500 
1501 /*
1502  * Initialize the current command-line info.
1503  */
1504     static int
init_ccline(int firstc,int indent)1505 init_ccline(int firstc, int indent)
1506 {
1507     ccline.overstrike = FALSE;		    // always start in insert mode
1508 
1509     /*
1510      * set some variables for redrawcmd()
1511      */
1512     ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
1513     ccline.cmdindent = (firstc > 0 ? indent : 0);
1514 
1515     // alloc initial ccline.cmdbuff
1516     alloc_cmdbuff(exmode_active ? 250 : indent + 1);
1517     if (ccline.cmdbuff == NULL)
1518 	return FAIL;
1519     ccline.cmdlen = ccline.cmdpos = 0;
1520     ccline.cmdbuff[0] = NUL;
1521     sb_text_start_cmdline();
1522 
1523     // autoindent for :insert and :append
1524     if (firstc <= 0)
1525     {
1526 	vim_memset(ccline.cmdbuff, ' ', indent);
1527 	ccline.cmdbuff[indent] = NUL;
1528 	ccline.cmdpos = indent;
1529 	ccline.cmdspos = indent;
1530 	ccline.cmdlen = indent;
1531     }
1532 
1533     return OK;
1534 }
1535 
1536 /*
1537  * getcmdline() - accept a command line starting with firstc.
1538  *
1539  * firstc == ':'	    get ":" command line.
1540  * firstc == '/' or '?'	    get search pattern
1541  * firstc == '='	    get expression
1542  * firstc == '@'	    get text for input() function
1543  * firstc == '>'	    get text for debug mode
1544  * firstc == NUL	    get text for :insert command
1545  * firstc == -1		    like NUL, and break on CTRL-C
1546  *
1547  * The line is collected in ccline.cmdbuff, which is reallocated to fit the
1548  * command line.
1549  *
1550  * Careful: getcmdline() can be called recursively!
1551  *
1552  * Return pointer to allocated string if there is a commandline, NULL
1553  * otherwise.
1554  */
1555     char_u *
getcmdline(int firstc,long count,int indent,int do_concat UNUSED)1556 getcmdline(
1557     int		firstc,
1558     long	count,		// only used for incremental search
1559     int		indent,		// indent for inside conditionals
1560     int		do_concat UNUSED)
1561 {
1562     return getcmdline_int(firstc, count, indent, TRUE);
1563 }
1564 
1565     static char_u *
getcmdline_int(int firstc,long count UNUSED,int indent,int clear_ccline)1566 getcmdline_int(
1567     int		firstc,
1568     long	count UNUSED,	// only used for incremental search
1569     int		indent,		// indent for inside conditionals
1570     int		clear_ccline)	// clear ccline first
1571 {
1572     int		c;
1573     int		i;
1574     int		j;
1575     int		gotesc = FALSE;		// TRUE when <ESC> just typed
1576     int		do_abbr;		// when TRUE check for abbr.
1577     char_u	*lookfor = NULL;	// string to match
1578     int		hiscnt;			// current history line in use
1579     int		histype;		// history type to be used
1580 #ifdef FEAT_SEARCH_EXTRA
1581     incsearch_state_T	is_state;
1582 #endif
1583     int		did_wild_list = FALSE;	// did wild_list() recently
1584     int		wim_index = 0;		// index in wim_flags[]
1585     int		res;
1586     int		save_msg_scroll = msg_scroll;
1587     int		save_State = State;	// remember State when called
1588     int		some_key_typed = FALSE;	// one of the keys was typed
1589     // mouse drag and release events are ignored, unless they are
1590     // preceded with a mouse down event
1591     int		ignore_drag_release = TRUE;
1592 #ifdef FEAT_EVAL
1593     int		break_ctrl_c = FALSE;
1594 #endif
1595     expand_T	xpc;
1596     long	*b_im_ptr = NULL;
1597     cmdline_info_T save_ccline;
1598     int		did_save_ccline = FALSE;
1599     int		cmdline_type;
1600 
1601     if (ccline.cmdbuff != NULL)
1602     {
1603 	// Being called recursively.  Since ccline is global, we need to save
1604 	// the current buffer and restore it when returning.
1605 	save_cmdline(&save_ccline);
1606 	did_save_ccline = TRUE;
1607     }
1608     if (clear_ccline)
1609 	CLEAR_FIELD(ccline);
1610 
1611 #ifdef FEAT_EVAL
1612     if (firstc == -1)
1613     {
1614 	firstc = NUL;
1615 	break_ctrl_c = TRUE;
1616     }
1617 #endif
1618 #ifdef FEAT_RIGHTLEFT
1619     // start without Hebrew mapping for a command line
1620     if (firstc == ':' || firstc == '=' || firstc == '>')
1621 	cmd_hkmap = 0;
1622 #endif
1623 
1624 #ifdef FEAT_SEARCH_EXTRA
1625     init_incsearch_state(&is_state);
1626 #endif
1627 
1628     if (init_ccline(firstc, indent) != OK)
1629 	goto theend;	// out of memory
1630 
1631     ExpandInit(&xpc);
1632     ccline.xpc = &xpc;
1633 
1634 #ifdef FEAT_RIGHTLEFT
1635     if (curwin->w_p_rl && *curwin->w_p_rlc == 's'
1636 					  && (firstc == '/' || firstc == '?'))
1637 	cmdmsg_rl = TRUE;
1638     else
1639 	cmdmsg_rl = FALSE;
1640 #endif
1641 
1642     redir_off = TRUE;		// don't redirect the typed command
1643     if (!cmd_silent)
1644     {
1645 	i = msg_scrolled;
1646 	msg_scrolled = 0;		// avoid wait_return message
1647 	gotocmdline(TRUE);
1648 	msg_scrolled += i;
1649 	redrawcmdprompt();		// draw prompt or indent
1650 	set_cmdspos();
1651     }
1652     xpc.xp_context = EXPAND_NOTHING;
1653     xpc.xp_backslash = XP_BS_NONE;
1654 #ifndef BACKSLASH_IN_FILENAME
1655     xpc.xp_shell = FALSE;
1656 #endif
1657 
1658 #if defined(FEAT_EVAL)
1659     if (ccline.input_fn)
1660     {
1661 	xpc.xp_context = ccline.xp_context;
1662 	xpc.xp_pattern = ccline.cmdbuff;
1663 	xpc.xp_arg = ccline.xp_arg;
1664     }
1665 #endif
1666 
1667     /*
1668      * Avoid scrolling when called by a recursive do_cmdline(), e.g. when
1669      * doing ":@0" when register 0 doesn't contain a CR.
1670      */
1671     msg_scroll = FALSE;
1672 
1673     State = CMDLINE;
1674 
1675     if (firstc == '/' || firstc == '?' || firstc == '@')
1676     {
1677 	// Use ":lmap" mappings for search pattern and input().
1678 	if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT)
1679 	    b_im_ptr = &curbuf->b_p_iminsert;
1680 	else
1681 	    b_im_ptr = &curbuf->b_p_imsearch;
1682 	if (*b_im_ptr == B_IMODE_LMAP)
1683 	    State |= LANGMAP;
1684 #ifdef HAVE_INPUT_METHOD
1685 	im_set_active(*b_im_ptr == B_IMODE_IM);
1686 #endif
1687     }
1688 #ifdef HAVE_INPUT_METHOD
1689     else if (p_imcmdline)
1690 	im_set_active(TRUE);
1691 #endif
1692 
1693     setmouse();
1694 #ifdef CURSOR_SHAPE
1695     ui_cursor_shape();		// may show different cursor shape
1696 #endif
1697 
1698     // When inside an autocommand for writing "exiting" may be set and
1699     // terminal mode set to cooked.  Need to set raw mode here then.
1700     settmode(TMODE_RAW);
1701 
1702     // Trigger CmdlineEnter autocommands.
1703     cmdline_type = firstc == NUL ? '-' : firstc;
1704     trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
1705 #ifdef FEAT_EVAL
1706     if (!debug_mode)
1707 	trigger_modechanged();
1708 #endif
1709 
1710     init_history();
1711     hiscnt = get_hislen();	// set hiscnt to impossible history value
1712     histype = hist_char2type(firstc);
1713 
1714 #ifdef FEAT_DIGRAPHS
1715     do_digraph(-1);		// init digraph typeahead
1716 #endif
1717 
1718     // If something above caused an error, reset the flags, we do want to type
1719     // and execute commands. Display may be messed up a bit.
1720     if (did_emsg)
1721 	redrawcmd();
1722 
1723 #ifdef FEAT_STL_OPT
1724     // Redraw the statusline in case it uses the current mode using the mode()
1725     // function.
1726     if (!cmd_silent && msg_scrolled == 0)
1727     {
1728 	int	found_one = FALSE;
1729 	win_T	*wp;
1730 
1731 	FOR_ALL_WINDOWS(wp)
1732 	    if (*p_stl != NUL || *wp->w_p_stl != NUL)
1733 	    {
1734 		wp->w_redr_status = TRUE;
1735 		found_one = TRUE;
1736 	    }
1737 	if (found_one)
1738 	    redraw_statuslines();
1739     }
1740 #endif
1741 
1742     did_emsg = FALSE;
1743     got_int = FALSE;
1744 
1745     /*
1746      * Collect the command string, handling editing keys.
1747      */
1748     for (;;)
1749     {
1750 	int trigger_cmdlinechanged = TRUE;
1751 
1752 	redir_off = TRUE;	// Don't redirect the typed command.
1753 				// Repeated, because a ":redir" inside
1754 				// completion may switch it on.
1755 #ifdef USE_ON_FLY_SCROLL
1756 	dont_scroll = FALSE;	// allow scrolling here
1757 #endif
1758 	quit_more = FALSE;	// reset after CTRL-D which had a more-prompt
1759 
1760 	did_emsg = FALSE;	// There can't really be a reason why an error
1761 				// that occurs while typing a command should
1762 				// cause the command not to be executed.
1763 
1764 	// Trigger SafeState if nothing is pending.
1765 	may_trigger_safestate(xpc.xp_numfiles <= 0);
1766 
1767 	// Get a character.  Ignore K_IGNORE and K_NOP, they should not do
1768 	// anything, such as stop completion.
1769 	do
1770 	{
1771 	    cursorcmd();		// set the cursor on the right spot
1772 	    c = safe_vgetc();
1773 	} while (c == K_IGNORE || c == K_NOP);
1774 
1775 	if (c == K_COMMAND)
1776 	{
1777 	    int	    clen = ccline.cmdlen;
1778 
1779 	    if (do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK)
1780 	    {
1781 		if (clen == ccline.cmdlen)
1782 		    trigger_cmdlinechanged = FALSE;
1783 		goto cmdline_changed;
1784 	    }
1785 	}
1786 
1787 	if (KeyTyped)
1788 	{
1789 	    some_key_typed = TRUE;
1790 #ifdef FEAT_RIGHTLEFT
1791 	    if (cmd_hkmap)
1792 		c = hkmap(c);
1793 	    if (cmdmsg_rl && !KeyStuffed)
1794 	    {
1795 		// Invert horizontal movements and operations.  Only when
1796 		// typed by the user directly, not when the result of a
1797 		// mapping.
1798 		switch (c)
1799 		{
1800 		    case K_RIGHT:   c = K_LEFT; break;
1801 		    case K_S_RIGHT: c = K_S_LEFT; break;
1802 		    case K_C_RIGHT: c = K_C_LEFT; break;
1803 		    case K_LEFT:    c = K_RIGHT; break;
1804 		    case K_S_LEFT:  c = K_S_RIGHT; break;
1805 		    case K_C_LEFT:  c = K_C_RIGHT; break;
1806 		}
1807 	    }
1808 #endif
1809 	}
1810 
1811 	/*
1812 	 * Ignore got_int when CTRL-C was typed here.
1813 	 * Don't ignore it in :global, we really need to break then, e.g., for
1814 	 * ":g/pat/normal /pat" (without the <CR>).
1815 	 * Don't ignore it for the input() function.
1816 	 */
1817 	if ((c == Ctrl_C
1818 #ifdef UNIX
1819 		|| c == intr_char
1820 #endif
1821 				)
1822 #if defined(FEAT_EVAL) || defined(FEAT_CRYPT)
1823 		&& firstc != '@'
1824 #endif
1825 #ifdef FEAT_EVAL
1826 		&& !break_ctrl_c
1827 #endif
1828 		&& !global_busy)
1829 	    got_int = FALSE;
1830 
1831 	// free old command line when finished moving around in the history
1832 	// list
1833 	if (lookfor != NULL
1834 		&& c != K_S_DOWN && c != K_S_UP
1835 		&& c != K_DOWN && c != K_UP
1836 		&& c != K_PAGEDOWN && c != K_PAGEUP
1837 		&& c != K_KPAGEDOWN && c != K_KPAGEUP
1838 		&& c != K_LEFT && c != K_RIGHT
1839 		&& (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N)))
1840 	    VIM_CLEAR(lookfor);
1841 
1842 	/*
1843 	 * When there are matching completions to select <S-Tab> works like
1844 	 * CTRL-P (unless 'wc' is <S-Tab>).
1845 	 */
1846 	if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles > 0)
1847 	    c = Ctrl_P;
1848 
1849 #ifdef FEAT_WILDMENU
1850 	c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
1851 #endif
1852 
1853 	// free expanded names when finished walking through matches
1854 	if (xpc.xp_numfiles != -1
1855 		&& !(c == p_wc && KeyTyped) && c != p_wcm
1856 		&& c != Ctrl_N && c != Ctrl_P && c != Ctrl_A
1857 		&& c != Ctrl_L)
1858 	{
1859 	    (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
1860 	    did_wild_list = FALSE;
1861 #ifdef FEAT_WILDMENU
1862 	    if (!p_wmnu || (c != K_UP && c != K_DOWN))
1863 #endif
1864 		xpc.xp_context = EXPAND_NOTHING;
1865 	    wim_index = 0;
1866 #ifdef FEAT_WILDMENU
1867 	    wildmenu_cleanup(&ccline);
1868 #endif
1869 	}
1870 
1871 #ifdef FEAT_WILDMENU
1872 	c = wildmenu_process_key(&ccline, c, &xpc);
1873 #endif
1874 
1875 	// CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
1876 	// mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
1877 	if (c == Ctrl_BSL)
1878 	{
1879 	    res = cmdline_handle_backslash_key(c, &gotesc);
1880 	    if (res == CMDLINE_CHANGED)
1881 		goto cmdline_changed;
1882 	    else if (res == CMDLINE_NOT_CHANGED)
1883 		goto cmdline_not_changed;
1884 	    else if (res == GOTO_NORMAL_MODE)
1885 		goto returncmd;		// back to cmd mode
1886 	    c = Ctrl_BSL;		// backslash key not processed by
1887 					// cmdline_handle_backslash_key()
1888 	}
1889 
1890 #ifdef FEAT_CMDWIN
1891 	if (c == cedit_key || c == K_CMDWIN)
1892 	{
1893 	    // TODO: why is ex_normal_busy checked here?
1894 	    if ((c == K_CMDWIN || ex_normal_busy == 0) && got_int == FALSE)
1895 	    {
1896 		/*
1897 		 * Open a window to edit the command line (and history).
1898 		 */
1899 		c = open_cmdwin();
1900 		some_key_typed = TRUE;
1901 	    }
1902 	}
1903 # ifdef FEAT_DIGRAPHS
1904 	else
1905 # endif
1906 #endif
1907 #ifdef FEAT_DIGRAPHS
1908 	    c = do_digraph(c);
1909 #endif
1910 
1911 	if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC
1912 			&& (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL)))
1913 	{
1914 	    // In Ex mode a backslash escapes a newline.
1915 	    if (exmode_active
1916 		    && c != ESC
1917 		    && ccline.cmdpos == ccline.cmdlen
1918 		    && ccline.cmdpos > 0
1919 		    && ccline.cmdbuff[ccline.cmdpos - 1] == '\\')
1920 	    {
1921 		if (c == K_KENTER)
1922 		    c = '\n';
1923 	    }
1924 	    else
1925 	    {
1926 		gotesc = FALSE;	// Might have typed ESC previously, don't
1927 				// truncate the cmdline now.
1928 		if (ccheck_abbr(c + ABBR_OFF))
1929 		    goto cmdline_changed;
1930 		if (!cmd_silent)
1931 		{
1932 		    windgoto(msg_row, 0);
1933 		    out_flush();
1934 		}
1935 		break;
1936 	    }
1937 	}
1938 
1939 	// Completion for 'wildchar' or 'wildcharm' key.
1940 	if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
1941 	{
1942 	    res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list,
1943 		    &wim_index, &xpc, &gotesc);
1944 	    if (res == CMDLINE_CHANGED)
1945 		goto cmdline_changed;
1946 	}
1947 
1948 	gotesc = FALSE;
1949 
1950 	// <S-Tab> goes to last match, in a clumsy way
1951 	if (c == K_S_TAB && KeyTyped)
1952 	{
1953 	    if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK
1954 		    && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
1955 		    && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
1956 		goto cmdline_changed;
1957 	}
1958 
1959 	if (c == NUL || c == K_ZERO)	    // NUL is stored as NL
1960 	    c = NL;
1961 
1962 	do_abbr = TRUE;		// default: check for abbreviation
1963 
1964 	/*
1965 	 * Big switch for a typed command line character.
1966 	 */
1967 	switch (c)
1968 	{
1969 	case K_BS:
1970 	case Ctrl_H:
1971 	case K_DEL:
1972 	case K_KDEL:
1973 	case Ctrl_W:
1974 	    res = cmdline_erase_chars(c, indent
1975 #ifdef FEAT_SEARCH_EXTRA
1976 		    , &is_state
1977 #endif
1978 		    );
1979 	    if (res == CMDLINE_NOT_CHANGED)
1980 		goto cmdline_not_changed;
1981 	    else if (res == GOTO_NORMAL_MODE)
1982 		goto returncmd;		// back to cmd mode
1983 	    goto cmdline_changed;
1984 
1985 	case K_INS:
1986 	case K_KINS:
1987 		ccline.overstrike = !ccline.overstrike;
1988 #ifdef CURSOR_SHAPE
1989 		ui_cursor_shape();	// may show different cursor shape
1990 #endif
1991 		goto cmdline_not_changed;
1992 
1993 	case Ctrl_HAT:
1994 		cmdline_toggle_langmap(b_im_ptr);
1995 		goto cmdline_not_changed;
1996 
1997 //	case '@':   only in very old vi
1998 	case Ctrl_U:
1999 		// delete all characters left of the cursor
2000 		j = ccline.cmdpos;
2001 		ccline.cmdlen -= j;
2002 		i = ccline.cmdpos = 0;
2003 		while (i < ccline.cmdlen)
2004 		    ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
2005 		// Truncate at the end, required for multi-byte chars.
2006 		ccline.cmdbuff[ccline.cmdlen] = NUL;
2007 #ifdef FEAT_SEARCH_EXTRA
2008 		if (ccline.cmdlen == 0)
2009 		    is_state.search_start = is_state.save_cursor;
2010 #endif
2011 		redrawcmd();
2012 		goto cmdline_changed;
2013 
2014 #ifdef FEAT_CLIPBOARD
2015 	case Ctrl_Y:
2016 		// Copy the modeless selection, if there is one.
2017 		if (clip_star.state != SELECT_CLEARED)
2018 		{
2019 		    if (clip_star.state == SELECT_DONE)
2020 			clip_copy_modeless_selection(TRUE);
2021 		    goto cmdline_not_changed;
2022 		}
2023 		break;
2024 #endif
2025 
2026 	case ESC:	// get here if p_wc != ESC or when ESC typed twice
2027 	case Ctrl_C:
2028 		// In exmode it doesn't make sense to return.  Except when
2029 		// ":normal" runs out of characters.
2030 		if (exmode_active
2031 			       && (ex_normal_busy == 0 || typebuf.tb_len > 0))
2032 		    goto cmdline_not_changed;
2033 
2034 		gotesc = TRUE;		// will free ccline.cmdbuff after
2035 					// putting it in history
2036 		goto returncmd;		// back to cmd mode
2037 
2038 	case Ctrl_R:			// insert register
2039 		res = cmdline_insert_reg(&gotesc);
2040 		if (res == CMDLINE_NOT_CHANGED)
2041 		    goto cmdline_not_changed;
2042 		else if (res == GOTO_NORMAL_MODE)
2043 		    goto returncmd;
2044 		goto cmdline_changed;
2045 
2046 	case Ctrl_D:
2047 		if (showmatches(&xpc, FALSE) == EXPAND_NOTHING)
2048 		    break;	// Use ^D as normal char instead
2049 
2050 		redrawcmd();
2051 		continue;	// don't do incremental search now
2052 
2053 	case K_RIGHT:
2054 	case K_S_RIGHT:
2055 	case K_C_RIGHT:
2056 		do
2057 		{
2058 		    if (ccline.cmdpos >= ccline.cmdlen)
2059 			break;
2060 		    i = cmdline_charsize(ccline.cmdpos);
2061 		    if (KeyTyped && ccline.cmdspos + i >= Columns * Rows)
2062 			break;
2063 		    ccline.cmdspos += i;
2064 		    if (has_mbyte)
2065 			ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
2066 							     + ccline.cmdpos);
2067 		    else
2068 			++ccline.cmdpos;
2069 		}
2070 		while ((c == K_S_RIGHT || c == K_C_RIGHT
2071 			       || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
2072 			&& ccline.cmdbuff[ccline.cmdpos] != ' ');
2073 		if (has_mbyte)
2074 		    set_cmdspos_cursor();
2075 		goto cmdline_not_changed;
2076 
2077 	case K_LEFT:
2078 	case K_S_LEFT:
2079 	case K_C_LEFT:
2080 		if (ccline.cmdpos == 0)
2081 		    goto cmdline_not_changed;
2082 		do
2083 		{
2084 		    --ccline.cmdpos;
2085 		    if (has_mbyte)	// move to first byte of char
2086 			ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff,
2087 					      ccline.cmdbuff + ccline.cmdpos);
2088 		    ccline.cmdspos -= cmdline_charsize(ccline.cmdpos);
2089 		}
2090 		while (ccline.cmdpos > 0
2091 			&& (c == K_S_LEFT || c == K_C_LEFT
2092 			       || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
2093 			&& ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
2094 		if (has_mbyte)
2095 		    set_cmdspos_cursor();
2096 		goto cmdline_not_changed;
2097 
2098 	case K_IGNORE:
2099 		// Ignore mouse event or open_cmdwin() result.
2100 		goto cmdline_not_changed;
2101 
2102 #ifdef FEAT_GUI_MSWIN
2103 	    // On MS-Windows ignore <M-F4>, we get it when closing the window
2104 	    // was cancelled.
2105 	case K_F4:
2106 	    if (mod_mask == MOD_MASK_ALT)
2107 	    {
2108 		redrawcmd();	    // somehow the cmdline is cleared
2109 		goto cmdline_not_changed;
2110 	    }
2111 	    break;
2112 #endif
2113 
2114 	case K_MIDDLEDRAG:
2115 	case K_MIDDLERELEASE:
2116 		goto cmdline_not_changed;	// Ignore mouse
2117 
2118 	case K_MIDDLEMOUSE:
2119 # ifdef FEAT_GUI
2120 		// When GUI is active, also paste when 'mouse' is empty
2121 		if (!gui.in_use)
2122 # endif
2123 		    if (!mouse_has(MOUSE_COMMAND))
2124 			goto cmdline_not_changed;   // Ignore mouse
2125 # ifdef FEAT_CLIPBOARD
2126 		if (clip_star.available)
2127 		    cmdline_paste('*', TRUE, TRUE);
2128 		else
2129 # endif
2130 		    cmdline_paste(0, TRUE, TRUE);
2131 		redrawcmd();
2132 		goto cmdline_changed;
2133 
2134 # ifdef FEAT_DND
2135 	case K_DROP:
2136 		cmdline_paste('~', TRUE, FALSE);
2137 		redrawcmd();
2138 		goto cmdline_changed;
2139 # endif
2140 
2141 	case K_LEFTDRAG:
2142 	case K_LEFTRELEASE:
2143 	case K_RIGHTDRAG:
2144 	case K_RIGHTRELEASE:
2145 		// Ignore drag and release events when the button-down wasn't
2146 		// seen before.
2147 		if (ignore_drag_release)
2148 		    goto cmdline_not_changed;
2149 		// FALLTHROUGH
2150 	case K_LEFTMOUSE:
2151 	case K_RIGHTMOUSE:
2152 		cmdline_left_right_mouse(c, &ignore_drag_release);
2153 		goto cmdline_not_changed;
2154 
2155 	// Mouse scroll wheel: ignored here
2156 	case K_MOUSEDOWN:
2157 	case K_MOUSEUP:
2158 	case K_MOUSELEFT:
2159 	case K_MOUSERIGHT:
2160 	// Alternate buttons ignored here
2161 	case K_X1MOUSE:
2162 	case K_X1DRAG:
2163 	case K_X1RELEASE:
2164 	case K_X2MOUSE:
2165 	case K_X2DRAG:
2166 	case K_X2RELEASE:
2167 	case K_MOUSEMOVE:
2168 		goto cmdline_not_changed;
2169 
2170 #ifdef FEAT_GUI
2171 	case K_LEFTMOUSE_NM:	// mousefocus click, ignored
2172 	case K_LEFTRELEASE_NM:
2173 		goto cmdline_not_changed;
2174 
2175 	case K_VER_SCROLLBAR:
2176 		if (msg_scrolled == 0)
2177 		{
2178 		    gui_do_scroll();
2179 		    redrawcmd();
2180 		}
2181 		goto cmdline_not_changed;
2182 
2183 	case K_HOR_SCROLLBAR:
2184 		if (msg_scrolled == 0)
2185 		{
2186 		    gui_do_horiz_scroll(scrollbar_value, FALSE);
2187 		    redrawcmd();
2188 		}
2189 		goto cmdline_not_changed;
2190 #endif
2191 #ifdef FEAT_GUI_TABLINE
2192 	case K_TABLINE:
2193 	case K_TABMENU:
2194 		// Don't want to change any tabs here.  Make sure the same tab
2195 		// is still selected.
2196 		if (gui_use_tabline())
2197 		    gui_mch_set_curtab(tabpage_index(curtab));
2198 		goto cmdline_not_changed;
2199 #endif
2200 
2201 	case K_SELECT:	    // end of Select mode mapping - ignore
2202 		goto cmdline_not_changed;
2203 
2204 	case Ctrl_B:	    // begin of command line
2205 	case K_HOME:
2206 	case K_KHOME:
2207 	case K_S_HOME:
2208 	case K_C_HOME:
2209 		ccline.cmdpos = 0;
2210 		set_cmdspos();
2211 		goto cmdline_not_changed;
2212 
2213 	case Ctrl_E:	    // end of command line
2214 	case K_END:
2215 	case K_KEND:
2216 	case K_S_END:
2217 	case K_C_END:
2218 		ccline.cmdpos = ccline.cmdlen;
2219 		set_cmdspos_cursor();
2220 		goto cmdline_not_changed;
2221 
2222 	case Ctrl_A:	    // all matches
2223 		if (nextwild(&xpc, WILD_ALL, 0, firstc != '@') == FAIL)
2224 		    break;
2225 		goto cmdline_changed;
2226 
2227 	case Ctrl_L:
2228 #ifdef FEAT_SEARCH_EXTRA
2229 		if (may_add_char_to_search(firstc, &c, &is_state) == OK)
2230 		    goto cmdline_not_changed;
2231 #endif
2232 
2233 		// completion: longest common part
2234 		if (nextwild(&xpc, WILD_LONGEST, 0, firstc != '@') == FAIL)
2235 		    break;
2236 		goto cmdline_changed;
2237 
2238 	case Ctrl_N:	    // next match
2239 	case Ctrl_P:	    // previous match
2240 		if (xpc.xp_numfiles > 0)
2241 		{
2242 		    if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT,
2243 						    0, firstc != '@') == FAIL)
2244 			break;
2245 		    goto cmdline_not_changed;
2246 		}
2247 		// FALLTHROUGH
2248 	case K_UP:
2249 	case K_DOWN:
2250 	case K_S_UP:
2251 	case K_S_DOWN:
2252 	case K_PAGEUP:
2253 	case K_KPAGEUP:
2254 	case K_PAGEDOWN:
2255 	case K_KPAGEDOWN:
2256 		res = cmdline_browse_history(c, firstc, &lookfor, histype,
2257 			&hiscnt, &xpc);
2258 		if (res == CMDLINE_CHANGED)
2259 		    goto cmdline_changed;
2260 		else if (res == GOTO_NORMAL_MODE)
2261 		    goto returncmd;
2262 		goto cmdline_not_changed;
2263 
2264 #ifdef FEAT_SEARCH_EXTRA
2265 	case Ctrl_G:	    // next match
2266 	case Ctrl_T:	    // previous match
2267 		if (may_adjust_incsearch_highlighting(
2268 					  firstc, count, &is_state, c) == FAIL)
2269 		    goto cmdline_not_changed;
2270 		break;
2271 #endif
2272 
2273 	case Ctrl_V:
2274 	case Ctrl_Q:
2275 		{
2276 		    ignore_drag_release = TRUE;
2277 		    putcmdline('^', TRUE);
2278 
2279 		    // Get next (two) character(s).  Do not change any
2280 		    // modifyOtherKeys ESC sequence to a normal key for
2281 		    // CTRL-SHIFT-V.
2282 		    c = get_literal(mod_mask & MOD_MASK_SHIFT);
2283 
2284 		    do_abbr = FALSE;	    // don't do abbreviation now
2285 		    extra_char = NUL;
2286 		    // may need to remove ^ when composing char was typed
2287 		    if (enc_utf8 && utf_iscomposing(c) && !cmd_silent)
2288 		    {
2289 			draw_cmdline(ccline.cmdpos,
2290 						ccline.cmdlen - ccline.cmdpos);
2291 			msg_putchar(' ');
2292 			cursorcmd();
2293 		    }
2294 		}
2295 
2296 		break;
2297 
2298 #ifdef FEAT_DIGRAPHS
2299 	case Ctrl_K:
2300 		ignore_drag_release = TRUE;
2301 		putcmdline('?', TRUE);
2302 # ifdef USE_ON_FLY_SCROLL
2303 		dont_scroll = TRUE;	    // disallow scrolling here
2304 # endif
2305 		c = get_digraph(TRUE);
2306 		extra_char = NUL;
2307 		if (c != NUL)
2308 		    break;
2309 
2310 		redrawcmd();
2311 		goto cmdline_not_changed;
2312 #endif // FEAT_DIGRAPHS
2313 
2314 #ifdef FEAT_RIGHTLEFT
2315 	case Ctrl__:	    // CTRL-_: switch language mode
2316 		if (!p_ari)
2317 		    break;
2318 		cmd_hkmap = !cmd_hkmap;
2319 		goto cmdline_not_changed;
2320 #endif
2321 
2322 	case K_PS:
2323 		bracketed_paste(PASTE_CMDLINE, FALSE, NULL);
2324 		goto cmdline_changed;
2325 
2326 	default:
2327 #ifdef UNIX
2328 		if (c == intr_char)
2329 		{
2330 		    gotesc = TRUE;	// will free ccline.cmdbuff after
2331 					// putting it in history
2332 		    goto returncmd;	// back to Normal mode
2333 		}
2334 #endif
2335 		/*
2336 		 * Normal character with no special meaning.  Just set mod_mask
2337 		 * to 0x0 so that typing Shift-Space in the GUI doesn't enter
2338 		 * the string <S-Space>.  This should only happen after ^V.
2339 		 */
2340 		if (!IS_SPECIAL(c))
2341 		    mod_mask = 0x0;
2342 		break;
2343 	}
2344 	/*
2345 	 * End of switch on command line character.
2346 	 * We come here if we have a normal character.
2347 	 */
2348 
2349 	if (do_abbr && (IS_SPECIAL(c) || !vim_iswordc(c))
2350 		&& (ccheck_abbr(
2351 			// Add ABBR_OFF for characters above 0x100, this is
2352 			// what check_abbr() expects.
2353 				(has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c)
2354 		    || c == Ctrl_RSB))
2355 	    goto cmdline_changed;
2356 
2357 	/*
2358 	 * put the character in the command line
2359 	 */
2360 	if (IS_SPECIAL(c) || mod_mask != 0)
2361 	    put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
2362 	else
2363 	{
2364 	    if (has_mbyte)
2365 	    {
2366 		j = (*mb_char2bytes)(c, IObuff);
2367 		IObuff[j] = NUL;	// exclude composing chars
2368 		put_on_cmdline(IObuff, j, TRUE);
2369 	    }
2370 	    else
2371 	    {
2372 		IObuff[0] = c;
2373 		put_on_cmdline(IObuff, 1, TRUE);
2374 	    }
2375 	}
2376 	goto cmdline_changed;
2377 
2378 /*
2379  * This part implements incremental searches for "/" and "?"
2380  * Jump to cmdline_not_changed when a character has been read but the command
2381  * line did not change. Then we only search and redraw if something changed in
2382  * the past.
2383  * Jump to cmdline_changed when the command line did change.
2384  * (Sorry for the goto's, I know it is ugly).
2385  */
2386 cmdline_not_changed:
2387 #ifdef FEAT_SEARCH_EXTRA
2388 	if (!is_state.incsearch_postponed)
2389 	    continue;
2390 #endif
2391 
2392 cmdline_changed:
2393 #ifdef FEAT_SEARCH_EXTRA
2394 	// If the window changed incremental search state is not valid.
2395 	if (is_state.winid != curwin->w_id)
2396 	    init_incsearch_state(&is_state);
2397 #endif
2398 	if (trigger_cmdlinechanged)
2399 	    // Trigger CmdlineChanged autocommands.
2400 	    trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED);
2401 
2402 #ifdef FEAT_SEARCH_EXTRA
2403 	if (xpc.xp_context == EXPAND_NOTHING && (KeyTyped || vpeekc() == NUL))
2404 	    may_do_incsearch_highlighting(firstc, count, &is_state);
2405 #endif
2406 
2407 #ifdef FEAT_RIGHTLEFT
2408 	if (cmdmsg_rl
2409 # ifdef FEAT_ARABIC
2410 		|| (p_arshape && !p_tbidi
2411 				       && cmdline_has_arabic(0, ccline.cmdlen))
2412 # endif
2413 		)
2414 	    // Always redraw the whole command line to fix shaping and
2415 	    // right-left typing.  Not efficient, but it works.
2416 	    // Do it only when there are no characters left to read
2417 	    // to avoid useless intermediate redraws.
2418 	    if (vpeekc() == NUL)
2419 		redrawcmd();
2420 #endif
2421     }
2422 
2423 returncmd:
2424 
2425 #ifdef FEAT_RIGHTLEFT
2426     cmdmsg_rl = FALSE;
2427 #endif
2428 
2429     ExpandCleanup(&xpc);
2430     ccline.xpc = NULL;
2431 
2432 #ifdef FEAT_SEARCH_EXTRA
2433     finish_incsearch_highlighting(gotesc, &is_state, FALSE);
2434 #endif
2435 
2436     if (ccline.cmdbuff != NULL)
2437     {
2438 	/*
2439 	 * Put line in history buffer (":" and "=" only when it was typed).
2440 	 */
2441 	if (ccline.cmdlen && firstc != NUL
2442 		&& (some_key_typed || histype == HIST_SEARCH))
2443 	{
2444 	    add_to_history(histype, ccline.cmdbuff, TRUE,
2445 				       histype == HIST_SEARCH ? firstc : NUL);
2446 	    if (firstc == ':')
2447 	    {
2448 		vim_free(new_last_cmdline);
2449 		new_last_cmdline = vim_strsave(ccline.cmdbuff);
2450 	    }
2451 	}
2452 
2453 	if (gotesc)
2454 	    abandon_cmdline();
2455     }
2456 
2457     /*
2458      * If the screen was shifted up, redraw the whole screen (later).
2459      * If the line is too long, clear it, so ruler and shown command do
2460      * not get printed in the middle of it.
2461      */
2462     msg_check();
2463     msg_scroll = save_msg_scroll;
2464     redir_off = FALSE;
2465 
2466     // When the command line was typed, no need for a wait-return prompt.
2467     if (some_key_typed)
2468 	need_wait_return = FALSE;
2469 
2470     // Trigger CmdlineLeave autocommands.
2471     trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINELEAVE);
2472 
2473     State = save_State;
2474 
2475 #ifdef FEAT_EVAL
2476     if (!debug_mode)
2477 	trigger_modechanged();
2478 #endif
2479 
2480 #ifdef HAVE_INPUT_METHOD
2481     if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP)
2482 	im_save_status(b_im_ptr);
2483     im_set_active(FALSE);
2484 #endif
2485     setmouse();
2486 #ifdef CURSOR_SHAPE
2487     ui_cursor_shape();		// may show different cursor shape
2488 #endif
2489     sb_text_end_cmdline();
2490 
2491 theend:
2492     {
2493 	char_u *p = ccline.cmdbuff;
2494 
2495 	if (did_save_ccline)
2496 	    restore_cmdline(&save_ccline);
2497 	else
2498 	    ccline.cmdbuff = NULL;
2499 	return p;
2500     }
2501 }
2502 
2503 #if (defined(FEAT_CRYPT) || defined(FEAT_EVAL)) || defined(PROTO)
2504 /*
2505  * Get a command line with a prompt.
2506  * This is prepared to be called recursively from getcmdline() (e.g. by
2507  * f_input() when evaluating an expression from CTRL-R =).
2508  * Returns the command line in allocated memory, or NULL.
2509  */
2510     char_u *
getcmdline_prompt(int firstc,char_u * prompt,int attr,int xp_context,char_u * xp_arg)2511 getcmdline_prompt(
2512     int		firstc,
2513     char_u	*prompt,	// command line prompt
2514     int		attr,		// attributes for prompt
2515     int		xp_context,	// type of expansion
2516     char_u	*xp_arg)	// user-defined expansion argument
2517 {
2518     char_u		*s;
2519     cmdline_info_T	save_ccline;
2520     int			did_save_ccline = FALSE;
2521     int			msg_col_save = msg_col;
2522     int			msg_silent_save = msg_silent;
2523 
2524     if (ccline.cmdbuff != NULL)
2525     {
2526 	// Save the values of the current cmdline and restore them below.
2527 	save_cmdline(&save_ccline);
2528 	did_save_ccline = TRUE;
2529     }
2530 
2531     CLEAR_FIELD(ccline);
2532     ccline.cmdprompt = prompt;
2533     ccline.cmdattr = attr;
2534 # ifdef FEAT_EVAL
2535     ccline.xp_context = xp_context;
2536     ccline.xp_arg = xp_arg;
2537     ccline.input_fn = (firstc == '@');
2538 # endif
2539     msg_silent = 0;
2540     s = getcmdline_int(firstc, 1L, 0, FALSE);
2541 
2542     if (did_save_ccline)
2543 	restore_cmdline(&save_ccline);
2544 
2545     msg_silent = msg_silent_save;
2546     // Restore msg_col, the prompt from input() may have changed it.
2547     // But only if called recursively and the commandline is therefore being
2548     // restored to an old one; if not, the input() prompt stays on the screen,
2549     // so we need its modified msg_col left intact.
2550     if (ccline.cmdbuff != NULL)
2551 	msg_col = msg_col_save;
2552 
2553     return s;
2554 }
2555 #endif
2556 
2557 /*
2558  * Read the 'wildmode' option, fill wim_flags[].
2559  */
2560     int
check_opt_wim(void)2561 check_opt_wim(void)
2562 {
2563     char_u	new_wim_flags[4];
2564     char_u	*p;
2565     int		i;
2566     int		idx = 0;
2567 
2568     for (i = 0; i < 4; ++i)
2569 	new_wim_flags[i] = 0;
2570 
2571     for (p = p_wim; *p; ++p)
2572     {
2573 	for (i = 0; ASCII_ISALPHA(p[i]); ++i)
2574 	    ;
2575 	if (p[i] != NUL && p[i] != ',' && p[i] != ':')
2576 	    return FAIL;
2577 	if (i == 7 && STRNCMP(p, "longest", 7) == 0)
2578 	    new_wim_flags[idx] |= WIM_LONGEST;
2579 	else if (i == 4 && STRNCMP(p, "full", 4) == 0)
2580 	    new_wim_flags[idx] |= WIM_FULL;
2581 	else if (i == 4 && STRNCMP(p, "list", 4) == 0)
2582 	    new_wim_flags[idx] |= WIM_LIST;
2583 	else if (i == 8 && STRNCMP(p, "lastused", 8) == 0)
2584 	    new_wim_flags[idx] |= WIM_BUFLASTUSED;
2585 	else
2586 	    return FAIL;
2587 	p += i;
2588 	if (*p == NUL)
2589 	    break;
2590 	if (*p == ',')
2591 	{
2592 	    if (idx == 3)
2593 		return FAIL;
2594 	    ++idx;
2595 	}
2596     }
2597 
2598     // fill remaining entries with last flag
2599     while (idx < 3)
2600     {
2601 	new_wim_flags[idx + 1] = new_wim_flags[idx];
2602 	++idx;
2603     }
2604 
2605     // only when there are no errors, wim_flags[] is changed
2606     for (i = 0; i < 4; ++i)
2607 	wim_flags[i] = new_wim_flags[i];
2608     return OK;
2609 }
2610 
2611 /*
2612  * Return TRUE when the text must not be changed and we can't switch to
2613  * another window or buffer.  TRUE when editing the command line, evaluating
2614  * 'balloonexpr', etc.
2615  */
2616     int
text_and_win_locked(void)2617 text_and_win_locked(void)
2618 {
2619 #ifdef FEAT_CMDWIN
2620     if (cmdwin_type != 0)
2621 	return TRUE;
2622 #endif
2623     return textwinlock != 0;
2624 }
2625 
2626 /*
2627  * Give an error message for a command that isn't allowed while the cmdline
2628  * window is open or editing the cmdline in another way.
2629  */
2630     void
text_locked_msg(void)2631 text_locked_msg(void)
2632 {
2633     emsg(_(get_text_locked_msg()));
2634 }
2635 
2636     char *
get_text_locked_msg(void)2637 get_text_locked_msg(void)
2638 {
2639 #ifdef FEAT_CMDWIN
2640     if (cmdwin_type != 0)
2641 	return e_invalid_in_cmdline_window;
2642 #endif
2643     if (textwinlock != 0)
2644 	return e_textwinlock;
2645     return e_textlock;
2646 }
2647 
2648 /*
2649  * Return TRUE when the text must not be changed and/or we cannot switch to
2650  * another window.  TRUE while evaluating 'completefunc'.
2651  */
2652     int
text_locked(void)2653 text_locked(void)
2654 {
2655     return text_and_win_locked() || textlock != 0;
2656 }
2657 
2658 /*
2659  * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
2660  * and give an error message.
2661  */
2662     int
curbuf_locked(void)2663 curbuf_locked(void)
2664 {
2665     if (curbuf_lock > 0)
2666     {
2667 	emsg(_("E788: Not allowed to edit another buffer now"));
2668 	return TRUE;
2669     }
2670     return allbuf_locked();
2671 }
2672 
2673 /*
2674  * Check if "allbuf_lock" is set and return TRUE when it is and give an error
2675  * message.
2676  */
2677     int
allbuf_locked(void)2678 allbuf_locked(void)
2679 {
2680     if (allbuf_lock > 0)
2681     {
2682 	emsg(_("E811: Not allowed to change buffer information now"));
2683 	return TRUE;
2684     }
2685     return FALSE;
2686 }
2687 
2688     static int
cmdline_charsize(int idx)2689 cmdline_charsize(int idx)
2690 {
2691 #if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
2692     if (cmdline_star > 0)	    // showing '*', always 1 position
2693 	return 1;
2694 #endif
2695     return ptr2cells(ccline.cmdbuff + idx);
2696 }
2697 
2698 /*
2699  * Compute the offset of the cursor on the command line for the prompt and
2700  * indent.
2701  */
2702     static void
set_cmdspos(void)2703 set_cmdspos(void)
2704 {
2705     if (ccline.cmdfirstc != NUL)
2706 	ccline.cmdspos = 1 + ccline.cmdindent;
2707     else
2708 	ccline.cmdspos = 0 + ccline.cmdindent;
2709 }
2710 
2711 /*
2712  * Compute the screen position for the cursor on the command line.
2713  */
2714     static void
set_cmdspos_cursor(void)2715 set_cmdspos_cursor(void)
2716 {
2717     int		i, m, c;
2718 
2719     set_cmdspos();
2720     if (KeyTyped)
2721     {
2722 	m = Columns * Rows;
2723 	if (m < 0)	// overflow, Columns or Rows at weird value
2724 	    m = MAXCOL;
2725     }
2726     else
2727 	m = MAXCOL;
2728     for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i)
2729     {
2730 	c = cmdline_charsize(i);
2731 	// Count ">" for double-wide multi-byte char that doesn't fit.
2732 	if (has_mbyte)
2733 	    correct_cmdspos(i, c);
2734 	// If the cmdline doesn't fit, show cursor on last visible char.
2735 	// Don't move the cursor itself, so we can still append.
2736 	if ((ccline.cmdspos += c) >= m)
2737 	{
2738 	    ccline.cmdspos -= c;
2739 	    break;
2740 	}
2741 	if (has_mbyte)
2742 	    i += (*mb_ptr2len)(ccline.cmdbuff + i) - 1;
2743     }
2744 }
2745 
2746 /*
2747  * Check if the character at "idx", which is "cells" wide, is a multi-byte
2748  * character that doesn't fit, so that a ">" must be displayed.
2749  */
2750     static void
correct_cmdspos(int idx,int cells)2751 correct_cmdspos(int idx, int cells)
2752 {
2753     if ((*mb_ptr2len)(ccline.cmdbuff + idx) > 1
2754 		&& (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1
2755 		&& ccline.cmdspos % Columns + cells > Columns)
2756 	ccline.cmdspos++;
2757 }
2758 
2759 /*
2760  * Get an Ex command line for the ":" command.
2761  */
2762     char_u *
getexline(int c,void * cookie UNUSED,int indent,getline_opt_T options)2763 getexline(
2764     int		c,		// normally ':', NUL for ":append"
2765     void	*cookie UNUSED,
2766     int		indent,		// indent for inside conditionals
2767     getline_opt_T options)
2768 {
2769     // When executing a register, remove ':' that's in front of each line.
2770     if (exec_from_reg && vpeekc() == ':')
2771 	(void)vgetc();
2772     return getcmdline(c, 1L, indent, options);
2773 }
2774 
2775 /*
2776  * Get an Ex command line for Ex mode.
2777  * In Ex mode we only use the OS supplied line editing features and no
2778  * mappings or abbreviations.
2779  * Returns a string in allocated memory or NULL.
2780  */
2781     char_u *
getexmodeline(int promptc,void * cookie UNUSED,int indent,getline_opt_T options UNUSED)2782 getexmodeline(
2783     int		promptc,	// normally ':', NUL for ":append" and '?' for
2784 				// :s prompt
2785     void	*cookie UNUSED,
2786     int		indent,		// indent for inside conditionals
2787     getline_opt_T options UNUSED)
2788 {
2789     garray_T	line_ga;
2790     char_u	*pend;
2791     int		startcol = 0;
2792     int		c1 = 0;
2793     int		escaped = FALSE;	// CTRL-V typed
2794     int		vcol = 0;
2795     char_u	*p;
2796     int		prev_char;
2797     int		len;
2798 
2799     // Switch cursor on now.  This avoids that it happens after the "\n", which
2800     // confuses the system function that computes tabstops.
2801     cursor_on();
2802 
2803     // always start in column 0; write a newline if necessary
2804     compute_cmdrow();
2805     if ((msg_col || msg_didout) && promptc != '?')
2806 	msg_putchar('\n');
2807     if (promptc == ':')
2808     {
2809 	// indent that is only displayed, not in the line itself
2810 	if (p_prompt)
2811 	    msg_putchar(':');
2812 	while (indent-- > 0)
2813 	    msg_putchar(' ');
2814 	startcol = msg_col;
2815     }
2816 
2817     ga_init2(&line_ga, 1, 30);
2818 
2819     // autoindent for :insert and :append is in the line itself
2820     if (promptc <= 0)
2821     {
2822 	vcol = indent;
2823 	while (indent >= 8)
2824 	{
2825 	    ga_append(&line_ga, TAB);
2826 	    msg_puts("        ");
2827 	    indent -= 8;
2828 	}
2829 	while (indent-- > 0)
2830 	{
2831 	    ga_append(&line_ga, ' ');
2832 	    msg_putchar(' ');
2833 	}
2834     }
2835     ++no_mapping;
2836     ++allow_keys;
2837 
2838     /*
2839      * Get the line, one character at a time.
2840      */
2841     got_int = FALSE;
2842     while (!got_int)
2843     {
2844 	long    sw;
2845 	char_u *s;
2846 
2847 	if (ga_grow(&line_ga, 40) == FAIL)
2848 	    break;
2849 
2850 	/*
2851 	 * Get one character at a time.
2852 	 */
2853 	prev_char = c1;
2854 
2855 	// Check for a ":normal" command and no more characters left.
2856 	if (ex_normal_busy > 0 && typebuf.tb_len == 0)
2857 	    c1 = '\n';
2858 	else
2859 	    c1 = vgetc();
2860 
2861 	/*
2862 	 * Handle line editing.
2863 	 * Previously this was left to the system, putting the terminal in
2864 	 * cooked mode, but then CTRL-D and CTRL-T can't be used properly.
2865 	 */
2866 	if (got_int)
2867 	{
2868 	    msg_putchar('\n');
2869 	    break;
2870 	}
2871 
2872 	if (c1 == K_PS)
2873 	{
2874 	    bracketed_paste(PASTE_EX, FALSE, &line_ga);
2875 	    goto redraw;
2876 	}
2877 
2878 	if (!escaped)
2879 	{
2880 	    // CR typed means "enter", which is NL
2881 	    if (c1 == '\r')
2882 		c1 = '\n';
2883 
2884 	    if (c1 == BS || c1 == K_BS
2885 			  || c1 == DEL || c1 == K_DEL || c1 == K_KDEL)
2886 	    {
2887 		if (line_ga.ga_len > 0)
2888 		{
2889 		    if (has_mbyte)
2890 		    {
2891 			p = (char_u *)line_ga.ga_data;
2892 			p[line_ga.ga_len] = NUL;
2893 			len = (*mb_head_off)(p, p + line_ga.ga_len - 1) + 1;
2894 			line_ga.ga_len -= len;
2895 		    }
2896 		    else
2897 			--line_ga.ga_len;
2898 		    goto redraw;
2899 		}
2900 		continue;
2901 	    }
2902 
2903 	    if (c1 == Ctrl_U)
2904 	    {
2905 		msg_col = startcol;
2906 		msg_clr_eos();
2907 		line_ga.ga_len = 0;
2908 		goto redraw;
2909 	    }
2910 
2911 	    if (c1 == Ctrl_T)
2912 	    {
2913 		sw = get_sw_value(curbuf);
2914 		p = (char_u *)line_ga.ga_data;
2915 		p[line_ga.ga_len] = NUL;
2916 		indent = get_indent_str(p, 8, FALSE);
2917 		indent += sw - indent % sw;
2918 add_indent:
2919 		while (get_indent_str(p, 8, FALSE) < indent)
2920 		{
2921 		    (void)ga_grow(&line_ga, 2);  // one more for the NUL
2922 		    p = (char_u *)line_ga.ga_data;
2923 		    s = skipwhite(p);
2924 		    mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1);
2925 		    *s = ' ';
2926 		    ++line_ga.ga_len;
2927 		}
2928 redraw:
2929 		// redraw the line
2930 		msg_col = startcol;
2931 		vcol = 0;
2932 		p = (char_u *)line_ga.ga_data;
2933 		p[line_ga.ga_len] = NUL;
2934 		while (p < (char_u *)line_ga.ga_data + line_ga.ga_len)
2935 		{
2936 		    if (*p == TAB)
2937 		    {
2938 			do
2939 			    msg_putchar(' ');
2940 			while (++vcol % 8);
2941 			++p;
2942 		    }
2943 		    else
2944 		    {
2945 			len = mb_ptr2len(p);
2946 			msg_outtrans_len(p, len);
2947 			vcol += ptr2cells(p);
2948 			p += len;
2949 		    }
2950 		}
2951 		msg_clr_eos();
2952 		windgoto(msg_row, msg_col);
2953 		continue;
2954 	    }
2955 
2956 	    if (c1 == Ctrl_D)
2957 	    {
2958 		// Delete one shiftwidth.
2959 		p = (char_u *)line_ga.ga_data;
2960 		if (prev_char == '0' || prev_char == '^')
2961 		{
2962 		    if (prev_char == '^')
2963 			ex_keep_indent = TRUE;
2964 		    indent = 0;
2965 		    p[--line_ga.ga_len] = NUL;
2966 		}
2967 		else
2968 		{
2969 		    p[line_ga.ga_len] = NUL;
2970 		    indent = get_indent_str(p, 8, FALSE);
2971 		    if (indent > 0)
2972 		    {
2973 			--indent;
2974 			indent -= indent % get_sw_value(curbuf);
2975 		    }
2976 		}
2977 		while (get_indent_str(p, 8, FALSE) > indent)
2978 		{
2979 		    s = skipwhite(p);
2980 		    mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);
2981 		    --line_ga.ga_len;
2982 		}
2983 		goto add_indent;
2984 	    }
2985 
2986 	    if (c1 == Ctrl_V || c1 == Ctrl_Q)
2987 	    {
2988 		escaped = TRUE;
2989 		continue;
2990 	    }
2991 
2992 	    // Ignore special key codes: mouse movement, K_IGNORE, etc.
2993 	    if (IS_SPECIAL(c1))
2994 		continue;
2995 	}
2996 
2997 	if (IS_SPECIAL(c1))
2998 	    c1 = '?';
2999 	if (has_mbyte)
3000 	    len = (*mb_char2bytes)(c1,
3001 				  (char_u *)line_ga.ga_data + line_ga.ga_len);
3002 	else
3003 	{
3004 	    len = 1;
3005 	    ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
3006 	}
3007 	if (c1 == '\n')
3008 	    msg_putchar('\n');
3009 	else if (c1 == TAB)
3010 	{
3011 	    // Don't use chartabsize(), 'ts' can be different
3012 	    do
3013 		msg_putchar(' ');
3014 	    while (++vcol % 8);
3015 	}
3016 	else
3017 	{
3018 	    msg_outtrans_len(
3019 		     ((char_u *)line_ga.ga_data) + line_ga.ga_len, len);
3020 	    vcol += char2cells(c1);
3021 	}
3022 	line_ga.ga_len += len;
3023 	escaped = FALSE;
3024 
3025 	windgoto(msg_row, msg_col);
3026 	pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
3027 
3028 	// We are done when a NL is entered, but not when it comes after an
3029 	// odd number of backslashes, that results in a NUL.
3030 	if (line_ga.ga_len > 0 && pend[-1] == '\n')
3031 	{
3032 	    int bcount = 0;
3033 
3034 	    while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\')
3035 		++bcount;
3036 
3037 	    if (bcount > 0)
3038 	    {
3039 		// Halve the number of backslashes: "\NL" -> "NUL", "\\NL" ->
3040 		// "\NL", etc.
3041 		line_ga.ga_len -= (bcount + 1) / 2;
3042 		pend -= (bcount + 1) / 2;
3043 		pend[-1] = '\n';
3044 	    }
3045 
3046 	    if ((bcount & 1) == 0)
3047 	    {
3048 		--line_ga.ga_len;
3049 		--pend;
3050 		*pend = NUL;
3051 		break;
3052 	    }
3053 	}
3054     }
3055 
3056     --no_mapping;
3057     --allow_keys;
3058 
3059     // make following messages go to the next line
3060     msg_didout = FALSE;
3061     msg_col = 0;
3062     if (msg_row < Rows - 1)
3063 	++msg_row;
3064     emsg_on_display = FALSE;		// don't want ui_delay()
3065 
3066     if (got_int)
3067 	ga_clear(&line_ga);
3068 
3069     return (char_u *)line_ga.ga_data;
3070 }
3071 
3072 # if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
3073 	|| defined(FEAT_MOUSESHAPE) || defined(PROTO)
3074 /*
3075  * Return TRUE if ccline.overstrike is on.
3076  */
3077     int
cmdline_overstrike(void)3078 cmdline_overstrike(void)
3079 {
3080     return ccline.overstrike;
3081 }
3082 
3083 /*
3084  * Return TRUE if the cursor is at the end of the cmdline.
3085  */
3086     int
cmdline_at_end(void)3087 cmdline_at_end(void)
3088 {
3089     return (ccline.cmdpos >= ccline.cmdlen);
3090 }
3091 #endif
3092 
3093 #if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK))) || defined(PROTO)
3094 /*
3095  * Return the virtual column number at the current cursor position.
3096  * This is used by the IM code to obtain the start of the preedit string.
3097  */
3098     colnr_T
cmdline_getvcol_cursor(void)3099 cmdline_getvcol_cursor(void)
3100 {
3101     if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen)
3102 	return MAXCOL;
3103 
3104     if (has_mbyte)
3105     {
3106 	colnr_T	col;
3107 	int	i = 0;
3108 
3109 	for (col = 0; i < ccline.cmdpos; ++col)
3110 	    i += (*mb_ptr2len)(ccline.cmdbuff + i);
3111 
3112 	return col;
3113     }
3114     else
3115 	return ccline.cmdpos;
3116 }
3117 #endif
3118 
3119 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
3120 /*
3121  * If part of the command line is an IM preedit string, redraw it with
3122  * IM feedback attributes.  The cursor position is restored after drawing.
3123  */
3124     static void
redrawcmd_preedit(void)3125 redrawcmd_preedit(void)
3126 {
3127     if ((State & CMDLINE)
3128 	    && xic != NULL
3129 	    // && im_get_status()  doesn't work when using SCIM
3130 	    && !p_imdisable
3131 	    && im_is_preediting())
3132     {
3133 	int	cmdpos = 0;
3134 	int	cmdspos;
3135 	int	old_row;
3136 	int	old_col;
3137 	colnr_T	col;
3138 
3139 	old_row = msg_row;
3140 	old_col = msg_col;
3141 	cmdspos = ((ccline.cmdfirstc != NUL) ? 1 : 0) + ccline.cmdindent;
3142 
3143 	if (has_mbyte)
3144 	{
3145 	    for (col = 0; col < preedit_start_col
3146 			  && cmdpos < ccline.cmdlen; ++col)
3147 	    {
3148 		cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos);
3149 		cmdpos  += (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
3150 	    }
3151 	}
3152 	else
3153 	{
3154 	    cmdspos += preedit_start_col;
3155 	    cmdpos  += preedit_start_col;
3156 	}
3157 
3158 	msg_row = cmdline_row + (cmdspos / (int)Columns);
3159 	msg_col = cmdspos % (int)Columns;
3160 	if (msg_row >= Rows)
3161 	    msg_row = Rows - 1;
3162 
3163 	for (col = 0; cmdpos < ccline.cmdlen; ++col)
3164 	{
3165 	    int char_len;
3166 	    int char_attr;
3167 
3168 	    char_attr = im_get_feedback_attr(col);
3169 	    if (char_attr < 0)
3170 		break; // end of preedit string
3171 
3172 	    if (has_mbyte)
3173 		char_len = (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
3174 	    else
3175 		char_len = 1;
3176 
3177 	    msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr);
3178 	    cmdpos += char_len;
3179 	}
3180 
3181 	msg_row = old_row;
3182 	msg_col = old_col;
3183     }
3184 }
3185 #endif // FEAT_XIM && FEAT_GUI_GTK
3186 
3187 /*
3188  * Allocate a new command line buffer.
3189  * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
3190  */
3191     static void
alloc_cmdbuff(int len)3192 alloc_cmdbuff(int len)
3193 {
3194     /*
3195      * give some extra space to avoid having to allocate all the time
3196      */
3197     if (len < 80)
3198 	len = 100;
3199     else
3200 	len += 20;
3201 
3202     ccline.cmdbuff = alloc(len);    // caller should check for out-of-memory
3203     ccline.cmdbufflen = len;
3204 }
3205 
3206 /*
3207  * Re-allocate the command line to length len + something extra.
3208  * return FAIL for failure, OK otherwise
3209  */
3210     int
realloc_cmdbuff(int len)3211 realloc_cmdbuff(int len)
3212 {
3213     char_u	*p;
3214 
3215     if (len < ccline.cmdbufflen)
3216 	return OK;			// no need to resize
3217 
3218     p = ccline.cmdbuff;
3219     alloc_cmdbuff(len);			// will get some more
3220     if (ccline.cmdbuff == NULL)		// out of memory
3221     {
3222 	ccline.cmdbuff = p;		// keep the old one
3223 	return FAIL;
3224     }
3225     // There isn't always a NUL after the command, but it may need to be
3226     // there, thus copy up to the NUL and add a NUL.
3227     mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen);
3228     ccline.cmdbuff[ccline.cmdlen] = NUL;
3229     vim_free(p);
3230 
3231     if (ccline.xpc != NULL
3232 	    && ccline.xpc->xp_pattern != NULL
3233 	    && ccline.xpc->xp_context != EXPAND_NOTHING
3234 	    && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL)
3235     {
3236 	int i = (int)(ccline.xpc->xp_pattern - p);
3237 
3238 	// If xp_pattern points inside the old cmdbuff it needs to be adjusted
3239 	// to point into the newly allocated memory.
3240 	if (i >= 0 && i <= ccline.cmdlen)
3241 	    ccline.xpc->xp_pattern = ccline.cmdbuff + i;
3242     }
3243 
3244     return OK;
3245 }
3246 
3247 #if defined(FEAT_ARABIC) || defined(PROTO)
3248 static char_u	*arshape_buf = NULL;
3249 
3250 # if defined(EXITFREE) || defined(PROTO)
3251     void
free_arshape_buf(void)3252 free_arshape_buf(void)
3253 {
3254     vim_free(arshape_buf);
3255 }
3256 # endif
3257 #endif
3258 
3259 /*
3260  * Draw part of the cmdline at the current cursor position.  But draw stars
3261  * when cmdline_star is TRUE.
3262  */
3263     static void
draw_cmdline(int start,int len)3264 draw_cmdline(int start, int len)
3265 {
3266 #if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
3267     int		i;
3268 
3269     if (cmdline_star > 0)
3270 	for (i = 0; i < len; ++i)
3271 	{
3272 	    msg_putchar('*');
3273 	    if (has_mbyte)
3274 		i += (*mb_ptr2len)(ccline.cmdbuff + start + i) - 1;
3275 	}
3276     else
3277 #endif
3278 #ifdef FEAT_ARABIC
3279 	if (p_arshape && !p_tbidi && cmdline_has_arabic(start, len))
3280     {
3281 	static int	buflen = 0;
3282 	char_u		*p;
3283 	int		j;
3284 	int		newlen = 0;
3285 	int		mb_l;
3286 	int		pc, pc1 = 0;
3287 	int		prev_c = 0;
3288 	int		prev_c1 = 0;
3289 	int		u8c;
3290 	int		u8cc[MAX_MCO];
3291 	int		nc = 0;
3292 
3293 	/*
3294 	 * Do arabic shaping into a temporary buffer.  This is very
3295 	 * inefficient!
3296 	 */
3297 	if (len * 2 + 2 > buflen)
3298 	{
3299 	    // Re-allocate the buffer.  We keep it around to avoid a lot of
3300 	    // alloc()/free() calls.
3301 	    vim_free(arshape_buf);
3302 	    buflen = len * 2 + 2;
3303 	    arshape_buf = alloc(buflen);
3304 	    if (arshape_buf == NULL)
3305 		return;	// out of memory
3306 	}
3307 
3308 	if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start)))
3309 	{
3310 	    // Prepend a space to draw the leading composing char on.
3311 	    arshape_buf[0] = ' ';
3312 	    newlen = 1;
3313 	}
3314 
3315 	for (j = start; j < start + len; j += mb_l)
3316 	{
3317 	    p = ccline.cmdbuff + j;
3318 	    u8c = utfc_ptr2char_len(p, u8cc, start + len - j);
3319 	    mb_l = utfc_ptr2len_len(p, start + len - j);
3320 	    if (ARABIC_CHAR(u8c))
3321 	    {
3322 		// Do Arabic shaping.
3323 		if (cmdmsg_rl)
3324 		{
3325 		    // displaying from right to left
3326 		    pc = prev_c;
3327 		    pc1 = prev_c1;
3328 		    prev_c1 = u8cc[0];
3329 		    if (j + mb_l >= start + len)
3330 			nc = NUL;
3331 		    else
3332 			nc = utf_ptr2char(p + mb_l);
3333 		}
3334 		else
3335 		{
3336 		    // displaying from left to right
3337 		    if (j + mb_l >= start + len)
3338 			pc = NUL;
3339 		    else
3340 		    {
3341 			int	pcc[MAX_MCO];
3342 
3343 			pc = utfc_ptr2char_len(p + mb_l, pcc,
3344 						      start + len - j - mb_l);
3345 			pc1 = pcc[0];
3346 		    }
3347 		    nc = prev_c;
3348 		}
3349 		prev_c = u8c;
3350 
3351 		u8c = arabic_shape(u8c, NULL, &u8cc[0], pc, pc1, nc);
3352 
3353 		newlen += (*mb_char2bytes)(u8c, arshape_buf + newlen);
3354 		if (u8cc[0] != 0)
3355 		{
3356 		    newlen += (*mb_char2bytes)(u8cc[0], arshape_buf + newlen);
3357 		    if (u8cc[1] != 0)
3358 			newlen += (*mb_char2bytes)(u8cc[1],
3359 							arshape_buf + newlen);
3360 		}
3361 	    }
3362 	    else
3363 	    {
3364 		prev_c = u8c;
3365 		mch_memmove(arshape_buf + newlen, p, mb_l);
3366 		newlen += mb_l;
3367 	    }
3368 	}
3369 
3370 	msg_outtrans_len(arshape_buf, newlen);
3371     }
3372     else
3373 #endif
3374 	msg_outtrans_len(ccline.cmdbuff + start, len);
3375 }
3376 
3377 /*
3378  * Put a character on the command line.  Shifts the following text to the
3379  * right when "shift" is TRUE.  Used for CTRL-V, CTRL-K, etc.
3380  * "c" must be printable (fit in one display cell)!
3381  */
3382     void
putcmdline(int c,int shift)3383 putcmdline(int c, int shift)
3384 {
3385     if (cmd_silent)
3386 	return;
3387     msg_no_more = TRUE;
3388     msg_putchar(c);
3389     if (shift)
3390 	draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
3391     msg_no_more = FALSE;
3392     cursorcmd();
3393     extra_char = c;
3394     extra_char_shift = shift;
3395 }
3396 
3397 /*
3398  * Undo a putcmdline(c, FALSE).
3399  */
3400     void
unputcmdline(void)3401 unputcmdline(void)
3402 {
3403     if (cmd_silent)
3404 	return;
3405     msg_no_more = TRUE;
3406     if (ccline.cmdlen == ccline.cmdpos)
3407 	msg_putchar(' ');
3408     else if (has_mbyte)
3409 	draw_cmdline(ccline.cmdpos,
3410 			       (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos));
3411     else
3412 	draw_cmdline(ccline.cmdpos, 1);
3413     msg_no_more = FALSE;
3414     cursorcmd();
3415     extra_char = NUL;
3416 }
3417 
3418 /*
3419  * Put the given string, of the given length, onto the command line.
3420  * If len is -1, then STRLEN() is used to calculate the length.
3421  * If 'redraw' is TRUE then the new part of the command line, and the remaining
3422  * part will be redrawn, otherwise it will not.  If this function is called
3423  * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
3424  * called afterwards.
3425  */
3426     int
put_on_cmdline(char_u * str,int len,int redraw)3427 put_on_cmdline(char_u *str, int len, int redraw)
3428 {
3429     int		retval;
3430     int		i;
3431     int		m;
3432     int		c;
3433 
3434     if (len < 0)
3435 	len = (int)STRLEN(str);
3436 
3437     // Check if ccline.cmdbuff needs to be longer
3438     if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen)
3439 	retval = realloc_cmdbuff(ccline.cmdlen + len + 1);
3440     else
3441 	retval = OK;
3442     if (retval == OK)
3443     {
3444 	if (!ccline.overstrike)
3445 	{
3446 	    mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
3447 					       ccline.cmdbuff + ccline.cmdpos,
3448 				     (size_t)(ccline.cmdlen - ccline.cmdpos));
3449 	    ccline.cmdlen += len;
3450 	}
3451 	else
3452 	{
3453 	    if (has_mbyte)
3454 	    {
3455 		// Count nr of characters in the new string.
3456 		m = 0;
3457 		for (i = 0; i < len; i += (*mb_ptr2len)(str + i))
3458 		    ++m;
3459 		// Count nr of bytes in cmdline that are overwritten by these
3460 		// characters.
3461 		for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0;
3462 				 i += (*mb_ptr2len)(ccline.cmdbuff + i))
3463 		    --m;
3464 		if (i < ccline.cmdlen)
3465 		{
3466 		    mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
3467 			    ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i));
3468 		    ccline.cmdlen += ccline.cmdpos + len - i;
3469 		}
3470 		else
3471 		    ccline.cmdlen = ccline.cmdpos + len;
3472 	    }
3473 	    else if (ccline.cmdpos + len > ccline.cmdlen)
3474 		ccline.cmdlen = ccline.cmdpos + len;
3475 	}
3476 	mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
3477 	ccline.cmdbuff[ccline.cmdlen] = NUL;
3478 
3479 	if (enc_utf8)
3480 	{
3481 	    // When the inserted text starts with a composing character,
3482 	    // backup to the character before it.  There could be two of them.
3483 	    i = 0;
3484 	    c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
3485 	    while (ccline.cmdpos > 0 && utf_iscomposing(c))
3486 	    {
3487 		i = (*mb_head_off)(ccline.cmdbuff,
3488 				      ccline.cmdbuff + ccline.cmdpos - 1) + 1;
3489 		ccline.cmdpos -= i;
3490 		len += i;
3491 		c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
3492 	    }
3493 #ifdef FEAT_ARABIC
3494 	    if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c))
3495 	    {
3496 		// Check the previous character for Arabic combining pair.
3497 		i = (*mb_head_off)(ccline.cmdbuff,
3498 				      ccline.cmdbuff + ccline.cmdpos - 1) + 1;
3499 		if (arabic_combine(utf_ptr2char(ccline.cmdbuff
3500 						     + ccline.cmdpos - i), c))
3501 		{
3502 		    ccline.cmdpos -= i;
3503 		    len += i;
3504 		}
3505 		else
3506 		    i = 0;
3507 	    }
3508 #endif
3509 	    if (i != 0)
3510 	    {
3511 		// Also backup the cursor position.
3512 		i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
3513 		ccline.cmdspos -= i;
3514 		msg_col -= i;
3515 		if (msg_col < 0)
3516 		{
3517 		    msg_col += Columns;
3518 		    --msg_row;
3519 		}
3520 	    }
3521 	}
3522 
3523 	if (redraw && !cmd_silent)
3524 	{
3525 	    msg_no_more = TRUE;
3526 	    i = cmdline_row;
3527 	    cursorcmd();
3528 	    draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
3529 	    // Avoid clearing the rest of the line too often.
3530 	    if (cmdline_row != i || ccline.overstrike)
3531 		msg_clr_eos();
3532 	    msg_no_more = FALSE;
3533 	}
3534 	if (KeyTyped)
3535 	{
3536 	    m = Columns * Rows;
3537 	    if (m < 0)	// overflow, Columns or Rows at weird value
3538 		m = MAXCOL;
3539 	}
3540 	else
3541 	    m = MAXCOL;
3542 	for (i = 0; i < len; ++i)
3543 	{
3544 	    c = cmdline_charsize(ccline.cmdpos);
3545 	    // count ">" for a double-wide char that doesn't fit.
3546 	    if (has_mbyte)
3547 		correct_cmdspos(ccline.cmdpos, c);
3548 	    // Stop cursor at the end of the screen, but do increment the
3549 	    // insert position, so that entering a very long command
3550 	    // works, even though you can't see it.
3551 	    if (ccline.cmdspos + c < m)
3552 		ccline.cmdspos += c;
3553 
3554 	    if (has_mbyte)
3555 	    {
3556 		c = (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos) - 1;
3557 		if (c > len - i - 1)
3558 		    c = len - i - 1;
3559 		ccline.cmdpos += c;
3560 		i += c;
3561 	    }
3562 	    ++ccline.cmdpos;
3563 	}
3564     }
3565     if (redraw)
3566 	msg_check();
3567     return retval;
3568 }
3569 
3570 static cmdline_info_T	prev_ccline;
3571 static int		prev_ccline_used = FALSE;
3572 
3573 /*
3574  * Save ccline, because obtaining the "=" register may execute "normal :cmd"
3575  * and overwrite it.  But get_cmdline_str() may need it, thus make it
3576  * available globally in prev_ccline.
3577  */
3578     static void
save_cmdline(cmdline_info_T * ccp)3579 save_cmdline(cmdline_info_T *ccp)
3580 {
3581     if (!prev_ccline_used)
3582     {
3583 	CLEAR_FIELD(prev_ccline);
3584 	prev_ccline_used = TRUE;
3585     }
3586     *ccp = prev_ccline;
3587     prev_ccline = ccline;
3588     ccline.cmdbuff = NULL;  // signal that ccline is not in use
3589 }
3590 
3591 /*
3592  * Restore ccline after it has been saved with save_cmdline().
3593  */
3594     static void
restore_cmdline(cmdline_info_T * ccp)3595 restore_cmdline(cmdline_info_T *ccp)
3596 {
3597     ccline = prev_ccline;
3598     prev_ccline = *ccp;
3599 }
3600 
3601 /*
3602  * Paste a yank register into the command line.
3603  * Used by CTRL-R command in command-line mode.
3604  * insert_reg() can't be used here, because special characters from the
3605  * register contents will be interpreted as commands.
3606  *
3607  * Return FAIL for failure, OK otherwise.
3608  */
3609     static int
cmdline_paste(int regname,int literally,int remcr)3610 cmdline_paste(
3611     int regname,
3612     int literally,	// Insert text literally instead of "as typed"
3613     int remcr)		// remove trailing CR
3614 {
3615     long		i;
3616     char_u		*arg;
3617     char_u		*p;
3618     int			allocated;
3619 
3620     // check for valid regname; also accept special characters for CTRL-R in
3621     // the command line
3622     if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
3623 	    && regname != Ctrl_A && regname != Ctrl_L
3624 	    && !valid_yank_reg(regname, FALSE))
3625 	return FAIL;
3626 
3627     // A register containing CTRL-R can cause an endless loop.  Allow using
3628     // CTRL-C to break the loop.
3629     line_breakcheck();
3630     if (got_int)
3631 	return FAIL;
3632 
3633 #ifdef FEAT_CLIPBOARD
3634     regname = may_get_selection(regname);
3635 #endif
3636 
3637     // Need to  set "textwinlock" to avoid nasty things like going to another
3638     // buffer when evaluating an expression.
3639     ++textwinlock;
3640     i = get_spec_reg(regname, &arg, &allocated, TRUE);
3641     --textwinlock;
3642 
3643     if (i)
3644     {
3645 	// Got the value of a special register in "arg".
3646 	if (arg == NULL)
3647 	    return FAIL;
3648 
3649 	// When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate
3650 	// part of the word.
3651 	p = arg;
3652 	if (p_is && regname == Ctrl_W)
3653 	{
3654 	    char_u  *w;
3655 	    int	    len;
3656 
3657 	    // Locate start of last word in the cmd buffer.
3658 	    for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; )
3659 	    {
3660 		if (has_mbyte)
3661 		{
3662 		    len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1;
3663 		    if (!vim_iswordc(mb_ptr2char(w - len)))
3664 			break;
3665 		    w -= len;
3666 		}
3667 		else
3668 		{
3669 		    if (!vim_iswordc(w[-1]))
3670 			break;
3671 		    --w;
3672 		}
3673 	    }
3674 	    len = (int)((ccline.cmdbuff + ccline.cmdpos) - w);
3675 	    if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0)
3676 		p += len;
3677 	}
3678 
3679 	cmdline_paste_str(p, literally);
3680 	if (allocated)
3681 	    vim_free(arg);
3682 	return OK;
3683     }
3684 
3685     return cmdline_paste_reg(regname, literally, remcr);
3686 }
3687 
3688 /*
3689  * Put a string on the command line.
3690  * When "literally" is TRUE, insert literally.
3691  * When "literally" is FALSE, insert as typed, but don't leave the command
3692  * line.
3693  */
3694     void
cmdline_paste_str(char_u * s,int literally)3695 cmdline_paste_str(char_u *s, int literally)
3696 {
3697     int		c, cv;
3698 
3699     if (literally)
3700 	put_on_cmdline(s, -1, TRUE);
3701     else
3702 	while (*s != NUL)
3703 	{
3704 	    cv = *s;
3705 	    if (cv == Ctrl_V && s[1])
3706 		++s;
3707 	    if (has_mbyte)
3708 		c = mb_cptr2char_adv(&s);
3709 	    else
3710 		c = *s++;
3711 	    if (cv == Ctrl_V || c == ESC || c == Ctrl_C
3712 		    || c == CAR || c == NL || c == Ctrl_L
3713 #ifdef UNIX
3714 		    || c == intr_char
3715 #endif
3716 		    || (c == Ctrl_BSL && *s == Ctrl_N))
3717 		stuffcharReadbuff(Ctrl_V);
3718 	    stuffcharReadbuff(c);
3719 	}
3720 }
3721 
3722 /*
3723  * This function is called when the screen size changes and with incremental
3724  * search and in other situations where the command line may have been
3725  * overwritten.
3726  */
3727     void
redrawcmdline(void)3728 redrawcmdline(void)
3729 {
3730     redrawcmdline_ex(TRUE);
3731 }
3732 
3733     void
redrawcmdline_ex(int do_compute_cmdrow)3734 redrawcmdline_ex(int do_compute_cmdrow)
3735 {
3736     if (cmd_silent)
3737 	return;
3738     need_wait_return = FALSE;
3739     if (do_compute_cmdrow)
3740 	compute_cmdrow();
3741     redrawcmd();
3742     cursorcmd();
3743 }
3744 
3745     static void
redrawcmdprompt(void)3746 redrawcmdprompt(void)
3747 {
3748     int		i;
3749 
3750     if (cmd_silent)
3751 	return;
3752     if (ccline.cmdfirstc != NUL)
3753 	msg_putchar(ccline.cmdfirstc);
3754     if (ccline.cmdprompt != NULL)
3755     {
3756 	msg_puts_attr((char *)ccline.cmdprompt, ccline.cmdattr);
3757 	ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
3758 	// do the reverse of set_cmdspos()
3759 	if (ccline.cmdfirstc != NUL)
3760 	    --ccline.cmdindent;
3761     }
3762     else
3763 	for (i = ccline.cmdindent; i > 0; --i)
3764 	    msg_putchar(' ');
3765 }
3766 
3767 /*
3768  * Redraw what is currently on the command line.
3769  */
3770     void
redrawcmd(void)3771 redrawcmd(void)
3772 {
3773     if (cmd_silent)
3774 	return;
3775 
3776     // when 'incsearch' is set there may be no command line while redrawing
3777     if (ccline.cmdbuff == NULL)
3778     {
3779 	windgoto(cmdline_row, 0);
3780 	msg_clr_eos();
3781 	return;
3782     }
3783 
3784     msg_start();
3785     redrawcmdprompt();
3786 
3787     // Don't use more prompt, truncate the cmdline if it doesn't fit.
3788     msg_no_more = TRUE;
3789     draw_cmdline(0, ccline.cmdlen);
3790     msg_clr_eos();
3791     msg_no_more = FALSE;
3792 
3793     set_cmdspos_cursor();
3794     if (extra_char != NUL)
3795 	putcmdline(extra_char, extra_char_shift);
3796 
3797     /*
3798      * An emsg() before may have set msg_scroll. This is used in normal mode,
3799      * in cmdline mode we can reset them now.
3800      */
3801     msg_scroll = FALSE;		// next message overwrites cmdline
3802 
3803     // Typing ':' at the more prompt may set skip_redraw.  We don't want this
3804     // in cmdline mode
3805     skip_redraw = FALSE;
3806 }
3807 
3808     void
compute_cmdrow(void)3809 compute_cmdrow(void)
3810 {
3811     if (exmode_active || msg_scrolled != 0)
3812 	cmdline_row = Rows - 1;
3813     else
3814 	cmdline_row = W_WINROW(lastwin) + lastwin->w_height
3815 						    + lastwin->w_status_height;
3816 }
3817 
3818     void
cursorcmd(void)3819 cursorcmd(void)
3820 {
3821     if (cmd_silent)
3822 	return;
3823 
3824 #ifdef FEAT_RIGHTLEFT
3825     if (cmdmsg_rl)
3826     {
3827 	msg_row = cmdline_row  + (ccline.cmdspos / (int)(Columns - 1));
3828 	msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
3829 	if (msg_row <= 0)
3830 	    msg_row = Rows - 1;
3831     }
3832     else
3833 #endif
3834     {
3835 	msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
3836 	msg_col = ccline.cmdspos % (int)Columns;
3837 	if (msg_row >= Rows)
3838 	    msg_row = Rows - 1;
3839     }
3840 
3841     windgoto(msg_row, msg_col);
3842 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
3843     if (p_imst == IM_ON_THE_SPOT)
3844 	redrawcmd_preedit();
3845 #endif
3846 #ifdef MCH_CURSOR_SHAPE
3847     mch_update_cursor();
3848 #endif
3849 }
3850 
3851     void
gotocmdline(int clr)3852 gotocmdline(int clr)
3853 {
3854     msg_start();
3855 #ifdef FEAT_RIGHTLEFT
3856     if (cmdmsg_rl)
3857 	msg_col = Columns - 1;
3858     else
3859 #endif
3860 	msg_col = 0;	    // always start in column 0
3861     if (clr)		    // clear the bottom line(s)
3862 	msg_clr_eos();	    // will reset clear_cmdline
3863     windgoto(cmdline_row, 0);
3864 }
3865 
3866 /*
3867  * Check the word in front of the cursor for an abbreviation.
3868  * Called when the non-id character "c" has been entered.
3869  * When an abbreviation is recognized it is removed from the text with
3870  * backspaces and the replacement string is inserted, followed by "c".
3871  */
3872     static int
ccheck_abbr(int c)3873 ccheck_abbr(int c)
3874 {
3875     int spos = 0;
3876 
3877     if (p_paste || no_abbr)	    // no abbreviations or in paste mode
3878 	return FALSE;
3879 
3880     // Do not consider '<,'> be part of the mapping, skip leading whitespace.
3881     // Actually accepts any mark.
3882     while (VIM_ISWHITE(ccline.cmdbuff[spos]) && spos < ccline.cmdlen)
3883 	spos++;
3884     if (ccline.cmdlen - spos > 5
3885 	    && ccline.cmdbuff[spos] == '\''
3886 	    && ccline.cmdbuff[spos + 2] == ','
3887 	    && ccline.cmdbuff[spos + 3] == '\'')
3888 	spos += 5;
3889     else
3890 	// check abbreviation from the beginning of the commandline
3891 	spos = 0;
3892 
3893     return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos);
3894 }
3895 
3896 /*
3897  * Escape special characters in "fname", depending on "what":
3898  * VSE_NONE: for when used as a file name argument after a Vim command.
3899  * VSE_SHELL: for a shell command.
3900  * VSE_BUFFER: for the ":buffer" command.
3901  * Returns the result in allocated memory.
3902  */
3903     char_u *
vim_strsave_fnameescape(char_u * fname,int what)3904 vim_strsave_fnameescape(char_u *fname, int what)
3905 {
3906     char_u	*p;
3907 #ifdef BACKSLASH_IN_FILENAME
3908     char_u	buf[20];
3909     int		j = 0;
3910 
3911     // Don't escape '[', '{' and '!' if they are in 'isfname' and for the
3912     // ":buffer" command.
3913     for (p = what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS;
3914 								*p != NUL; ++p)
3915 	if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p))
3916 	    buf[j++] = *p;
3917     buf[j] = NUL;
3918     p = vim_strsave_escaped(fname, buf);
3919 #else
3920     p = vim_strsave_escaped(fname, what == VSE_SHELL ? SHELL_ESC_CHARS
3921 		    : what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS);
3922     if (what == VSE_SHELL && csh_like_shell() && p != NULL)
3923     {
3924 	char_u	    *s;
3925 
3926 	// For csh and similar shells need to put two backslashes before '!'.
3927 	// One is taken by Vim, one by the shell.
3928 	s = vim_strsave_escaped(p, (char_u *)"!");
3929 	vim_free(p);
3930 	p = s;
3931     }
3932 #endif
3933 
3934     // '>' and '+' are special at the start of some commands, e.g. ":edit" and
3935     // ":write".  "cd -" has a special meaning.
3936     if (p != NULL && (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)))
3937 	escape_fname(&p);
3938 
3939     return p;
3940 }
3941 
3942 /*
3943  * Put a backslash before the file name in "pp", which is in allocated memory.
3944  */
3945     void
escape_fname(char_u ** pp)3946 escape_fname(char_u **pp)
3947 {
3948     char_u	*p;
3949 
3950     p = alloc(STRLEN(*pp) + 2);
3951     if (p != NULL)
3952     {
3953 	p[0] = '\\';
3954 	STRCPY(p + 1, *pp);
3955 	vim_free(*pp);
3956 	*pp = p;
3957     }
3958 }
3959 
3960 /*
3961  * For each file name in files[num_files]:
3962  * If 'orig_pat' starts with "~/", replace the home directory with "~".
3963  */
3964     void
tilde_replace(char_u * orig_pat,int num_files,char_u ** files)3965 tilde_replace(
3966     char_u  *orig_pat,
3967     int	    num_files,
3968     char_u  **files)
3969 {
3970     int	    i;
3971     char_u  *p;
3972 
3973     if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
3974     {
3975 	for (i = 0; i < num_files; ++i)
3976 	{
3977 	    p = home_replace_save(NULL, files[i]);
3978 	    if (p != NULL)
3979 	    {
3980 		vim_free(files[i]);
3981 		files[i] = p;
3982 	    }
3983 	}
3984     }
3985 }
3986 
3987 /*
3988  * Get a pointer to the current command line info.
3989  */
3990     cmdline_info_T *
get_cmdline_info(void)3991 get_cmdline_info(void)
3992 {
3993     return &ccline;
3994 }
3995 
3996 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
3997 /*
3998  * Get pointer to the command line info to use. save_ccline() may clear
3999  * ccline and put the previous value in prev_ccline.
4000  */
4001     static cmdline_info_T *
get_ccline_ptr(void)4002 get_ccline_ptr(void)
4003 {
4004     if ((State & CMDLINE) == 0)
4005 	return NULL;
4006     if (ccline.cmdbuff != NULL)
4007 	return &ccline;
4008     if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
4009 	return &prev_ccline;
4010     return NULL;
4011 }
4012 #endif
4013 
4014 #if defined(FEAT_EVAL) || defined(PROTO)
4015 /*
4016  * Get the current command line in allocated memory.
4017  * Only works when the command line is being edited.
4018  * Returns NULL when something is wrong.
4019  */
4020     static char_u *
get_cmdline_str(void)4021 get_cmdline_str(void)
4022 {
4023     cmdline_info_T *p;
4024 
4025     if (cmdline_star > 0)
4026 	return NULL;
4027     p = get_ccline_ptr();
4028     if (p == NULL)
4029 	return NULL;
4030     return vim_strnsave(p->cmdbuff, p->cmdlen);
4031 }
4032 
4033 /*
4034  * "getcmdline()" function
4035  */
4036     void
f_getcmdline(typval_T * argvars UNUSED,typval_T * rettv)4037 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4038 {
4039     rettv->v_type = VAR_STRING;
4040     rettv->vval.v_string = get_cmdline_str();
4041 }
4042 
4043 /*
4044  * "getcmdpos()" function
4045  */
4046     void
f_getcmdpos(typval_T * argvars UNUSED,typval_T * rettv)4047 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4048 {
4049     cmdline_info_T *p = get_ccline_ptr();
4050 
4051     rettv->vval.v_number = 0;
4052     if (p != NULL)
4053     rettv->vval.v_number = p->cmdpos + 1;
4054 }
4055 
4056 /*
4057  * Set the command line byte position to "pos".  Zero is the first position.
4058  * Only works when the command line is being edited.
4059  * Returns 1 when failed, 0 when OK.
4060  */
4061     static int
set_cmdline_pos(int pos)4062 set_cmdline_pos(
4063     int		pos)
4064 {
4065     cmdline_info_T *p = get_ccline_ptr();
4066 
4067     if (p == NULL)
4068 	return 1;
4069 
4070     // The position is not set directly but after CTRL-\ e or CTRL-R = has
4071     // changed the command line.
4072     if (pos < 0)
4073 	new_cmdpos = 0;
4074     else
4075 	new_cmdpos = pos;
4076     return 0;
4077 }
4078 
4079 /*
4080  * "setcmdpos()" function
4081  */
4082     void
f_setcmdpos(typval_T * argvars,typval_T * rettv)4083 f_setcmdpos(typval_T *argvars, typval_T *rettv)
4084 {
4085     int		pos;
4086 
4087     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
4088 	return;
4089 
4090     pos = (int)tv_get_number(&argvars[0]) - 1;
4091     if (pos >= 0)
4092 	rettv->vval.v_number = set_cmdline_pos(pos);
4093 }
4094 
4095 /*
4096  * "getcmdtype()" function
4097  */
4098     void
f_getcmdtype(typval_T * argvars UNUSED,typval_T * rettv)4099 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4100 {
4101     rettv->v_type = VAR_STRING;
4102     rettv->vval.v_string = alloc(2);
4103     if (rettv->vval.v_string != NULL)
4104     {
4105 	rettv->vval.v_string[0] = get_cmdline_type();
4106 	rettv->vval.v_string[1] = NUL;
4107     }
4108 }
4109 
4110 #endif
4111 
4112 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
4113 /*
4114  * Get the current command-line type.
4115  * Returns ':' or '/' or '?' or '@' or '>' or '-'
4116  * Only works when the command line is being edited.
4117  * Returns NUL when something is wrong.
4118  */
4119     int
get_cmdline_type(void)4120 get_cmdline_type(void)
4121 {
4122     cmdline_info_T *p = get_ccline_ptr();
4123 
4124     if (p == NULL)
4125 	return NUL;
4126     if (p->cmdfirstc == NUL)
4127 	return
4128 # ifdef FEAT_EVAL
4129 	    (p->input_fn) ? '@' :
4130 # endif
4131 	    '-';
4132     return p->cmdfirstc;
4133 }
4134 #endif
4135 
4136 /*
4137  * Return the first character of the current command line.
4138  */
4139     int
get_cmdline_firstc(void)4140 get_cmdline_firstc(void)
4141 {
4142     return ccline.cmdfirstc;
4143 }
4144 
4145 /*
4146  * Get indices "num1,num2" that specify a range within a list (not a range of
4147  * text lines in a buffer!) from a string.  Used for ":history" and ":clist".
4148  * Returns OK if parsed successfully, otherwise FAIL.
4149  */
4150     int
get_list_range(char_u ** str,int * num1,int * num2)4151 get_list_range(char_u **str, int *num1, int *num2)
4152 {
4153     int		len;
4154     int		first = FALSE;
4155     varnumber_T	num;
4156 
4157     *str = skipwhite(*str);
4158     if (**str == '-' || vim_isdigit(**str))  // parse "from" part of range
4159     {
4160 	vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
4161 	*str += len;
4162 	*num1 = (int)num;
4163 	first = TRUE;
4164     }
4165     *str = skipwhite(*str);
4166     if (**str == ',')			// parse "to" part of range
4167     {
4168 	*str = skipwhite(*str + 1);
4169 	vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
4170 	if (len > 0)
4171 	{
4172 	    *num2 = (int)num;
4173 	    *str = skipwhite(*str + len);
4174 	}
4175 	else if (!first)		// no number given at all
4176 	    return FAIL;
4177     }
4178     else if (first)			// only one number given
4179 	*num2 = *num1;
4180     return OK;
4181 }
4182 
4183 #if defined(FEAT_CMDWIN) || defined(PROTO)
4184 /*
4185  * Check value of 'cedit' and set cedit_key.
4186  * Returns NULL if value is OK, error message otherwise.
4187  */
4188     char *
check_cedit(void)4189 check_cedit(void)
4190 {
4191     int n;
4192 
4193     if (*p_cedit == NUL)
4194 	cedit_key = -1;
4195     else
4196     {
4197 	n = string_to_key(p_cedit, FALSE);
4198 	if (vim_isprintc(n))
4199 	    return e_invarg;
4200 	cedit_key = n;
4201     }
4202     return NULL;
4203 }
4204 
4205 /*
4206  * Open a window on the current command line and history.  Allow editing in
4207  * the window.  Returns when the window is closed.
4208  * Returns:
4209  *	CR	 if the command is to be executed
4210  *	Ctrl_C	 if it is to be abandoned
4211  *	K_IGNORE if editing continues
4212  */
4213     static int
open_cmdwin(void)4214 open_cmdwin(void)
4215 {
4216     bufref_T		old_curbuf;
4217     win_T		*old_curwin = curwin;
4218     bufref_T		bufref;
4219     win_T		*wp;
4220     int			i;
4221     linenr_T		lnum;
4222     int			histtype;
4223     garray_T		winsizes;
4224     int			save_restart_edit = restart_edit;
4225     int			save_State = State;
4226     int			save_exmode = exmode_active;
4227 #ifdef FEAT_RIGHTLEFT
4228     int			save_cmdmsg_rl = cmdmsg_rl;
4229 #endif
4230 #ifdef FEAT_FOLDING
4231     int			save_KeyTyped;
4232 #endif
4233 
4234     // Can't do this recursively.  Can't do it when typing a password.
4235     if (cmdwin_type != 0
4236 # if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
4237 	    || cmdline_star > 0
4238 # endif
4239 	    )
4240     {
4241 	beep_flush();
4242 	return K_IGNORE;
4243     }
4244     set_bufref(&old_curbuf, curbuf);
4245 
4246     // Save current window sizes.
4247     win_size_save(&winsizes);
4248 
4249     // When using completion in Insert mode with <C-R>=<C-F> one can open the
4250     // command line window, but we don't want the popup menu then.
4251     pum_undisplay();
4252 
4253     // don't use a new tab page
4254     cmdmod.cmod_tab = 0;
4255     cmdmod.cmod_flags |= CMOD_NOSWAPFILE;
4256 
4257     // Create a window for the command-line buffer.
4258     if (win_split((int)p_cwh, WSP_BOT) == FAIL)
4259     {
4260 	beep_flush();
4261 	ga_clear(&winsizes);
4262 	return K_IGNORE;
4263     }
4264     // Don't let quitting the More prompt make this fail.
4265     got_int = FALSE;
4266 
4267     // Set "cmdwin_type" before any autocommands may mess things up.
4268     cmdwin_type = get_cmdline_type();
4269 
4270     // Create the command-line buffer empty.
4271     if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL)
4272     {
4273 	// Some autocommand messed it up?
4274 	win_close(curwin, TRUE);
4275 	ga_clear(&winsizes);
4276 	cmdwin_type = 0;
4277 	return Ctrl_C;
4278     }
4279 
4280     apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
4281     (void)setfname(curbuf, (char_u *)_("[Command Line]"), NULL, TRUE);
4282     apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
4283     set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
4284     curbuf->b_p_ma = TRUE;
4285 #ifdef FEAT_FOLDING
4286     curwin->w_p_fen = FALSE;
4287 #endif
4288 # ifdef FEAT_RIGHTLEFT
4289     curwin->w_p_rl = cmdmsg_rl;
4290     cmdmsg_rl = FALSE;
4291 # endif
4292     RESET_BINDING(curwin);
4293 
4294     // Don't allow switching to another buffer.
4295     ++curbuf_lock;
4296 
4297     // Showing the prompt may have set need_wait_return, reset it.
4298     need_wait_return = FALSE;
4299 
4300     histtype = hist_char2type(cmdwin_type);
4301     if (histtype == HIST_CMD || histtype == HIST_DEBUG)
4302     {
4303 	if (p_wc == TAB)
4304 	{
4305 	    add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
4306 	    add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
4307 	}
4308 	set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
4309     }
4310     --curbuf_lock;
4311 
4312     // Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
4313     // sets 'textwidth' to 78).
4314     curbuf->b_p_tw = 0;
4315 
4316     // Fill the buffer with the history.
4317     init_history();
4318     if (get_hislen() > 0)
4319     {
4320 	i = *get_hisidx(histtype);
4321 	if (i >= 0)
4322 	{
4323 	    lnum = 0;
4324 	    do
4325 	    {
4326 		if (++i == get_hislen())
4327 		    i = 0;
4328 		if (get_histentry(histtype)[i].hisstr != NULL)
4329 		    ml_append(lnum++, get_histentry(histtype)[i].hisstr,
4330 							   (colnr_T)0, FALSE);
4331 	    }
4332 	    while (i != *get_hisidx(histtype));
4333 	}
4334     }
4335 
4336     // Replace the empty last line with the current command-line and put the
4337     // cursor there.
4338     ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE);
4339     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4340     curwin->w_cursor.col = ccline.cmdpos;
4341     changed_line_abv_curs();
4342     invalidate_botline();
4343     redraw_later(SOME_VALID);
4344 
4345     // No Ex mode here!
4346     exmode_active = 0;
4347 
4348     State = NORMAL;
4349     setmouse();
4350 
4351     // Reset here so it can be set by a CmdWinEnter autocommand.
4352     cmdwin_result = 0;
4353 
4354     // Trigger CmdwinEnter autocommands.
4355     trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER);
4356     if (restart_edit != 0)	// autocmd with ":startinsert"
4357 	stuffcharReadbuff(K_NOP);
4358 
4359     i = RedrawingDisabled;
4360     RedrawingDisabled = 0;
4361 
4362     /*
4363      * Call the main loop until <CR> or CTRL-C is typed.
4364      */
4365     main_loop(TRUE, FALSE);
4366 
4367     RedrawingDisabled = i;
4368 
4369 # ifdef FEAT_FOLDING
4370     save_KeyTyped = KeyTyped;
4371 # endif
4372 
4373     // Trigger CmdwinLeave autocommands.
4374     trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINLEAVE);
4375 
4376 # ifdef FEAT_FOLDING
4377     // Restore KeyTyped in case it is modified by autocommands
4378     KeyTyped = save_KeyTyped;
4379 # endif
4380 
4381     cmdwin_type = 0;
4382     exmode_active = save_exmode;
4383 
4384     // Safety check: The old window or buffer was deleted: It's a bug when
4385     // this happens!
4386     if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf))
4387     {
4388 	cmdwin_result = Ctrl_C;
4389 	emsg(_("E199: Active window or buffer deleted"));
4390     }
4391     else
4392     {
4393 # if defined(FEAT_EVAL)
4394 	// autocmds may abort script processing
4395 	if (aborting() && cmdwin_result != K_IGNORE)
4396 	    cmdwin_result = Ctrl_C;
4397 # endif
4398 	// Set the new command line from the cmdline buffer.
4399 	vim_free(ccline.cmdbuff);
4400 	if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) // :qa[!] typed
4401 	{
4402 	    char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
4403 
4404 	    if (histtype == HIST_CMD)
4405 	    {
4406 		// Execute the command directly.
4407 		ccline.cmdbuff = vim_strsave((char_u *)p);
4408 		cmdwin_result = CAR;
4409 	    }
4410 	    else
4411 	    {
4412 		// First need to cancel what we were doing.
4413 		ccline.cmdbuff = NULL;
4414 		stuffcharReadbuff(':');
4415 		stuffReadbuff((char_u *)p);
4416 		stuffcharReadbuff(CAR);
4417 	    }
4418 	}
4419 	else if (cmdwin_result == K_XF2)	// :qa typed
4420 	{
4421 	    ccline.cmdbuff = vim_strsave((char_u *)"qa");
4422 	    cmdwin_result = CAR;
4423 	}
4424 	else if (cmdwin_result == Ctrl_C)
4425 	{
4426 	    // :q or :close, don't execute any command
4427 	    // and don't modify the cmd window.
4428 	    ccline.cmdbuff = NULL;
4429 	}
4430 	else
4431 	    ccline.cmdbuff = vim_strsave(ml_get_curline());
4432 	if (ccline.cmdbuff == NULL)
4433 	{
4434 	    ccline.cmdbuff = vim_strsave((char_u *)"");
4435 	    ccline.cmdlen = 0;
4436 	    ccline.cmdbufflen = 1;
4437 	    ccline.cmdpos = 0;
4438 	    cmdwin_result = Ctrl_C;
4439 	}
4440 	else
4441 	{
4442 	    ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
4443 	    ccline.cmdbufflen = ccline.cmdlen + 1;
4444 	    ccline.cmdpos = curwin->w_cursor.col;
4445 	    if (ccline.cmdpos > ccline.cmdlen)
4446 		ccline.cmdpos = ccline.cmdlen;
4447 	    if (cmdwin_result == K_IGNORE)
4448 	    {
4449 		set_cmdspos_cursor();
4450 		redrawcmd();
4451 	    }
4452 	}
4453 
4454 # ifdef FEAT_CONCEAL
4455 	// Avoid command-line window first character being concealed.
4456 	curwin->w_p_cole = 0;
4457 # endif
4458 	// First go back to the original window.
4459 	wp = curwin;
4460 	set_bufref(&bufref, curbuf);
4461 	win_goto(old_curwin);
4462 
4463 	// win_goto() may trigger an autocommand that already closes the
4464 	// cmdline window.
4465 	if (win_valid(wp) && wp != curwin)
4466 	    win_close(wp, TRUE);
4467 
4468 	// win_close() may have already wiped the buffer when 'bh' is
4469 	// set to 'wipe', autocommands may have closed other windows
4470 	if (bufref_valid(&bufref) && bufref.br_buf != curbuf)
4471 	    close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, FALSE, FALSE);
4472 
4473 	// Restore window sizes.
4474 	win_size_restore(&winsizes);
4475     }
4476 
4477     ga_clear(&winsizes);
4478     restart_edit = save_restart_edit;
4479 # ifdef FEAT_RIGHTLEFT
4480     cmdmsg_rl = save_cmdmsg_rl;
4481 # endif
4482 
4483     State = save_State;
4484     setmouse();
4485 
4486     return cmdwin_result;
4487 }
4488 
4489 /*
4490  * Return TRUE if in the cmdwin, not editing the command line.
4491  */
4492     int
is_in_cmdwin(void)4493 is_in_cmdwin(void)
4494 {
4495     return cmdwin_type != 0 && get_cmdline_type() == NUL;
4496 }
4497 #endif // FEAT_CMDWIN
4498 
4499 /*
4500  * Used for commands that either take a simple command string argument, or:
4501  *	cmd << endmarker
4502  *	  {script}
4503  *	endmarker
4504  * Returns a pointer to allocated memory with {script} or NULL.
4505  */
4506     char_u *
script_get(exarg_T * eap UNUSED,char_u * cmd UNUSED)4507 script_get(exarg_T *eap UNUSED, char_u *cmd UNUSED)
4508 {
4509 #ifdef FEAT_EVAL
4510     list_T	*l;
4511     listitem_T	*li;
4512     char_u	*s;
4513     garray_T	ga;
4514 
4515     if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL)
4516 	return NULL;
4517     cmd += 2;
4518 
4519     l = heredoc_get(eap, cmd, TRUE);
4520     if (l == NULL)
4521 	return NULL;
4522 
4523     ga_init2(&ga, 1, 0x400);
4524 
4525     FOR_ALL_LIST_ITEMS(l, li)
4526     {
4527 	s = tv_get_string(&li->li_tv);
4528 	ga_concat(&ga, s);
4529 	ga_append(&ga, '\n');
4530     }
4531     ga_append(&ga, NUL);
4532 
4533     list_free(l);
4534     return (char_u *)ga.ga_data;
4535 #else
4536     return NULL;
4537 #endif
4538 }
4539 
4540 #if defined(FEAT_EVAL) || defined(PROTO)
4541 /*
4542  * This function is used by f_input() and f_inputdialog() functions. The third
4543  * argument to f_input() specifies the type of completion to use at the
4544  * prompt. The third argument to f_inputdialog() specifies the value to return
4545  * when the user cancels the prompt.
4546  */
4547     void
get_user_input(typval_T * argvars,typval_T * rettv,int inputdialog,int secret)4548 get_user_input(
4549     typval_T	*argvars,
4550     typval_T	*rettv,
4551     int		inputdialog,
4552     int		secret)
4553 {
4554     char_u	*prompt;
4555     char_u	*p = NULL;
4556     int		c;
4557     char_u	buf[NUMBUFLEN];
4558     int		cmd_silent_save = cmd_silent;
4559     char_u	*defstr = (char_u *)"";
4560     int		xp_type = EXPAND_NOTHING;
4561     char_u	*xp_arg = NULL;
4562 
4563     rettv->v_type = VAR_STRING;
4564     rettv->vval.v_string = NULL;
4565     if (input_busy)
4566 	return;  // this doesn't work recursively.
4567 
4568     if (in_vim9script()
4569 	    && (check_for_string_arg(argvars, 0) == FAIL
4570 		|| check_for_opt_string_arg(argvars, 1) == FAIL
4571 		|| (argvars[1].v_type != VAR_UNKNOWN
4572 		    && check_for_opt_string_arg(argvars, 2) == FAIL)))
4573 	return;
4574 
4575     prompt = tv_get_string_chk(&argvars[0]);
4576 
4577 #ifdef NO_CONSOLE_INPUT
4578     // While starting up, there is no place to enter text. When running tests
4579     // with --not-a-term we assume feedkeys() will be used.
4580     if (no_console_input() && !is_not_a_term())
4581 	return;
4582 #endif
4583 
4584     cmd_silent = FALSE;		// Want to see the prompt.
4585     if (prompt != NULL)
4586     {
4587 	// Only the part of the message after the last NL is considered as
4588 	// prompt for the command line
4589 	p = vim_strrchr(prompt, '\n');
4590 	if (p == NULL)
4591 	    p = prompt;
4592 	else
4593 	{
4594 	    ++p;
4595 	    c = *p;
4596 	    *p = NUL;
4597 	    msg_start();
4598 	    msg_clr_eos();
4599 	    msg_puts_attr((char *)prompt, get_echo_attr());
4600 	    msg_didout = FALSE;
4601 	    msg_starthere();
4602 	    *p = c;
4603 	}
4604 	cmdline_row = msg_row;
4605 
4606 	if (argvars[1].v_type != VAR_UNKNOWN)
4607 	{
4608 	    defstr = tv_get_string_buf_chk(&argvars[1], buf);
4609 	    if (defstr != NULL)
4610 		stuffReadbuffSpec(defstr);
4611 
4612 	    if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
4613 	    {
4614 		char_u	*xp_name;
4615 		int	xp_namelen;
4616 		long	argt;
4617 
4618 		// input() with a third argument: completion
4619 		rettv->vval.v_string = NULL;
4620 
4621 		xp_name = tv_get_string_buf_chk(&argvars[2], buf);
4622 		if (xp_name == NULL)
4623 		    return;
4624 
4625 		xp_namelen = (int)STRLEN(xp_name);
4626 
4627 		if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
4628 							     &xp_arg) == FAIL)
4629 		    return;
4630 	    }
4631 	}
4632 
4633 	if (defstr != NULL)
4634 	{
4635 	    int save_ex_normal_busy = ex_normal_busy;
4636 	    int save_vgetc_busy = vgetc_busy;
4637 	    int save_input_busy = input_busy;
4638 
4639 	    input_busy |= vgetc_busy;
4640 	    ex_normal_busy = 0;
4641 	    vgetc_busy = 0;
4642 	    rettv->vval.v_string =
4643 		getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(),
4644 							      xp_type, xp_arg);
4645 	    ex_normal_busy = save_ex_normal_busy;
4646 	    vgetc_busy = save_vgetc_busy;
4647 	    input_busy = save_input_busy;
4648 	}
4649 	if (inputdialog && rettv->vval.v_string == NULL
4650 		&& argvars[1].v_type != VAR_UNKNOWN
4651 		&& argvars[2].v_type != VAR_UNKNOWN)
4652 	    rettv->vval.v_string = vim_strsave(tv_get_string_buf(
4653 							   &argvars[2], buf));
4654 
4655 	vim_free(xp_arg);
4656 
4657 	// since the user typed this, no need to wait for return
4658 	need_wait_return = FALSE;
4659 	msg_didout = FALSE;
4660     }
4661     cmd_silent = cmd_silent_save;
4662 }
4663 #endif
4664