blob: ba10af3a4eaec8e51c93a8e7a31be9a3833584d4 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaar37b15562018-08-14 22:08:25 +020016#ifndef MAX
17# define MAX(x,y) ((x) > (y) ? (x) : (y))
18#endif
19
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +020020// 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
Bram Moolenaar438d1762018-09-30 17:11:48 +020025// The current cmdline_info. It is initialized in getcmdline() and after that
26// used by other functions. When invoking getcmdline() recursively it needs
27// to be saved with save_cmdline() and restored with restore_cmdline().
Bram Moolenaar66b51422019-08-18 21:44:12 +020028static cmdline_info_T ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +000029
30#ifdef FEAT_EVAL
Bram Moolenaar217e1b82019-12-01 21:41:28 +010031static int new_cmdpos; // position set by set_cmdline_pos()
Bram Moolenaar071d4272004-06-13 20:20:40 +000032#endif
33
Bram Moolenaar217e1b82019-12-01 21:41:28 +010034static int extra_char = NUL; // extra character to display when redrawing
35 // the command line
Bram Moolenaar6a77d262017-07-16 15:24:01 +020036static int extra_char_shift;
37
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#ifdef FEAT_RIGHTLEFT
Bram Moolenaar217e1b82019-12-01 21:41:28 +010039static int cmd_hkmap = 0; // Hebrew mapping during command line
Bram Moolenaar071d4272004-06-13 20:20:40 +000040#endif
41
Bram Moolenaar438d1762018-09-30 17:11:48 +020042static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010043static int cmdline_charsize(int idx);
44static void set_cmdspos(void);
45static void set_cmdspos_cursor(void);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010046static void correct_cmdspos(int idx, int cells);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010047static void alloc_cmdbuff(int len);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010048static void draw_cmdline(int start, int len);
Bram Moolenaar66b51422019-08-18 21:44:12 +020049static void save_cmdline(cmdline_info_T *ccp);
50static void restore_cmdline(cmdline_info_T *ccp);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010051static int cmdline_paste(int regname, int literally, int remcr);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010052static void redrawcmdprompt(void);
Bram Moolenaard25c16e2016-01-29 22:13:30 +010053static int ccheck_abbr(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +000054
55#ifdef FEAT_CMDWIN
Bram Moolenaar3bab9392017-04-07 15:42:25 +020056static int open_cmdwin(void);
Bram Moolenaar7bae0b12019-11-21 22:14:18 +010057
58static int cedit_key INIT(= -1); // key value of 'cedit' option
Bram Moolenaar071d4272004-06-13 20:20:40 +000059#endif
60
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +020061
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +020062 static void
63trigger_cmd_autocmd(int typechar, int evt)
64{
65 char_u typestr[2];
66
67 typestr[0] = typechar;
68 typestr[1] = NUL;
69 apply_autocmds(evt, typestr, typestr, FALSE, curbuf);
70}
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +020071
Bram Moolenaar071d4272004-06-13 20:20:40 +000072/*
Bram Moolenaarf8e8c062017-10-22 14:44:17 +020073 * Abandon the command line.
74 */
75 static void
76abandon_cmdline(void)
77{
Bram Moolenaard23a8232018-02-10 18:45:26 +010078 VIM_CLEAR(ccline.cmdbuff);
Bram Moolenaarf8e8c062017-10-22 14:44:17 +020079 if (msg_scrolled == 0)
80 compute_cmdrow();
Bram Moolenaar32526b32019-01-19 17:43:09 +010081 msg("");
Bram Moolenaarf8e8c062017-10-22 14:44:17 +020082 redraw_cmdline = TRUE;
83}
84
Bram Moolenaaree219b02017-12-17 14:55:01 +010085#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarf8e8c062017-10-22 14:44:17 +020086/*
Bram Moolenaar66216052017-12-16 16:33:44 +010087 * Guess that the pattern matches everything. Only finds specific cases, such
88 * as a trailing \|, which can happen while typing a pattern.
89 */
90 static int
91empty_pattern(char_u *p)
92{
Bram Moolenaar200ea8f2018-01-02 15:37:46 +010093 size_t n = STRLEN(p);
Bram Moolenaar66216052017-12-16 16:33:44 +010094
Bram Moolenaar217e1b82019-12-01 21:41:28 +010095 // remove trailing \v and the like
Bram Moolenaar66216052017-12-16 16:33:44 +010096 while (n >= 2 && p[n - 2] == '\\'
97 && vim_strchr((char_u *)"mMvVcCZ", p[n - 1]) != NULL)
98 n -= 2;
99 return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|');
100}
101
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200102// Struct to store the viewstate during 'incsearch' highlighting.
Bram Moolenaar9b25af32018-04-28 13:56:09 +0200103typedef struct {
104 colnr_T vs_curswant;
105 colnr_T vs_leftcol;
106 linenr_T vs_topline;
107# ifdef FEAT_DIFF
108 int vs_topfill;
109# endif
110 linenr_T vs_botline;
111 linenr_T vs_empty_rows;
112} viewstate_T;
113
114 static void
115save_viewstate(viewstate_T *vs)
116{
117 vs->vs_curswant = curwin->w_curswant;
118 vs->vs_leftcol = curwin->w_leftcol;
119 vs->vs_topline = curwin->w_topline;
120# ifdef FEAT_DIFF
121 vs->vs_topfill = curwin->w_topfill;
122# endif
123 vs->vs_botline = curwin->w_botline;
124 vs->vs_empty_rows = curwin->w_empty_rows;
125}
126
127 static void
128restore_viewstate(viewstate_T *vs)
129{
130 curwin->w_curswant = vs->vs_curswant;
131 curwin->w_leftcol = vs->vs_leftcol;
132 curwin->w_topline = vs->vs_topline;
133# ifdef FEAT_DIFF
134 curwin->w_topfill = vs->vs_topfill;
135# endif
136 curwin->w_botline = vs->vs_botline;
137 curwin->w_empty_rows = vs->vs_empty_rows;
138}
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200139
140// Struct to store the state of 'incsearch' highlighting.
141typedef struct {
142 pos_T search_start; // where 'incsearch' starts searching
Bram Moolenaar23324a02019-10-01 17:39:04 +0200143 pos_T save_cursor;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200144 viewstate_T init_viewstate;
145 viewstate_T old_viewstate;
Bram Moolenaar23324a02019-10-01 17:39:04 +0200146 pos_T match_start;
147 pos_T match_end;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200148 int did_incsearch;
149 int incsearch_postponed;
Bram Moolenaar167ae422018-08-14 21:32:21 +0200150 int magic_save;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200151} incsearch_state_T;
152
153 static void
154init_incsearch_state(incsearch_state_T *is_state)
155{
156 is_state->match_start = curwin->w_cursor;
157 is_state->did_incsearch = FALSE;
158 is_state->incsearch_postponed = FALSE;
Bram Moolenaar167ae422018-08-14 21:32:21 +0200159 is_state->magic_save = p_magic;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200160 CLEAR_POS(&is_state->match_end);
161 is_state->save_cursor = curwin->w_cursor; // may be restored later
162 is_state->search_start = curwin->w_cursor;
163 save_viewstate(&is_state->init_viewstate);
164 save_viewstate(&is_state->old_viewstate);
165}
166
167/*
168 * First move cursor to end of match, then to the start. This
169 * moves the whole match onto the screen when 'nowrap' is set.
170 */
171 static void
172set_search_match(pos_T *t)
173{
174 t->lnum += search_match_lines;
175 t->col = search_match_endcol;
176 if (t->lnum > curbuf->b_ml.ml_line_count)
177 {
178 t->lnum = curbuf->b_ml.ml_line_count;
179 coladvance((colnr_T)MAXCOL);
180 }
181}
182
183/*
184 * Return TRUE when 'incsearch' highlighting is to be done.
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200185 * Sets search_first_line and search_last_line to the address range.
Bram Moolenaar198cb662018-09-06 21:44:17 +0200186 * May change the last search pattern.
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200187 */
188 static int
Bram Moolenaarc036e872020-02-21 21:30:52 +0100189do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *is_state,
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200190 int *skiplen, int *patlen)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200191{
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200192 char_u *cmd;
193 cmdmod_T save_cmdmod = cmdmod;
194 char_u *p;
195 int delim_optional = FALSE;
196 int delim;
197 char_u *end;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100198 char *dummy;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200199 exarg_T ea;
200 pos_T save_cursor;
Bram Moolenaar8b0d5ce2018-08-22 23:05:44 +0200201 int use_last_pat;
Bram Moolenaarc6725252019-11-23 21:56:46 +0100202 int retval = FALSE;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200203
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200204 *skiplen = 0;
205 *patlen = ccline.cmdlen;
206
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200207 if (!p_is || cmd_silent)
208 return FALSE;
209
210 // by default search all lines
211 search_first_line = 0;
212 search_last_line = MAXLNUM;
213
214 if (firstc == '/' || firstc == '?')
Bram Moolenaarc036e872020-02-21 21:30:52 +0100215 {
216 *search_delim = firstc;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200217 return TRUE;
Bram Moolenaarc036e872020-02-21 21:30:52 +0100218 }
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200219 if (firstc != ':')
220 return FALSE;
221
Bram Moolenaarc6725252019-11-23 21:56:46 +0100222 ++emsg_off;
Bram Moolenaara80faa82020-04-12 19:37:17 +0200223 CLEAR_FIELD(ea);
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200224 ea.line1 = 1;
225 ea.line2 = 1;
226 ea.cmd = ccline.cmdbuff;
227 ea.addr_type = ADDR_LINES;
228
229 parse_command_modifiers(&ea, &dummy, TRUE);
230 cmdmod = save_cmdmod;
231
232 cmd = skip_range(ea.cmd, NULL);
233 if (vim_strchr((char_u *)"sgvl", *cmd) == NULL)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100234 goto theend;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200235
236 // Skip over "substitute" to find the pattern separator.
237 for (p = cmd; ASCII_ISALPHA(*p); ++p)
238 ;
239 if (*skipwhite(p) == NUL)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100240 goto theend;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200241
242 if (STRNCMP(cmd, "substitute", p - cmd) == 0
243 || STRNCMP(cmd, "smagic", p - cmd) == 0
244 || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0
245 || STRNCMP(cmd, "vglobal", p - cmd) == 0)
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200246 {
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200247 if (*cmd == 's' && cmd[1] == 'm')
248 p_magic = TRUE;
249 else if (*cmd == 's' && cmd[1] == 'n')
250 p_magic = FALSE;
251 }
252 else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0)
253 {
Bram Moolenaar333015a2020-04-25 15:54:16 +0200254 // skip over ! and flags
255 if (*p == '!')
256 p = skipwhite(p + 1);
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200257 while (ASCII_ISALPHA(*(p = skipwhite(p))))
258 ++p;
259 if (*p == NUL)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100260 goto theend;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200261 }
262 else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
263 || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
264 || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0
265 || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0
266 || STRNCMP(cmd, "global", p - cmd) == 0)
267 {
268 // skip over "!"
269 if (*p == '!')
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200270 {
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200271 p++;
272 if (*skipwhite(p) == NUL)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100273 goto theend;
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200274 }
275 if (*cmd != 'g')
276 delim_optional = TRUE;
277 }
278 else
Bram Moolenaarc6725252019-11-23 21:56:46 +0100279 goto theend;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200280
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200281 p = skipwhite(p);
282 delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
Bram Moolenaarc036e872020-02-21 21:30:52 +0100283 *search_delim = delim;
Bram Moolenaare8c4abb2020-04-02 21:13:25 +0200284 end = skip_regexp(p, delim, p_magic);
Bram Moolenaar33c4dbb2018-08-14 16:06:16 +0200285
Bram Moolenaar8b0d5ce2018-08-22 23:05:44 +0200286 use_last_pat = end == p && *end == delim;
Bram Moolenaar33c4dbb2018-08-14 16:06:16 +0200287
Bram Moolenaar8b0d5ce2018-08-22 23:05:44 +0200288 if (end == p && !use_last_pat)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100289 goto theend;
Bram Moolenaar8b0d5ce2018-08-22 23:05:44 +0200290
291 // Don't do 'hlsearch' highlighting if the pattern matches everything.
292 if (!use_last_pat)
293 {
294 char c = *end;
295 int empty;
296
297 *end = NUL;
298 empty = empty_pattern(p);
299 *end = c;
300 if (empty)
Bram Moolenaarc6725252019-11-23 21:56:46 +0100301 goto theend;
Bram Moolenaar8b0d5ce2018-08-22 23:05:44 +0200302 }
303
304 // found a non-empty pattern or //
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200305 *skiplen = (int)(p - ccline.cmdbuff);
306 *patlen = (int)(end - p);
Bram Moolenaar264cf5c2018-08-18 21:05:31 +0200307
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200308 // parse the address range
309 save_cursor = curwin->w_cursor;
310 curwin->w_cursor = is_state->search_start;
Bram Moolenaar50eb16c2018-09-15 15:42:40 +0200311 parse_cmd_address(&ea, &dummy, TRUE);
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200312 if (ea.addr_count > 0)
313 {
314 // Allow for reverse match.
315 if (ea.line2 < ea.line1)
316 {
317 search_first_line = ea.line2;
318 search_last_line = ea.line1;
319 }
320 else
321 {
322 search_first_line = ea.line1;
323 search_last_line = ea.line2;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200324 }
325 }
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200326 else if (cmd[0] == 's' && cmd[1] != 'o')
327 {
328 // :s defaults to the current line
329 search_first_line = curwin->w_cursor.lnum;
330 search_last_line = curwin->w_cursor.lnum;
331 }
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200332
Bram Moolenaar111bbd62018-08-18 21:23:05 +0200333 curwin->w_cursor = save_cursor;
Bram Moolenaarc6725252019-11-23 21:56:46 +0100334 retval = TRUE;
335theend:
336 --emsg_off;
337 return retval;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200338}
339
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200340 static void
341finish_incsearch_highlighting(
342 int gotesc,
343 incsearch_state_T *is_state,
344 int call_update_screen)
345{
346 if (is_state->did_incsearch)
347 {
348 is_state->did_incsearch = FALSE;
349 if (gotesc)
350 curwin->w_cursor = is_state->save_cursor;
351 else
352 {
353 if (!EQUAL_POS(is_state->save_cursor, is_state->search_start))
354 {
355 // put the '" mark at the original position
356 curwin->w_cursor = is_state->save_cursor;
357 setpcmark();
358 }
359 curwin->w_cursor = is_state->search_start;
360 }
361 restore_viewstate(&is_state->old_viewstate);
362 highlight_match = FALSE;
Bram Moolenaarf13daa42018-08-31 22:09:54 +0200363
364 // by default search all lines
365 search_first_line = 0;
366 search_last_line = MAXLNUM;
367
368 p_magic = is_state->magic_save;
369
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100370 validate_cursor(); // needed for TAB
Bram Moolenaar65985ac2018-09-16 17:08:04 +0200371 redraw_all_later(SOME_VALID);
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200372 if (call_update_screen)
373 update_screen(SOME_VALID);
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200374 }
375}
376
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200377/*
378 * Do 'incsearch' highlighting if desired.
379 */
380 static void
381may_do_incsearch_highlighting(
382 int firstc,
383 long count,
384 incsearch_state_T *is_state)
385{
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200386 int skiplen, patlen;
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200387 int found; // do_search() result
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200388 pos_T end_pos;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200389#ifdef FEAT_RELTIME
390 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200391 searchit_arg_T sia;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200392#endif
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200393 int next_char;
394 int use_last_pat;
Bram Moolenaar693f7dc2019-06-21 02:30:38 +0200395 int did_do_incsearch = is_state->did_incsearch;
Bram Moolenaarc036e872020-02-21 21:30:52 +0100396 int search_delim;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200397
Bram Moolenaar198cb662018-09-06 21:44:17 +0200398 // Parsing range may already set the last search pattern.
Bram Moolenaar01a060d2018-11-30 21:57:55 +0100399 // NOTE: must call restore_last_search_pattern() before returning!
Bram Moolenaar198cb662018-09-06 21:44:17 +0200400 save_last_search_pattern();
401
Bram Moolenaara60053b2020-09-03 16:50:13 +0200402 if (!do_incsearch_highlighting(firstc, &search_delim, is_state,
403 &skiplen, &patlen))
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200404 {
Bram Moolenaar198cb662018-09-06 21:44:17 +0200405 restore_last_search_pattern();
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200406 finish_incsearch_highlighting(FALSE, is_state, TRUE);
Bram Moolenaar693f7dc2019-06-21 02:30:38 +0200407 if (did_do_incsearch && vpeekc() == NUL)
408 // may have skipped a redraw, do it now
409 redrawcmd();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200410 return;
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200411 }
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200412
413 // If there is a character waiting, search and redraw later.
414 if (char_avail())
415 {
Bram Moolenaar198cb662018-09-06 21:44:17 +0200416 restore_last_search_pattern();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200417 is_state->incsearch_postponed = TRUE;
418 return;
419 }
420 is_state->incsearch_postponed = FALSE;
421
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200422 if (search_first_line == 0)
423 // start at the original cursor position
424 curwin->w_cursor = is_state->search_start;
Bram Moolenaar1c299432018-10-28 14:36:09 +0100425 else if (search_first_line > curbuf->b_ml.ml_line_count)
426 {
427 // start after the last line
428 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
429 curwin->w_cursor.col = MAXCOL;
430 }
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200431 else
432 {
433 // start at the first line in the range
434 curwin->w_cursor.lnum = search_first_line;
435 curwin->w_cursor.col = 0;
436 }
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200437
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200438 // Use the previous pattern for ":s//".
439 next_char = ccline.cmdbuff[skiplen + patlen];
440 use_last_pat = patlen == 0 && skiplen > 0
441 && ccline.cmdbuff[skiplen - 1] == next_char;
442
443 // If there is no pattern, don't do anything.
444 if (patlen == 0 && !use_last_pat)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200445 {
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200446 found = 0;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200447 set_no_hlsearch(TRUE); // turn off previous highlight
448 redraw_all_later(SOME_VALID);
449 }
450 else
451 {
452 int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
453
454 cursor_off(); // so the user knows we're busy
455 out_flush();
456 ++emsg_off; // so it doesn't beep if bad expr
457#ifdef FEAT_RELTIME
458 // Set the time limit to half a second.
459 profile_setlimit(500L, &tm);
460#endif
461 if (!p_hls)
462 search_flags += SEARCH_KEEP;
Bram Moolenaar976b8472018-08-12 15:49:47 +0200463 if (search_first_line != 0)
464 search_flags += SEARCH_START;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200465 ccline.cmdbuff[skiplen + patlen] = NUL;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200466#ifdef FEAT_RELTIME
Bram Moolenaara80faa82020-04-12 19:37:17 +0200467 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200468 sia.sa_tm = &tm;
469#endif
Bram Moolenaarc036e872020-02-21 21:30:52 +0100470 found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200471 ccline.cmdbuff + skiplen, count, search_flags,
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200472#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200473 &sia
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200474#else
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200475 NULL
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200476#endif
477 );
Bram Moolenaarc7f08b72018-08-12 17:39:14 +0200478 ccline.cmdbuff[skiplen + patlen] = next_char;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200479 --emsg_off;
480
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200481 if (curwin->w_cursor.lnum < search_first_line
482 || curwin->w_cursor.lnum > search_last_line)
Bram Moolenaar2f6a3462018-08-14 18:16:52 +0200483 {
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200484 // match outside of address range
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200485 found = 0;
Bram Moolenaar2f6a3462018-08-14 18:16:52 +0200486 curwin->w_cursor = is_state->search_start;
487 }
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200488
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200489 // if interrupted while searching, behave like it failed
490 if (got_int)
491 {
492 (void)vpeekc(); // remove <C-C> from input stream
493 got_int = FALSE; // don't abandon the command line
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200494 found = 0;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200495 }
496 else if (char_avail())
497 // cancelled searching because a char was typed
498 is_state->incsearch_postponed = TRUE;
499 }
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200500 if (found != 0)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200501 highlight_match = TRUE; // highlight position
502 else
503 highlight_match = FALSE; // remove highlight
504
505 // First restore the old curwin values, so the screen is positioned in the
506 // same way as the actual search command.
507 restore_viewstate(&is_state->old_viewstate);
508 changed_cline_bef_curs();
509 update_topline();
510
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200511 if (found != 0)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200512 {
513 pos_T save_pos = curwin->w_cursor;
514
515 is_state->match_start = curwin->w_cursor;
516 set_search_match(&curwin->w_cursor);
517 validate_cursor();
518 end_pos = curwin->w_cursor;
519 is_state->match_end = end_pos;
520 curwin->w_cursor = save_pos;
521 }
522 else
523 end_pos = curwin->w_cursor; // shutup gcc 4
524
Bram Moolenaar4edfe2d2018-08-23 20:55:45 +0200525 // Disable 'hlsearch' highlighting if the pattern matches everything.
526 // Avoids a flash when typing "foo\|".
527 if (!use_last_pat)
528 {
529 next_char = ccline.cmdbuff[skiplen + patlen];
530 ccline.cmdbuff[skiplen + patlen] = NUL;
Bram Moolenaar65985ac2018-09-16 17:08:04 +0200531 if (empty_pattern(ccline.cmdbuff) && !no_hlsearch)
532 {
533 redraw_all_later(SOME_VALID);
Bram Moolenaar4edfe2d2018-08-23 20:55:45 +0200534 set_no_hlsearch(TRUE);
Bram Moolenaar65985ac2018-09-16 17:08:04 +0200535 }
Bram Moolenaar4edfe2d2018-08-23 20:55:45 +0200536 ccline.cmdbuff[skiplen + patlen] = next_char;
537 }
538
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200539 validate_cursor();
540 // May redraw the status line to show the cursor position.
541 if (p_ru && curwin->w_status_height > 0)
542 curwin->w_redr_status = TRUE;
543
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200544 update_screen(SOME_VALID);
Bram Moolenaar7ab5d772019-10-26 20:45:24 +0200545 highlight_match = FALSE;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200546 restore_last_search_pattern();
547
Bram Moolenaar99f043a2018-09-09 15:54:14 +0200548 // Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the
549 // end of the pattern, e.g. for ":s/pat/".
550 if (ccline.cmdbuff[skiplen + patlen] != NUL)
551 curwin->w_cursor = is_state->search_start;
552 else if (found != 0)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200553 curwin->w_cursor = end_pos;
554
555 msg_starthere();
556 redrawcmdline();
557 is_state->did_incsearch = TRUE;
558}
559
560/*
561 * May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
562 * or previous match.
563 * Returns FAIL when jumping to cmdline_not_changed;
564 */
565 static int
566may_adjust_incsearch_highlighting(
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200567 int firstc,
568 long count,
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200569 incsearch_state_T *is_state,
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200570 int c)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200571{
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200572 int skiplen, patlen;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200573 pos_T t;
574 char_u *pat;
575 int search_flags = SEARCH_NOOF;
576 int i;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200577 int save;
Bram Moolenaarc036e872020-02-21 21:30:52 +0100578 int search_delim;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200579
Bram Moolenaar198cb662018-09-06 21:44:17 +0200580 // Parsing range may already set the last search pattern.
Bram Moolenaar01a060d2018-11-30 21:57:55 +0100581 // NOTE: must call restore_last_search_pattern() before returning!
Bram Moolenaar198cb662018-09-06 21:44:17 +0200582 save_last_search_pattern();
583
Bram Moolenaarc036e872020-02-21 21:30:52 +0100584 if (!do_incsearch_highlighting(firstc, &search_delim, is_state, &skiplen, &patlen))
Bram Moolenaar198cb662018-09-06 21:44:17 +0200585 {
586 restore_last_search_pattern();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200587 return OK;
Bram Moolenaar198cb662018-09-06 21:44:17 +0200588 }
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200589 if (patlen == 0 && ccline.cmdbuff[skiplen] == NUL)
Bram Moolenaar198cb662018-09-06 21:44:17 +0200590 {
591 restore_last_search_pattern();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200592 return FAIL;
Bram Moolenaar198cb662018-09-06 21:44:17 +0200593 }
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200594
Bram Moolenaarc036e872020-02-21 21:30:52 +0100595 if (search_delim == ccline.cmdbuff[skiplen])
Bram Moolenaaref73a282018-08-11 19:02:22 +0200596 {
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200597 pat = last_search_pattern();
Bram Moolenaaref73a282018-08-11 19:02:22 +0200598 skiplen = 0;
Bram Moolenaard7cc1632018-08-14 20:18:26 +0200599 patlen = (int)STRLEN(pat);
Bram Moolenaaref73a282018-08-11 19:02:22 +0200600 }
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200601 else
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200602 pat = ccline.cmdbuff + skiplen;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200603
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200604 cursor_off();
605 out_flush();
606 if (c == Ctrl_G)
607 {
608 t = is_state->match_end;
609 if (LT_POS(is_state->match_start, is_state->match_end))
610 // Start searching at the end of the match not at the beginning of
611 // the next column.
612 (void)decl(&t);
613 search_flags += SEARCH_COL;
614 }
615 else
616 t = is_state->match_start;
617 if (!p_hls)
618 search_flags += SEARCH_KEEP;
619 ++emsg_off;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200620 save = pat[patlen];
621 pat[patlen] = NUL;
Bram Moolenaar5d24a222018-12-23 19:10:09 +0100622 i = searchit(curwin, curbuf, &t, NULL,
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200623 c == Ctrl_G ? FORWARD : BACKWARD,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +0200624 pat, count, search_flags, RE_SEARCH, NULL);
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200625 --emsg_off;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200626 pat[patlen] = save;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200627 if (i)
628 {
629 is_state->search_start = is_state->match_start;
630 is_state->match_end = t;
631 is_state->match_start = t;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200632 if (c == Ctrl_T && firstc != '?')
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200633 {
634 // Move just before the current match, so that when nv_search
635 // finishes the cursor will be put back on the match.
636 is_state->search_start = t;
637 (void)decl(&is_state->search_start);
638 }
639 else if (c == Ctrl_G && firstc == '?')
640 {
641 // Move just after the current match, so that when nv_search
642 // finishes the cursor will be put back on the match.
643 is_state->search_start = t;
644 (void)incl(&is_state->search_start);
645 }
646 if (LT_POS(t, is_state->search_start) && c == Ctrl_G)
647 {
648 // wrap around
649 is_state->search_start = t;
650 if (firstc == '?')
651 (void)incl(&is_state->search_start);
652 else
653 (void)decl(&is_state->search_start);
654 }
655
656 set_search_match(&is_state->match_end);
657 curwin->w_cursor = is_state->match_start;
658 changed_cline_bef_curs();
659 update_topline();
660 validate_cursor();
661 highlight_match = TRUE;
662 save_viewstate(&is_state->old_viewstate);
663 update_screen(NOT_VALID);
Bram Moolenaar7ab5d772019-10-26 20:45:24 +0200664 highlight_match = FALSE;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200665 redrawcmdline();
Bram Moolenaar69a5b862019-07-16 21:38:51 +0200666 curwin->w_cursor = is_state->match_end;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200667 }
668 else
669 vim_beep(BO_ERROR);
670 restore_last_search_pattern();
671 return FAIL;
672}
673
674/*
675 * When CTRL-L typed: add character from the match to the pattern.
676 * May set "*c" to the added character.
677 * Return OK when jumping to cmdline_not_changed.
678 */
679 static int
680may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state)
681{
Bram Moolenaarc036e872020-02-21 21:30:52 +0100682 int skiplen, patlen, search_delim;
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200683
Bram Moolenaar198cb662018-09-06 21:44:17 +0200684 // Parsing range may already set the last search pattern.
Bram Moolenaar01a060d2018-11-30 21:57:55 +0100685 // NOTE: must call restore_last_search_pattern() before returning!
Bram Moolenaar198cb662018-09-06 21:44:17 +0200686 save_last_search_pattern();
687
Bram Moolenaar9b7cce22020-06-06 15:14:08 +0200688 if (!do_incsearch_highlighting(firstc, &search_delim, is_state,
689 &skiplen, &patlen))
Bram Moolenaar198cb662018-09-06 21:44:17 +0200690 {
691 restore_last_search_pattern();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200692 return FAIL;
Bram Moolenaar198cb662018-09-06 21:44:17 +0200693 }
Bram Moolenaar01a060d2018-11-30 21:57:55 +0100694 restore_last_search_pattern();
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200695
696 // Add a character from under the cursor for 'incsearch'.
697 if (is_state->did_incsearch)
698 {
699 curwin->w_cursor = is_state->match_end;
Bram Moolenaar730f48f2019-04-11 13:45:57 +0200700 *c = gchar_cursor();
701 if (*c != NUL)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200702 {
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200703 // If 'ignorecase' and 'smartcase' are set and the
704 // command line has no uppercase characters, convert
705 // the character to lowercase.
Bram Moolenaarb0acacd2018-08-11 16:40:43 +0200706 if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff + skiplen))
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200707 *c = MB_TOLOWER(*c);
Bram Moolenaarc036e872020-02-21 21:30:52 +0100708 if (*c == search_delim || vim_strchr((char_u *)(
Bram Moolenaar730f48f2019-04-11 13:45:57 +0200709 p_magic ? "\\~^$.*[" : "\\^$"), *c) != NULL)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200710 {
Bram Moolenaar730f48f2019-04-11 13:45:57 +0200711 // put a backslash before special characters
712 stuffcharReadbuff(*c);
713 *c = '\\';
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200714 }
Bram Moolenaar730f48f2019-04-11 13:45:57 +0200715 // add any composing characters
716 if (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
717 {
718 int save_c = *c;
719
720 while (mb_char2len(*c) != mb_ptr2len(ml_get_cursor()))
721 {
722 curwin->w_cursor.col += mb_char2len(*c);
723 *c = gchar_cursor();
724 stuffcharReadbuff(*c);
725 }
726 *c = save_c;
727 }
728 return FAIL;
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +0200729 }
730 }
731 return OK;
732}
Bram Moolenaar9b25af32018-04-28 13:56:09 +0200733#endif
734
Bram Moolenaar693f7dc2019-06-21 02:30:38 +0200735#ifdef FEAT_ARABIC
736/*
737 * Return TRUE if the command line has an Arabic character at or after "start"
738 * for "len" bytes.
739 */
740 static int
741cmdline_has_arabic(int start, int len)
742{
743 int j;
744 int mb_l;
745 int u8c;
746 char_u *p;
747 int u8cc[MAX_MCO];
748
749 if (!enc_utf8)
750 return FALSE;
751
752 for (j = start; j < start + len; j += mb_l)
753 {
754 p = ccline.cmdbuff + j;
755 u8c = utfc_ptr2char_len(p, u8cc, start + len - j);
756 mb_l = utfc_ptr2len_len(p, start + len - j);
757 if (ARABIC_CHAR(u8c))
758 return TRUE;
759 }
760 return FALSE;
761}
762#endif
763
Bram Moolenaard3dc0622018-09-30 17:45:30 +0200764 void
765cmdline_init(void)
766{
Bram Moolenaara80faa82020-04-12 19:37:17 +0200767 CLEAR_FIELD(ccline);
Bram Moolenaard3dc0622018-09-30 17:45:30 +0200768}
769
Bram Moolenaar66216052017-12-16 16:33:44 +0100770/*
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +0200771 * Handle backspace, delete and CTRL-W keys in the command-line mode.
772 * Returns:
773 * CMDLINE_NOT_CHANGED - if the command line is not changed
774 * CMDLINE_CHANGED - if the command line is changed
775 * GOTO_NORMAL_MODE - go back to normal mode
776 */
777 static int
778cmdline_erase_chars(
779 int c,
780 int indent
781#ifdef FEAT_SEARCH_EXTRA
782 , incsearch_state_T *isp
783#endif
784 )
785{
786 int i;
787 int j;
788
789 if (c == K_KDEL)
790 c = K_DEL;
791
792 /*
793 * Delete current character is the same as backspace on next
794 * character, except at end of line.
795 */
796 if (c == K_DEL && ccline.cmdpos != ccline.cmdlen)
797 ++ccline.cmdpos;
798 if (has_mbyte && c == K_DEL)
799 ccline.cmdpos += mb_off_next(ccline.cmdbuff,
800 ccline.cmdbuff + ccline.cmdpos);
801 if (ccline.cmdpos > 0)
802 {
803 char_u *p;
804
805 j = ccline.cmdpos;
806 p = ccline.cmdbuff + j;
807 if (has_mbyte)
808 {
809 p = mb_prevptr(ccline.cmdbuff, p);
810 if (c == Ctrl_W)
811 {
812 while (p > ccline.cmdbuff && vim_isspace(*p))
813 p = mb_prevptr(ccline.cmdbuff, p);
814 i = mb_get_class(p);
815 while (p > ccline.cmdbuff && mb_get_class(p) == i)
816 p = mb_prevptr(ccline.cmdbuff, p);
817 if (mb_get_class(p) != i)
818 p += (*mb_ptr2len)(p);
819 }
820 }
821 else if (c == Ctrl_W)
822 {
823 while (p > ccline.cmdbuff && vim_isspace(p[-1]))
824 --p;
825 i = vim_iswordc(p[-1]);
826 while (p > ccline.cmdbuff && !vim_isspace(p[-1])
827 && vim_iswordc(p[-1]) == i)
828 --p;
829 }
830 else
831 --p;
832 ccline.cmdpos = (int)(p - ccline.cmdbuff);
833 ccline.cmdlen -= j - ccline.cmdpos;
834 i = ccline.cmdpos;
835 while (i < ccline.cmdlen)
836 ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
837
838 // Truncate at the end, required for multi-byte chars.
839 ccline.cmdbuff[ccline.cmdlen] = NUL;
840#ifdef FEAT_SEARCH_EXTRA
841 if (ccline.cmdlen == 0)
842 {
843 isp->search_start = isp->save_cursor;
844 // save view settings, so that the screen
845 // won't be restored at the wrong position
846 isp->old_viewstate = isp->init_viewstate;
847 }
848#endif
849 redrawcmd();
850 }
851 else if (ccline.cmdlen == 0 && c != Ctrl_W
852 && ccline.cmdprompt == NULL && indent == 0)
853 {
854 // In ex and debug mode it doesn't make sense to return.
855 if (exmode_active
856#ifdef FEAT_EVAL
857 || ccline.cmdfirstc == '>'
858#endif
859 )
860 return CMDLINE_NOT_CHANGED;
861
862 VIM_CLEAR(ccline.cmdbuff); // no commandline to return
863 if (!cmd_silent)
864 {
865#ifdef FEAT_RIGHTLEFT
866 if (cmdmsg_rl)
867 msg_col = Columns;
868 else
869#endif
870 msg_col = 0;
871 msg_putchar(' '); // delete ':'
872 }
873#ifdef FEAT_SEARCH_EXTRA
874 if (ccline.cmdlen == 0)
875 isp->search_start = isp->save_cursor;
876#endif
877 redraw_cmdline = TRUE;
878 return GOTO_NORMAL_MODE;
879 }
880 return CMDLINE_CHANGED;
881}
882
883/*
884 * Handle the CTRL-^ key in the command-line mode and toggle the use of the
885 * language :lmap mappings and/or Input Method.
886 */
887 static void
888cmdline_toggle_langmap(long *b_im_ptr)
889{
890 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
891 {
892 // ":lmap" mappings exists, toggle use of mappings.
893 State ^= LANGMAP;
894#ifdef HAVE_INPUT_METHOD
895 im_set_active(FALSE); // Disable input method
896#endif
897 if (b_im_ptr != NULL)
898 {
899 if (State & LANGMAP)
900 *b_im_ptr = B_IMODE_LMAP;
901 else
902 *b_im_ptr = B_IMODE_NONE;
903 }
904 }
905#ifdef HAVE_INPUT_METHOD
906 else
907 {
908 // There are no ":lmap" mappings, toggle IM. When
909 // 'imdisable' is set don't try getting the status, it's
910 // always off.
911 if ((p_imdisable && b_im_ptr != NULL)
912 ? *b_im_ptr == B_IMODE_IM : im_get_status())
913 {
914 im_set_active(FALSE); // Disable input method
915 if (b_im_ptr != NULL)
916 *b_im_ptr = B_IMODE_NONE;
917 }
918 else
919 {
920 im_set_active(TRUE); // Enable input method
921 if (b_im_ptr != NULL)
922 *b_im_ptr = B_IMODE_IM;
923 }
924 }
925#endif
926 if (b_im_ptr != NULL)
927 {
928 if (b_im_ptr == &curbuf->b_p_iminsert)
929 set_iminsert_global();
930 else
931 set_imsearch_global();
932 }
933#ifdef CURSOR_SHAPE
934 ui_cursor_shape(); // may show different cursor shape
935#endif
936#if defined(FEAT_KEYMAP)
937 // Show/unshow value of 'keymap' in status lines later.
938 status_redraw_curbuf();
939#endif
940}
941
942/*
943 * Handle the CTRL-R key in the command-line mode and insert the contents of a
944 * numbered or named register.
945 */
946 static int
947cmdline_insert_reg(int *gotesc UNUSED)
948{
949 int i;
950 int c;
951
952#ifdef USE_ON_FLY_SCROLL
953 dont_scroll = TRUE; // disallow scrolling here
954#endif
955 putcmdline('"', TRUE);
956 ++no_mapping;
957 ++allow_keys;
958 i = c = plain_vgetc(); // CTRL-R <char>
959 if (i == Ctrl_O)
960 i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R
961 if (i == Ctrl_R)
962 c = plain_vgetc(); // CTRL-R CTRL-R <char>
963 extra_char = NUL;
964 --no_mapping;
965 --allow_keys;
966#ifdef FEAT_EVAL
967 /*
968 * Insert the result of an expression.
969 * Need to save the current command line, to be able to enter
970 * a new one...
971 */
972 new_cmdpos = -1;
973 if (c == '=')
974 {
975 if (ccline.cmdfirstc == '=' // can't do this recursively
976 || cmdline_star > 0) // or when typing a password
977 {
978 beep_flush();
979 c = ESC;
980 }
981 else
982 c = get_expr_register();
983 }
984#endif
985 if (c != ESC) // use ESC to cancel inserting register
986 {
987 cmdline_paste(c, i == Ctrl_R, FALSE);
988
989#ifdef FEAT_EVAL
990 // When there was a serious error abort getting the
991 // command line.
992 if (aborting())
993 {
994 *gotesc = TRUE; // will free ccline.cmdbuff after
995 // putting it in history
996 return GOTO_NORMAL_MODE;
997 }
998#endif
999 KeyTyped = FALSE; // Don't do p_wc completion.
1000#ifdef FEAT_EVAL
1001 if (new_cmdpos >= 0)
1002 {
1003 // set_cmdline_pos() was used
1004 if (new_cmdpos > ccline.cmdlen)
1005 ccline.cmdpos = ccline.cmdlen;
1006 else
1007 ccline.cmdpos = new_cmdpos;
1008 }
1009#endif
1010 }
1011 redrawcmd();
1012 return CMDLINE_CHANGED;
1013}
1014
1015/*
1016 * Handle the Left and Right mouse clicks in the command-line mode.
1017 */
1018 static void
1019cmdline_left_right_mouse(int c, int *ignore_drag_release)
1020{
1021 if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
1022 *ignore_drag_release = TRUE;
1023 else
1024 *ignore_drag_release = FALSE;
1025# ifdef FEAT_GUI
1026 // When GUI is active, also move when 'mouse' is empty
1027 if (!gui.in_use)
1028# endif
1029 if (!mouse_has(MOUSE_COMMAND))
1030 return;
1031# ifdef FEAT_CLIPBOARD
1032 if (mouse_row < cmdline_row && clip_star.available)
1033 {
1034 int button, is_click, is_drag;
1035
1036 /*
1037 * Handle modeless selection.
1038 */
1039 button = get_mouse_button(KEY2TERMCAP1(c),
1040 &is_click, &is_drag);
1041 if (mouse_model_popup() && button == MOUSE_LEFT
1042 && (mod_mask & MOD_MASK_SHIFT))
1043 {
1044 // Translate shift-left to right button.
1045 button = MOUSE_RIGHT;
1046 mod_mask &= ~MOD_MASK_SHIFT;
1047 }
1048 clip_modeless(button, is_click, is_drag);
1049 return;
1050 }
1051# endif
1052
1053 set_cmdspos();
1054 for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
1055 ++ccline.cmdpos)
1056 {
1057 int i;
1058
1059 i = cmdline_charsize(ccline.cmdpos);
1060 if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
1061 && mouse_col < ccline.cmdspos % Columns + i)
1062 break;
1063 if (has_mbyte)
1064 {
1065 // Count ">" for double-wide char that doesn't fit.
1066 correct_cmdspos(ccline.cmdpos, i);
1067 ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
1068 + ccline.cmdpos) - 1;
1069 }
1070 ccline.cmdspos += i;
1071 }
1072}
1073
1074/*
1075 * Handle the Up, Down, Page Up, Page down, CTRL-N and CTRL-P key in the
1076 * command-line mode. The pressed key is in 'c'.
1077 * Returns:
1078 * CMDLINE_NOT_CHANGED - if the command line is not changed
1079 * CMDLINE_CHANGED - if the command line is changed
1080 * GOTO_NORMAL_MODE - go back to normal mode
1081 */
1082 static int
1083cmdline_browse_history(
1084 int c,
1085 int firstc,
1086 char_u **curcmdstr,
1087 int histype,
1088 int *hiscnt_p,
1089 expand_T *xp)
1090{
1091 int i;
1092 int j;
1093 char_u *lookfor = *curcmdstr;
1094 int hiscnt = *hiscnt_p;
1095 int res;
1096
1097 if (get_hislen() == 0 || firstc == NUL) // no history
1098 return CMDLINE_NOT_CHANGED;
1099
1100 i = hiscnt;
1101
1102 // save current command string so it can be restored later
1103 if (lookfor == NULL)
1104 {
1105 if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL)
1106 return CMDLINE_NOT_CHANGED;
1107 lookfor[ccline.cmdpos] = NUL;
1108 }
1109
1110 j = (int)STRLEN(lookfor);
1111 for (;;)
1112 {
1113 // one step backwards
1114 if (c == K_UP|| c == K_S_UP || c == Ctrl_P
1115 || c == K_PAGEUP || c == K_KPAGEUP)
1116 {
1117 if (hiscnt == get_hislen()) // first time
1118 hiscnt = *get_hisidx(histype);
1119 else if (hiscnt == 0 && *get_hisidx(histype)
1120 != get_hislen() - 1)
1121 hiscnt = get_hislen() - 1;
1122 else if (hiscnt != *get_hisidx(histype) + 1)
1123 --hiscnt;
1124 else // at top of list
1125 {
1126 hiscnt = i;
1127 break;
1128 }
1129 }
1130 else // one step forwards
1131 {
1132 // on last entry, clear the line
1133 if (hiscnt == *get_hisidx(histype))
1134 {
1135 hiscnt = get_hislen();
1136 break;
1137 }
1138
1139 // not on a history line, nothing to do
1140 if (hiscnt == get_hislen())
1141 break;
1142 if (hiscnt == get_hislen() - 1) // wrap around
1143 hiscnt = 0;
1144 else
1145 ++hiscnt;
1146 }
1147 if (hiscnt < 0 || get_histentry(histype)[hiscnt].hisstr
1148 == NULL)
1149 {
1150 hiscnt = i;
1151 break;
1152 }
1153 if ((c != K_UP && c != K_DOWN)
1154 || hiscnt == i
1155 || STRNCMP(get_histentry(histype)[hiscnt].hisstr,
1156 lookfor, (size_t)j) == 0)
1157 break;
1158 }
1159
1160 if (hiscnt != i) // jumped to other entry
1161 {
1162 char_u *p;
1163 int len;
1164 int old_firstc;
1165
1166 VIM_CLEAR(ccline.cmdbuff);
1167 xp->xp_context = EXPAND_NOTHING;
1168 if (hiscnt == get_hislen())
1169 p = lookfor; // back to the old one
1170 else
1171 p = get_histentry(histype)[hiscnt].hisstr;
1172
1173 if (histype == HIST_SEARCH
1174 && p != lookfor
1175 && (old_firstc = p[STRLEN(p) + 1]) != firstc)
1176 {
1177 // Correct for the separator character used when
1178 // adding the history entry vs the one used now.
1179 // First loop: count length.
1180 // Second loop: copy the characters.
1181 for (i = 0; i <= 1; ++i)
1182 {
1183 len = 0;
1184 for (j = 0; p[j] != NUL; ++j)
1185 {
1186 // Replace old sep with new sep, unless it is
1187 // escaped.
1188 if (p[j] == old_firstc
1189 && (j == 0 || p[j - 1] != '\\'))
1190 {
1191 if (i > 0)
1192 ccline.cmdbuff[len] = firstc;
1193 }
1194 else
1195 {
1196 // Escape new sep, unless it is already
1197 // escaped.
1198 if (p[j] == firstc
1199 && (j == 0 || p[j - 1] != '\\'))
1200 {
1201 if (i > 0)
1202 ccline.cmdbuff[len] = '\\';
1203 ++len;
1204 }
1205 if (i > 0)
1206 ccline.cmdbuff[len] = p[j];
1207 }
1208 ++len;
1209 }
1210 if (i == 0)
1211 {
1212 alloc_cmdbuff(len);
1213 if (ccline.cmdbuff == NULL)
1214 {
1215 res = GOTO_NORMAL_MODE;
1216 goto done;
1217 }
1218 }
1219 }
1220 ccline.cmdbuff[len] = NUL;
1221 }
1222 else
1223 {
1224 alloc_cmdbuff((int)STRLEN(p));
1225 if (ccline.cmdbuff == NULL)
1226 {
1227 res = GOTO_NORMAL_MODE;
1228 goto done;
1229 }
1230 STRCPY(ccline.cmdbuff, p);
1231 }
1232
1233 ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
1234 redrawcmd();
1235 res = CMDLINE_CHANGED;
1236 goto done;
1237 }
1238 beep_flush();
1239 res = CMDLINE_NOT_CHANGED;
1240
1241done:
1242 *curcmdstr = lookfor;
1243 *hiscnt_p = hiscnt;
1244 return res;
1245}
1246
1247/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 * getcmdline() - accept a command line starting with firstc.
1249 *
1250 * firstc == ':' get ":" command line.
1251 * firstc == '/' or '?' get search pattern
1252 * firstc == '=' get expression
1253 * firstc == '@' get text for input() function
1254 * firstc == '>' get text for debug mode
1255 * firstc == NUL get text for :insert command
1256 * firstc == -1 like NUL, and break on CTRL-C
1257 *
1258 * The line is collected in ccline.cmdbuff, which is reallocated to fit the
1259 * command line.
1260 *
1261 * Careful: getcmdline() can be called recursively!
1262 *
1263 * Return pointer to allocated string if there is a commandline, NULL
1264 * otherwise.
1265 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001267getcmdline(
1268 int firstc,
Bram Moolenaar438d1762018-09-30 17:11:48 +02001269 long count, // only used for incremental search
Bram Moolenaare96a2492019-06-25 04:12:16 +02001270 int indent, // indent for inside conditionals
1271 int do_concat UNUSED)
Bram Moolenaar438d1762018-09-30 17:11:48 +02001272{
1273 return getcmdline_int(firstc, count, indent, TRUE);
1274}
1275
1276 static char_u *
1277getcmdline_int(
1278 int firstc,
1279 long count UNUSED, // only used for incremental search
1280 int indent, // indent for inside conditionals
1281 int init_ccline) // clear ccline first
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282{
1283 int c;
1284 int i;
1285 int j;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001286 int gotesc = FALSE; // TRUE when <ESC> just typed
1287 int do_abbr; // when TRUE check for abbr.
1288 char_u *lookfor = NULL; // string to match
1289 int hiscnt; // current history line in use
1290 int histype; // history type to be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02001292 incsearch_state_T is_state;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001294 int did_wild_list = FALSE; // did wild_list() recently
1295 int wim_index = 0; // index in wim_flags[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 int res;
1297 int save_msg_scroll = msg_scroll;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001298 int save_State = State; // remember State when called
1299 int some_key_typed = FALSE; // one of the keys was typed
1300 // mouse drag and release events are ignored, unless they are
1301 // preceded with a mouse down event
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302 int ignore_drag_release = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303#ifdef FEAT_EVAL
1304 int break_ctrl_c = FALSE;
1305#endif
1306 expand_T xpc;
1307 long *b_im_ptr = NULL;
Bram Moolenaar66b51422019-08-18 21:44:12 +02001308 cmdline_info_T save_ccline;
Bram Moolenaar438d1762018-09-30 17:11:48 +02001309 int did_save_ccline = FALSE;
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02001310 int cmdline_type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
Bram Moolenaar438d1762018-09-30 17:11:48 +02001312 if (ccline.cmdbuff != NULL)
1313 {
1314 // Being called recursively. Since ccline is global, we need to save
1315 // the current buffer and restore it when returning.
1316 save_cmdline(&save_ccline);
1317 did_save_ccline = TRUE;
1318 }
1319 if (init_ccline)
Bram Moolenaara80faa82020-04-12 19:37:17 +02001320 CLEAR_FIELD(ccline);
Bram Moolenaar438d1762018-09-30 17:11:48 +02001321
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322#ifdef FEAT_EVAL
1323 if (firstc == -1)
1324 {
1325 firstc = NUL;
1326 break_ctrl_c = TRUE;
1327 }
1328#endif
1329#ifdef FEAT_RIGHTLEFT
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001330 // start without Hebrew mapping for a command line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001331 if (firstc == ':' || firstc == '=' || firstc == '>')
1332 cmd_hkmap = 0;
1333#endif
1334
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001335 ccline.overstrike = FALSE; // always start in insert mode
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02001336
Bram Moolenaar071d4272004-06-13 20:20:40 +00001337#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02001338 init_incsearch_state(&is_state);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339#endif
1340
1341 /*
1342 * set some variables for redrawcmd()
1343 */
1344 ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001345 ccline.cmdindent = (firstc > 0 ? indent : 0);
1346
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001347 // alloc initial ccline.cmdbuff
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001348 alloc_cmdbuff(exmode_active ? 250 : indent + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001349 if (ccline.cmdbuff == NULL)
Bram Moolenaar438d1762018-09-30 17:11:48 +02001350 goto theend; // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351 ccline.cmdlen = ccline.cmdpos = 0;
1352 ccline.cmdbuff[0] = NUL;
Bram Moolenaarf2405ed2017-03-16 19:58:25 +01001353 sb_text_start_cmdline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001355 // autoindent for :insert and :append
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001356 if (firstc <= 0)
1357 {
Bram Moolenaar2536d4f2015-07-17 13:22:51 +02001358 vim_memset(ccline.cmdbuff, ' ', indent);
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001359 ccline.cmdbuff[indent] = NUL;
1360 ccline.cmdpos = indent;
1361 ccline.cmdspos = indent;
1362 ccline.cmdlen = indent;
1363 }
1364
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365 ExpandInit(&xpc);
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00001366 ccline.xpc = &xpc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367
1368#ifdef FEAT_RIGHTLEFT
1369 if (curwin->w_p_rl && *curwin->w_p_rlc == 's'
1370 && (firstc == '/' || firstc == '?'))
1371 cmdmsg_rl = TRUE;
1372 else
1373 cmdmsg_rl = FALSE;
1374#endif
1375
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001376 redir_off = TRUE; // don't redirect the typed command
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377 if (!cmd_silent)
1378 {
1379 i = msg_scrolled;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001380 msg_scrolled = 0; // avoid wait_return message
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 gotocmdline(TRUE);
1382 msg_scrolled += i;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001383 redrawcmdprompt(); // draw prompt or indent
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 set_cmdspos();
1385 }
1386 xpc.xp_context = EXPAND_NOTHING;
1387 xpc.xp_backslash = XP_BS_NONE;
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00001388#ifndef BACKSLASH_IN_FILENAME
1389 xpc.xp_shell = FALSE;
1390#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001392#if defined(FEAT_EVAL)
1393 if (ccline.input_fn)
1394 {
1395 xpc.xp_context = ccline.xp_context;
1396 xpc.xp_pattern = ccline.cmdbuff;
1397 xpc.xp_arg = ccline.xp_arg;
1398 }
1399#endif
1400
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401 /*
1402 * Avoid scrolling when called by a recursive do_cmdline(), e.g. when
1403 * doing ":@0" when register 0 doesn't contain a CR.
1404 */
1405 msg_scroll = FALSE;
1406
1407 State = CMDLINE;
1408
1409 if (firstc == '/' || firstc == '?' || firstc == '@')
1410 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001411 // Use ":lmap" mappings for search pattern and input().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412 if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT)
1413 b_im_ptr = &curbuf->b_p_iminsert;
1414 else
1415 b_im_ptr = &curbuf->b_p_imsearch;
1416 if (*b_im_ptr == B_IMODE_LMAP)
1417 State |= LANGMAP;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001418#ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 im_set_active(*b_im_ptr == B_IMODE_IM);
1420#endif
1421 }
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001422#ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +00001423 else if (p_imcmdline)
1424 im_set_active(TRUE);
1425#endif
1426
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427 setmouse();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001428#ifdef CURSOR_SHAPE
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001429 ui_cursor_shape(); // may show different cursor shape
Bram Moolenaar071d4272004-06-13 20:20:40 +00001430#endif
1431
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001432 // When inside an autocommand for writing "exiting" may be set and
1433 // terminal mode set to cooked. Need to set raw mode here then.
Bram Moolenaarf4d11452005-12-02 00:46:37 +00001434 settmode(TMODE_RAW);
1435
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001436 // Trigger CmdlineEnter autocommands.
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02001437 cmdline_type = firstc == NUL ? '-' : firstc;
1438 trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINEENTER);
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02001439
Bram Moolenaar071d4272004-06-13 20:20:40 +00001440 init_history();
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001441 hiscnt = get_hislen(); // set hiscnt to impossible history value
Bram Moolenaar071d4272004-06-13 20:20:40 +00001442 histype = hist_char2type(firstc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443
1444#ifdef FEAT_DIGRAPHS
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001445 do_digraph(-1); // init digraph typeahead
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446#endif
1447
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001448 // If something above caused an error, reset the flags, we do want to type
1449 // and execute commands. Display may be messed up a bit.
Bram Moolenaar15a35c42014-06-25 12:26:46 +02001450 if (did_emsg)
1451 redrawcmd();
1452 did_emsg = FALSE;
1453 got_int = FALSE;
1454
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 /*
1456 * Collect the command string, handling editing keys.
1457 */
1458 for (;;)
1459 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001460 redir_off = TRUE; // Don't redirect the typed command.
1461 // Repeated, because a ":redir" inside
1462 // completion may switch it on.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463#ifdef USE_ON_FLY_SCROLL
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001464 dont_scroll = FALSE; // allow scrolling here
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001466 quit_more = FALSE; // reset after CTRL-D which had a more-prompt
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001468 did_emsg = FALSE; // There can't really be a reason why an error
1469 // that occurs while typing a command should
1470 // cause the command not to be executed.
Bram Moolenaar72532d32018-04-07 19:09:09 +02001471
Bram Moolenaar8aeec402019-09-15 23:02:04 +02001472 // Trigger SafeState if nothing is pending.
1473 may_trigger_safestate(xpc.xp_numfiles <= 0);
1474
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001475 cursorcmd(); // set the cursor on the right spot
Bram Moolenaar30405d32008-01-02 20:55:27 +00001476
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001477 // Get a character. Ignore K_IGNORE and K_NOP, they should not do
1478 // anything, such as stop completion.
Bram Moolenaar30405d32008-01-02 20:55:27 +00001479 do
Bram Moolenaar30405d32008-01-02 20:55:27 +00001480 c = safe_vgetc();
Bram Moolenaarabab0b02019-03-30 18:47:01 +01001481 while (c == K_IGNORE || c == K_NOP);
Bram Moolenaar30405d32008-01-02 20:55:27 +00001482
Bram Moolenaar071d4272004-06-13 20:20:40 +00001483 if (KeyTyped)
1484 {
1485 some_key_typed = TRUE;
1486#ifdef FEAT_RIGHTLEFT
1487 if (cmd_hkmap)
1488 c = hkmap(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489 if (cmdmsg_rl && !KeyStuffed)
1490 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001491 // Invert horizontal movements and operations. Only when
1492 // typed by the user directly, not when the result of a
1493 // mapping.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494 switch (c)
1495 {
1496 case K_RIGHT: c = K_LEFT; break;
1497 case K_S_RIGHT: c = K_S_LEFT; break;
1498 case K_C_RIGHT: c = K_C_LEFT; break;
1499 case K_LEFT: c = K_RIGHT; break;
1500 case K_S_LEFT: c = K_S_RIGHT; break;
1501 case K_C_LEFT: c = K_C_RIGHT; break;
1502 }
1503 }
1504#endif
1505 }
1506
1507 /*
1508 * Ignore got_int when CTRL-C was typed here.
1509 * Don't ignore it in :global, we really need to break then, e.g., for
1510 * ":g/pat/normal /pat" (without the <CR>).
1511 * Don't ignore it for the input() function.
1512 */
1513 if ((c == Ctrl_C
1514#ifdef UNIX
1515 || c == intr_char
1516#endif
1517 )
1518#if defined(FEAT_EVAL) || defined(FEAT_CRYPT)
1519 && firstc != '@'
1520#endif
1521#ifdef FEAT_EVAL
1522 && !break_ctrl_c
1523#endif
1524 && !global_busy)
1525 got_int = FALSE;
1526
Bram Moolenaard7663c22019-08-06 21:59:57 +02001527 // free old command line when finished moving around in the history
1528 // list
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529 if (lookfor != NULL
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001530 && c != K_S_DOWN && c != K_S_UP
Bram Moolenaar68b76a62005-03-25 21:53:48 +00001531 && c != K_DOWN && c != K_UP
Bram Moolenaar071d4272004-06-13 20:20:40 +00001532 && c != K_PAGEDOWN && c != K_PAGEUP
1533 && c != K_KPAGEDOWN && c != K_KPAGEUP
Bram Moolenaar68b76a62005-03-25 21:53:48 +00001534 && c != K_LEFT && c != K_RIGHT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535 && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N)))
Bram Moolenaard23a8232018-02-10 18:45:26 +01001536 VIM_CLEAR(lookfor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537
1538 /*
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00001539 * When there are matching completions to select <S-Tab> works like
1540 * CTRL-P (unless 'wc' is <S-Tab>).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 */
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00001542 if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001543 c = Ctrl_P;
1544
1545#ifdef FEAT_WILDMENU
Bram Moolenaareadee482020-09-04 15:37:31 +02001546 c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547#endif
1548
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001549 // free expanded names when finished walking through matches
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 if (xpc.xp_numfiles != -1
1551 && !(c == p_wc && KeyTyped) && c != p_wcm
1552 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A
1553 && c != Ctrl_L)
1554 {
1555 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
1556 did_wild_list = FALSE;
1557#ifdef FEAT_WILDMENU
Bram Moolenaar68b76a62005-03-25 21:53:48 +00001558 if (!p_wmnu || (c != K_UP && c != K_DOWN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559#endif
1560 xpc.xp_context = EXPAND_NOTHING;
1561 wim_index = 0;
1562#ifdef FEAT_WILDMENU
Bram Moolenaareadee482020-09-04 15:37:31 +02001563 wildmenu_cleanup(&ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001564#endif
1565 }
1566
1567#ifdef FEAT_WILDMENU
Bram Moolenaareadee482020-09-04 15:37:31 +02001568 c = wildmenu_process_key(&ccline, c, &xpc);
1569#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001571 // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
1572 // mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573 if (c == Ctrl_BSL)
1574 {
1575 ++no_mapping;
1576 ++allow_keys;
Bram Moolenaar61abfd12007-09-13 16:26:47 +00001577 c = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578 --no_mapping;
1579 --allow_keys;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001580 // CTRL-\ e doesn't work when obtaining an expression, unless it
1581 // is in a mapping.
Bram Moolenaarb7356812012-10-11 04:04:37 +02001582 if (c != Ctrl_N && c != Ctrl_G && (c != 'e'
Bram Moolenaar31cbadf2018-09-25 20:48:57 +02001583 || (ccline.cmdfirstc == '=' && KeyTyped)
1584#ifdef FEAT_EVAL
Bram Moolenaaree91c332018-09-25 22:27:35 +02001585 || cmdline_star > 0
Bram Moolenaar31cbadf2018-09-25 20:48:57 +02001586#endif
1587 ))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 {
1589 vungetc(c);
1590 c = Ctrl_BSL;
1591 }
1592#ifdef FEAT_EVAL
1593 else if (c == 'e')
1594 {
Bram Moolenaar673b87b2010-08-13 19:12:07 +02001595 char_u *p = NULL;
1596 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597
1598 /*
1599 * Replace the command line with the result of an expression.
Bram Moolenaar4770d092006-01-12 23:22:24 +00001600 * Need to save and restore the current command line, to be
1601 * able to enter a new one...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 */
1603 if (ccline.cmdpos == ccline.cmdlen)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001604 new_cmdpos = 99999; // keep it at the end
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 else
1606 new_cmdpos = ccline.cmdpos;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001607
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 c = get_expr_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609 if (c == '=')
1610 {
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001611 // Need to save and restore ccline. And set "textwinlock"
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001612 // to avoid nasty things like going to another buffer when
1613 // evaluating an expression.
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001614 ++textwinlock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 p = get_expr_line();
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001616 --textwinlock;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001617
Bram Moolenaarfc3c83e2010-10-27 12:58:23 +02001618 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 {
Bram Moolenaarfc3c83e2010-10-27 12:58:23 +02001620 len = (int)STRLEN(p);
1621 if (realloc_cmdbuff(len + 1) == OK)
1622 {
1623 ccline.cmdlen = len;
1624 STRCPY(ccline.cmdbuff, p);
1625 vim_free(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001627 // Restore the cursor or use the position set with
1628 // set_cmdline_pos().
Bram Moolenaarfc3c83e2010-10-27 12:58:23 +02001629 if (new_cmdpos > ccline.cmdlen)
1630 ccline.cmdpos = ccline.cmdlen;
1631 else
1632 ccline.cmdpos = new_cmdpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001634 KeyTyped = FALSE; // Don't do p_wc completion.
Bram Moolenaarfc3c83e2010-10-27 12:58:23 +02001635 redrawcmd();
1636 goto cmdline_changed;
1637 }
Bram Moolenaar4e303c82018-11-24 14:27:44 +01001638 vim_free(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639 }
1640 }
1641 beep_flush();
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001642 got_int = FALSE; // don't abandon the command line
Bram Moolenaar66b4bf82010-11-16 14:06:08 +01001643 did_emsg = FALSE;
1644 emsg_on_display = FALSE;
1645 redrawcmd();
1646 goto cmdline_not_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001647 }
1648#endif
1649 else
1650 {
1651 if (c == Ctrl_G && p_im && restart_edit == 0)
1652 restart_edit = 'a';
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001653 gotesc = TRUE; // will free ccline.cmdbuff after putting it
1654 // in history
1655 goto returncmd; // back to Normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656 }
1657 }
1658
1659#ifdef FEAT_CMDWIN
1660 if (c == cedit_key || c == K_CMDWIN)
1661 {
Bram Moolenaar85db5472019-12-04 15:11:08 +01001662 // TODO: why is ex_normal_busy checked here?
1663 if ((c == K_CMDWIN || ex_normal_busy == 0) && got_int == FALSE)
Bram Moolenaar58da7072014-09-09 18:45:49 +02001664 {
1665 /*
1666 * Open a window to edit the command line (and history).
1667 */
Bram Moolenaar3bab9392017-04-07 15:42:25 +02001668 c = open_cmdwin();
Bram Moolenaar58da7072014-09-09 18:45:49 +02001669 some_key_typed = TRUE;
1670 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671 }
1672# ifdef FEAT_DIGRAPHS
1673 else
1674# endif
1675#endif
1676#ifdef FEAT_DIGRAPHS
1677 c = do_digraph(c);
1678#endif
1679
1680 if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC
1681 && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL)))
1682 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001683 // In Ex mode a backslash escapes a newline.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001684 if (exmode_active
1685 && c != ESC
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001686 && ccline.cmdpos == ccline.cmdlen
Bram Moolenaar5f2c5db2007-07-17 16:15:36 +00001687 && ccline.cmdpos > 0
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001688 && ccline.cmdbuff[ccline.cmdpos - 1] == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001690 if (c == K_KENTER)
1691 c = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001693 else
1694 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001695 gotesc = FALSE; // Might have typed ESC previously, don't
1696 // truncate the cmdline now.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001697 if (ccheck_abbr(c + ABBR_OFF))
1698 goto cmdline_changed;
1699 if (!cmd_silent)
1700 {
1701 windgoto(msg_row, 0);
1702 out_flush();
1703 }
1704 break;
1705 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001706 }
1707
1708 /*
1709 * Completion for 'wildchar' or 'wildcharm' key.
1710 * - hitting <ESC> twice means: abandon command line.
1711 * - wildcard expansion is only done when the 'wildchar' key is really
1712 * typed, not when it comes from a macro
1713 */
1714 if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
1715 {
Bram Moolenaar52410572019-10-27 05:12:45 +01001716 int options = WILD_NO_BEEP;
Bram Moolenaara60053b2020-09-03 16:50:13 +02001717
Bram Moolenaar52410572019-10-27 05:12:45 +01001718 if (wim_flags[wim_index] & WIM_BUFLASTUSED)
1719 options |= WILD_BUFLASTUSED;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001720 if (xpc.xp_numfiles > 0) // typed p_wc at least twice
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001722 // if 'wildmode' contains "list" may still need to list
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723 if (xpc.xp_numfiles > 1
1724 && !did_wild_list
1725 && (wim_flags[wim_index] & WIM_LIST))
1726 {
1727 (void)showmatches(&xpc, FALSE);
1728 redrawcmd();
1729 did_wild_list = TRUE;
1730 }
1731 if (wim_flags[wim_index] & WIM_LONGEST)
Bram Moolenaar52410572019-10-27 05:12:45 +01001732 res = nextwild(&xpc, WILD_LONGEST, options,
Bram Moolenaarb3479632012-11-28 16:49:58 +01001733 firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 else if (wim_flags[wim_index] & WIM_FULL)
Bram Moolenaara60053b2020-09-03 16:50:13 +02001735 res = nextwild(&xpc, WILD_NEXT, options, firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001737 res = OK; // don't insert 'wildchar' now
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001739 else // typed p_wc first time
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 {
1741 wim_index = 0;
1742 j = ccline.cmdpos;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001743 // if 'wildmode' first contains "longest", get longest
1744 // common part
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 if (wim_flags[0] & WIM_LONGEST)
Bram Moolenaara60053b2020-09-03 16:50:13 +02001746 res = nextwild(&xpc, WILD_LONGEST, options, firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747 else
Bram Moolenaar52410572019-10-27 05:12:45 +01001748 res = nextwild(&xpc, WILD_EXPAND_KEEP, options,
Bram Moolenaara60053b2020-09-03 16:50:13 +02001749 firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001751 // if interrupted while completing, behave like it failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 if (got_int)
1753 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001754 (void)vpeekc(); // remove <C-C> from input stream
1755 got_int = FALSE; // don't abandon the command line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
1757#ifdef FEAT_WILDMENU
1758 xpc.xp_context = EXPAND_NOTHING;
1759#endif
1760 goto cmdline_changed;
1761 }
1762
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001763 // when more than one match, and 'wildmode' first contains
1764 // "list", or no change and 'wildmode' contains "longest,list",
1765 // list all matches
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766 if (res == OK && xpc.xp_numfiles > 1)
1767 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001768 // a "longest" that didn't do anything is skipped (but not
1769 // "list:longest")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
1771 wim_index = 1;
1772 if ((wim_flags[wim_index] & WIM_LIST)
1773#ifdef FEAT_WILDMENU
Bram Moolenaara60053b2020-09-03 16:50:13 +02001774 || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775#endif
1776 )
1777 {
1778 if (!(wim_flags[0] & WIM_LONGEST))
1779 {
1780#ifdef FEAT_WILDMENU
1781 int p_wmnu_save = p_wmnu;
1782 p_wmnu = 0;
1783#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001784 // remove match
Bram Moolenaarb3479632012-11-28 16:49:58 +01001785 nextwild(&xpc, WILD_PREV, 0, firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786#ifdef FEAT_WILDMENU
1787 p_wmnu = p_wmnu_save;
1788#endif
1789 }
1790#ifdef FEAT_WILDMENU
1791 (void)showmatches(&xpc, p_wmnu
1792 && ((wim_flags[wim_index] & WIM_LIST) == 0));
1793#else
1794 (void)showmatches(&xpc, FALSE);
1795#endif
1796 redrawcmd();
1797 did_wild_list = TRUE;
1798 if (wim_flags[wim_index] & WIM_LONGEST)
Bram Moolenaar52410572019-10-27 05:12:45 +01001799 nextwild(&xpc, WILD_LONGEST, options,
Bram Moolenaarb3479632012-11-28 16:49:58 +01001800 firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 else if (wim_flags[wim_index] & WIM_FULL)
Bram Moolenaara60053b2020-09-03 16:50:13 +02001802 nextwild(&xpc, WILD_NEXT, options, firstc != '@');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 }
1804 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02001805 vim_beep(BO_WILD);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 }
1807#ifdef FEAT_WILDMENU
1808 else if (xpc.xp_numfiles == -1)
1809 xpc.xp_context = EXPAND_NOTHING;
1810#endif
1811 }
1812 if (wim_index < 3)
1813 ++wim_index;
1814 if (c == ESC)
1815 gotesc = TRUE;
1816 if (res == OK)
1817 goto cmdline_changed;
1818 }
1819
1820 gotesc = FALSE;
1821
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001822 // <S-Tab> goes to last match, in a clumsy way
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 if (c == K_S_TAB && KeyTyped)
1824 {
Bram Moolenaarb3479632012-11-28 16:49:58 +01001825 if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK
1826 && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK
1827 && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 goto cmdline_changed;
1829 }
1830
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001831 if (c == NUL || c == K_ZERO) // NUL is stored as NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 c = NL;
1833
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001834 do_abbr = TRUE; // default: check for abbreviation
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
1836 /*
1837 * Big switch for a typed command line character.
1838 */
1839 switch (c)
1840 {
1841 case K_BS:
1842 case Ctrl_H:
1843 case K_DEL:
1844 case K_KDEL:
1845 case Ctrl_W:
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02001846 res = cmdline_erase_chars(c, indent
Bram Moolenaar4d6f32c2016-08-26 19:13:46 +02001847#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02001848 , &is_state
Bram Moolenaar4d6f32c2016-08-26 19:13:46 +02001849#endif
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02001850 );
1851 if (res == CMDLINE_NOT_CHANGED)
1852 goto cmdline_not_changed;
1853 else if (res == GOTO_NORMAL_MODE)
1854 goto returncmd; // back to cmd mode
1855 goto cmdline_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856
1857 case K_INS:
1858 case K_KINS:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 ccline.overstrike = !ccline.overstrike;
1860#ifdef CURSOR_SHAPE
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001861 ui_cursor_shape(); // may show different cursor shape
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862#endif
1863 goto cmdline_not_changed;
1864
1865 case Ctrl_HAT:
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02001866 cmdline_toggle_langmap(b_im_ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001867 goto cmdline_not_changed;
1868
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001869// case '@': only in very old vi
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 case Ctrl_U:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001871 // delete all characters left of the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 j = ccline.cmdpos;
1873 ccline.cmdlen -= j;
1874 i = ccline.cmdpos = 0;
1875 while (i < ccline.cmdlen)
1876 ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001877 // Truncate at the end, required for multi-byte chars.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 ccline.cmdbuff[ccline.cmdlen] = NUL;
Bram Moolenaar4d6f32c2016-08-26 19:13:46 +02001879#ifdef FEAT_SEARCH_EXTRA
1880 if (ccline.cmdlen == 0)
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02001881 is_state.search_start = is_state.save_cursor;
Bram Moolenaar4d6f32c2016-08-26 19:13:46 +02001882#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 redrawcmd();
1884 goto cmdline_changed;
1885
1886#ifdef FEAT_CLIPBOARD
1887 case Ctrl_Y:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001888 // Copy the modeless selection, if there is one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 if (clip_star.state != SELECT_CLEARED)
1890 {
1891 if (clip_star.state == SELECT_DONE)
1892 clip_copy_modeless_selection(TRUE);
1893 goto cmdline_not_changed;
1894 }
1895 break;
1896#endif
1897
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001898 case ESC: // get here if p_wc != ESC or when ESC typed twice
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 case Ctrl_C:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001900 // In exmode it doesn't make sense to return. Except when
1901 // ":normal" runs out of characters.
Bram Moolenaar7c626922005-02-07 22:01:03 +00001902 if (exmode_active
Bram Moolenaare2c38102016-01-31 14:55:40 +01001903 && (ex_normal_busy == 0 || typebuf.tb_len > 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 goto cmdline_not_changed;
1905
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001906 gotesc = TRUE; // will free ccline.cmdbuff after
1907 // putting it in history
1908 goto returncmd; // back to cmd mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001910 case Ctrl_R: // insert register
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02001911 res = cmdline_insert_reg(&gotesc);
1912 if (res == CMDLINE_NOT_CHANGED)
1913 goto cmdline_not_changed;
1914 else if (res == GOTO_NORMAL_MODE)
1915 goto returncmd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 goto cmdline_changed;
1917
1918 case Ctrl_D:
1919 if (showmatches(&xpc, FALSE) == EXPAND_NOTHING)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001920 break; // Use ^D as normal char instead
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921
1922 redrawcmd();
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001923 continue; // don't do incremental search now
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924
1925 case K_RIGHT:
1926 case K_S_RIGHT:
1927 case K_C_RIGHT:
1928 do
1929 {
1930 if (ccline.cmdpos >= ccline.cmdlen)
1931 break;
1932 i = cmdline_charsize(ccline.cmdpos);
1933 if (KeyTyped && ccline.cmdspos + i >= Columns * Rows)
1934 break;
1935 ccline.cmdspos += i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001937 ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 + ccline.cmdpos);
1939 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 ++ccline.cmdpos;
1941 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001942 while ((c == K_S_RIGHT || c == K_C_RIGHT
1943 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 && ccline.cmdbuff[ccline.cmdpos] != ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 if (has_mbyte)
1946 set_cmdspos_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 goto cmdline_not_changed;
1948
1949 case K_LEFT:
1950 case K_S_LEFT:
1951 case K_C_LEFT:
Bram Moolenaar49feabd2007-12-07 19:28:58 +00001952 if (ccline.cmdpos == 0)
1953 goto cmdline_not_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954 do
1955 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 --ccline.cmdpos;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001957 if (has_mbyte) // move to first byte of char
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff,
1959 ccline.cmdbuff + ccline.cmdpos);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 ccline.cmdspos -= cmdline_charsize(ccline.cmdpos);
1961 }
Bram Moolenaar49feabd2007-12-07 19:28:58 +00001962 while (ccline.cmdpos > 0
1963 && (c == K_S_LEFT || c == K_C_LEFT
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001964 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 && ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 if (has_mbyte)
1967 set_cmdspos_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968 goto cmdline_not_changed;
1969
1970 case K_IGNORE:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001971 // Ignore mouse event or open_cmdwin() result.
Bram Moolenaar30405d32008-01-02 20:55:27 +00001972 goto cmdline_not_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973
Bram Moolenaar4f974752019-02-17 17:44:42 +01001974#ifdef FEAT_GUI_MSWIN
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001975 // On MS-Windows ignore <M-F4>, we get it when closing the window
1976 // was cancelled.
Bram Moolenaar4770d092006-01-12 23:22:24 +00001977 case K_F4:
1978 if (mod_mask == MOD_MASK_ALT)
1979 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001980 redrawcmd(); // somehow the cmdline is cleared
Bram Moolenaar4770d092006-01-12 23:22:24 +00001981 goto cmdline_not_changed;
1982 }
1983 break;
1984#endif
1985
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 case K_MIDDLEDRAG:
1987 case K_MIDDLERELEASE:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001988 goto cmdline_not_changed; // Ignore mouse
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989
1990 case K_MIDDLEMOUSE:
1991# ifdef FEAT_GUI
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001992 // When GUI is active, also paste when 'mouse' is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 if (!gui.in_use)
1994# endif
1995 if (!mouse_has(MOUSE_COMMAND))
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001996 goto cmdline_not_changed; // Ignore mouse
Bram Moolenaara23ccb82006-02-27 00:08:02 +00001997# ifdef FEAT_CLIPBOARD
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998 if (clip_star.available)
Bram Moolenaar1769d5a2006-10-17 14:25:24 +00001999 cmdline_paste('*', TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 else
Bram Moolenaara23ccb82006-02-27 00:08:02 +00002001# endif
Bram Moolenaar1769d5a2006-10-17 14:25:24 +00002002 cmdline_paste(0, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003 redrawcmd();
2004 goto cmdline_changed;
2005
Bram Moolenaara23ccb82006-02-27 00:08:02 +00002006# ifdef FEAT_DND
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 case K_DROP:
Bram Moolenaar1769d5a2006-10-17 14:25:24 +00002008 cmdline_paste('~', TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009 redrawcmd();
2010 goto cmdline_changed;
Bram Moolenaara23ccb82006-02-27 00:08:02 +00002011# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012
2013 case K_LEFTDRAG:
2014 case K_LEFTRELEASE:
2015 case K_RIGHTDRAG:
2016 case K_RIGHTRELEASE:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002017 // Ignore drag and release events when the button-down wasn't
2018 // seen before.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019 if (ignore_drag_release)
2020 goto cmdline_not_changed;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002021 // FALLTHROUGH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022 case K_LEFTMOUSE:
2023 case K_RIGHTMOUSE:
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02002024 cmdline_left_right_mouse(c, &ignore_drag_release);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025 goto cmdline_not_changed;
2026
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002027 // Mouse scroll wheel: ignored here
Bram Moolenaar071d4272004-06-13 20:20:40 +00002028 case K_MOUSEDOWN:
2029 case K_MOUSEUP:
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02002030 case K_MOUSELEFT:
2031 case K_MOUSERIGHT:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002032 // Alternate buttons ignored here
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033 case K_X1MOUSE:
2034 case K_X1DRAG:
2035 case K_X1RELEASE:
2036 case K_X2MOUSE:
2037 case K_X2DRAG:
2038 case K_X2RELEASE:
Bram Moolenaar51b0f372017-11-18 18:52:04 +01002039 case K_MOUSEMOVE:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040 goto cmdline_not_changed;
2041
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042#ifdef FEAT_GUI
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002043 case K_LEFTMOUSE_NM: // mousefocus click, ignored
Bram Moolenaar071d4272004-06-13 20:20:40 +00002044 case K_LEFTRELEASE_NM:
2045 goto cmdline_not_changed;
2046
2047 case K_VER_SCROLLBAR:
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002048 if (msg_scrolled == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 {
2050 gui_do_scroll();
2051 redrawcmd();
2052 }
2053 goto cmdline_not_changed;
2054
2055 case K_HOR_SCROLLBAR:
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00002056 if (msg_scrolled == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 {
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02002058 gui_do_horiz_scroll(scrollbar_value, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059 redrawcmd();
2060 }
2061 goto cmdline_not_changed;
2062#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +00002063#ifdef FEAT_GUI_TABLINE
2064 case K_TABLINE:
2065 case K_TABMENU:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002066 // Don't want to change any tabs here. Make sure the same tab
2067 // is still selected.
Bram Moolenaara23ccb82006-02-27 00:08:02 +00002068 if (gui_use_tabline())
2069 gui_mch_set_curtab(tabpage_index(curtab));
2070 goto cmdline_not_changed;
2071#endif
2072
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002073 case K_SELECT: // end of Select mode mapping - ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 goto cmdline_not_changed;
2075
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002076 case Ctrl_B: // begin of command line
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077 case K_HOME:
2078 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079 case K_S_HOME:
2080 case K_C_HOME:
2081 ccline.cmdpos = 0;
2082 set_cmdspos();
2083 goto cmdline_not_changed;
2084
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002085 case Ctrl_E: // end of command line
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086 case K_END:
2087 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 case K_S_END:
2089 case K_C_END:
2090 ccline.cmdpos = ccline.cmdlen;
2091 set_cmdspos_cursor();
2092 goto cmdline_not_changed;
2093
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002094 case Ctrl_A: // all matches
Bram Moolenaarb3479632012-11-28 16:49:58 +01002095 if (nextwild(&xpc, WILD_ALL, 0, firstc != '@') == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 break;
2097 goto cmdline_changed;
2098
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00002099 case Ctrl_L:
2100#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02002101 if (may_add_char_to_search(firstc, &c, &is_state) == OK)
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00002102 goto cmdline_not_changed;
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00002103#endif
2104
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002105 // completion: longest common part
Bram Moolenaarb3479632012-11-28 16:49:58 +01002106 if (nextwild(&xpc, WILD_LONGEST, 0, firstc != '@') == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 break;
2108 goto cmdline_changed;
2109
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002110 case Ctrl_N: // next match
2111 case Ctrl_P: // previous match
Bram Moolenaar7df0f632016-08-26 19:56:00 +02002112 if (xpc.xp_numfiles > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113 {
Bram Moolenaarb3479632012-11-28 16:49:58 +01002114 if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT,
2115 0, firstc != '@') == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 break;
Bram Moolenaar11956692016-08-27 16:26:56 +02002117 goto cmdline_not_changed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002119 // FALLTHROUGH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120 case K_UP:
2121 case K_DOWN:
2122 case K_S_UP:
2123 case K_S_DOWN:
2124 case K_PAGEUP:
2125 case K_KPAGEUP:
2126 case K_PAGEDOWN:
2127 case K_KPAGEDOWN:
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02002128 res = cmdline_browse_history(c, firstc, &lookfor, histype,
2129 &hiscnt, &xpc);
2130 if (res == CMDLINE_CHANGED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 goto cmdline_changed;
Bram Moolenaar2f3cd2e2020-09-06 15:54:00 +02002132 else if (res == GOTO_NORMAL_MODE)
2133 goto returncmd;
Bram Moolenaar11956692016-08-27 16:26:56 +02002134 goto cmdline_not_changed;
2135
Bram Moolenaar349e7d92016-09-03 20:04:34 +02002136#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002137 case Ctrl_G: // next match
2138 case Ctrl_T: // previous match
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02002139 if (may_adjust_incsearch_highlighting(
2140 firstc, count, &is_state, c) == FAIL)
Bram Moolenaar349e7d92016-09-03 20:04:34 +02002141 goto cmdline_not_changed;
Bram Moolenaar349e7d92016-09-03 20:04:34 +02002142 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143#endif
2144
2145 case Ctrl_V:
2146 case Ctrl_Q:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 {
Bram Moolenaarfc4ea2a2019-11-26 19:33:22 +01002148 int prev_mod_mask = mod_mask;
2149
2150 ignore_drag_release = TRUE;
2151 putcmdline('^', TRUE);
Bram Moolenaar673fc3e2020-06-07 15:46:11 +02002152 no_reduce_keys = TRUE; // don't merge modifyOtherKeys
Bram Moolenaarfc4ea2a2019-11-26 19:33:22 +01002153 c = get_literal(); // get next (two) character(s)
Bram Moolenaar673fc3e2020-06-07 15:46:11 +02002154 no_reduce_keys = FALSE;
Bram Moolenaarfc4ea2a2019-11-26 19:33:22 +01002155 do_abbr = FALSE; // don't do abbreviation now
2156 extra_char = NUL;
2157 // may need to remove ^ when composing char was typed
2158 if (enc_utf8 && utf_iscomposing(c) && !cmd_silent)
2159 {
2160 draw_cmdline(ccline.cmdpos,
2161 ccline.cmdlen - ccline.cmdpos);
2162 msg_putchar(' ');
2163 cursorcmd();
2164 }
2165
2166 if ((c == ESC || c == CSI)
2167 && !(prev_mod_mask & MOD_MASK_SHIFT))
2168 // Using CTRL-V: Change any modifyOtherKeys ESC
2169 // sequence to a normal key. Don't do this for
2170 // CTRL-SHIFT-V.
2171 c = decodeModifyOtherKeys(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 }
Bram Moolenaarfc4ea2a2019-11-26 19:33:22 +01002173
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174 break;
2175
2176#ifdef FEAT_DIGRAPHS
2177 case Ctrl_K:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 ignore_drag_release = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179 putcmdline('?', TRUE);
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02002180# ifdef USE_ON_FLY_SCROLL
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002181 dont_scroll = TRUE; // disallow scrolling here
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02002182# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 c = get_digraph(TRUE);
Bram Moolenaara92522f2017-07-15 15:21:38 +02002184 extra_char = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 if (c != NUL)
2186 break;
2187
2188 redrawcmd();
2189 goto cmdline_not_changed;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02002190#endif // FEAT_DIGRAPHS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191
2192#ifdef FEAT_RIGHTLEFT
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002193 case Ctrl__: // CTRL-_: switch language mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00002194 if (!p_ari)
2195 break;
Bram Moolenaar14184a32019-02-16 15:10:30 +01002196 cmd_hkmap = !cmd_hkmap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 goto cmdline_not_changed;
2198#endif
2199
Bram Moolenaarabbc4482017-01-24 15:57:55 +01002200 case K_PS:
2201 bracketed_paste(PASTE_CMDLINE, FALSE, NULL);
2202 goto cmdline_changed;
2203
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204 default:
2205#ifdef UNIX
2206 if (c == intr_char)
2207 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002208 gotesc = TRUE; // will free ccline.cmdbuff after
2209 // putting it in history
2210 goto returncmd; // back to Normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 }
2212#endif
2213 /*
2214 * Normal character with no special meaning. Just set mod_mask
2215 * to 0x0 so that typing Shift-Space in the GUI doesn't enter
2216 * the string <S-Space>. This should only happen after ^V.
2217 */
2218 if (!IS_SPECIAL(c))
2219 mod_mask = 0x0;
2220 break;
2221 }
2222 /*
2223 * End of switch on command line character.
2224 * We come here if we have a normal character.
2225 */
2226
Bram Moolenaar13505972019-01-24 15:04:48 +01002227 if (do_abbr && (IS_SPECIAL(c) || !vim_iswordc(c))
2228 && (ccheck_abbr(
2229 // Add ABBR_OFF for characters above 0x100, this is
2230 // what check_abbr() expects.
2231 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c)
2232 || c == Ctrl_RSB))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233 goto cmdline_changed;
2234
2235 /*
2236 * put the character in the command line
2237 */
2238 if (IS_SPECIAL(c) || mod_mask != 0)
2239 put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
2240 else
2241 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 if (has_mbyte)
2243 {
2244 j = (*mb_char2bytes)(c, IObuff);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002245 IObuff[j] = NUL; // exclude composing chars
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 put_on_cmdline(IObuff, j, TRUE);
2247 }
2248 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 {
2250 IObuff[0] = c;
2251 put_on_cmdline(IObuff, 1, TRUE);
2252 }
2253 }
2254 goto cmdline_changed;
2255
2256/*
2257 * This part implements incremental searches for "/" and "?"
2258 * Jump to cmdline_not_changed when a character has been read but the command
2259 * line did not change. Then we only search and redraw if something changed in
2260 * the past.
2261 * Jump to cmdline_changed when the command line did change.
2262 * (Sorry for the goto's, I know it is ugly).
2263 */
2264cmdline_not_changed:
2265#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar0ee81cb2018-08-10 22:07:32 +02002266 if (!is_state.incsearch_postponed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 continue;
2268#endif
2269
2270cmdline_changed:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002271 // Trigger CmdlineChanged autocommands.
Bram Moolenaar153b7042018-01-31 15:48:32 +01002272 trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED);
Bram Moolenaar153b7042018-01-31 15:48:32 +01002273
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaara60053b2020-09-03 16:50:13 +02002275 if (xpc.xp_context == EXPAND_NOTHING)
2276 may_do_incsearch_highlighting(firstc, count, &is_state);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277#endif
2278
2279#ifdef FEAT_RIGHTLEFT
2280 if (cmdmsg_rl
2281# ifdef FEAT_ARABIC
Bram Moolenaar693f7dc2019-06-21 02:30:38 +02002282 || (p_arshape && !p_tbidi
2283 && cmdline_has_arabic(0, ccline.cmdlen))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284# endif
2285 )
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002286 // Always redraw the whole command line to fix shaping and
2287 // right-left typing. Not efficient, but it works.
2288 // Do it only when there are no characters left to read
2289 // to avoid useless intermediate redraws.
Bram Moolenaar58437e02012-02-22 17:58:04 +01002290 if (vpeekc() == NUL)
2291 redrawcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292#endif
2293 }
2294
2295returncmd:
2296
2297#ifdef FEAT_RIGHTLEFT
2298 cmdmsg_rl = FALSE;
2299#endif
2300
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 ExpandCleanup(&xpc);
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00002302 ccline.xpc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303
2304#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaarc7f08b72018-08-12 17:39:14 +02002305 finish_incsearch_highlighting(gotesc, &is_state, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306#endif
2307
2308 if (ccline.cmdbuff != NULL)
2309 {
2310 /*
2311 * Put line in history buffer (":" and "=" only when it was typed).
2312 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 if (ccline.cmdlen && firstc != NUL
2314 && (some_key_typed || histype == HIST_SEARCH))
2315 {
2316 add_to_history(histype, ccline.cmdbuff, TRUE,
2317 histype == HIST_SEARCH ? firstc : NUL);
2318 if (firstc == ':')
2319 {
2320 vim_free(new_last_cmdline);
2321 new_last_cmdline = vim_strsave(ccline.cmdbuff);
2322 }
2323 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324
Bram Moolenaarf8e8c062017-10-22 14:44:17 +02002325 if (gotesc)
2326 abandon_cmdline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 }
2328
2329 /*
2330 * If the screen was shifted up, redraw the whole screen (later).
2331 * If the line is too long, clear it, so ruler and shown command do
2332 * not get printed in the middle of it.
2333 */
2334 msg_check();
2335 msg_scroll = save_msg_scroll;
2336 redir_off = FALSE;
2337
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002338 // When the command line was typed, no need for a wait-return prompt.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 if (some_key_typed)
2340 need_wait_return = FALSE;
2341
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002342 // Trigger CmdlineLeave autocommands.
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02002343 trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINELEAVE);
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02002344
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 State = save_State;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002346#ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347 if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP)
2348 im_save_status(b_im_ptr);
2349 im_set_active(FALSE);
2350#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 setmouse();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352#ifdef CURSOR_SHAPE
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002353 ui_cursor_shape(); // may show different cursor shape
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354#endif
Bram Moolenaarf2405ed2017-03-16 19:58:25 +01002355 sb_text_end_cmdline();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356
Bram Moolenaar438d1762018-09-30 17:11:48 +02002357theend:
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00002358 {
2359 char_u *p = ccline.cmdbuff;
2360
Bram Moolenaar438d1762018-09-30 17:11:48 +02002361 if (did_save_ccline)
2362 restore_cmdline(&save_ccline);
2363 else
2364 ccline.cmdbuff = NULL;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00002365 return p;
2366 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367}
2368
2369#if (defined(FEAT_CRYPT) || defined(FEAT_EVAL)) || defined(PROTO)
2370/*
2371 * Get a command line with a prompt.
2372 * This is prepared to be called recursively from getcmdline() (e.g. by
2373 * f_input() when evaluating an expression from CTRL-R =).
2374 * Returns the command line in allocated memory, or NULL.
2375 */
2376 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002377getcmdline_prompt(
2378 int firstc,
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002379 char_u *prompt, // command line prompt
2380 int attr, // attributes for prompt
2381 int xp_context, // type of expansion
2382 char_u *xp_arg) // user-defined expansion argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383{
2384 char_u *s;
Bram Moolenaar66b51422019-08-18 21:44:12 +02002385 cmdline_info_T save_ccline;
Bram Moolenaar438d1762018-09-30 17:11:48 +02002386 int did_save_ccline = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 int msg_col_save = msg_col;
Bram Moolenaar6135d0d2016-03-22 20:31:13 +01002388 int msg_silent_save = msg_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389
Bram Moolenaar438d1762018-09-30 17:11:48 +02002390 if (ccline.cmdbuff != NULL)
2391 {
2392 // Save the values of the current cmdline and restore them below.
2393 save_cmdline(&save_ccline);
2394 did_save_ccline = TRUE;
2395 }
2396
Bram Moolenaara80faa82020-04-12 19:37:17 +02002397 CLEAR_FIELD(ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 ccline.cmdprompt = prompt;
2399 ccline.cmdattr = attr;
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00002400# ifdef FEAT_EVAL
2401 ccline.xp_context = xp_context;
2402 ccline.xp_arg = xp_arg;
2403 ccline.input_fn = (firstc == '@');
2404# endif
Bram Moolenaar6135d0d2016-03-22 20:31:13 +01002405 msg_silent = 0;
Bram Moolenaar438d1762018-09-30 17:11:48 +02002406 s = getcmdline_int(firstc, 1L, 0, FALSE);
2407
2408 if (did_save_ccline)
2409 restore_cmdline(&save_ccline);
2410
Bram Moolenaar6135d0d2016-03-22 20:31:13 +01002411 msg_silent = msg_silent_save;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002412 // Restore msg_col, the prompt from input() may have changed it.
2413 // But only if called recursively and the commandline is therefore being
2414 // restored to an old one; if not, the input() prompt stays on the screen,
2415 // so we need its modified msg_col left intact.
Bram Moolenaar1db1f772011-08-17 16:25:48 +02002416 if (ccline.cmdbuff != NULL)
2417 msg_col = msg_col_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418
2419 return s;
2420}
2421#endif
2422
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002423/*
Bram Moolenaar7bae0b12019-11-21 22:14:18 +01002424 * Read the 'wildmode' option, fill wim_flags[].
2425 */
2426 int
2427check_opt_wim(void)
2428{
2429 char_u new_wim_flags[4];
2430 char_u *p;
2431 int i;
2432 int idx = 0;
2433
2434 for (i = 0; i < 4; ++i)
2435 new_wim_flags[i] = 0;
2436
2437 for (p = p_wim; *p; ++p)
2438 {
2439 for (i = 0; ASCII_ISALPHA(p[i]); ++i)
2440 ;
2441 if (p[i] != NUL && p[i] != ',' && p[i] != ':')
2442 return FAIL;
2443 if (i == 7 && STRNCMP(p, "longest", 7) == 0)
2444 new_wim_flags[idx] |= WIM_LONGEST;
2445 else if (i == 4 && STRNCMP(p, "full", 4) == 0)
2446 new_wim_flags[idx] |= WIM_FULL;
2447 else if (i == 4 && STRNCMP(p, "list", 4) == 0)
2448 new_wim_flags[idx] |= WIM_LIST;
2449 else if (i == 8 && STRNCMP(p, "lastused", 8) == 0)
2450 new_wim_flags[idx] |= WIM_BUFLASTUSED;
2451 else
2452 return FAIL;
2453 p += i;
2454 if (*p == NUL)
2455 break;
2456 if (*p == ',')
2457 {
2458 if (idx == 3)
2459 return FAIL;
2460 ++idx;
2461 }
2462 }
2463
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002464 // fill remaining entries with last flag
Bram Moolenaar7bae0b12019-11-21 22:14:18 +01002465 while (idx < 3)
2466 {
2467 new_wim_flags[idx + 1] = new_wim_flags[idx];
2468 ++idx;
2469 }
2470
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002471 // only when there are no errors, wim_flags[] is changed
Bram Moolenaar7bae0b12019-11-21 22:14:18 +01002472 for (i = 0; i < 4; ++i)
2473 wim_flags[i] = new_wim_flags[i];
2474 return OK;
2475}
2476
2477/*
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002478 * Return TRUE when the text must not be changed and we can't switch to
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002479 * another window or buffer. TRUE when editing the command line, evaluating
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002480 * 'balloonexpr', etc.
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002481 */
2482 int
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002483text_and_win_locked(void)
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002484{
2485#ifdef FEAT_CMDWIN
2486 if (cmdwin_type != 0)
2487 return TRUE;
2488#endif
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002489 return textwinlock != 0;
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002490}
2491
2492/*
2493 * Give an error message for a command that isn't allowed while the cmdline
2494 * window is open or editing the cmdline in another way.
2495 */
2496 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002497text_locked_msg(void)
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002498{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002499 emsg(_(get_text_locked_msg()));
Bram Moolenaar5a497892016-09-03 16:29:04 +02002500}
2501
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002502 char *
Bram Moolenaar5a497892016-09-03 16:29:04 +02002503get_text_locked_msg(void)
2504{
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002505#ifdef FEAT_CMDWIN
2506 if (cmdwin_type != 0)
Bram Moolenaar5a497892016-09-03 16:29:04 +02002507 return e_cmdwin;
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002508#endif
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002509 if (textwinlock != 0)
2510 return e_textwinlock;
Bram Moolenaarff06f282020-04-21 22:01:14 +02002511 return e_textlock;
Bram Moolenaar8ada17c2006-01-19 22:16:24 +00002512}
2513
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002514/*
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002515 * Return TRUE when the text must not be changed and/or we cannot switch to
2516 * another window. TRUE while evaluating 'completefunc'.
2517 */
2518 int
2519text_locked(void)
2520{
2521 return text_and_win_locked() || textlock != 0;
2522}
2523
2524/*
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00002525 * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
2526 * and give an error message.
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002527 */
2528 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002529curbuf_locked(void)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002530{
2531 if (curbuf_lock > 0)
2532 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002533 emsg(_("E788: Not allowed to edit another buffer now"));
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002534 return TRUE;
2535 }
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00002536 return allbuf_locked();
2537}
2538
2539/*
2540 * Check if "allbuf_lock" is set and return TRUE when it is and give an error
2541 * message.
2542 */
2543 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002544allbuf_locked(void)
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00002545{
2546 if (allbuf_lock > 0)
2547 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002548 emsg(_("E811: Not allowed to change buffer information now"));
Bram Moolenaarbf1b7a72009-03-05 02:15:53 +00002549 return TRUE;
2550 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002551 return FALSE;
2552}
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002553
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002555cmdline_charsize(int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556{
2557#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002558 if (cmdline_star > 0) // showing '*', always 1 position
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 return 1;
2560#endif
2561 return ptr2cells(ccline.cmdbuff + idx);
2562}
2563
2564/*
2565 * Compute the offset of the cursor on the command line for the prompt and
2566 * indent.
2567 */
2568 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002569set_cmdspos(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570{
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00002571 if (ccline.cmdfirstc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 ccline.cmdspos = 1 + ccline.cmdindent;
2573 else
2574 ccline.cmdspos = 0 + ccline.cmdindent;
2575}
2576
2577/*
2578 * Compute the screen position for the cursor on the command line.
2579 */
2580 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002581set_cmdspos_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582{
2583 int i, m, c;
2584
2585 set_cmdspos();
2586 if (KeyTyped)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002587 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 m = Columns * Rows;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002589 if (m < 0) // overflow, Columns or Rows at weird value
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00002590 m = MAXCOL;
2591 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 else
2593 m = MAXCOL;
2594 for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i)
2595 {
2596 c = cmdline_charsize(i);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002597 // Count ">" for double-wide multi-byte char that doesn't fit.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 if (has_mbyte)
2599 correct_cmdspos(i, c);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002600 // If the cmdline doesn't fit, show cursor on last visible char.
2601 // Don't move the cursor itself, so we can still append.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 if ((ccline.cmdspos += c) >= m)
2603 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604 ccline.cmdspos -= c;
2605 break;
2606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002608 i += (*mb_ptr2len)(ccline.cmdbuff + i) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609 }
2610}
2611
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612/*
2613 * Check if the character at "idx", which is "cells" wide, is a multi-byte
2614 * character that doesn't fit, so that a ">" must be displayed.
2615 */
2616 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002617correct_cmdspos(int idx, int cells)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618{
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002619 if ((*mb_ptr2len)(ccline.cmdbuff + idx) > 1
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 && (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1
2621 && ccline.cmdspos % Columns + cells > Columns)
2622 ccline.cmdspos++;
2623}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624
2625/*
2626 * Get an Ex command line for the ":" command.
2627 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002629getexline(
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002630 int c, // normally ':', NUL for ":append"
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002631 void *cookie UNUSED,
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002632 int indent, // indent for inside conditionals
Bram Moolenaar66250c92020-08-20 15:02:42 +02002633 getline_opt_T options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634{
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002635 // When executing a register, remove ':' that's in front of each line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 if (exec_from_reg && vpeekc() == ':')
2637 (void)vgetc();
Bram Moolenaar66250c92020-08-20 15:02:42 +02002638 return getcmdline(c, 1L, indent, options);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639}
2640
2641/*
2642 * Get an Ex command line for Ex mode.
2643 * In Ex mode we only use the OS supplied line editing features and no
2644 * mappings or abbreviations.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002645 * Returns a string in allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002648getexmodeline(
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002649 int promptc, // normally ':', NUL for ":append" and '?' for
2650 // :s prompt
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002651 void *cookie UNUSED,
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002652 int indent, // indent for inside conditionals
Bram Moolenaar66250c92020-08-20 15:02:42 +02002653 getline_opt_T options UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002655 garray_T line_ga;
2656 char_u *pend;
2657 int startcol = 0;
Bram Moolenaar76624232007-07-28 12:21:47 +00002658 int c1 = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002659 int escaped = FALSE; // CTRL-V typed
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002660 int vcol = 0;
2661 char_u *p;
Bram Moolenaar76624232007-07-28 12:21:47 +00002662 int prev_char;
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002663 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002665 // Switch cursor on now. This avoids that it happens after the "\n", which
2666 // confuses the system function that computes tabstops.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 cursor_on();
2668
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002669 // always start in column 0; write a newline if necessary
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670 compute_cmdrow();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002671 if ((msg_col || msg_didout) && promptc != '?')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672 msg_putchar('\n');
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002673 if (promptc == ':')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002675 // indent that is only displayed, not in the line itself
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002676 if (p_prompt)
2677 msg_putchar(':');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678 while (indent-- > 0)
2679 msg_putchar(' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 startcol = msg_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 }
2682
2683 ga_init2(&line_ga, 1, 30);
2684
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002685 // autoindent for :insert and :append is in the line itself
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002686 if (promptc <= 0)
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002687 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002688 vcol = indent;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002689 while (indent >= 8)
2690 {
2691 ga_append(&line_ga, TAB);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002692 msg_puts(" ");
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002693 indent -= 8;
2694 }
2695 while (indent-- > 0)
2696 {
2697 ga_append(&line_ga, ' ');
2698 msg_putchar(' ');
2699 }
2700 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002701 ++no_mapping;
2702 ++allow_keys;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002703
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 /*
2705 * Get the line, one character at a time.
2706 */
2707 got_int = FALSE;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002708 while (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 {
Bram Moolenaarda636572015-04-03 17:11:45 +02002710 long sw;
2711 char_u *s;
2712
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 if (ga_grow(&line_ga, 40) == FAIL)
2714 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715
Bram Moolenaarba748c82017-02-26 14:00:07 +01002716 /*
2717 * Get one character at a time.
2718 */
Bram Moolenaar76624232007-07-28 12:21:47 +00002719 prev_char = c1;
Bram Moolenaarba748c82017-02-26 14:00:07 +01002720
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002721 // Check for a ":normal" command and no more characters left.
Bram Moolenaarba748c82017-02-26 14:00:07 +01002722 if (ex_normal_busy > 0 && typebuf.tb_len == 0)
2723 c1 = '\n';
2724 else
2725 c1 = vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
2727 /*
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002728 * Handle line editing.
2729 * Previously this was left to the system, putting the terminal in
2730 * cooked mode, but then CTRL-D and CTRL-T can't be used properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002732 if (got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002734 msg_putchar('\n');
2735 break;
2736 }
2737
Bram Moolenaarabbc4482017-01-24 15:57:55 +01002738 if (c1 == K_PS)
2739 {
2740 bracketed_paste(PASTE_EX, FALSE, &line_ga);
2741 goto redraw;
2742 }
2743
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002744 if (!escaped)
2745 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002746 // CR typed means "enter", which is NL
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002747 if (c1 == '\r')
2748 c1 = '\n';
2749
2750 if (c1 == BS || c1 == K_BS
2751 || c1 == DEL || c1 == K_DEL || c1 == K_KDEL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002753 if (line_ga.ga_len > 0)
2754 {
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002755 if (has_mbyte)
2756 {
2757 p = (char_u *)line_ga.ga_data;
2758 p[line_ga.ga_len] = NUL;
2759 len = (*mb_head_off)(p, p + line_ga.ga_len - 1) + 1;
2760 line_ga.ga_len -= len;
2761 }
2762 else
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002763 --line_ga.ga_len;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002764 goto redraw;
2765 }
2766 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 }
2768
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002769 if (c1 == Ctrl_U)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002771 msg_col = startcol;
2772 msg_clr_eos();
2773 line_ga.ga_len = 0;
Bram Moolenaarda636572015-04-03 17:11:45 +02002774 goto redraw;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002775 }
2776
2777 if (c1 == Ctrl_T)
2778 {
Bram Moolenaarda636572015-04-03 17:11:45 +02002779 sw = get_sw_value(curbuf);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002780 p = (char_u *)line_ga.ga_data;
2781 p[line_ga.ga_len] = NUL;
Bram Moolenaar597a4222014-06-25 14:39:50 +02002782 indent = get_indent_str(p, 8, FALSE);
Bram Moolenaar14f24742012-08-08 18:01:05 +02002783 indent += sw - indent % sw;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002784add_indent:
Bram Moolenaar597a4222014-06-25 14:39:50 +02002785 while (get_indent_str(p, 8, FALSE) < indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002787 (void)ga_grow(&line_ga, 2); // one more for the NUL
Bram Moolenaarda636572015-04-03 17:11:45 +02002788 p = (char_u *)line_ga.ga_data;
2789 s = skipwhite(p);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002790 mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1);
2791 *s = ' ';
2792 ++line_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002793 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002794redraw:
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002795 // redraw the line
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002796 msg_col = startcol;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002797 vcol = 0;
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002798 p = (char_u *)line_ga.ga_data;
2799 p[line_ga.ga_len] = NUL;
2800 while (p < (char_u *)line_ga.ga_data + line_ga.ga_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002802 if (*p == TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002804 do
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002805 msg_putchar(' ');
Bram Moolenaarabab0b02019-03-30 18:47:01 +01002806 while (++vcol % 8);
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002807 ++p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002809 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 {
Bram Moolenaar1614a142019-10-06 22:00:13 +02002811 len = mb_ptr2len(p);
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002812 msg_outtrans_len(p, len);
2813 vcol += ptr2cells(p);
2814 p += len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815 }
2816 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002817 msg_clr_eos();
Bram Moolenaar76624232007-07-28 12:21:47 +00002818 windgoto(msg_row, msg_col);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002819 continue;
2820 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002822 if (c1 == Ctrl_D)
2823 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002824 // Delete one shiftwidth.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002825 p = (char_u *)line_ga.ga_data;
2826 if (prev_char == '0' || prev_char == '^')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002828 if (prev_char == '^')
2829 ex_keep_indent = TRUE;
2830 indent = 0;
2831 p[--line_ga.ga_len] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 }
2833 else
2834 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002835 p[line_ga.ga_len] = NUL;
Bram Moolenaar597a4222014-06-25 14:39:50 +02002836 indent = get_indent_str(p, 8, FALSE);
Bram Moolenaarda636572015-04-03 17:11:45 +02002837 if (indent > 0)
2838 {
2839 --indent;
2840 indent -= indent % get_sw_value(curbuf);
2841 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 }
Bram Moolenaar597a4222014-06-25 14:39:50 +02002843 while (get_indent_str(p, 8, FALSE) > indent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002844 {
Bram Moolenaarda636572015-04-03 17:11:45 +02002845 s = skipwhite(p);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002846 mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);
2847 --line_ga.ga_len;
2848 }
2849 goto add_indent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002851
2852 if (c1 == Ctrl_V || c1 == Ctrl_Q)
2853 {
2854 escaped = TRUE;
2855 continue;
2856 }
2857
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002858 // Ignore special key codes: mouse movement, K_IGNORE, etc.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002859 if (IS_SPECIAL(c1))
2860 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002862
2863 if (IS_SPECIAL(c1))
2864 c1 = '?';
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002865 if (has_mbyte)
2866 len = (*mb_char2bytes)(c1,
2867 (char_u *)line_ga.ga_data + line_ga.ga_len);
2868 else
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002869 {
2870 len = 1;
2871 ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
2872 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002873 if (c1 == '\n')
2874 msg_putchar('\n');
2875 else if (c1 == TAB)
2876 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002877 // Don't use chartabsize(), 'ts' can be different
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002878 do
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002879 msg_putchar(' ');
Bram Moolenaarabab0b02019-03-30 18:47:01 +01002880 while (++vcol % 8);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002881 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002884 msg_outtrans_len(
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002885 ((char_u *)line_ga.ga_data) + line_ga.ga_len, len);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002886 vcol += char2cells(c1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 }
Bram Moolenaar2d54ec92014-06-12 19:44:48 +02002888 line_ga.ga_len += len;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002889 escaped = FALSE;
2890
2891 windgoto(msg_row, msg_col);
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002892 pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002893
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002894 // We are done when a NL is entered, but not when it comes after an
2895 // odd number of backslashes, that results in a NUL.
Bram Moolenaar417f5e72010-09-29 15:50:30 +02002896 if (line_ga.ga_len > 0 && pend[-1] == '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 {
Bram Moolenaar417f5e72010-09-29 15:50:30 +02002898 int bcount = 0;
2899
2900 while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\')
2901 ++bcount;
2902
2903 if (bcount > 0)
2904 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002905 // Halve the number of backslashes: "\NL" -> "NUL", "\\NL" ->
2906 // "\NL", etc.
Bram Moolenaar417f5e72010-09-29 15:50:30 +02002907 line_ga.ga_len -= (bcount + 1) / 2;
2908 pend -= (bcount + 1) / 2;
2909 pend[-1] = '\n';
2910 }
2911
2912 if ((bcount & 1) == 0)
2913 {
2914 --line_ga.ga_len;
2915 --pend;
2916 *pend = NUL;
2917 break;
2918 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919 }
2920 }
2921
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002922 --no_mapping;
2923 --allow_keys;
2924
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002925 // make following messages go to the next line
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 msg_didout = FALSE;
2927 msg_col = 0;
2928 if (msg_row < Rows - 1)
2929 ++msg_row;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002930 emsg_on_display = FALSE; // don't want ui_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931
2932 if (got_int)
2933 ga_clear(&line_ga);
2934
2935 return (char_u *)line_ga.ga_data;
2936}
2937
Bram Moolenaare344bea2005-09-01 20:46:49 +00002938# if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
2939 || defined(FEAT_MOUSESHAPE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940/*
2941 * Return TRUE if ccline.overstrike is on.
2942 */
2943 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002944cmdline_overstrike(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945{
2946 return ccline.overstrike;
2947}
2948
2949/*
2950 * Return TRUE if the cursor is at the end of the cmdline.
2951 */
2952 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002953cmdline_at_end(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954{
2955 return (ccline.cmdpos >= ccline.cmdlen);
2956}
2957#endif
2958
Bram Moolenaar9372a112005-12-06 19:59:18 +00002959#if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK))) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960/*
2961 * Return the virtual column number at the current cursor position.
2962 * This is used by the IM code to obtain the start of the preedit string.
2963 */
2964 colnr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002965cmdline_getvcol_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966{
2967 if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen)
2968 return MAXCOL;
2969
Bram Moolenaar071d4272004-06-13 20:20:40 +00002970 if (has_mbyte)
2971 {
2972 colnr_T col;
2973 int i = 0;
2974
2975 for (col = 0; i < ccline.cmdpos; ++col)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002976 i += (*mb_ptr2len)(ccline.cmdbuff + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977
2978 return col;
2979 }
2980 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 return ccline.cmdpos;
2982}
2983#endif
2984
2985#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2986/*
2987 * If part of the command line is an IM preedit string, redraw it with
2988 * IM feedback attributes. The cursor position is restored after drawing.
2989 */
2990 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002991redrawcmd_preedit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992{
2993 if ((State & CMDLINE)
2994 && xic != NULL
Bram Moolenaar217e1b82019-12-01 21:41:28 +01002995 // && im_get_status() doesn't work when using SCIM
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996 && !p_imdisable
2997 && im_is_preediting())
2998 {
2999 int cmdpos = 0;
3000 int cmdspos;
3001 int old_row;
3002 int old_col;
3003 colnr_T col;
3004
3005 old_row = msg_row;
3006 old_col = msg_col;
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003007 cmdspos = ((ccline.cmdfirstc != NUL) ? 1 : 0) + ccline.cmdindent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 if (has_mbyte)
3010 {
3011 for (col = 0; col < preedit_start_col
3012 && cmdpos < ccline.cmdlen; ++col)
3013 {
3014 cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003015 cmdpos += (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 }
3017 }
3018 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 {
3020 cmdspos += preedit_start_col;
3021 cmdpos += preedit_start_col;
3022 }
3023
3024 msg_row = cmdline_row + (cmdspos / (int)Columns);
3025 msg_col = cmdspos % (int)Columns;
3026 if (msg_row >= Rows)
3027 msg_row = Rows - 1;
3028
3029 for (col = 0; cmdpos < ccline.cmdlen; ++col)
3030 {
3031 int char_len;
3032 int char_attr;
3033
3034 char_attr = im_get_feedback_attr(col);
3035 if (char_attr < 0)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003036 break; // end of preedit string
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003039 char_len = (*mb_ptr2len)(ccline.cmdbuff + cmdpos);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 char_len = 1;
3042
3043 msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr);
3044 cmdpos += char_len;
3045 }
3046
3047 msg_row = old_row;
3048 msg_col = old_col;
3049 }
3050}
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003051#endif // FEAT_XIM && FEAT_GUI_GTK
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052
3053/*
3054 * Allocate a new command line buffer.
3055 * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 */
3057 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003058alloc_cmdbuff(int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059{
3060 /*
3061 * give some extra space to avoid having to allocate all the time
3062 */
3063 if (len < 80)
3064 len = 100;
3065 else
3066 len += 20;
3067
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003068 ccline.cmdbuff = alloc(len); // caller should check for out-of-memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 ccline.cmdbufflen = len;
3070}
3071
3072/*
3073 * Re-allocate the command line to length len + something extra.
3074 * return FAIL for failure, OK otherwise
3075 */
Bram Moolenaar66b51422019-08-18 21:44:12 +02003076 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003077realloc_cmdbuff(int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078{
3079 char_u *p;
3080
Bram Moolenaar673b87b2010-08-13 19:12:07 +02003081 if (len < ccline.cmdbufflen)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003082 return OK; // no need to resize
Bram Moolenaar673b87b2010-08-13 19:12:07 +02003083
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 p = ccline.cmdbuff;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003085 alloc_cmdbuff(len); // will get some more
3086 if (ccline.cmdbuff == NULL) // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003088 ccline.cmdbuff = p; // keep the old one
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089 return FAIL;
3090 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003091 // There isn't always a NUL after the command, but it may need to be
3092 // there, thus copy up to the NUL and add a NUL.
Bram Moolenaar35a34232010-08-13 16:51:26 +02003093 mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen);
3094 ccline.cmdbuff[ccline.cmdlen] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 vim_free(p);
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00003096
3097 if (ccline.xpc != NULL
3098 && ccline.xpc->xp_pattern != NULL
3099 && ccline.xpc->xp_context != EXPAND_NOTHING
3100 && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL)
3101 {
Bram Moolenaarbb5ddda2008-11-28 10:01:10 +00003102 int i = (int)(ccline.xpc->xp_pattern - p);
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00003103
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003104 // If xp_pattern points inside the old cmdbuff it needs to be adjusted
3105 // to point into the newly allocated memory.
Bram Moolenaard6e7cc62008-09-14 12:42:29 +00003106 if (i >= 0 && i <= ccline.cmdlen)
3107 ccline.xpc->xp_pattern = ccline.cmdbuff + i;
3108 }
3109
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110 return OK;
3111}
3112
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003113#if defined(FEAT_ARABIC) || defined(PROTO)
3114static char_u *arshape_buf = NULL;
3115
3116# if defined(EXITFREE) || defined(PROTO)
3117 void
Bram Moolenaar48ac6712019-07-04 20:26:21 +02003118free_arshape_buf(void)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003119{
3120 vim_free(arshape_buf);
3121}
3122# endif
3123#endif
3124
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125/*
3126 * Draw part of the cmdline at the current cursor position. But draw stars
3127 * when cmdline_star is TRUE.
3128 */
3129 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003130draw_cmdline(int start, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131{
3132#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
3133 int i;
3134
3135 if (cmdline_star > 0)
3136 for (i = 0; i < len; ++i)
3137 {
3138 msg_putchar('*');
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003140 i += (*mb_ptr2len)(ccline.cmdbuff + start + i) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 }
3142 else
3143#endif
3144#ifdef FEAT_ARABIC
Bram Moolenaar693f7dc2019-06-21 02:30:38 +02003145 if (p_arshape && !p_tbidi && cmdline_has_arabic(start, len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147 static int buflen = 0;
3148 char_u *p;
3149 int j;
3150 int newlen = 0;
3151 int mb_l;
Bram Moolenaar4ea8fe12006-03-09 22:32:39 +00003152 int pc, pc1 = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 int prev_c = 0;
3154 int prev_c1 = 0;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003155 int u8c;
3156 int u8cc[MAX_MCO];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157 int nc = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158
3159 /*
3160 * Do arabic shaping into a temporary buffer. This is very
3161 * inefficient!
3162 */
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003163 if (len * 2 + 2 > buflen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003165 // Re-allocate the buffer. We keep it around to avoid a lot of
3166 // alloc()/free() calls.
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003167 vim_free(arshape_buf);
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003168 buflen = len * 2 + 2;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003169 arshape_buf = alloc(buflen);
3170 if (arshape_buf == NULL)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003171 return; // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 }
3173
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003174 if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start)))
3175 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003176 // Prepend a space to draw the leading composing char on.
Bram Moolenaarcafda4f2005-09-06 19:25:11 +00003177 arshape_buf[0] = ' ';
3178 newlen = 1;
3179 }
3180
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181 for (j = start; j < start + len; j += mb_l)
3182 {
3183 p = ccline.cmdbuff + j;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003184 u8c = utfc_ptr2char_len(p, u8cc, start + len - j);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003185 mb_l = utfc_ptr2len_len(p, start + len - j);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 if (ARABIC_CHAR(u8c))
3187 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003188 // Do Arabic shaping.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 if (cmdmsg_rl)
3190 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003191 // displaying from right to left
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 pc = prev_c;
3193 pc1 = prev_c1;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003194 prev_c1 = u8cc[0];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 if (j + mb_l >= start + len)
3196 nc = NUL;
3197 else
3198 nc = utf_ptr2char(p + mb_l);
3199 }
3200 else
3201 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003202 // displaying from left to right
Bram Moolenaar071d4272004-06-13 20:20:40 +00003203 if (j + mb_l >= start + len)
3204 pc = NUL;
3205 else
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003206 {
3207 int pcc[MAX_MCO];
3208
3209 pc = utfc_ptr2char_len(p + mb_l, pcc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 start + len - j - mb_l);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003211 pc1 = pcc[0];
3212 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 nc = prev_c;
3214 }
3215 prev_c = u8c;
3216
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003217 u8c = arabic_shape(u8c, NULL, &u8cc[0], pc, pc1, nc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003219 newlen += (*mb_char2bytes)(u8c, arshape_buf + newlen);
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003220 if (u8cc[0] != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00003222 newlen += (*mb_char2bytes)(u8cc[0], arshape_buf + newlen);
3223 if (u8cc[1] != 0)
3224 newlen += (*mb_char2bytes)(u8cc[1],
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003225 arshape_buf + newlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 }
3227 }
3228 else
3229 {
3230 prev_c = u8c;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003231 mch_memmove(arshape_buf + newlen, p, mb_l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 newlen += mb_l;
3233 }
3234 }
3235
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003236 msg_outtrans_len(arshape_buf, newlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 }
3238 else
3239#endif
3240 msg_outtrans_len(ccline.cmdbuff + start, len);
3241}
3242
3243/*
3244 * Put a character on the command line. Shifts the following text to the
3245 * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
3246 * "c" must be printable (fit in one display cell)!
3247 */
3248 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003249putcmdline(int c, int shift)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250{
3251 if (cmd_silent)
3252 return;
3253 msg_no_more = TRUE;
3254 msg_putchar(c);
3255 if (shift)
3256 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
3257 msg_no_more = FALSE;
3258 cursorcmd();
Bram Moolenaar6a77d262017-07-16 15:24:01 +02003259 extra_char = c;
3260 extra_char_shift = shift;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261}
3262
3263/*
3264 * Undo a putcmdline(c, FALSE).
3265 */
3266 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003267unputcmdline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268{
3269 if (cmd_silent)
3270 return;
3271 msg_no_more = TRUE;
3272 if (ccline.cmdlen == ccline.cmdpos)
3273 msg_putchar(' ');
Bram Moolenaar64fdf5c2012-06-06 12:03:06 +02003274 else if (has_mbyte)
3275 draw_cmdline(ccline.cmdpos,
3276 (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 else
3278 draw_cmdline(ccline.cmdpos, 1);
3279 msg_no_more = FALSE;
3280 cursorcmd();
Bram Moolenaar6a77d262017-07-16 15:24:01 +02003281 extra_char = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282}
3283
3284/*
3285 * Put the given string, of the given length, onto the command line.
3286 * If len is -1, then STRLEN() is used to calculate the length.
3287 * If 'redraw' is TRUE then the new part of the command line, and the remaining
3288 * part will be redrawn, otherwise it will not. If this function is called
3289 * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
3290 * called afterwards.
3291 */
3292 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003293put_on_cmdline(char_u *str, int len, int redraw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294{
3295 int retval;
3296 int i;
3297 int m;
3298 int c;
3299
3300 if (len < 0)
3301 len = (int)STRLEN(str);
3302
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003303 // Check if ccline.cmdbuff needs to be longer
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen)
Bram Moolenaar673b87b2010-08-13 19:12:07 +02003305 retval = realloc_cmdbuff(ccline.cmdlen + len + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 else
3307 retval = OK;
3308 if (retval == OK)
3309 {
3310 if (!ccline.overstrike)
3311 {
3312 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
3313 ccline.cmdbuff + ccline.cmdpos,
3314 (size_t)(ccline.cmdlen - ccline.cmdpos));
3315 ccline.cmdlen += len;
3316 }
3317 else
3318 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319 if (has_mbyte)
3320 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003321 // Count nr of characters in the new string.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 m = 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003323 for (i = 0; i < len; i += (*mb_ptr2len)(str + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 ++m;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003325 // Count nr of bytes in cmdline that are overwritten by these
3326 // characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003328 i += (*mb_ptr2len)(ccline.cmdbuff + i))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329 --m;
3330 if (i < ccline.cmdlen)
3331 {
3332 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
3333 ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i));
3334 ccline.cmdlen += ccline.cmdpos + len - i;
3335 }
3336 else
3337 ccline.cmdlen = ccline.cmdpos + len;
3338 }
Bram Moolenaar13505972019-01-24 15:04:48 +01003339 else if (ccline.cmdpos + len > ccline.cmdlen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 ccline.cmdlen = ccline.cmdpos + len;
3341 }
3342 mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
3343 ccline.cmdbuff[ccline.cmdlen] = NUL;
3344
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 if (enc_utf8)
3346 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003347 // When the inserted text starts with a composing character,
3348 // backup to the character before it. There could be two of them.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 i = 0;
3350 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
3351 while (ccline.cmdpos > 0 && utf_iscomposing(c))
3352 {
3353 i = (*mb_head_off)(ccline.cmdbuff,
3354 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
3355 ccline.cmdpos -= i;
3356 len += i;
3357 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
3358 }
Bram Moolenaar13505972019-01-24 15:04:48 +01003359#ifdef FEAT_ARABIC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360 if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c))
3361 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003362 // Check the previous character for Arabic combining pair.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 i = (*mb_head_off)(ccline.cmdbuff,
3364 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
3365 if (arabic_combine(utf_ptr2char(ccline.cmdbuff
3366 + ccline.cmdpos - i), c))
3367 {
3368 ccline.cmdpos -= i;
3369 len += i;
3370 }
3371 else
3372 i = 0;
3373 }
Bram Moolenaar13505972019-01-24 15:04:48 +01003374#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 if (i != 0)
3376 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003377 // Also backup the cursor position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
3379 ccline.cmdspos -= i;
3380 msg_col -= i;
3381 if (msg_col < 0)
3382 {
3383 msg_col += Columns;
3384 --msg_row;
3385 }
3386 }
3387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388
3389 if (redraw && !cmd_silent)
3390 {
3391 msg_no_more = TRUE;
3392 i = cmdline_row;
Bram Moolenaar73dc59a2011-09-30 17:46:21 +02003393 cursorcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003395 // Avoid clearing the rest of the line too often.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 if (cmdline_row != i || ccline.overstrike)
3397 msg_clr_eos();
3398 msg_no_more = FALSE;
3399 }
Bram Moolenaar14184a32019-02-16 15:10:30 +01003400 if (KeyTyped)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003401 {
Bram Moolenaar14184a32019-02-16 15:10:30 +01003402 m = Columns * Rows;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003403 if (m < 0) // overflow, Columns or Rows at weird value
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404 m = MAXCOL;
Bram Moolenaar14184a32019-02-16 15:10:30 +01003405 }
3406 else
3407 m = MAXCOL;
3408 for (i = 0; i < len; ++i)
3409 {
3410 c = cmdline_charsize(ccline.cmdpos);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003411 // count ">" for a double-wide char that doesn't fit.
Bram Moolenaar14184a32019-02-16 15:10:30 +01003412 if (has_mbyte)
3413 correct_cmdspos(ccline.cmdpos, c);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003414 // Stop cursor at the end of the screen, but do increment the
3415 // insert position, so that entering a very long command
3416 // works, even though you can't see it.
Bram Moolenaar14184a32019-02-16 15:10:30 +01003417 if (ccline.cmdspos + c < m)
3418 ccline.cmdspos += c;
Bram Moolenaar13505972019-01-24 15:04:48 +01003419
Bram Moolenaar14184a32019-02-16 15:10:30 +01003420 if (has_mbyte)
3421 {
3422 c = (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos) - 1;
3423 if (c > len - i - 1)
3424 c = len - i - 1;
3425 ccline.cmdpos += c;
3426 i += c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 }
Bram Moolenaar14184a32019-02-16 15:10:30 +01003428 ++ccline.cmdpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429 }
3430 }
3431 if (redraw)
3432 msg_check();
3433 return retval;
3434}
3435
Bram Moolenaar66b51422019-08-18 21:44:12 +02003436static cmdline_info_T prev_ccline;
3437static int prev_ccline_used = FALSE;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003438
3439/*
3440 * Save ccline, because obtaining the "=" register may execute "normal :cmd"
3441 * and overwrite it. But get_cmdline_str() may need it, thus make it
3442 * available globally in prev_ccline.
3443 */
3444 static void
Bram Moolenaar66b51422019-08-18 21:44:12 +02003445save_cmdline(cmdline_info_T *ccp)
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003446{
3447 if (!prev_ccline_used)
3448 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003449 CLEAR_FIELD(prev_ccline);
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003450 prev_ccline_used = TRUE;
3451 }
3452 *ccp = prev_ccline;
3453 prev_ccline = ccline;
Bram Moolenaar438d1762018-09-30 17:11:48 +02003454 ccline.cmdbuff = NULL; // signal that ccline is not in use
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003455}
3456
3457/*
Bram Moolenaarccc18222007-05-10 18:25:20 +00003458 * Restore ccline after it has been saved with save_cmdline().
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003459 */
3460 static void
Bram Moolenaar66b51422019-08-18 21:44:12 +02003461restore_cmdline(cmdline_info_T *ccp)
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00003462{
3463 ccline = prev_ccline;
3464 prev_ccline = *ccp;
3465}
3466
Bram Moolenaar8299df92004-07-10 09:47:34 +00003467/*
Bram Moolenaar6f62fed2015-12-17 14:04:24 +01003468 * Paste a yank register into the command line.
3469 * Used by CTRL-R command in command-line mode.
Bram Moolenaar8299df92004-07-10 09:47:34 +00003470 * insert_reg() can't be used here, because special characters from the
3471 * register contents will be interpreted as commands.
3472 *
Bram Moolenaar6f62fed2015-12-17 14:04:24 +01003473 * Return FAIL for failure, OK otherwise.
Bram Moolenaar8299df92004-07-10 09:47:34 +00003474 */
3475 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003476cmdline_paste(
3477 int regname,
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003478 int literally, // Insert text literally instead of "as typed"
3479 int remcr) // remove trailing CR
Bram Moolenaar8299df92004-07-10 09:47:34 +00003480{
3481 long i;
3482 char_u *arg;
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003483 char_u *p;
Bram Moolenaar8299df92004-07-10 09:47:34 +00003484 int allocated;
Bram Moolenaar8299df92004-07-10 09:47:34 +00003485
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003486 // check for valid regname; also accept special characters for CTRL-R in
3487 // the command line
Bram Moolenaar8299df92004-07-10 09:47:34 +00003488 if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
Bram Moolenaare2c8d832018-05-01 19:24:03 +02003489 && regname != Ctrl_A && regname != Ctrl_L
3490 && !valid_yank_reg(regname, FALSE))
Bram Moolenaar8299df92004-07-10 09:47:34 +00003491 return FAIL;
3492
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003493 // A register containing CTRL-R can cause an endless loop. Allow using
3494 // CTRL-C to break the loop.
Bram Moolenaar8299df92004-07-10 09:47:34 +00003495 line_breakcheck();
3496 if (got_int)
3497 return FAIL;
3498
3499#ifdef FEAT_CLIPBOARD
3500 regname = may_get_selection(regname);
3501#endif
3502
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02003503 // Need to set "textwinlock" to avoid nasty things like going to another
Bram Moolenaar438d1762018-09-30 17:11:48 +02003504 // buffer when evaluating an expression.
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02003505 ++textwinlock;
Bram Moolenaar8299df92004-07-10 09:47:34 +00003506 i = get_spec_reg(regname, &arg, &allocated, TRUE);
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02003507 --textwinlock;
Bram Moolenaar8299df92004-07-10 09:47:34 +00003508
3509 if (i)
3510 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003511 // Got the value of a special register in "arg".
Bram Moolenaar8299df92004-07-10 09:47:34 +00003512 if (arg == NULL)
3513 return FAIL;
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003514
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003515 // When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate
3516 // part of the word.
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003517 p = arg;
3518 if (p_is && regname == Ctrl_W)
3519 {
3520 char_u *w;
3521 int len;
3522
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003523 // Locate start of last word in the cmd buffer.
Bram Moolenaar80ae7b22011-07-07 16:44:37 +02003524 for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; )
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003525 {
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003526 if (has_mbyte)
3527 {
3528 len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1;
3529 if (!vim_iswordc(mb_ptr2char(w - len)))
3530 break;
3531 w -= len;
3532 }
3533 else
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003534 {
3535 if (!vim_iswordc(w[-1]))
3536 break;
3537 --w;
3538 }
3539 }
Bram Moolenaar80ae7b22011-07-07 16:44:37 +02003540 len = (int)((ccline.cmdbuff + ccline.cmdpos) - w);
Bram Moolenaarefd2bf12006-03-16 21:41:35 +00003541 if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0)
3542 p += len;
3543 }
3544
3545 cmdline_paste_str(p, literally);
Bram Moolenaar8299df92004-07-10 09:47:34 +00003546 if (allocated)
3547 vim_free(arg);
3548 return OK;
3549 }
3550
Bram Moolenaar1769d5a2006-10-17 14:25:24 +00003551 return cmdline_paste_reg(regname, literally, remcr);
Bram Moolenaar8299df92004-07-10 09:47:34 +00003552}
3553
3554/*
3555 * Put a string on the command line.
3556 * When "literally" is TRUE, insert literally.
3557 * When "literally" is FALSE, insert as typed, but don't leave the command
3558 * line.
3559 */
3560 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003561cmdline_paste_str(char_u *s, int literally)
Bram Moolenaar8299df92004-07-10 09:47:34 +00003562{
3563 int c, cv;
3564
3565 if (literally)
3566 put_on_cmdline(s, -1, TRUE);
3567 else
3568 while (*s != NUL)
3569 {
3570 cv = *s;
3571 if (cv == Ctrl_V && s[1])
3572 ++s;
Bram Moolenaar8299df92004-07-10 09:47:34 +00003573 if (has_mbyte)
Bram Moolenaar48be32b2008-06-20 10:56:16 +00003574 c = mb_cptr2char_adv(&s);
Bram Moolenaar8299df92004-07-10 09:47:34 +00003575 else
Bram Moolenaar8299df92004-07-10 09:47:34 +00003576 c = *s++;
Bram Moolenaare79abdd2012-06-29 13:44:41 +02003577 if (cv == Ctrl_V || c == ESC || c == Ctrl_C
3578 || c == CAR || c == NL || c == Ctrl_L
Bram Moolenaar8299df92004-07-10 09:47:34 +00003579#ifdef UNIX
3580 || c == intr_char
3581#endif
3582 || (c == Ctrl_BSL && *s == Ctrl_N))
3583 stuffcharReadbuff(Ctrl_V);
3584 stuffcharReadbuff(c);
3585 }
3586}
3587
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588/*
Bram Moolenaar89c79b92016-05-05 17:18:41 +02003589 * This function is called when the screen size changes and with incremental
3590 * search and in other situations where the command line may have been
3591 * overwritten.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592 */
3593 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003594redrawcmdline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595{
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003596 redrawcmdline_ex(TRUE);
3597}
3598
3599 void
3600redrawcmdline_ex(int do_compute_cmdrow)
3601{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 if (cmd_silent)
3603 return;
3604 need_wait_return = FALSE;
Bram Moolenaar29ae3772017-04-30 19:39:39 +02003605 if (do_compute_cmdrow)
3606 compute_cmdrow();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 redrawcmd();
3608 cursorcmd();
3609}
3610
3611 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003612redrawcmdprompt(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613{
3614 int i;
3615
3616 if (cmd_silent)
3617 return;
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003618 if (ccline.cmdfirstc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619 msg_putchar(ccline.cmdfirstc);
3620 if (ccline.cmdprompt != NULL)
3621 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01003622 msg_puts_attr((char *)ccline.cmdprompt, ccline.cmdattr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623 ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003624 // do the reverse of set_cmdspos()
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00003625 if (ccline.cmdfirstc != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003626 --ccline.cmdindent;
3627 }
3628 else
3629 for (i = ccline.cmdindent; i > 0; --i)
3630 msg_putchar(' ');
3631}
3632
3633/*
3634 * Redraw what is currently on the command line.
3635 */
3636 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003637redrawcmd(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638{
3639 if (cmd_silent)
3640 return;
3641
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003642 // when 'incsearch' is set there may be no command line while redrawing
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00003643 if (ccline.cmdbuff == NULL)
3644 {
3645 windgoto(cmdline_row, 0);
3646 msg_clr_eos();
3647 return;
3648 }
3649
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650 msg_start();
3651 redrawcmdprompt();
3652
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003653 // Don't use more prompt, truncate the cmdline if it doesn't fit.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 msg_no_more = TRUE;
3655 draw_cmdline(0, ccline.cmdlen);
3656 msg_clr_eos();
3657 msg_no_more = FALSE;
3658
3659 set_cmdspos_cursor();
Bram Moolenaara92522f2017-07-15 15:21:38 +02003660 if (extra_char != NUL)
Bram Moolenaar6a77d262017-07-16 15:24:01 +02003661 putcmdline(extra_char, extra_char_shift);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662
3663 /*
3664 * An emsg() before may have set msg_scroll. This is used in normal mode,
3665 * in cmdline mode we can reset them now.
3666 */
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003667 msg_scroll = FALSE; // next message overwrites cmdline
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003669 // Typing ':' at the more prompt may set skip_redraw. We don't want this
3670 // in cmdline mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 skip_redraw = FALSE;
3672}
3673
3674 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003675compute_cmdrow(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676{
Bram Moolenaar1c7715d2005-10-03 22:02:18 +00003677 if (exmode_active || msg_scrolled != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 cmdline_row = Rows - 1;
3679 else
3680 cmdline_row = W_WINROW(lastwin) + lastwin->w_height
Bram Moolenaare0de17d2017-09-24 16:24:34 +02003681 + lastwin->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682}
3683
Bram Moolenaar66b51422019-08-18 21:44:12 +02003684 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003685cursorcmd(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686{
3687 if (cmd_silent)
3688 return;
3689
3690#ifdef FEAT_RIGHTLEFT
3691 if (cmdmsg_rl)
3692 {
3693 msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
3694 msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
3695 if (msg_row <= 0)
3696 msg_row = Rows - 1;
3697 }
3698 else
3699#endif
3700 {
3701 msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
3702 msg_col = ccline.cmdspos % (int)Columns;
3703 if (msg_row >= Rows)
3704 msg_row = Rows - 1;
3705 }
3706
3707 windgoto(msg_row, msg_col);
3708#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02003709 if (p_imst == IM_ON_THE_SPOT)
3710 redrawcmd_preedit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711#endif
3712#ifdef MCH_CURSOR_SHAPE
3713 mch_update_cursor();
3714#endif
3715}
3716
3717 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003718gotocmdline(int clr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719{
3720 msg_start();
3721#ifdef FEAT_RIGHTLEFT
3722 if (cmdmsg_rl)
3723 msg_col = Columns - 1;
3724 else
3725#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003726 msg_col = 0; // always start in column 0
3727 if (clr) // clear the bottom line(s)
3728 msg_clr_eos(); // will reset clear_cmdline
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 windgoto(cmdline_row, 0);
3730}
3731
3732/*
3733 * Check the word in front of the cursor for an abbreviation.
3734 * Called when the non-id character "c" has been entered.
3735 * When an abbreviation is recognized it is removed from the text with
3736 * backspaces and the replacement string is inserted, followed by "c".
3737 */
3738 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003739ccheck_abbr(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740{
Bram Moolenaar5e3423d2018-05-13 18:36:27 +02003741 int spos = 0;
3742
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003743 if (p_paste || no_abbr) // no abbreviations or in paste mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 return FALSE;
3745
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003746 // Do not consider '<,'> be part of the mapping, skip leading whitespace.
3747 // Actually accepts any mark.
Bram Moolenaar5e3423d2018-05-13 18:36:27 +02003748 while (VIM_ISWHITE(ccline.cmdbuff[spos]) && spos < ccline.cmdlen)
3749 spos++;
3750 if (ccline.cmdlen - spos > 5
3751 && ccline.cmdbuff[spos] == '\''
3752 && ccline.cmdbuff[spos + 2] == ','
3753 && ccline.cmdbuff[spos + 3] == '\'')
3754 spos += 5;
3755 else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003756 // check abbreviation from the beginning of the commandline
Bram Moolenaar5e3423d2018-05-13 18:36:27 +02003757 spos = 0;
3758
3759 return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760}
3761
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762/*
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003763 * Escape special characters in "fname" for when used as a file name argument
3764 * after a Vim command, or, when "shell" is non-zero, a shell command.
3765 * Returns the result in allocated memory.
3766 */
3767 char_u *
Bram Moolenaarbd67aac2019-09-21 23:09:04 +02003768vim_strsave_fnameescape(char_u *fname, int shell UNUSED)
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003769{
Bram Moolenaar7693ec62008-07-24 18:29:37 +00003770 char_u *p;
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003771#ifdef BACKSLASH_IN_FILENAME
3772 char_u buf[20];
3773 int j = 0;
3774
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003775 // Don't escape '[', '{' and '!' if they are in 'isfname'.
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003776 for (p = PATH_ESC_CHARS; *p != NUL; ++p)
Bram Moolenaar8f5610d2013-11-12 05:28:26 +01003777 if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p))
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003778 buf[j++] = *p;
3779 buf[j] = NUL;
Bram Moolenaar1b24e4b2008-08-08 10:59:17 +00003780 p = vim_strsave_escaped(fname, buf);
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003781#else
Bram Moolenaar7693ec62008-07-24 18:29:37 +00003782 p = vim_strsave_escaped(fname, shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS);
3783 if (shell && csh_like_shell() && p != NULL)
3784 {
3785 char_u *s;
3786
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003787 // For csh and similar shells need to put two backslashes before '!'.
3788 // One is taken by Vim, one by the shell.
Bram Moolenaar7693ec62008-07-24 18:29:37 +00003789 s = vim_strsave_escaped(p, (char_u *)"!");
3790 vim_free(p);
3791 p = s;
3792 }
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003793#endif
Bram Moolenaar1b24e4b2008-08-08 10:59:17 +00003794
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003795 // '>' and '+' are special at the start of some commands, e.g. ":edit" and
3796 // ":write". "cd -" has a special meaning.
Bram Moolenaara9d52e32010-07-31 16:44:19 +02003797 if (p != NULL && (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)))
Bram Moolenaar1b24e4b2008-08-08 10:59:17 +00003798 escape_fname(&p);
3799
3800 return p;
Bram Moolenaaraebaf892008-05-28 14:49:58 +00003801}
3802
3803/*
Bram Moolenaar45360022005-07-21 21:08:21 +00003804 * Put a backslash before the file name in "pp", which is in allocated memory.
3805 */
Bram Moolenaar66b51422019-08-18 21:44:12 +02003806 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003807escape_fname(char_u **pp)
Bram Moolenaar45360022005-07-21 21:08:21 +00003808{
3809 char_u *p;
3810
Bram Moolenaar964b3742019-05-24 18:54:09 +02003811 p = alloc(STRLEN(*pp) + 2);
Bram Moolenaar45360022005-07-21 21:08:21 +00003812 if (p != NULL)
3813 {
3814 p[0] = '\\';
3815 STRCPY(p + 1, *pp);
3816 vim_free(*pp);
3817 *pp = p;
3818 }
3819}
3820
3821/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 * For each file name in files[num_files]:
3823 * If 'orig_pat' starts with "~/", replace the home directory with "~".
3824 */
3825 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003826tilde_replace(
3827 char_u *orig_pat,
3828 int num_files,
3829 char_u **files)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830{
3831 int i;
3832 char_u *p;
3833
3834 if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
3835 {
3836 for (i = 0; i < num_files; ++i)
3837 {
3838 p = home_replace_save(NULL, files[i]);
3839 if (p != NULL)
3840 {
3841 vim_free(files[i]);
3842 files[i] = p;
3843 }
3844 }
3845 }
3846}
3847
3848/*
Bram Moolenaar66b51422019-08-18 21:44:12 +02003849 * Get a pointer to the current command line info.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 */
Bram Moolenaar66b51422019-08-18 21:44:12 +02003851 cmdline_info_T *
3852get_cmdline_info(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853{
Bram Moolenaar66b51422019-08-18 21:44:12 +02003854 return &ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855}
3856
Bram Moolenaar064154c2016-03-19 22:50:43 +01003857#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003858/*
Bram Moolenaar438d1762018-09-30 17:11:48 +02003859 * Get pointer to the command line info to use. save_ccline() may clear
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003860 * ccline and put the previous value in prev_ccline.
3861 */
Bram Moolenaar66b51422019-08-18 21:44:12 +02003862 static cmdline_info_T *
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003863get_ccline_ptr(void)
3864{
3865 if ((State & CMDLINE) == 0)
3866 return NULL;
3867 if (ccline.cmdbuff != NULL)
3868 return &ccline;
3869 if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
3870 return &prev_ccline;
3871 return NULL;
3872}
Bram Moolenaar064154c2016-03-19 22:50:43 +01003873#endif
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003874
Bram Moolenaar064154c2016-03-19 22:50:43 +01003875#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003876/*
3877 * Get the current command line in allocated memory.
3878 * Only works when the command line is being edited.
3879 * Returns NULL when something is wrong.
3880 */
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003881 static char_u *
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003882get_cmdline_str(void)
3883{
Bram Moolenaar66b51422019-08-18 21:44:12 +02003884 cmdline_info_T *p;
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003885
Bram Moolenaaree91c332018-09-25 22:27:35 +02003886 if (cmdline_star > 0)
3887 return NULL;
3888 p = get_ccline_ptr();
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003889 if (p == NULL)
3890 return NULL;
3891 return vim_strnsave(p->cmdbuff, p->cmdlen);
3892}
3893
3894/*
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003895 * "getcmdline()" function
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003896 */
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003897 void
3898f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
3899{
3900 rettv->v_type = VAR_STRING;
3901 rettv->vval.v_string = get_cmdline_str();
3902}
3903
3904/*
3905 * "getcmdpos()" function
3906 */
3907 void
3908f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003909{
Bram Moolenaar66b51422019-08-18 21:44:12 +02003910 cmdline_info_T *p = get_ccline_ptr();
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003911
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003912 rettv->vval.v_number = 0;
3913 if (p != NULL)
3914 rettv->vval.v_number = p->cmdpos + 1;
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003915}
3916
3917/*
3918 * Set the command line byte position to "pos". Zero is the first position.
3919 * Only works when the command line is being edited.
3920 * Returns 1 when failed, 0 when OK.
3921 */
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003922 static int
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003923set_cmdline_pos(
3924 int pos)
3925{
Bram Moolenaar66b51422019-08-18 21:44:12 +02003926 cmdline_info_T *p = get_ccline_ptr();
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003927
3928 if (p == NULL)
3929 return 1;
3930
Bram Moolenaar217e1b82019-12-01 21:41:28 +01003931 // The position is not set directly but after CTRL-\ e or CTRL-R = has
3932 // changed the command line.
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003933 if (pos < 0)
3934 new_cmdpos = 0;
3935 else
3936 new_cmdpos = pos;
3937 return 0;
3938}
Bram Moolenaar08c308a2019-09-04 17:48:15 +02003939
3940/*
3941 * "setcmdpos()" function
3942 */
3943 void
3944f_setcmdpos(typval_T *argvars, typval_T *rettv)
3945{
3946 int pos = (int)tv_get_number(&argvars[0]) - 1;
3947
3948 if (pos >= 0)
3949 rettv->vval.v_number = set_cmdline_pos(pos);
3950}
3951
3952/*
3953 * "getcmdtype()" function
3954 */
3955 void
3956f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
3957{
3958 rettv->v_type = VAR_STRING;
3959 rettv->vval.v_string = alloc(2);
3960 if (rettv->vval.v_string != NULL)
3961 {
3962 rettv->vval.v_string[0] = get_cmdline_type();
3963 rettv->vval.v_string[1] = NUL;
3964 }
3965}
3966
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003967#endif
3968
3969#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
3970/*
3971 * Get the current command-line type.
3972 * Returns ':' or '/' or '?' or '@' or '>' or '-'
3973 * Only works when the command line is being edited.
3974 * Returns NUL when something is wrong.
3975 */
3976 int
3977get_cmdline_type(void)
3978{
Bram Moolenaar66b51422019-08-18 21:44:12 +02003979 cmdline_info_T *p = get_ccline_ptr();
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003980
3981 if (p == NULL)
3982 return NUL;
3983 if (p->cmdfirstc == NUL)
Bram Moolenaar064154c2016-03-19 22:50:43 +01003984 return
3985# ifdef FEAT_EVAL
3986 (p->input_fn) ? '@' :
3987# endif
3988 '-';
Bram Moolenaard293b2b2016-03-19 22:29:49 +01003989 return p->cmdfirstc;
3990}
3991#endif
3992
Bram Moolenaard7663c22019-08-06 21:59:57 +02003993/*
3994 * Return the first character of the current command line.
3995 */
3996 int
3997get_cmdline_firstc(void)
3998{
3999 return ccline.cmdfirstc;
4000}
4001
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002/*
4003 * Get indices "num1,num2" that specify a range within a list (not a range of
4004 * text lines in a buffer!) from a string. Used for ":history" and ":clist".
4005 * Returns OK if parsed successfully, otherwise FAIL.
4006 */
4007 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004008get_list_range(char_u **str, int *num1, int *num2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009{
4010 int len;
4011 int first = FALSE;
Bram Moolenaar22fcfad2016-07-01 18:17:26 +02004012 varnumber_T num;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013
4014 *str = skipwhite(*str);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004015 if (**str == '-' || vim_isdigit(**str)) // parse "from" part of range
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 {
Bram Moolenaar16e9b852019-05-19 19:59:35 +02004017 vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018 *str += len;
4019 *num1 = (int)num;
4020 first = TRUE;
4021 }
4022 *str = skipwhite(*str);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004023 if (**str == ',') // parse "to" part of range
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 {
4025 *str = skipwhite(*str + 1);
Bram Moolenaar16e9b852019-05-19 19:59:35 +02004026 vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 if (len > 0)
4028 {
4029 *num2 = (int)num;
4030 *str = skipwhite(*str + len);
4031 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004032 else if (!first) // no number given at all
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 return FAIL;
4034 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004035 else if (first) // only one number given
Bram Moolenaar071d4272004-06-13 20:20:40 +00004036 *num2 = *num1;
4037 return OK;
4038}
Bram Moolenaar1fd99c12016-06-09 20:24:28 +02004039
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040#if defined(FEAT_CMDWIN) || defined(PROTO)
4041/*
Bram Moolenaar7bae0b12019-11-21 22:14:18 +01004042 * Check value of 'cedit' and set cedit_key.
4043 * Returns NULL if value is OK, error message otherwise.
4044 */
4045 char *
4046check_cedit(void)
4047{
4048 int n;
4049
4050 if (*p_cedit == NUL)
4051 cedit_key = -1;
4052 else
4053 {
4054 n = string_to_key(p_cedit, FALSE);
4055 if (vim_isprintc(n))
4056 return e_invarg;
4057 cedit_key = n;
4058 }
4059 return NULL;
4060}
4061
4062/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 * Open a window on the current command line and history. Allow editing in
4064 * the window. Returns when the window is closed.
4065 * Returns:
4066 * CR if the command is to be executed
4067 * Ctrl_C if it is to be abandoned
4068 * K_IGNORE if editing continues
4069 */
4070 static int
Bram Moolenaar3bab9392017-04-07 15:42:25 +02004071open_cmdwin(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004073 bufref_T old_curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 win_T *old_curwin = curwin;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004075 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004076 win_T *wp;
4077 int i;
4078 linenr_T lnum;
4079 int histtype;
4080 garray_T winsizes;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004081 int save_restart_edit = restart_edit;
4082 int save_State = State;
4083 int save_exmode = exmode_active;
Bram Moolenaar46152342005-09-07 21:18:43 +00004084#ifdef FEAT_RIGHTLEFT
4085 int save_cmdmsg_rl = cmdmsg_rl;
4086#endif
Bram Moolenaar42f06f92014-08-17 17:24:07 +02004087#ifdef FEAT_FOLDING
4088 int save_KeyTyped;
4089#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004091 // Can't do this recursively. Can't do it when typing a password.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 if (cmdwin_type != 0
4093# if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
4094 || cmdline_star > 0
4095# endif
4096 )
4097 {
4098 beep_flush();
4099 return K_IGNORE;
4100 }
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004101 set_bufref(&old_curbuf, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004103 // Save current window sizes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 win_size_save(&winsizes);
4105
Bram Moolenaar9e26f7d2019-01-22 22:08:09 +01004106 // When using completion in Insert mode with <C-R>=<C-F> one can open the
4107 // command line window, but we don't want the popup menu then.
4108 pum_undisplay();
4109
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004110 // don't use a new tab page
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00004111 cmdmod.tab = 0;
Bram Moolenaar3bab9392017-04-07 15:42:25 +02004112 cmdmod.noswapfile = 1;
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00004113
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004114 // Create a window for the command-line buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 if (win_split((int)p_cwh, WSP_BOT) == FAIL)
4116 {
4117 beep_flush();
Bram Moolenaar292b90d2020-03-18 15:23:16 +01004118 ga_clear(&winsizes);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 return K_IGNORE;
4120 }
Bram Moolenaar9b7cce22020-06-06 15:14:08 +02004121 // Don't let quitting the More prompt make this fail.
4122 got_int = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004124 // Create the command-line buffer empty.
Bram Moolenaar9b7cce22020-06-06 15:14:08 +02004125 if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL)
4126 {
4127 // Some autocommand messed it up?
4128 win_close(curwin, TRUE);
4129 ga_clear(&winsizes);
4130 return Ctrl_C;
4131 }
4132 cmdwin_type = get_cmdline_type();
4133
Bram Moolenaar5e94a292020-03-19 18:46:57 +01004134 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar446cb832008-06-24 21:56:24 +00004135 (void)setfname(curbuf, (char_u *)"[Command Line]", NULL, TRUE);
Bram Moolenaar5e94a292020-03-19 18:46:57 +01004136 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004137 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 curbuf->b_p_ma = TRUE;
Bram Moolenaar876f6d72009-04-29 10:05:51 +00004139#ifdef FEAT_FOLDING
4140 curwin->w_p_fen = FALSE;
4141#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142# ifdef FEAT_RIGHTLEFT
Bram Moolenaar46152342005-09-07 21:18:43 +00004143 curwin->w_p_rl = cmdmsg_rl;
4144 cmdmsg_rl = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145# endif
Bram Moolenaar3368ea22010-09-21 16:56:35 +02004146 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004148 // Don't allow switching to another buffer.
Bram Moolenaar18141832017-06-25 21:17:25 +02004149 ++curbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004151 // Showing the prompt may have set need_wait_return, reset it.
Bram Moolenaar46152342005-09-07 21:18:43 +00004152 need_wait_return = FALSE;
4153
Bram Moolenaare8bd5ce2009-03-02 01:12:48 +00004154 histtype = hist_char2type(cmdwin_type);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004155 if (histtype == HIST_CMD || histtype == HIST_DEBUG)
4156 {
4157 if (p_wc == TAB)
4158 {
4159 add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
4160 add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
4161 }
4162 set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
4163 }
Bram Moolenaar18141832017-06-25 21:17:25 +02004164 --curbuf_lock;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004166 // Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
4167 // sets 'textwidth' to 78).
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00004168 curbuf->b_p_tw = 0;
4169
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004170 // Fill the buffer with the history.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 init_history();
Bram Moolenaard7663c22019-08-06 21:59:57 +02004172 if (get_hislen() > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173 {
Bram Moolenaard7663c22019-08-06 21:59:57 +02004174 i = *get_hisidx(histtype);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 if (i >= 0)
4176 {
4177 lnum = 0;
4178 do
4179 {
Bram Moolenaard7663c22019-08-06 21:59:57 +02004180 if (++i == get_hislen())
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 i = 0;
Bram Moolenaard7663c22019-08-06 21:59:57 +02004182 if (get_histentry(histtype)[i].hisstr != NULL)
4183 ml_append(lnum++, get_histentry(histtype)[i].hisstr,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 (colnr_T)0, FALSE);
4185 }
Bram Moolenaard7663c22019-08-06 21:59:57 +02004186 while (i != *get_hisidx(histtype));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 }
4188 }
4189
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004190 // Replace the empty last line with the current command-line and put the
4191 // cursor there.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE);
4193 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4194 curwin->w_cursor.col = ccline.cmdpos;
Bram Moolenaar46152342005-09-07 21:18:43 +00004195 changed_line_abv_curs();
4196 invalidate_botline();
Bram Moolenaar600dddc2006-03-12 22:05:10 +00004197 redraw_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198
Bram Moolenaar23324a02019-10-01 17:39:04 +02004199 // No Ex mode here!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 exmode_active = 0;
4201
4202 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 setmouse();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204
Bram Moolenaar23324a02019-10-01 17:39:04 +02004205 // Reset here so it can be set by a CmdWinEnter autocommand.
4206 cmdwin_result = 0;
4207
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004208 // Trigger CmdwinEnter autocommands.
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02004209 trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER);
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004210 if (restart_edit != 0) // autocmd with ":startinsert"
Bram Moolenaar5495cc92006-08-16 14:23:04 +00004211 stuffcharReadbuff(K_NOP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212
4213 i = RedrawingDisabled;
4214 RedrawingDisabled = 0;
4215
4216 /*
4217 * Call the main loop until <CR> or CTRL-C is typed.
4218 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004219 main_loop(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220
4221 RedrawingDisabled = i;
4222
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004223# ifdef FEAT_FOLDING
Bram Moolenaar42f06f92014-08-17 17:24:07 +02004224 save_KeyTyped = KeyTyped;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004225# endif
Bram Moolenaar42f06f92014-08-17 17:24:07 +02004226
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004227 // Trigger CmdwinLeave autocommands.
Bram Moolenaarfafcf0d2017-10-19 18:35:51 +02004228 trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINLEAVE);
Bram Moolenaar42f06f92014-08-17 17:24:07 +02004229
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004230# ifdef FEAT_FOLDING
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004231 // Restore KeyTyped in case it is modified by autocommands
Bram Moolenaar42f06f92014-08-17 17:24:07 +02004232 KeyTyped = save_KeyTyped;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233# endif
4234
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 cmdwin_type = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236 exmode_active = save_exmode;
4237
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004238 // Safety check: The old window or buffer was deleted: It's a bug when
4239 // this happens!
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004240 if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 {
4242 cmdwin_result = Ctrl_C;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004243 emsg(_("E199: Active window or buffer deleted"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244 }
4245 else
4246 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004247# if defined(FEAT_EVAL)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004248 // autocmds may abort script processing
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249 if (aborting() && cmdwin_result != K_IGNORE)
4250 cmdwin_result = Ctrl_C;
4251# endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004252 // Set the new command line from the cmdline buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 vim_free(ccline.cmdbuff);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004254 if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) // :qa[!] typed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 {
Bram Moolenaar46152342005-09-07 21:18:43 +00004256 char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
4257
4258 if (histtype == HIST_CMD)
4259 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004260 // Execute the command directly.
Bram Moolenaar46152342005-09-07 21:18:43 +00004261 ccline.cmdbuff = vim_strsave((char_u *)p);
4262 cmdwin_result = CAR;
4263 }
4264 else
4265 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004266 // First need to cancel what we were doing.
Bram Moolenaar46152342005-09-07 21:18:43 +00004267 ccline.cmdbuff = NULL;
4268 stuffcharReadbuff(':');
4269 stuffReadbuff((char_u *)p);
4270 stuffcharReadbuff(CAR);
4271 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004272 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004273 else if (cmdwin_result == K_XF2) // :qa typed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 {
4275 ccline.cmdbuff = vim_strsave((char_u *)"qa");
4276 cmdwin_result = CAR;
4277 }
Bram Moolenaar9bd1a7e2011-05-19 14:50:54 +02004278 else if (cmdwin_result == Ctrl_C)
4279 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01004280 // :q or :close, don't execute any command
4281 // and don't modify the cmd window.
Bram Moolenaar9bd1a7e2011-05-19 14:50:54 +02004282 ccline.cmdbuff = NULL;
4283 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004284 else
4285 ccline.cmdbuff = vim_strsave(ml_get_curline());
4286 if (ccline.cmdbuff == NULL)
Bram Moolenaar5a15b6a2017-07-11 15:11:57 +02004287 {
4288 ccline.cmdbuff = vim_strsave((char_u *)"");
4289 ccline.cmdlen = 0;
4290 ccline.cmdbufflen = 1;
4291 ccline.cmdpos = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 cmdwin_result = Ctrl_C;
Bram Moolenaar5a15b6a2017-07-11 15:11:57 +02004293 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 else
4295 {
4296 ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
4297 ccline.cmdbufflen = ccline.cmdlen + 1;
4298 ccline.cmdpos = curwin->w_cursor.col;
4299 if (ccline.cmdpos > ccline.cmdlen)
4300 ccline.cmdpos = ccline.cmdlen;
4301 if (cmdwin_result == K_IGNORE)
4302 {
4303 set_cmdspos_cursor();
4304 redrawcmd();
4305 }
4306 }
4307
Bram Moolenaarfa67fbe2015-06-25 18:20:36 +02004308# ifdef FEAT_CONCEAL
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004309 // Avoid command-line window first character being concealed.
Bram Moolenaarfa67fbe2015-06-25 18:20:36 +02004310 curwin->w_p_cole = 0;
4311# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 wp = curwin;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004313 set_bufref(&bufref, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 win_goto(old_curwin);
4315 win_close(wp, TRUE);
Bram Moolenaar8006d692010-03-02 17:23:21 +01004316
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004317 // win_close() may have already wiped the buffer when 'bh' is
4318 // set to 'wipe'
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02004319 if (bufref_valid(&bufref))
Bram Moolenaara6e8f882019-12-14 16:18:15 +01004320 close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004322 // Restore window sizes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 win_size_restore(&winsizes);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324 }
4325
4326 ga_clear(&winsizes);
4327 restart_edit = save_restart_edit;
Bram Moolenaar46152342005-09-07 21:18:43 +00004328# ifdef FEAT_RIGHTLEFT
4329 cmdmsg_rl = save_cmdmsg_rl;
4330# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331
4332 State = save_State;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333 setmouse();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334
4335 return cmdwin_result;
4336}
Bram Moolenaar96e38a82019-09-09 18:35:33 +02004337#endif // FEAT_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338
4339/*
4340 * Used for commands that either take a simple command string argument, or:
4341 * cmd << endmarker
4342 * {script}
4343 * endmarker
4344 * Returns a pointer to allocated memory with {script} or NULL.
4345 */
4346 char_u *
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004347script_get(exarg_T *eap UNUSED, char_u *cmd UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348{
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004349#ifdef FEAT_EVAL
4350 list_T *l;
4351 listitem_T *li;
4352 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 garray_T ga;
4354
4355 if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL)
4356 return NULL;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004357 cmd += 2;
4358
4359 l = heredoc_get(eap, cmd, TRUE);
4360 if (l == NULL)
4361 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362
4363 ga_init2(&ga, 1, 0x400);
4364
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004365 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366 {
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004367 s = tv_get_string(&li->li_tv);
4368 ga_concat(&ga, s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 ga_append(&ga, '\n');
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 }
Bram Moolenaar269ec652004-07-29 08:43:53 +00004371 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004373 list_free(l);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 return (char_u *)ga.ga_data;
Bram Moolenaar6c2b7b82020-04-14 20:15:49 +02004375#else
4376 return NULL;
4377#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378}
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004379
4380#if defined(FEAT_EVAL) || defined(PROTO)
4381/*
4382 * This function is used by f_input() and f_inputdialog() functions. The third
4383 * argument to f_input() specifies the type of completion to use at the
4384 * prompt. The third argument to f_inputdialog() specifies the value to return
4385 * when the user cancels the prompt.
4386 */
4387 void
4388get_user_input(
4389 typval_T *argvars,
4390 typval_T *rettv,
4391 int inputdialog,
4392 int secret)
4393{
4394 char_u *prompt = tv_get_string_chk(&argvars[0]);
4395 char_u *p = NULL;
4396 int c;
4397 char_u buf[NUMBUFLEN];
4398 int cmd_silent_save = cmd_silent;
4399 char_u *defstr = (char_u *)"";
4400 int xp_type = EXPAND_NOTHING;
4401 char_u *xp_arg = NULL;
4402
4403 rettv->v_type = VAR_STRING;
4404 rettv->vval.v_string = NULL;
Bram Moolenaardfc33a62020-04-29 22:30:13 +02004405 if (input_busy)
4406 return; // this doesn't work recursively.
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004407
4408#ifdef NO_CONSOLE_INPUT
4409 // While starting up, there is no place to enter text. When running tests
4410 // with --not-a-term we assume feedkeys() will be used.
4411 if (no_console_input() && !is_not_a_term())
4412 return;
4413#endif
4414
4415 cmd_silent = FALSE; // Want to see the prompt.
4416 if (prompt != NULL)
4417 {
4418 // Only the part of the message after the last NL is considered as
4419 // prompt for the command line
4420 p = vim_strrchr(prompt, '\n');
4421 if (p == NULL)
4422 p = prompt;
4423 else
4424 {
4425 ++p;
4426 c = *p;
4427 *p = NUL;
4428 msg_start();
4429 msg_clr_eos();
4430 msg_puts_attr((char *)prompt, get_echo_attr());
4431 msg_didout = FALSE;
4432 msg_starthere();
4433 *p = c;
4434 }
4435 cmdline_row = msg_row;
4436
4437 if (argvars[1].v_type != VAR_UNKNOWN)
4438 {
4439 defstr = tv_get_string_buf_chk(&argvars[1], buf);
4440 if (defstr != NULL)
4441 stuffReadbuffSpec(defstr);
4442
4443 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
4444 {
4445 char_u *xp_name;
4446 int xp_namelen;
4447 long argt;
4448
4449 // input() with a third argument: completion
4450 rettv->vval.v_string = NULL;
4451
4452 xp_name = tv_get_string_buf_chk(&argvars[2], buf);
4453 if (xp_name == NULL)
4454 return;
4455
4456 xp_namelen = (int)STRLEN(xp_name);
4457
4458 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
4459 &xp_arg) == FAIL)
4460 return;
4461 }
4462 }
4463
4464 if (defstr != NULL)
4465 {
4466 int save_ex_normal_busy = ex_normal_busy;
Bram Moolenaardfc33a62020-04-29 22:30:13 +02004467 int save_vgetc_busy = vgetc_busy;
4468 int save_input_busy = input_busy;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004469
Bram Moolenaardfc33a62020-04-29 22:30:13 +02004470 input_busy |= vgetc_busy;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004471 ex_normal_busy = 0;
Bram Moolenaardfc33a62020-04-29 22:30:13 +02004472 vgetc_busy = 0;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004473 rettv->vval.v_string =
4474 getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(),
4475 xp_type, xp_arg);
4476 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaardfc33a62020-04-29 22:30:13 +02004477 vgetc_busy = save_vgetc_busy;
4478 input_busy = save_input_busy;
Bram Moolenaarda6c0332019-09-01 16:01:30 +02004479 }
4480 if (inputdialog && rettv->vval.v_string == NULL
4481 && argvars[1].v_type != VAR_UNKNOWN
4482 && argvars[2].v_type != VAR_UNKNOWN)
4483 rettv->vval.v_string = vim_strsave(tv_get_string_buf(
4484 &argvars[2], buf));
4485
4486 vim_free(xp_arg);
4487
4488 // since the user typed this, no need to wait for return
4489 need_wait_return = FALSE;
4490 msg_didout = FALSE;
4491 }
4492 cmd_silent = cmd_silent_save;
4493}
4494#endif