blob: 4c6175b6fb8682f7d4b759d17c35dd5a4a1bb3dc [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_getln.c: Functions for entering and editing an Ex command line.
12 */
13
14#include "vim.h"
15
16/*
17 * Variables shared between getcmdline(), redrawcmdline() and others.
18 * These need to be saved when using CTRL-R |, that's why they are in a
19 * structure.
20 */
21struct cmdline_info
22{
23 char_u *cmdbuff; /* pointer to command line buffer */
24 int cmdbufflen; /* length of cmdbuff */
25 int cmdlen; /* number of chars in command line */
26 int cmdpos; /* current cursor position */
27 int cmdspos; /* cursor column on screen */
28 int cmdfirstc; /* ':', '/', '?', '=' or NUL */
29 int cmdindent; /* number of spaces before cmdline */
30 char_u *cmdprompt; /* message in front of cmdline */
31 int cmdattr; /* attributes for prompt */
32 int overstrike; /* Typing mode on the command line. Shared by
33 getcmdline() and put_on_cmdline(). */
34};
35
36static struct cmdline_info ccline; /* current cmdline_info */
37
38static int cmd_showtail; /* Only show path tail in lists ? */
39
40#ifdef FEAT_EVAL
41static int new_cmdpos; /* position set by set_cmdline_pos() */
42#endif
43
44#ifdef FEAT_CMDHIST
45typedef struct hist_entry
46{
47 int hisnum; /* identifying number */
48 char_u *hisstr; /* actual entry, separator char after the NUL */
49} histentry_T;
50
51static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
52static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
53static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
54 /* identifying (unique) number of newest history entry */
55static int hislen = 0; /* actual length of history tables */
56
57static int hist_char2type __ARGS((int c));
58static void init_history __ARGS((void));
59
60static int in_history __ARGS((int, char_u *, int));
61# ifdef FEAT_EVAL
62static int calc_hist_idx __ARGS((int histype, int num));
63# endif
64#endif
65
66#ifdef FEAT_RIGHTLEFT
67static int cmd_hkmap = 0; /* Hebrew mapping during command line */
68#endif
69
70#ifdef FEAT_FKMAP
71static int cmd_fkmap = 0; /* Farsi mapping during command line */
72#endif
73
74static int cmdline_charsize __ARGS((int idx));
75static void set_cmdspos __ARGS((void));
76static void set_cmdspos_cursor __ARGS((void));
77#ifdef FEAT_MBYTE
78static void correct_cmdspos __ARGS((int idx, int cells));
79#endif
80static void alloc_cmdbuff __ARGS((int len));
81static int realloc_cmdbuff __ARGS((int len));
82static void draw_cmdline __ARGS((int start, int len));
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +000083static void save_cmdline __ARGS((struct cmdline_info *ccp));
84static void restore_cmdline __ARGS((struct cmdline_info *ccp));
Bram Moolenaar8299df92004-07-10 09:47:34 +000085static int cmdline_paste __ARGS((int regname, int literally));
Bram Moolenaar071d4272004-06-13 20:20:40 +000086#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
87static void redrawcmd_preedit __ARGS((void));
88#endif
89#ifdef FEAT_WILDMENU
90static void cmdline_del __ARGS((int from));
91#endif
92static void redrawcmdprompt __ARGS((void));
93static void cursorcmd __ARGS((void));
94static int ccheck_abbr __ARGS((int));
95static int nextwild __ARGS((expand_T *xp, int type, int options));
96static int showmatches __ARGS((expand_T *xp, int wildmenu));
97static void set_expand_context __ARGS((expand_T *xp));
98static int ExpandFromContext __ARGS((expand_T *xp, char_u *, int *, char_u ***, int));
99static int expand_showtail __ARGS((expand_T *xp));
100#ifdef FEAT_CMDL_COMPL
101static int ExpandRTDir __ARGS((char_u *pat, int *num_file, char_u ***file, char *dirname));
102# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
103static int ExpandUserDefined __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file));
104# endif
105#endif
106
107#ifdef FEAT_CMDWIN
108static int ex_window __ARGS((void));
109#endif
110
111/*
112 * getcmdline() - accept a command line starting with firstc.
113 *
114 * firstc == ':' get ":" command line.
115 * firstc == '/' or '?' get search pattern
116 * firstc == '=' get expression
117 * firstc == '@' get text for input() function
118 * firstc == '>' get text for debug mode
119 * firstc == NUL get text for :insert command
120 * firstc == -1 like NUL, and break on CTRL-C
121 *
122 * The line is collected in ccline.cmdbuff, which is reallocated to fit the
123 * command line.
124 *
125 * Careful: getcmdline() can be called recursively!
126 *
127 * Return pointer to allocated string if there is a commandline, NULL
128 * otherwise.
129 */
130/*ARGSUSED*/
131 char_u *
132getcmdline(firstc, count, indent)
133 int firstc;
134 long count; /* only used for incremental search */
135 int indent; /* indent for inside conditionals */
136{
137 int c;
138 int i;
139 int j;
140 int gotesc = FALSE; /* TRUE when <ESC> just typed */
141 int do_abbr; /* when TRUE check for abbr. */
142#ifdef FEAT_CMDHIST
143 char_u *lookfor = NULL; /* string to match */
144 int hiscnt; /* current history line in use */
145 int histype; /* history type to be used */
146#endif
147#ifdef FEAT_SEARCH_EXTRA
148 pos_T old_cursor;
149 colnr_T old_curswant;
150 colnr_T old_leftcol;
151 linenr_T old_topline;
152# ifdef FEAT_DIFF
153 int old_topfill;
154# endif
155 linenr_T old_botline;
156 int did_incsearch = FALSE;
157 int incsearch_postponed = FALSE;
158#endif
159 int did_wild_list = FALSE; /* did wild_list() recently */
160 int wim_index = 0; /* index in wim_flags[] */
161 int res;
162 int save_msg_scroll = msg_scroll;
163 int save_State = State; /* remember State when called */
164 int some_key_typed = FALSE; /* one of the keys was typed */
165#ifdef FEAT_MOUSE
166 /* mouse drag and release events are ignored, unless they are
167 * preceded with a mouse down event */
168 int ignore_drag_release = TRUE;
169#endif
170#ifdef FEAT_EVAL
171 int break_ctrl_c = FALSE;
172#endif
173 expand_T xpc;
174 long *b_im_ptr = NULL;
175
176#ifdef FEAT_SNIFF
177 want_sniff_request = 0;
178#endif
179#ifdef FEAT_EVAL
180 if (firstc == -1)
181 {
182 firstc = NUL;
183 break_ctrl_c = TRUE;
184 }
185#endif
186#ifdef FEAT_RIGHTLEFT
187 /* start without Hebrew mapping for a command line */
188 if (firstc == ':' || firstc == '=' || firstc == '>')
189 cmd_hkmap = 0;
190#endif
191
192 ccline.overstrike = FALSE; /* always start in insert mode */
193#ifdef FEAT_SEARCH_EXTRA
194 old_cursor = curwin->w_cursor; /* needs to be restored later */
195 old_curswant = curwin->w_curswant;
196 old_leftcol = curwin->w_leftcol;
197 old_topline = curwin->w_topline;
198# ifdef FEAT_DIFF
199 old_topfill = curwin->w_topfill;
200# endif
201 old_botline = curwin->w_botline;
202#endif
203
204 /*
205 * set some variables for redrawcmd()
206 */
207 ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000208 ccline.cmdindent = (firstc > 0 ? indent : 0);
209
210 /* alloc initial ccline.cmdbuff */
211 alloc_cmdbuff(exmode_active ? 250 : indent + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212 if (ccline.cmdbuff == NULL)
213 return NULL; /* out of memory */
214 ccline.cmdlen = ccline.cmdpos = 0;
215 ccline.cmdbuff[0] = NUL;
216
Bram Moolenaar4399ef42005-02-12 14:29:27 +0000217 /* autoindent for :insert and :append */
218 if (firstc <= 0)
219 {
220 copy_spaces(ccline.cmdbuff, indent);
221 ccline.cmdbuff[indent] = NUL;
222 ccline.cmdpos = indent;
223 ccline.cmdspos = indent;
224 ccline.cmdlen = indent;
225 }
226
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 ExpandInit(&xpc);
228
229#ifdef FEAT_RIGHTLEFT
230 if (curwin->w_p_rl && *curwin->w_p_rlc == 's'
231 && (firstc == '/' || firstc == '?'))
232 cmdmsg_rl = TRUE;
233 else
234 cmdmsg_rl = FALSE;
235#endif
236
237 redir_off = TRUE; /* don't redirect the typed command */
238 if (!cmd_silent)
239 {
240 i = msg_scrolled;
241 msg_scrolled = 0; /* avoid wait_return message */
242 gotocmdline(TRUE);
243 msg_scrolled += i;
244 redrawcmdprompt(); /* draw prompt or indent */
245 set_cmdspos();
246 }
247 xpc.xp_context = EXPAND_NOTHING;
248 xpc.xp_backslash = XP_BS_NONE;
249
250 /*
251 * Avoid scrolling when called by a recursive do_cmdline(), e.g. when
252 * doing ":@0" when register 0 doesn't contain a CR.
253 */
254 msg_scroll = FALSE;
255
256 State = CMDLINE;
257
258 if (firstc == '/' || firstc == '?' || firstc == '@')
259 {
260 /* Use ":lmap" mappings for search pattern and input(). */
261 if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT)
262 b_im_ptr = &curbuf->b_p_iminsert;
263 else
264 b_im_ptr = &curbuf->b_p_imsearch;
265 if (*b_im_ptr == B_IMODE_LMAP)
266 State |= LANGMAP;
267#ifdef USE_IM_CONTROL
268 im_set_active(*b_im_ptr == B_IMODE_IM);
269#endif
270 }
271#ifdef USE_IM_CONTROL
272 else if (p_imcmdline)
273 im_set_active(TRUE);
274#endif
275
276#ifdef FEAT_MOUSE
277 setmouse();
278#endif
279#ifdef CURSOR_SHAPE
280 ui_cursor_shape(); /* may show different cursor shape */
281#endif
282
283#ifdef FEAT_CMDHIST
284 init_history();
285 hiscnt = hislen; /* set hiscnt to impossible history value */
286 histype = hist_char2type(firstc);
287#endif
288
289#ifdef FEAT_DIGRAPHS
290 do_digraph(-1); /* init digraph typahead */
291#endif
292
293 /*
294 * Collect the command string, handling editing keys.
295 */
296 for (;;)
297 {
298#ifdef USE_ON_FLY_SCROLL
299 dont_scroll = FALSE; /* allow scrolling here */
300#endif
301 quit_more = FALSE; /* reset after CTRL-D which had a more-prompt */
302
303 cursorcmd(); /* set the cursor on the right spot */
304 c = safe_vgetc();
305 if (KeyTyped)
306 {
307 some_key_typed = TRUE;
308#ifdef FEAT_RIGHTLEFT
309 if (cmd_hkmap)
310 c = hkmap(c);
311# ifdef FEAT_FKMAP
312 if (cmd_fkmap)
313 c = cmdl_fkmap(c);
314# endif
315 if (cmdmsg_rl && !KeyStuffed)
316 {
317 /* Invert horizontal movements and operations. Only when
318 * typed by the user directly, not when the result of a
319 * mapping. */
320 switch (c)
321 {
322 case K_RIGHT: c = K_LEFT; break;
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000323 case K_XRIGHT: c = K_XLEFT; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324 case K_S_RIGHT: c = K_S_LEFT; break;
325 case K_C_RIGHT: c = K_C_LEFT; break;
326 case K_LEFT: c = K_RIGHT; break;
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000327 case K_XLEFT: c = K_XRIGHT; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328 case K_S_LEFT: c = K_S_RIGHT; break;
329 case K_C_LEFT: c = K_C_RIGHT; break;
330 }
331 }
332#endif
333 }
334
335 /*
336 * Ignore got_int when CTRL-C was typed here.
337 * Don't ignore it in :global, we really need to break then, e.g., for
338 * ":g/pat/normal /pat" (without the <CR>).
339 * Don't ignore it for the input() function.
340 */
341 if ((c == Ctrl_C
342#ifdef UNIX
343 || c == intr_char
344#endif
345 )
346#if defined(FEAT_EVAL) || defined(FEAT_CRYPT)
347 && firstc != '@'
348#endif
349#ifdef FEAT_EVAL
350 && !break_ctrl_c
351#endif
352 && !global_busy)
353 got_int = FALSE;
354
355#ifdef FEAT_CMDHIST
356 /* free old command line when finished moving around in the history
357 * list */
358 if (lookfor != NULL
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000359 && c != K_S_DOWN && c != K_S_UP
360 && c != K_DOWN && c != K_UP && c != K_XDOWN && c != K_XUP
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 && c != K_PAGEDOWN && c != K_PAGEUP
362 && c != K_KPAGEDOWN && c != K_KPAGEUP
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000363 && c != K_LEFT && c != K_RIGHT && c != K_XLEFT && c != K_XRIGHT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N)))
365 {
366 vim_free(lookfor);
367 lookfor = NULL;
368 }
369#endif
370
371 /*
372 * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>).
373 */
374 if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles != -1)
375 c = Ctrl_P;
376
377#ifdef FEAT_WILDMENU
378 /* Special translations for 'wildmenu' */
379 if (did_wild_list && p_wmnu)
380 {
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000381 if (c == K_LEFT || c == K_XLEFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 c = Ctrl_P;
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000383 else if (c == K_RIGHT || c == K_XRIGHT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 c = Ctrl_N;
385 }
386 /* Hitting CR after "emenu Name.": complete submenu */
387 if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu
388 && ccline.cmdpos > 1
389 && ccline.cmdbuff[ccline.cmdpos - 1] == '.'
390 && ccline.cmdbuff[ccline.cmdpos - 2] != '\\'
391 && (c == '\n' || c == '\r' || c == K_KENTER))
392 c = K_DOWN;
393#endif
394
395 /* free expanded names when finished walking through matches */
396 if (xpc.xp_numfiles != -1
397 && !(c == p_wc && KeyTyped) && c != p_wcm
398 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A
399 && c != Ctrl_L)
400 {
401 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
402 did_wild_list = FALSE;
403#ifdef FEAT_WILDMENU
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000404 if (!p_wmnu || (c != K_UP && c != K_DOWN
405 && c != K_XUP && c != K_XDOWN))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406#endif
407 xpc.xp_context = EXPAND_NOTHING;
408 wim_index = 0;
409#ifdef FEAT_WILDMENU
410 if (p_wmnu && wild_menu_showing != 0)
411 {
412 int skt = KeyTyped;
413
414 if (wild_menu_showing == WM_SCROLLED)
415 {
416 /* Entered command line, move it up */
417 cmdline_row--;
418 redrawcmd();
419 }
420 else if (save_p_ls != -1)
421 {
422 /* restore 'laststatus' and 'winminheight' */
423 p_ls = save_p_ls;
424 p_wmh = save_p_wmh;
425 last_status(FALSE);
426 update_screen(VALID); /* redraw the screen NOW */
427 redrawcmd();
428 save_p_ls = -1;
429 }
430 else
431 {
432# ifdef FEAT_VERTSPLIT
433 win_redraw_last_status(topframe);
434# else
435 lastwin->w_redr_status = TRUE;
436# endif
437 redraw_statuslines();
438 }
439 KeyTyped = skt;
440 wild_menu_showing = 0;
441 }
442#endif
443 }
444
445#ifdef FEAT_WILDMENU
446 /* Special translations for 'wildmenu' */
447 if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu)
448 {
449 /* Hitting <Down> after "emenu Name.": complete submenu */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000450 if (ccline.cmdbuff[ccline.cmdpos - 1] == '.'
451 && (c == K_DOWN || c == K_XDOWN))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452 c = p_wc;
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000453 else if (c == K_UP || c == K_XUP)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 {
455 /* Hitting <Up>: Remove one submenu name in front of the
456 * cursor */
457 int found = FALSE;
458
459 j = (int)(xpc.xp_pattern - ccline.cmdbuff);
460 i = 0;
461 while (--j > 0)
462 {
463 /* check for start of menu name */
464 if (ccline.cmdbuff[j] == ' '
465 && ccline.cmdbuff[j - 1] != '\\')
466 {
467 i = j + 1;
468 break;
469 }
470 /* check for start of submenu name */
471 if (ccline.cmdbuff[j] == '.'
472 && ccline.cmdbuff[j - 1] != '\\')
473 {
474 if (found)
475 {
476 i = j + 1;
477 break;
478 }
479 else
480 found = TRUE;
481 }
482 }
483 if (i > 0)
484 cmdline_del(i);
485 c = p_wc;
486 xpc.xp_context = EXPAND_NOTHING;
487 }
488 }
489 if (xpc.xp_context == EXPAND_FILES && p_wmnu)
490 {
491 char_u upseg[5];
492
493 upseg[0] = PATHSEP;
494 upseg[1] = '.';
495 upseg[2] = '.';
496 upseg[3] = PATHSEP;
497 upseg[4] = NUL;
498
499 if (ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000500 && (c == K_DOWN || c == K_XDOWN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501 && (ccline.cmdbuff[ccline.cmdpos - 2] != '.'
502 || ccline.cmdbuff[ccline.cmdpos - 3] != '.'))
503 {
504 /* go down a directory */
505 c = p_wc;
506 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000507 else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0
508 && (c == K_DOWN || c == K_XDOWN))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509 {
510 /* If in a direct ancestor, strip off one ../ to go down */
511 int found = FALSE;
512
513 j = ccline.cmdpos;
514 i = (int)(xpc.xp_pattern - ccline.cmdbuff);
515 while (--j > i)
516 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000517#ifdef FEAT_MBYTE
518 if (has_mbyte)
519 j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
520#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 if (vim_ispathsep(ccline.cmdbuff[j]))
522 {
523 found = TRUE;
524 break;
525 }
526 }
527 if (found
528 && ccline.cmdbuff[j - 1] == '.'
529 && ccline.cmdbuff[j - 2] == '.'
530 && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2))
531 {
532 cmdline_del(j - 2);
533 c = p_wc;
534 }
535 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000536 else if (c == K_UP || c == K_XUP)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 {
538 /* go up a directory */
539 int found = FALSE;
540
541 j = ccline.cmdpos - 1;
542 i = (int)(xpc.xp_pattern - ccline.cmdbuff);
543 while (--j > i)
544 {
545#ifdef FEAT_MBYTE
546 if (has_mbyte)
547 j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j);
548#endif
549 if (vim_ispathsep(ccline.cmdbuff[j])
550#ifdef BACKSLASH_IN_FILENAME
551 && vim_strchr(" *?[{`$%#", ccline.cmdbuff[j + 1])
552 == NULL
553#endif
554 )
555 {
556 if (found)
557 {
558 i = j + 1;
559 break;
560 }
561 else
562 found = TRUE;
563 }
564 }
565
566 if (!found)
567 j = i;
568 else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0)
569 j += 4;
570 else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0
571 && j == i)
572 j += 3;
573 else
574 j = 0;
575 if (j > 0)
576 {
577 /* TODO this is only for DOS/UNIX systems - need to put in
578 * machine-specific stuff here and in upseg init */
579 cmdline_del(j);
580 put_on_cmdline(upseg + 1, 3, FALSE);
581 }
582 else if (ccline.cmdpos > i)
583 cmdline_del(i);
584 c = p_wc;
585 }
586 }
587#if 0 /* If enabled <Down> on a file takes you _completely_ out of wildmenu */
588 if (p_wmnu
589 && (xpc.xp_context == EXPAND_FILES
590 || xpc.xp_context == EXPAND_MENUNAMES)
591 && (c == K_UP || c == K_DOWN))
592 xpc.xp_context = EXPAND_NOTHING;
593#endif
594
595#endif /* FEAT_WILDMENU */
596
597 /* CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert
598 * mode when 'insertmode' is set, CTRL-\ e prompts for an expression. */
599 if (c == Ctrl_BSL)
600 {
601 ++no_mapping;
602 ++allow_keys;
603 c = safe_vgetc();
604 --no_mapping;
605 --allow_keys;
606 /* CTRL-\ e doesn't work when obtaining an expression. */
607 if (c != Ctrl_N && c != Ctrl_G
608 && (c != 'e' || ccline.cmdfirstc == '='))
609 {
610 vungetc(c);
611 c = Ctrl_BSL;
612 }
613#ifdef FEAT_EVAL
614 else if (c == 'e')
615 {
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +0000616 struct cmdline_info save_ccline;
617 char_u *p = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618
619 /*
620 * Replace the command line with the result of an expression.
621 * Need to save the current command line, to be able to enter
622 * a new one...
623 */
624 if (ccline.cmdpos == ccline.cmdlen)
625 new_cmdpos = 99999; /* keep it at the end */
626 else
627 new_cmdpos = ccline.cmdpos;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +0000628
629 save_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 c = get_expr_register();
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +0000631 restore_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 if (c == '=')
633 {
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +0000634 save_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 p = get_expr_line();
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +0000636 restore_cmdline(&save_ccline);
637
638 if (p != NULL && realloc_cmdbuff((int)STRLEN(p) + 1) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 {
640 ccline.cmdlen = STRLEN(p);
641 STRCPY(ccline.cmdbuff, p);
642 vim_free(p);
643
644 /* Restore the cursor or use the position set with
645 * set_cmdline_pos(). */
646 if (new_cmdpos > ccline.cmdlen)
647 ccline.cmdpos = ccline.cmdlen;
648 else
649 ccline.cmdpos = new_cmdpos;
650
651 KeyTyped = FALSE; /* Don't do p_wc completion. */
652 redrawcmd();
653 goto cmdline_changed;
654 }
655 }
656 beep_flush();
657 c = ESC;
658 }
659#endif
660 else
661 {
662 if (c == Ctrl_G && p_im && restart_edit == 0)
663 restart_edit = 'a';
664 gotesc = TRUE; /* will free ccline.cmdbuff after putting it
665 in history */
666 goto returncmd; /* back to Normal mode */
667 }
668 }
669
670#ifdef FEAT_CMDWIN
671 if (c == cedit_key || c == K_CMDWIN)
672 {
673 /*
674 * Open a window to edit the command line (and history).
675 */
676 c = ex_window();
677 some_key_typed = TRUE;
678 }
679# ifdef FEAT_DIGRAPHS
680 else
681# endif
682#endif
683#ifdef FEAT_DIGRAPHS
684 c = do_digraph(c);
685#endif
686
687 if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC
688 && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL)))
689 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000690 /* In Ex mode a backslash escapes a newline. */
691 if (exmode_active
692 && c != ESC
693 && ccline.cmdpos > 0
694 && ccline.cmdpos == ccline.cmdlen
695 && ccline.cmdbuff[ccline.cmdpos - 1] == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000697 if (c == K_KENTER)
698 c = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000700 else
701 {
702 gotesc = FALSE; /* Might have typed ESC previously, don't
703 truncate the cmdline now. */
704 if (ccheck_abbr(c + ABBR_OFF))
705 goto cmdline_changed;
706 if (!cmd_silent)
707 {
708 windgoto(msg_row, 0);
709 out_flush();
710 }
711 break;
712 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713 }
714
715 /*
716 * Completion for 'wildchar' or 'wildcharm' key.
717 * - hitting <ESC> twice means: abandon command line.
718 * - wildcard expansion is only done when the 'wildchar' key is really
719 * typed, not when it comes from a macro
720 */
721 if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
722 {
723 if (xpc.xp_numfiles > 0) /* typed p_wc at least twice */
724 {
725 /* if 'wildmode' contains "list" may still need to list */
726 if (xpc.xp_numfiles > 1
727 && !did_wild_list
728 && (wim_flags[wim_index] & WIM_LIST))
729 {
730 (void)showmatches(&xpc, FALSE);
731 redrawcmd();
732 did_wild_list = TRUE;
733 }
734 if (wim_flags[wim_index] & WIM_LONGEST)
735 res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP);
736 else if (wim_flags[wim_index] & WIM_FULL)
737 res = nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP);
738 else
739 res = OK; /* don't insert 'wildchar' now */
740 }
741 else /* typed p_wc first time */
742 {
743 wim_index = 0;
744 j = ccline.cmdpos;
745 /* if 'wildmode' first contains "longest", get longest
746 * common part */
747 if (wim_flags[0] & WIM_LONGEST)
748 res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP);
749 else
750 res = nextwild(&xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP);
751
752 /* if interrupted while completing, behave like it failed */
753 if (got_int)
754 {
755 (void)vpeekc(); /* remove <C-C> from input stream */
756 got_int = FALSE; /* don't abandon the command line */
757 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
758#ifdef FEAT_WILDMENU
759 xpc.xp_context = EXPAND_NOTHING;
760#endif
761 goto cmdline_changed;
762 }
763
764 /* when more than one match, and 'wildmode' first contains
765 * "list", or no change and 'wildmode' contains "longest,list",
766 * list all matches */
767 if (res == OK && xpc.xp_numfiles > 1)
768 {
769 /* a "longest" that didn't do anything is skipped (but not
770 * "list:longest") */
771 if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
772 wim_index = 1;
773 if ((wim_flags[wim_index] & WIM_LIST)
774#ifdef FEAT_WILDMENU
775 || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
776#endif
777 )
778 {
779 if (!(wim_flags[0] & WIM_LONGEST))
780 {
781#ifdef FEAT_WILDMENU
782 int p_wmnu_save = p_wmnu;
783 p_wmnu = 0;
784#endif
785 nextwild(&xpc, WILD_PREV, 0); /* remove match */
786#ifdef FEAT_WILDMENU
787 p_wmnu = p_wmnu_save;
788#endif
789 }
790#ifdef FEAT_WILDMENU
791 (void)showmatches(&xpc, p_wmnu
792 && ((wim_flags[wim_index] & WIM_LIST) == 0));
793#else
794 (void)showmatches(&xpc, FALSE);
795#endif
796 redrawcmd();
797 did_wild_list = TRUE;
798 if (wim_flags[wim_index] & WIM_LONGEST)
799 nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP);
800 else if (wim_flags[wim_index] & WIM_FULL)
801 nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP);
802 }
803 else
804 vim_beep();
805 }
806#ifdef FEAT_WILDMENU
807 else if (xpc.xp_numfiles == -1)
808 xpc.xp_context = EXPAND_NOTHING;
809#endif
810 }
811 if (wim_index < 3)
812 ++wim_index;
813 if (c == ESC)
814 gotesc = TRUE;
815 if (res == OK)
816 goto cmdline_changed;
817 }
818
819 gotesc = FALSE;
820
821 /* <S-Tab> goes to last match, in a clumsy way */
822 if (c == K_S_TAB && KeyTyped)
823 {
824 if (nextwild(&xpc, WILD_EXPAND_KEEP, 0) == OK
825 && nextwild(&xpc, WILD_PREV, 0) == OK
826 && nextwild(&xpc, WILD_PREV, 0) == OK)
827 goto cmdline_changed;
828 }
829
830 if (c == NUL || c == K_ZERO) /* NUL is stored as NL */
831 c = NL;
832
833 do_abbr = TRUE; /* default: check for abbreviation */
834
835 /*
836 * Big switch for a typed command line character.
837 */
838 switch (c)
839 {
840 case K_BS:
841 case Ctrl_H:
842 case K_DEL:
843 case K_KDEL:
844 case Ctrl_W:
845#ifdef FEAT_FKMAP
846 if (cmd_fkmap && c == K_BS)
847 c = K_DEL;
848#endif
849 if (c == K_KDEL)
850 c = K_DEL;
851
852 /*
853 * delete current character is the same as backspace on next
854 * character, except at end of line
855 */
856 if (c == K_DEL && ccline.cmdpos != ccline.cmdlen)
857 ++ccline.cmdpos;
858#ifdef FEAT_MBYTE
859 if (has_mbyte && c == K_DEL)
860 ccline.cmdpos += mb_off_next(ccline.cmdbuff,
861 ccline.cmdbuff + ccline.cmdpos);
862#endif
863 if (ccline.cmdpos > 0)
864 {
865 char_u *p;
866
867 j = ccline.cmdpos;
868 p = ccline.cmdbuff + j;
869#ifdef FEAT_MBYTE
870 if (has_mbyte)
871 {
872 p = mb_prevptr(ccline.cmdbuff, p);
873 if (c == Ctrl_W)
874 {
875 while (p > ccline.cmdbuff && vim_isspace(*p))
876 p = mb_prevptr(ccline.cmdbuff, p);
877 i = mb_get_class(p);
878 while (p > ccline.cmdbuff && mb_get_class(p) == i)
879 p = mb_prevptr(ccline.cmdbuff, p);
880 if (mb_get_class(p) != i)
881 p += (*mb_ptr2len_check)(p);
882 }
883 }
884 else
885#endif
886 if (c == Ctrl_W)
887 {
888 while (p > ccline.cmdbuff && vim_isspace(p[-1]))
889 --p;
890 i = vim_iswordc(p[-1]);
891 while (p > ccline.cmdbuff && !vim_isspace(p[-1])
892 && vim_iswordc(p[-1]) == i)
893 --p;
894 }
895 else
896 --p;
897 ccline.cmdpos = (int)(p - ccline.cmdbuff);
898 ccline.cmdlen -= j - ccline.cmdpos;
899 i = ccline.cmdpos;
900 while (i < ccline.cmdlen)
901 ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
902
903 /* Truncate at the end, required for multi-byte chars. */
904 ccline.cmdbuff[ccline.cmdlen] = NUL;
905 redrawcmd();
906 }
907 else if (ccline.cmdlen == 0 && c != Ctrl_W
908 && ccline.cmdprompt == NULL && indent == 0)
909 {
910 /* In ex and debug mode it doesn't make sense to return. */
911 if (exmode_active
912#ifdef FEAT_EVAL
913 || ccline.cmdfirstc == '>'
914#endif
915 )
916 goto cmdline_not_changed;
917
918 vim_free(ccline.cmdbuff); /* no commandline to return */
919 ccline.cmdbuff = NULL;
920 if (!cmd_silent)
921 {
922#ifdef FEAT_RIGHTLEFT
923 if (cmdmsg_rl)
924 msg_col = Columns;
925 else
926#endif
927 msg_col = 0;
928 msg_putchar(' '); /* delete ':' */
929 }
930 redraw_cmdline = TRUE;
931 goto returncmd; /* back to cmd mode */
932 }
933 goto cmdline_changed;
934
935 case K_INS:
936 case K_KINS:
937#ifdef FEAT_FKMAP
938 /* if Farsi mode set, we are in reverse insert mode -
939 Do not change the mode */
940 if (cmd_fkmap)
941 beep_flush();
942 else
943#endif
944 ccline.overstrike = !ccline.overstrike;
945#ifdef CURSOR_SHAPE
946 ui_cursor_shape(); /* may show different cursor shape */
947#endif
948 goto cmdline_not_changed;
949
950 case Ctrl_HAT:
951 if (map_to_exists_mode((char_u *)"", LANGMAP))
952 {
953 /* ":lmap" mappings exists, toggle use of mappings. */
954 State ^= LANGMAP;
955#ifdef USE_IM_CONTROL
956 im_set_active(FALSE); /* Disable input method */
957#endif
958 if (b_im_ptr != NULL)
959 {
960 if (State & LANGMAP)
961 *b_im_ptr = B_IMODE_LMAP;
962 else
963 *b_im_ptr = B_IMODE_NONE;
964 }
965 }
966#ifdef USE_IM_CONTROL
967 else
968 {
969 /* There are no ":lmap" mappings, toggle IM. When
970 * 'imdisable' is set don't try getting the status, it's
971 * always off. */
972 if ((p_imdisable && b_im_ptr != NULL)
973 ? *b_im_ptr == B_IMODE_IM : im_get_status())
974 {
975 im_set_active(FALSE); /* Disable input method */
976 if (b_im_ptr != NULL)
977 *b_im_ptr = B_IMODE_NONE;
978 }
979 else
980 {
981 im_set_active(TRUE); /* Enable input method */
982 if (b_im_ptr != NULL)
983 *b_im_ptr = B_IMODE_IM;
984 }
985 }
986#endif
987 if (b_im_ptr != NULL)
988 {
989 if (b_im_ptr == &curbuf->b_p_iminsert)
990 set_iminsert_global();
991 else
992 set_imsearch_global();
993 }
994#ifdef CURSOR_SHAPE
995 ui_cursor_shape(); /* may show different cursor shape */
996#endif
997#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
998 /* Show/unshow value of 'keymap' in status lines later. */
999 status_redraw_curbuf();
1000#endif
1001 goto cmdline_not_changed;
1002
1003/* case '@': only in very old vi */
1004 case Ctrl_U:
1005 /* delete all characters left of the cursor */
1006 j = ccline.cmdpos;
1007 ccline.cmdlen -= j;
1008 i = ccline.cmdpos = 0;
1009 while (i < ccline.cmdlen)
1010 ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
1011 /* Truncate at the end, required for multi-byte chars. */
1012 ccline.cmdbuff[ccline.cmdlen] = NUL;
1013 redrawcmd();
1014 goto cmdline_changed;
1015
1016#ifdef FEAT_CLIPBOARD
1017 case Ctrl_Y:
1018 /* Copy the modeless selection, if there is one. */
1019 if (clip_star.state != SELECT_CLEARED)
1020 {
1021 if (clip_star.state == SELECT_DONE)
1022 clip_copy_modeless_selection(TRUE);
1023 goto cmdline_not_changed;
1024 }
1025 break;
1026#endif
1027
1028 case ESC: /* get here if p_wc != ESC or when ESC typed twice */
1029 case Ctrl_C:
Bram Moolenaar7c626922005-02-07 22:01:03 +00001030 /* In exmode it doesn't make sense to return. Except when
1031 * ":normal" runs out of characters. */
1032 if (exmode_active
1033#ifdef FEAT_EX_EXTRA
1034 && (ex_normal_busy == 0 || typebuf.tb_len > 0)
1035#endif
1036 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 goto cmdline_not_changed;
1038
1039 gotesc = TRUE; /* will free ccline.cmdbuff after
1040 putting it in history */
1041 goto returncmd; /* back to cmd mode */
1042
1043 case Ctrl_R: /* insert register */
1044#ifdef USE_ON_FLY_SCROLL
1045 dont_scroll = TRUE; /* disallow scrolling here */
1046#endif
1047 putcmdline('"', TRUE);
1048 ++no_mapping;
1049 i = c = safe_vgetc(); /* CTRL-R <char> */
1050 if (i == Ctrl_O)
1051 i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */
1052 if (i == Ctrl_R)
1053 c = safe_vgetc(); /* CTRL-R CTRL-R <char> */
1054 --no_mapping;
1055#ifdef FEAT_EVAL
1056 /*
1057 * Insert the result of an expression.
1058 * Need to save the current command line, to be able to enter
1059 * a new one...
1060 */
1061 new_cmdpos = -1;
1062 if (c == '=')
1063 {
1064 struct cmdline_info save_ccline;
1065
1066 if (ccline.cmdfirstc == '=')/* can't do this recursively */
1067 {
1068 beep_flush();
1069 c = ESC;
1070 }
1071 else
1072 {
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001073 save_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 c = get_expr_register();
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001075 restore_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 }
1077 }
1078#endif
1079 if (c != ESC) /* use ESC to cancel inserting register */
1080 {
1081 cmdline_paste(c, i == Ctrl_R);
1082 KeyTyped = FALSE; /* Don't do p_wc completion. */
1083#ifdef FEAT_EVAL
1084 if (new_cmdpos >= 0)
1085 {
1086 /* set_cmdline_pos() was used */
1087 if (new_cmdpos > ccline.cmdlen)
1088 ccline.cmdpos = ccline.cmdlen;
1089 else
1090 ccline.cmdpos = new_cmdpos;
1091 }
1092#endif
1093 }
1094 redrawcmd();
1095 goto cmdline_changed;
1096
1097 case Ctrl_D:
1098 if (showmatches(&xpc, FALSE) == EXPAND_NOTHING)
1099 break; /* Use ^D as normal char instead */
1100
1101 redrawcmd();
1102 continue; /* don't do incremental search now */
1103
1104 case K_RIGHT:
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001105 case K_XRIGHT:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 case K_S_RIGHT:
1107 case K_C_RIGHT:
1108 do
1109 {
1110 if (ccline.cmdpos >= ccline.cmdlen)
1111 break;
1112 i = cmdline_charsize(ccline.cmdpos);
1113 if (KeyTyped && ccline.cmdspos + i >= Columns * Rows)
1114 break;
1115 ccline.cmdspos += i;
1116#ifdef FEAT_MBYTE
1117 if (has_mbyte)
1118 ccline.cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff
1119 + ccline.cmdpos);
1120 else
1121#endif
1122 ++ccline.cmdpos;
1123 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001124 while ((c == K_S_RIGHT || c == K_C_RIGHT
1125 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 && ccline.cmdbuff[ccline.cmdpos] != ' ');
1127#ifdef FEAT_MBYTE
1128 if (has_mbyte)
1129 set_cmdspos_cursor();
1130#endif
1131 goto cmdline_not_changed;
1132
1133 case K_LEFT:
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001134 case K_XLEFT:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135 case K_S_LEFT:
1136 case K_C_LEFT:
1137 do
1138 {
1139 if (ccline.cmdpos == 0)
1140 break;
1141 --ccline.cmdpos;
1142#ifdef FEAT_MBYTE
1143 if (has_mbyte) /* move to first byte of char */
1144 ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff,
1145 ccline.cmdbuff + ccline.cmdpos);
1146#endif
1147 ccline.cmdspos -= cmdline_charsize(ccline.cmdpos);
1148 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001149 while ((c == K_S_LEFT || c == K_C_LEFT
1150 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 && ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
1152#ifdef FEAT_MBYTE
1153 if (has_mbyte)
1154 set_cmdspos_cursor();
1155#endif
1156 goto cmdline_not_changed;
1157
1158 case K_IGNORE:
1159 goto cmdline_not_changed; /* Ignore mouse */
1160
1161#ifdef FEAT_MOUSE
1162 case K_MIDDLEDRAG:
1163 case K_MIDDLERELEASE:
1164 goto cmdline_not_changed; /* Ignore mouse */
1165
1166 case K_MIDDLEMOUSE:
1167# ifdef FEAT_GUI
1168 /* When GUI is active, also paste when 'mouse' is empty */
1169 if (!gui.in_use)
1170# endif
1171 if (!mouse_has(MOUSE_COMMAND))
1172 goto cmdline_not_changed; /* Ignore mouse */
1173#ifdef FEAT_CLIPBOARD
1174 if (clip_star.available)
1175 cmdline_paste('*', TRUE);
1176 else
1177#endif
1178 cmdline_paste(0, TRUE);
1179 redrawcmd();
1180 goto cmdline_changed;
1181
1182#ifdef FEAT_DND
1183 case K_DROP:
1184 cmdline_paste('~', TRUE);
1185 redrawcmd();
1186 goto cmdline_changed;
1187#endif
1188
1189 case K_LEFTDRAG:
1190 case K_LEFTRELEASE:
1191 case K_RIGHTDRAG:
1192 case K_RIGHTRELEASE:
1193 /* Ignore drag and release events when the button-down wasn't
1194 * seen before. */
1195 if (ignore_drag_release)
1196 goto cmdline_not_changed;
1197 /* FALLTHROUGH */
1198 case K_LEFTMOUSE:
1199 case K_RIGHTMOUSE:
1200 if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
1201 ignore_drag_release = TRUE;
1202 else
1203 ignore_drag_release = FALSE;
1204# ifdef FEAT_GUI
1205 /* When GUI is active, also move when 'mouse' is empty */
1206 if (!gui.in_use)
1207# endif
1208 if (!mouse_has(MOUSE_COMMAND))
1209 goto cmdline_not_changed; /* Ignore mouse */
1210# ifdef FEAT_CLIPBOARD
1211 if (mouse_row < cmdline_row && clip_star.available)
1212 {
1213 int button, is_click, is_drag;
1214
1215 /*
1216 * Handle modeless selection.
1217 */
1218 button = get_mouse_button(KEY2TERMCAP1(c),
1219 &is_click, &is_drag);
1220 if (mouse_model_popup() && button == MOUSE_LEFT
1221 && (mod_mask & MOD_MASK_SHIFT))
1222 {
1223 /* Translate shift-left to right button. */
1224 button = MOUSE_RIGHT;
1225 mod_mask &= ~MOD_MASK_SHIFT;
1226 }
1227 clip_modeless(button, is_click, is_drag);
1228 goto cmdline_not_changed;
1229 }
1230# endif
1231
1232 set_cmdspos();
1233 for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
1234 ++ccline.cmdpos)
1235 {
1236 i = cmdline_charsize(ccline.cmdpos);
1237 if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
1238 && mouse_col < ccline.cmdspos % Columns + i)
1239 break;
1240#ifdef FEAT_MBYTE
1241 if (has_mbyte)
1242 {
1243 /* Count ">" for double-wide char that doesn't fit. */
1244 correct_cmdspos(ccline.cmdpos, i);
1245 ccline.cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff
1246 + ccline.cmdpos) - 1;
1247 }
1248#endif
1249 ccline.cmdspos += i;
1250 }
1251 goto cmdline_not_changed;
1252
1253 /* Mouse scroll wheel: ignored here */
1254 case K_MOUSEDOWN:
1255 case K_MOUSEUP:
1256 /* Alternate buttons ignored here */
1257 case K_X1MOUSE:
1258 case K_X1DRAG:
1259 case K_X1RELEASE:
1260 case K_X2MOUSE:
1261 case K_X2DRAG:
1262 case K_X2RELEASE:
1263 goto cmdline_not_changed;
1264
1265#endif /* FEAT_MOUSE */
1266
1267#ifdef FEAT_GUI
1268 case K_LEFTMOUSE_NM: /* mousefocus click, ignored */
1269 case K_LEFTRELEASE_NM:
1270 goto cmdline_not_changed;
1271
1272 case K_VER_SCROLLBAR:
1273 if (!msg_scrolled)
1274 {
1275 gui_do_scroll();
1276 redrawcmd();
1277 }
1278 goto cmdline_not_changed;
1279
1280 case K_HOR_SCROLLBAR:
1281 if (!msg_scrolled)
1282 {
1283 gui_do_horiz_scroll();
1284 redrawcmd();
1285 }
1286 goto cmdline_not_changed;
1287#endif
1288 case K_SELECT: /* end of Select mode mapping - ignore */
1289 goto cmdline_not_changed;
1290
1291 case Ctrl_B: /* begin of command line */
1292 case K_HOME:
1293 case K_KHOME:
1294 case K_XHOME:
1295 case K_S_HOME:
1296 case K_C_HOME:
1297 ccline.cmdpos = 0;
1298 set_cmdspos();
1299 goto cmdline_not_changed;
1300
1301 case Ctrl_E: /* end of command line */
1302 case K_END:
1303 case K_KEND:
1304 case K_XEND:
1305 case K_S_END:
1306 case K_C_END:
1307 ccline.cmdpos = ccline.cmdlen;
1308 set_cmdspos_cursor();
1309 goto cmdline_not_changed;
1310
1311 case Ctrl_A: /* all matches */
1312 if (nextwild(&xpc, WILD_ALL, 0) == FAIL)
1313 break;
1314 goto cmdline_changed;
1315
1316 case Ctrl_L: /* longest common part */
1317 if (nextwild(&xpc, WILD_LONGEST, 0) == FAIL)
1318 break;
1319 goto cmdline_changed;
1320
1321 case Ctrl_N: /* next match */
1322 case Ctrl_P: /* previous match */
1323 if (xpc.xp_numfiles > 0)
1324 {
1325 if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT, 0)
1326 == FAIL)
1327 break;
1328 goto cmdline_changed;
1329 }
1330
1331#ifdef FEAT_CMDHIST
1332 case K_UP:
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001333 case K_XUP:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334 case K_DOWN:
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001335 case K_XDOWN:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 case K_S_UP:
1337 case K_S_DOWN:
1338 case K_PAGEUP:
1339 case K_KPAGEUP:
1340 case K_PAGEDOWN:
1341 case K_KPAGEDOWN:
1342 if (hislen == 0 || firstc == NUL) /* no history */
1343 goto cmdline_not_changed;
1344
1345 i = hiscnt;
1346
1347 /* save current command string so it can be restored later */
1348 if (lookfor == NULL)
1349 {
1350 if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL)
1351 goto cmdline_not_changed;
1352 lookfor[ccline.cmdpos] = NUL;
1353 }
1354
1355 j = (int)STRLEN(lookfor);
1356 for (;;)
1357 {
1358 /* one step backwards */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001359 if (c == K_UP || c == K_XUP || c == K_S_UP || c == Ctrl_P
1360 || c == K_PAGEUP || c == K_KPAGEUP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361 {
1362 if (hiscnt == hislen) /* first time */
1363 hiscnt = hisidx[histype];
1364 else if (hiscnt == 0 && hisidx[histype] != hislen - 1)
1365 hiscnt = hislen - 1;
1366 else if (hiscnt != hisidx[histype] + 1)
1367 --hiscnt;
1368 else /* at top of list */
1369 {
1370 hiscnt = i;
1371 break;
1372 }
1373 }
1374 else /* one step forwards */
1375 {
1376 /* on last entry, clear the line */
1377 if (hiscnt == hisidx[histype])
1378 {
1379 hiscnt = hislen;
1380 break;
1381 }
1382
1383 /* not on a history line, nothing to do */
1384 if (hiscnt == hislen)
1385 break;
1386 if (hiscnt == hislen - 1) /* wrap around */
1387 hiscnt = 0;
1388 else
1389 ++hiscnt;
1390 }
1391 if (hiscnt < 0 || history[histype][hiscnt].hisstr == NULL)
1392 {
1393 hiscnt = i;
1394 break;
1395 }
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001396 if ((c != K_UP && c != K_DOWN && c != K_XUP && c != K_XDOWN)
1397 || hiscnt == i
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 || STRNCMP(history[histype][hiscnt].hisstr,
1399 lookfor, (size_t)j) == 0)
1400 break;
1401 }
1402
1403 if (hiscnt != i) /* jumped to other entry */
1404 {
1405 char_u *p;
1406 int len;
1407 int old_firstc;
1408
1409 vim_free(ccline.cmdbuff);
1410 if (hiscnt == hislen)
1411 p = lookfor; /* back to the old one */
1412 else
1413 p = history[histype][hiscnt].hisstr;
1414
1415 if (histype == HIST_SEARCH
1416 && p != lookfor
1417 && (old_firstc = p[STRLEN(p) + 1]) != firstc)
1418 {
1419 /* Correct for the separator character used when
1420 * adding the history entry vs the one used now.
1421 * First loop: count length.
1422 * Second loop: copy the characters. */
1423 for (i = 0; i <= 1; ++i)
1424 {
1425 len = 0;
1426 for (j = 0; p[j] != NUL; ++j)
1427 {
1428 /* Replace old sep with new sep, unless it is
1429 * escaped. */
1430 if (p[j] == old_firstc
1431 && (j == 0 || p[j - 1] != '\\'))
1432 {
1433 if (i > 0)
1434 ccline.cmdbuff[len] = firstc;
1435 }
1436 else
1437 {
1438 /* Escape new sep, unless it is already
1439 * escaped. */
1440 if (p[j] == firstc
1441 && (j == 0 || p[j - 1] != '\\'))
1442 {
1443 if (i > 0)
1444 ccline.cmdbuff[len] = '\\';
1445 ++len;
1446 }
1447 if (i > 0)
1448 ccline.cmdbuff[len] = p[j];
1449 }
1450 ++len;
1451 }
1452 if (i == 0)
1453 {
1454 alloc_cmdbuff(len);
1455 if (ccline.cmdbuff == NULL)
1456 goto returncmd;
1457 }
1458 }
1459 ccline.cmdbuff[len] = NUL;
1460 }
1461 else
1462 {
1463 alloc_cmdbuff((int)STRLEN(p));
1464 if (ccline.cmdbuff == NULL)
1465 goto returncmd;
1466 STRCPY(ccline.cmdbuff, p);
1467 }
1468
1469 ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
1470 redrawcmd();
1471 goto cmdline_changed;
1472 }
1473 beep_flush();
1474 goto cmdline_not_changed;
1475#endif
1476
1477 case Ctrl_V:
1478 case Ctrl_Q:
1479#ifdef FEAT_MOUSE
1480 ignore_drag_release = TRUE;
1481#endif
1482 putcmdline('^', TRUE);
1483 c = get_literal(); /* get next (two) character(s) */
1484 do_abbr = FALSE; /* don't do abbreviation now */
1485#ifdef FEAT_MBYTE
1486 /* may need to remove ^ when composing char was typed */
1487 if (enc_utf8 && utf_iscomposing(c) && !cmd_silent)
1488 {
1489 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
1490 msg_putchar(' ');
1491 cursorcmd();
1492 }
1493#endif
1494 break;
1495
1496#ifdef FEAT_DIGRAPHS
1497 case Ctrl_K:
1498#ifdef FEAT_MOUSE
1499 ignore_drag_release = TRUE;
1500#endif
1501 putcmdline('?', TRUE);
1502#ifdef USE_ON_FLY_SCROLL
1503 dont_scroll = TRUE; /* disallow scrolling here */
1504#endif
1505 c = get_digraph(TRUE);
1506 if (c != NUL)
1507 break;
1508
1509 redrawcmd();
1510 goto cmdline_not_changed;
1511#endif /* FEAT_DIGRAPHS */
1512
1513#ifdef FEAT_RIGHTLEFT
1514 case Ctrl__: /* CTRL-_: switch language mode */
1515 if (!p_ari)
1516 break;
1517#ifdef FEAT_FKMAP
1518 if (p_altkeymap)
1519 {
1520 cmd_fkmap = !cmd_fkmap;
1521 if (cmd_fkmap) /* in Farsi always in Insert mode */
1522 ccline.overstrike = FALSE;
1523 }
1524 else /* Hebrew is default */
1525#endif
1526 cmd_hkmap = !cmd_hkmap;
1527 goto cmdline_not_changed;
1528#endif
1529
1530 default:
1531#ifdef UNIX
1532 if (c == intr_char)
1533 {
1534 gotesc = TRUE; /* will free ccline.cmdbuff after
1535 putting it in history */
1536 goto returncmd; /* back to Normal mode */
1537 }
1538#endif
1539 /*
1540 * Normal character with no special meaning. Just set mod_mask
1541 * to 0x0 so that typing Shift-Space in the GUI doesn't enter
1542 * the string <S-Space>. This should only happen after ^V.
1543 */
1544 if (!IS_SPECIAL(c))
1545 mod_mask = 0x0;
1546 break;
1547 }
1548 /*
1549 * End of switch on command line character.
1550 * We come here if we have a normal character.
1551 */
1552
1553 if (do_abbr && (IS_SPECIAL(c) || !vim_iswordc(c)) && ccheck_abbr(
1554#ifdef FEAT_MBYTE
1555 /* Add ABBR_OFF for characters above 0x100, this is
1556 * what check_abbr() expects. */
1557 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) :
1558#endif
1559 c))
1560 goto cmdline_changed;
1561
1562 /*
1563 * put the character in the command line
1564 */
1565 if (IS_SPECIAL(c) || mod_mask != 0)
1566 put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
1567 else
1568 {
1569#ifdef FEAT_MBYTE
1570 if (has_mbyte)
1571 {
1572 j = (*mb_char2bytes)(c, IObuff);
1573 IObuff[j] = NUL; /* exclude composing chars */
1574 put_on_cmdline(IObuff, j, TRUE);
1575 }
1576 else
1577#endif
1578 {
1579 IObuff[0] = c;
1580 put_on_cmdline(IObuff, 1, TRUE);
1581 }
1582 }
1583 goto cmdline_changed;
1584
1585/*
1586 * This part implements incremental searches for "/" and "?"
1587 * Jump to cmdline_not_changed when a character has been read but the command
1588 * line did not change. Then we only search and redraw if something changed in
1589 * the past.
1590 * Jump to cmdline_changed when the command line did change.
1591 * (Sorry for the goto's, I know it is ugly).
1592 */
1593cmdline_not_changed:
1594#ifdef FEAT_SEARCH_EXTRA
1595 if (!incsearch_postponed)
1596 continue;
1597#endif
1598
1599cmdline_changed:
1600#ifdef FEAT_SEARCH_EXTRA
1601 /*
1602 * 'incsearch' highlighting.
1603 */
1604 if (p_is && !cmd_silent && (firstc == '/' || firstc == '?'))
1605 {
1606 /* if there is a character waiting, search and redraw later */
1607 if (char_avail())
1608 {
1609 incsearch_postponed = TRUE;
1610 continue;
1611 }
1612 incsearch_postponed = FALSE;
1613 curwin->w_cursor = old_cursor; /* start at old position */
1614
1615 /* If there is no command line, don't do anything */
1616 if (ccline.cmdlen == 0)
1617 i = 0;
1618 else
1619 {
1620 cursor_off(); /* so the user knows we're busy */
1621 out_flush();
1622 ++emsg_off; /* So it doesn't beep if bad expr */
1623 i = do_search(NULL, firstc, ccline.cmdbuff, count,
1624 SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK);
1625 --emsg_off;
1626 /* if interrupted while searching, behave like it failed */
1627 if (got_int)
1628 {
1629 (void)vpeekc(); /* remove <C-C> from input stream */
1630 got_int = FALSE; /* don't abandon the command line */
1631 i = 0;
1632 }
1633 else if (char_avail())
1634 /* cancelled searching because a char was typed */
1635 incsearch_postponed = TRUE;
1636 }
1637 if (i)
1638 highlight_match = TRUE; /* highlight position */
1639 else
1640 highlight_match = FALSE; /* remove highlight */
1641
1642 /* first restore the old curwin values, so the screen is
1643 * positioned in the same way as the actual search command */
1644 curwin->w_leftcol = old_leftcol;
1645 curwin->w_topline = old_topline;
1646# ifdef FEAT_DIFF
1647 curwin->w_topfill = old_topfill;
1648# endif
1649 curwin->w_botline = old_botline;
1650 changed_cline_bef_curs();
1651 update_topline();
1652
1653 if (i != 0)
1654 {
1655 /*
1656 * First move cursor to end of match, then to start. This
1657 * moves the whole match onto the screen when 'nowrap' is set.
1658 */
1659 i = curwin->w_cursor.col;
1660 curwin->w_cursor.lnum += search_match_lines;
1661 curwin->w_cursor.col = search_match_endcol;
1662 validate_cursor();
1663 curwin->w_cursor.lnum -= search_match_lines;
1664 curwin->w_cursor.col = i;
1665 }
1666 validate_cursor();
1667
1668 update_screen(NOT_VALID);
1669 msg_starthere();
1670 redrawcmdline();
1671 did_incsearch = TRUE;
1672 }
1673#else /* FEAT_SEARCH_EXTRA */
1674 ;
1675#endif
1676
1677#ifdef FEAT_RIGHTLEFT
1678 if (cmdmsg_rl
1679# ifdef FEAT_ARABIC
1680 || p_arshape
1681# endif
1682 )
1683 /* Always redraw the whole command line to fix shaping and
1684 * right-left typing. Not efficient, but it works. */
1685 redrawcmd();
1686#endif
1687 }
1688
1689returncmd:
1690
1691#ifdef FEAT_RIGHTLEFT
1692 cmdmsg_rl = FALSE;
1693#endif
1694
1695#ifdef FEAT_FKMAP
1696 cmd_fkmap = 0;
1697#endif
1698
1699 ExpandCleanup(&xpc);
1700
1701#ifdef FEAT_SEARCH_EXTRA
1702 if (did_incsearch)
1703 {
1704 curwin->w_cursor = old_cursor;
1705 curwin->w_curswant = old_curswant;
1706 curwin->w_leftcol = old_leftcol;
1707 curwin->w_topline = old_topline;
1708# ifdef FEAT_DIFF
1709 curwin->w_topfill = old_topfill;
1710# endif
1711 curwin->w_botline = old_botline;
1712 highlight_match = FALSE;
1713 validate_cursor(); /* needed for TAB */
1714 redraw_later(NOT_VALID);
1715 }
1716#endif
1717
1718 if (ccline.cmdbuff != NULL)
1719 {
1720 /*
1721 * Put line in history buffer (":" and "=" only when it was typed).
1722 */
1723#ifdef FEAT_CMDHIST
1724 if (ccline.cmdlen && firstc != NUL
1725 && (some_key_typed || histype == HIST_SEARCH))
1726 {
1727 add_to_history(histype, ccline.cmdbuff, TRUE,
1728 histype == HIST_SEARCH ? firstc : NUL);
1729 if (firstc == ':')
1730 {
1731 vim_free(new_last_cmdline);
1732 new_last_cmdline = vim_strsave(ccline.cmdbuff);
1733 }
1734 }
1735#endif
1736
1737 if (gotesc) /* abandon command line */
1738 {
1739 vim_free(ccline.cmdbuff);
1740 ccline.cmdbuff = NULL;
1741 if (msg_scrolled == 0)
1742 compute_cmdrow();
1743 MSG("");
1744 redraw_cmdline = TRUE;
1745 }
1746 }
1747
1748 /*
1749 * If the screen was shifted up, redraw the whole screen (later).
1750 * If the line is too long, clear it, so ruler and shown command do
1751 * not get printed in the middle of it.
1752 */
1753 msg_check();
1754 msg_scroll = save_msg_scroll;
1755 redir_off = FALSE;
1756
1757 /* When the command line was typed, no need for a wait-return prompt. */
1758 if (some_key_typed)
1759 need_wait_return = FALSE;
1760
1761 State = save_State;
1762#ifdef USE_IM_CONTROL
1763 if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP)
1764 im_save_status(b_im_ptr);
1765 im_set_active(FALSE);
1766#endif
1767#ifdef FEAT_MOUSE
1768 setmouse();
1769#endif
1770#ifdef CURSOR_SHAPE
1771 ui_cursor_shape(); /* may show different cursor shape */
1772#endif
1773
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001774 {
1775 char_u *p = ccline.cmdbuff;
1776
1777 /* Make ccline empty, getcmdline() may try to use it. */
1778 ccline.cmdbuff = NULL;
1779 return p;
1780 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781}
1782
1783#if (defined(FEAT_CRYPT) || defined(FEAT_EVAL)) || defined(PROTO)
1784/*
1785 * Get a command line with a prompt.
1786 * This is prepared to be called recursively from getcmdline() (e.g. by
1787 * f_input() when evaluating an expression from CTRL-R =).
1788 * Returns the command line in allocated memory, or NULL.
1789 */
1790 char_u *
1791getcmdline_prompt(firstc, prompt, attr)
1792 int firstc;
1793 char_u *prompt; /* command line prompt */
1794 int attr; /* attributes for prompt */
1795{
1796 char_u *s;
1797 struct cmdline_info save_ccline;
1798 int msg_col_save = msg_col;
1799
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001800 save_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 ccline.cmdprompt = prompt;
1802 ccline.cmdattr = attr;
1803 s = getcmdline(firstc, 1L, 0);
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00001804 restore_cmdline(&save_ccline);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805 /* Restore msg_col, the prompt from input() may have changed it. */
1806 msg_col = msg_col_save;
1807
1808 return s;
1809}
1810#endif
1811
1812 static int
1813cmdline_charsize(idx)
1814 int idx;
1815{
1816#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
1817 if (cmdline_star > 0) /* showing '*', always 1 position */
1818 return 1;
1819#endif
1820 return ptr2cells(ccline.cmdbuff + idx);
1821}
1822
1823/*
1824 * Compute the offset of the cursor on the command line for the prompt and
1825 * indent.
1826 */
1827 static void
1828set_cmdspos()
1829{
1830 if (ccline.cmdfirstc)
1831 ccline.cmdspos = 1 + ccline.cmdindent;
1832 else
1833 ccline.cmdspos = 0 + ccline.cmdindent;
1834}
1835
1836/*
1837 * Compute the screen position for the cursor on the command line.
1838 */
1839 static void
1840set_cmdspos_cursor()
1841{
1842 int i, m, c;
1843
1844 set_cmdspos();
1845 if (KeyTyped)
1846 m = Columns * Rows;
1847 else
1848 m = MAXCOL;
1849 for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i)
1850 {
1851 c = cmdline_charsize(i);
1852#ifdef FEAT_MBYTE
1853 /* Count ">" for double-wide multi-byte char that doesn't fit. */
1854 if (has_mbyte)
1855 correct_cmdspos(i, c);
1856#endif
1857 /* If the cmdline doesn't fit, put cursor on last visible char. */
1858 if ((ccline.cmdspos += c) >= m)
1859 {
1860 ccline.cmdpos = i - 1;
1861 ccline.cmdspos -= c;
1862 break;
1863 }
1864#ifdef FEAT_MBYTE
1865 if (has_mbyte)
1866 i += (*mb_ptr2len_check)(ccline.cmdbuff + i) - 1;
1867#endif
1868 }
1869}
1870
1871#ifdef FEAT_MBYTE
1872/*
1873 * Check if the character at "idx", which is "cells" wide, is a multi-byte
1874 * character that doesn't fit, so that a ">" must be displayed.
1875 */
1876 static void
1877correct_cmdspos(idx, cells)
1878 int idx;
1879 int cells;
1880{
1881 if ((*mb_ptr2len_check)(ccline.cmdbuff + idx) > 1
1882 && (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1
1883 && ccline.cmdspos % Columns + cells > Columns)
1884 ccline.cmdspos++;
1885}
1886#endif
1887
1888/*
1889 * Get an Ex command line for the ":" command.
1890 */
1891/* ARGSUSED */
1892 char_u *
1893getexline(c, dummy, indent)
1894 int c; /* normally ':', NUL for ":append" */
1895 void *dummy; /* cookie not used */
1896 int indent; /* indent for inside conditionals */
1897{
1898 /* When executing a register, remove ':' that's in front of each line. */
1899 if (exec_from_reg && vpeekc() == ':')
1900 (void)vgetc();
1901 return getcmdline(c, 1L, indent);
1902}
1903
1904/*
1905 * Get an Ex command line for Ex mode.
1906 * In Ex mode we only use the OS supplied line editing features and no
1907 * mappings or abbreviations.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001908 * Returns a string in allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 */
1910/* ARGSUSED */
1911 char_u *
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001912getexmodeline(promptc, dummy, indent)
1913 int promptc; /* normally ':', NUL for ":append" and '?' for
1914 :s prompt */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 void *dummy; /* cookie not used */
1916 int indent; /* indent for inside conditionals */
1917{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001918 garray_T line_ga;
1919 char_u *pend;
1920 int startcol = 0;
1921 int c1;
1922 int escaped = FALSE; /* CTRL-V typed */
1923 int vcol = 0;
1924 char_u *p;
1925 int prev_char = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926
1927 /* Switch cursor on now. This avoids that it happens after the "\n", which
1928 * confuses the system function that computes tabstops. */
1929 cursor_on();
1930
1931 /* always start in column 0; write a newline if necessary */
1932 compute_cmdrow();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001933 if ((msg_col || msg_didout) && promptc != '?')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 msg_putchar('\n');
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001935 if (promptc == ':')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001937 /* indent that is only displayed, not in the line itself */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001938 if (p_prompt)
1939 msg_putchar(':');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 while (indent-- > 0)
1941 msg_putchar(' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 startcol = msg_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 }
1944
1945 ga_init2(&line_ga, 1, 30);
1946
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001947 /* autoindent for :insert and :append is in the line itself */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001948 if (promptc <= 0)
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001949 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001950 vcol = indent;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001951 while (indent >= 8)
1952 {
1953 ga_append(&line_ga, TAB);
1954 msg_puts((char_u *)" ");
1955 indent -= 8;
1956 }
1957 while (indent-- > 0)
1958 {
1959 ga_append(&line_ga, ' ');
1960 msg_putchar(' ');
1961 }
1962 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001963 ++no_mapping;
1964 ++allow_keys;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001965
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 /*
1967 * Get the line, one character at a time.
1968 */
1969 got_int = FALSE;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001970 while (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 {
1972 if (ga_grow(&line_ga, 40) == FAIL)
1973 break;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001974 pend = (char_u *)line_ga.ga_data + line_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001976 /* Get one character at a time. Don't use inchar(), it can't handle
1977 * special characters. */
1978 c1 = vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979
1980 /*
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001981 * Handle line editing.
1982 * Previously this was left to the system, putting the terminal in
1983 * cooked mode, but then CTRL-D and CTRL-T can't be used properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001985 if (got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001987 msg_putchar('\n');
1988 break;
1989 }
1990
1991 if (!escaped)
1992 {
1993 /* CR typed means "enter", which is NL */
1994 if (c1 == '\r')
1995 c1 = '\n';
1996
1997 if (c1 == BS || c1 == K_BS
1998 || c1 == DEL || c1 == K_DEL || c1 == K_KDEL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002000 if (line_ga.ga_len > 0)
2001 {
2002 --line_ga.ga_len;
2003 goto redraw;
2004 }
2005 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 }
2007
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002008 if (c1 == Ctrl_U)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002010 msg_col = startcol;
2011 msg_clr_eos();
2012 line_ga.ga_len = 0;
2013 continue;
2014 }
2015
2016 if (c1 == Ctrl_T)
2017 {
2018 p = (char_u *)line_ga.ga_data;
2019 p[line_ga.ga_len] = NUL;
2020 indent = get_indent_str(p, 8);
2021 indent += curbuf->b_p_sw - indent % curbuf->b_p_sw;
2022add_indent:
2023 while (get_indent_str(p, 8) < indent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002025 char_u *s = skipwhite(p);
2026
2027 ga_grow(&line_ga, 1);
2028 mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1);
2029 *s = ' ';
2030 ++line_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002032redraw:
2033 /* redraw the line */
2034 msg_col = startcol;
2035 windgoto(msg_row, msg_col);
2036 vcol = 0;
2037 for (p = (char_u *)line_ga.ga_data;
2038 p < (char_u *)line_ga.ga_data + line_ga.ga_len; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002040 if (*p == TAB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002042 do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002044 msg_putchar(' ');
2045 } while (++vcol % 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002047 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002049 msg_outtrans_len(p, 1);
2050 vcol += char2cells(*p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 }
2052 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002053 msg_clr_eos();
2054 continue;
2055 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002056
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002057 if (c1 == Ctrl_D)
2058 {
2059 /* Delete one shiftwidth. */
2060 p = (char_u *)line_ga.ga_data;
2061 if (prev_char == '0' || prev_char == '^')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002063 if (prev_char == '^')
2064 ex_keep_indent = TRUE;
2065 indent = 0;
2066 p[--line_ga.ga_len] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067 }
2068 else
2069 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002070 p[line_ga.ga_len] = NUL;
2071 indent = get_indent_str(p, 8);
2072 --indent;
2073 indent -= indent % curbuf->b_p_sw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002075 while (get_indent_str(p, 8) > indent)
2076 {
2077 char_u *s = skipwhite(p);
2078
2079 mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1);
2080 --line_ga.ga_len;
2081 }
2082 goto add_indent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002084
2085 if (c1 == Ctrl_V || c1 == Ctrl_Q)
2086 {
2087 escaped = TRUE;
2088 continue;
2089 }
2090
2091 /* Ignore special key codes: mouse movement, K_IGNORE, etc. */
2092 if (IS_SPECIAL(c1))
2093 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002095
2096 if (IS_SPECIAL(c1))
2097 c1 = '?';
2098 ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
2099 prev_char = c1;
2100 if (c1 == '\n')
2101 msg_putchar('\n');
2102 else if (c1 == TAB)
2103 {
2104 /* Don't use chartabsize(), 'ts' can be different */
2105 do
2106 {
2107 msg_putchar(' ');
2108 } while (++vcol % 8);
2109 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002112 msg_outtrans_len(
2113 ((char_u *)line_ga.ga_data) + line_ga.ga_len, 1);
2114 vcol += char2cells(c1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002116 ++line_ga.ga_len;
2117 escaped = FALSE;
2118
2119 windgoto(msg_row, msg_col);
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002120 pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002121
2122 /* we are done when a NL is entered, but not when it comes after a
2123 * backslash */
2124 if (line_ga.ga_len > 0 && pend[-1] == '\n'
2125 && (line_ga.ga_len <= 1 || pend[-2] != '\\'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127 --line_ga.ga_len;
Bram Moolenaar4399ef42005-02-12 14:29:27 +00002128 --pend;
2129 *pend = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002130 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 }
2132 }
2133
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002134 --no_mapping;
2135 --allow_keys;
2136
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 /* make following messages go to the next line */
2138 msg_didout = FALSE;
2139 msg_col = 0;
2140 if (msg_row < Rows - 1)
2141 ++msg_row;
2142 emsg_on_display = FALSE; /* don't want ui_delay() */
2143
2144 if (got_int)
2145 ga_clear(&line_ga);
2146
2147 return (char_u *)line_ga.ga_data;
2148}
2149
2150#ifdef CURSOR_SHAPE
2151/*
2152 * Return TRUE if ccline.overstrike is on.
2153 */
2154 int
2155cmdline_overstrike()
2156{
2157 return ccline.overstrike;
2158}
2159
2160/*
2161 * Return TRUE if the cursor is at the end of the cmdline.
2162 */
2163 int
2164cmdline_at_end()
2165{
2166 return (ccline.cmdpos >= ccline.cmdlen);
2167}
2168#endif
2169
Bram Moolenaar81695252004-12-29 20:58:21 +00002170#if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE))) \
2171 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172/*
2173 * Return the virtual column number at the current cursor position.
2174 * This is used by the IM code to obtain the start of the preedit string.
2175 */
2176 colnr_T
2177cmdline_getvcol_cursor()
2178{
2179 if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen)
2180 return MAXCOL;
2181
2182# ifdef FEAT_MBYTE
2183 if (has_mbyte)
2184 {
2185 colnr_T col;
2186 int i = 0;
2187
2188 for (col = 0; i < ccline.cmdpos; ++col)
2189 i += (*mb_ptr2len_check)(ccline.cmdbuff + i);
2190
2191 return col;
2192 }
2193 else
2194# endif
2195 return ccline.cmdpos;
2196}
2197#endif
2198
2199#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2200/*
2201 * If part of the command line is an IM preedit string, redraw it with
2202 * IM feedback attributes. The cursor position is restored after drawing.
2203 */
2204 static void
2205redrawcmd_preedit()
2206{
2207 if ((State & CMDLINE)
2208 && xic != NULL
2209 && im_get_status()
2210 && !p_imdisable
2211 && im_is_preediting())
2212 {
2213 int cmdpos = 0;
2214 int cmdspos;
2215 int old_row;
2216 int old_col;
2217 colnr_T col;
2218
2219 old_row = msg_row;
2220 old_col = msg_col;
2221 cmdspos = ((ccline.cmdfirstc) ? 1 : 0) + ccline.cmdindent;
2222
2223# ifdef FEAT_MBYTE
2224 if (has_mbyte)
2225 {
2226 for (col = 0; col < preedit_start_col
2227 && cmdpos < ccline.cmdlen; ++col)
2228 {
2229 cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos);
2230 cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff + cmdpos);
2231 }
2232 }
2233 else
2234# endif
2235 {
2236 cmdspos += preedit_start_col;
2237 cmdpos += preedit_start_col;
2238 }
2239
2240 msg_row = cmdline_row + (cmdspos / (int)Columns);
2241 msg_col = cmdspos % (int)Columns;
2242 if (msg_row >= Rows)
2243 msg_row = Rows - 1;
2244
2245 for (col = 0; cmdpos < ccline.cmdlen; ++col)
2246 {
2247 int char_len;
2248 int char_attr;
2249
2250 char_attr = im_get_feedback_attr(col);
2251 if (char_attr < 0)
2252 break; /* end of preedit string */
2253
2254# ifdef FEAT_MBYTE
2255 if (has_mbyte)
2256 char_len = (*mb_ptr2len_check)(ccline.cmdbuff + cmdpos);
2257 else
2258# endif
2259 char_len = 1;
2260
2261 msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr);
2262 cmdpos += char_len;
2263 }
2264
2265 msg_row = old_row;
2266 msg_col = old_col;
2267 }
2268}
2269#endif /* FEAT_XIM && FEAT_GUI_GTK */
2270
2271/*
2272 * Allocate a new command line buffer.
2273 * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
2274 * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
2275 */
2276 static void
2277alloc_cmdbuff(len)
2278 int len;
2279{
2280 /*
2281 * give some extra space to avoid having to allocate all the time
2282 */
2283 if (len < 80)
2284 len = 100;
2285 else
2286 len += 20;
2287
2288 ccline.cmdbuff = alloc(len); /* caller should check for out-of-memory */
2289 ccline.cmdbufflen = len;
2290}
2291
2292/*
2293 * Re-allocate the command line to length len + something extra.
2294 * return FAIL for failure, OK otherwise
2295 */
2296 static int
2297realloc_cmdbuff(len)
2298 int len;
2299{
2300 char_u *p;
2301
2302 p = ccline.cmdbuff;
2303 alloc_cmdbuff(len); /* will get some more */
2304 if (ccline.cmdbuff == NULL) /* out of memory */
2305 {
2306 ccline.cmdbuff = p; /* keep the old one */
2307 return FAIL;
2308 }
2309 mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen + 1);
2310 vim_free(p);
2311 return OK;
2312}
2313
2314/*
2315 * Draw part of the cmdline at the current cursor position. But draw stars
2316 * when cmdline_star is TRUE.
2317 */
2318 static void
2319draw_cmdline(start, len)
2320 int start;
2321 int len;
2322{
2323#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
2324 int i;
2325
2326 if (cmdline_star > 0)
2327 for (i = 0; i < len; ++i)
2328 {
2329 msg_putchar('*');
2330# ifdef FEAT_MBYTE
2331 if (has_mbyte)
2332 i += (*mb_ptr2len_check)(ccline.cmdbuff + start + i) - 1;
2333# endif
2334 }
2335 else
2336#endif
2337#ifdef FEAT_ARABIC
2338 if (p_arshape && !p_tbidi && enc_utf8 && len > 0)
2339 {
2340 static char_u *buf;
2341 static int buflen = 0;
2342 char_u *p;
2343 int j;
2344 int newlen = 0;
2345 int mb_l;
2346 int pc, pc1;
2347 int prev_c = 0;
2348 int prev_c1 = 0;
2349 int u8c, u8c_c1, u8c_c2;
2350 int nc = 0;
2351 int dummy;
2352
2353 /*
2354 * Do arabic shaping into a temporary buffer. This is very
2355 * inefficient!
2356 */
2357 if (len * 2 > buflen)
2358 {
2359 /* Re-allocate the buffer. We keep it around to avoid a lot of
2360 * alloc()/free() calls. */
2361 vim_free(buf);
2362 buflen = len * 2;
2363 buf = alloc(buflen);
2364 if (buf == NULL)
2365 return; /* out of memory */
2366 }
2367
2368 for (j = start; j < start + len; j += mb_l)
2369 {
2370 p = ccline.cmdbuff + j;
2371 u8c = utfc_ptr2char_len(p, &u8c_c1, &u8c_c2, start + len - j);
2372 mb_l = utfc_ptr2len_check_len(p, start + len - j);
2373 if (ARABIC_CHAR(u8c))
2374 {
2375 /* Do Arabic shaping. */
2376 if (cmdmsg_rl)
2377 {
2378 /* displaying from right to left */
2379 pc = prev_c;
2380 pc1 = prev_c1;
2381 prev_c1 = u8c_c1;
2382 if (j + mb_l >= start + len)
2383 nc = NUL;
2384 else
2385 nc = utf_ptr2char(p + mb_l);
2386 }
2387 else
2388 {
2389 /* displaying from left to right */
2390 if (j + mb_l >= start + len)
2391 pc = NUL;
2392 else
2393 pc = utfc_ptr2char_len(p + mb_l, &pc1, &dummy,
2394 start + len - j - mb_l);
2395 nc = prev_c;
2396 }
2397 prev_c = u8c;
2398
2399 u8c = arabic_shape(u8c, NULL, &u8c_c1, pc, pc1, nc);
2400
2401 newlen += (*mb_char2bytes)(u8c, buf + newlen);
2402 if (u8c_c1 != 0)
2403 {
2404 newlen += (*mb_char2bytes)(u8c_c1, buf + newlen);
2405 if (u8c_c2 != 0)
2406 newlen += (*mb_char2bytes)(u8c_c2, buf + newlen);
2407 }
2408 }
2409 else
2410 {
2411 prev_c = u8c;
2412 mch_memmove(buf + newlen, p, mb_l);
2413 newlen += mb_l;
2414 }
2415 }
2416
2417 msg_outtrans_len(buf, newlen);
2418 }
2419 else
2420#endif
2421 msg_outtrans_len(ccline.cmdbuff + start, len);
2422}
2423
2424/*
2425 * Put a character on the command line. Shifts the following text to the
2426 * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
2427 * "c" must be printable (fit in one display cell)!
2428 */
2429 void
2430putcmdline(c, shift)
2431 int c;
2432 int shift;
2433{
2434 if (cmd_silent)
2435 return;
2436 msg_no_more = TRUE;
2437 msg_putchar(c);
2438 if (shift)
2439 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
2440 msg_no_more = FALSE;
2441 cursorcmd();
2442}
2443
2444/*
2445 * Undo a putcmdline(c, FALSE).
2446 */
2447 void
2448unputcmdline()
2449{
2450 if (cmd_silent)
2451 return;
2452 msg_no_more = TRUE;
2453 if (ccline.cmdlen == ccline.cmdpos)
2454 msg_putchar(' ');
2455 else
2456 draw_cmdline(ccline.cmdpos, 1);
2457 msg_no_more = FALSE;
2458 cursorcmd();
2459}
2460
2461/*
2462 * Put the given string, of the given length, onto the command line.
2463 * If len is -1, then STRLEN() is used to calculate the length.
2464 * If 'redraw' is TRUE then the new part of the command line, and the remaining
2465 * part will be redrawn, otherwise it will not. If this function is called
2466 * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
2467 * called afterwards.
2468 */
2469 int
2470put_on_cmdline(str, len, redraw)
2471 char_u *str;
2472 int len;
2473 int redraw;
2474{
2475 int retval;
2476 int i;
2477 int m;
2478 int c;
2479
2480 if (len < 0)
2481 len = (int)STRLEN(str);
2482
2483 /* Check if ccline.cmdbuff needs to be longer */
2484 if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen)
2485 retval = realloc_cmdbuff(ccline.cmdlen + len);
2486 else
2487 retval = OK;
2488 if (retval == OK)
2489 {
2490 if (!ccline.overstrike)
2491 {
2492 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
2493 ccline.cmdbuff + ccline.cmdpos,
2494 (size_t)(ccline.cmdlen - ccline.cmdpos));
2495 ccline.cmdlen += len;
2496 }
2497 else
2498 {
2499#ifdef FEAT_MBYTE
2500 if (has_mbyte)
2501 {
2502 /* Count nr of characters in the new string. */
2503 m = 0;
2504 for (i = 0; i < len; i += (*mb_ptr2len_check)(str + i))
2505 ++m;
2506 /* Count nr of bytes in cmdline that are overwritten by these
2507 * characters. */
2508 for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0;
2509 i += (*mb_ptr2len_check)(ccline.cmdbuff + i))
2510 --m;
2511 if (i < ccline.cmdlen)
2512 {
2513 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
2514 ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i));
2515 ccline.cmdlen += ccline.cmdpos + len - i;
2516 }
2517 else
2518 ccline.cmdlen = ccline.cmdpos + len;
2519 }
2520 else
2521#endif
2522 if (ccline.cmdpos + len > ccline.cmdlen)
2523 ccline.cmdlen = ccline.cmdpos + len;
2524 }
2525 mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
2526 ccline.cmdbuff[ccline.cmdlen] = NUL;
2527
2528#ifdef FEAT_MBYTE
2529 if (enc_utf8)
2530 {
2531 /* When the inserted text starts with a composing character,
2532 * backup to the character before it. There could be two of them.
2533 */
2534 i = 0;
2535 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
2536 while (ccline.cmdpos > 0 && utf_iscomposing(c))
2537 {
2538 i = (*mb_head_off)(ccline.cmdbuff,
2539 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
2540 ccline.cmdpos -= i;
2541 len += i;
2542 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
2543 }
2544# ifdef FEAT_ARABIC
2545 if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c))
2546 {
2547 /* Check the previous character for Arabic combining pair. */
2548 i = (*mb_head_off)(ccline.cmdbuff,
2549 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
2550 if (arabic_combine(utf_ptr2char(ccline.cmdbuff
2551 + ccline.cmdpos - i), c))
2552 {
2553 ccline.cmdpos -= i;
2554 len += i;
2555 }
2556 else
2557 i = 0;
2558 }
2559# endif
2560 if (i != 0)
2561 {
2562 /* Also backup the cursor position. */
2563 i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
2564 ccline.cmdspos -= i;
2565 msg_col -= i;
2566 if (msg_col < 0)
2567 {
2568 msg_col += Columns;
2569 --msg_row;
2570 }
2571 }
2572 }
2573#endif
2574
2575 if (redraw && !cmd_silent)
2576 {
2577 msg_no_more = TRUE;
2578 i = cmdline_row;
2579 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
2580 /* Avoid clearing the rest of the line too often. */
2581 if (cmdline_row != i || ccline.overstrike)
2582 msg_clr_eos();
2583 msg_no_more = FALSE;
2584 }
2585#ifdef FEAT_FKMAP
2586 /*
2587 * If we are in Farsi command mode, the character input must be in
2588 * Insert mode. So do not advance the cmdpos.
2589 */
2590 if (!cmd_fkmap)
2591#endif
2592 {
2593 if (KeyTyped)
2594 m = Columns * Rows;
2595 else
2596 m = MAXCOL;
2597 for (i = 0; i < len; ++i)
2598 {
2599 c = cmdline_charsize(ccline.cmdpos);
2600#ifdef FEAT_MBYTE
2601 /* count ">" for a double-wide char that doesn't fit. */
2602 if (has_mbyte)
2603 correct_cmdspos(ccline.cmdpos, c);
2604#endif
2605 /* Stop cursor at the end of the screen */
2606 if (ccline.cmdspos + c >= m)
2607 break;
2608 ccline.cmdspos += c;
2609#ifdef FEAT_MBYTE
2610 if (has_mbyte)
2611 {
2612 c = (*mb_ptr2len_check)(ccline.cmdbuff + ccline.cmdpos) - 1;
2613 if (c > len - i - 1)
2614 c = len - i - 1;
2615 ccline.cmdpos += c;
2616 i += c;
2617 }
2618#endif
2619 ++ccline.cmdpos;
2620 }
2621 }
2622 }
2623 if (redraw)
2624 msg_check();
2625 return retval;
2626}
2627
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00002628static struct cmdline_info prev_ccline;
2629static int prev_ccline_used = FALSE;
2630
2631/*
2632 * Save ccline, because obtaining the "=" register may execute "normal :cmd"
2633 * and overwrite it. But get_cmdline_str() may need it, thus make it
2634 * available globally in prev_ccline.
2635 */
2636 static void
2637save_cmdline(ccp)
2638 struct cmdline_info *ccp;
2639{
2640 if (!prev_ccline_used)
2641 {
2642 vim_memset(&prev_ccline, 0, sizeof(struct cmdline_info));
2643 prev_ccline_used = TRUE;
2644 }
2645 *ccp = prev_ccline;
2646 prev_ccline = ccline;
2647 ccline.cmdbuff = NULL;
2648 ccline.cmdprompt = NULL;
2649}
2650
2651/*
2652 * Resture ccline after it has been saved with save_cmdline().
2653 */
2654 static void
2655restore_cmdline(ccp)
2656 struct cmdline_info *ccp;
2657{
2658 ccline = prev_ccline;
2659 prev_ccline = *ccp;
2660}
2661
Bram Moolenaar8299df92004-07-10 09:47:34 +00002662/*
2663 * paste a yank register into the command line.
2664 * used by CTRL-R command in command-line mode
2665 * insert_reg() can't be used here, because special characters from the
2666 * register contents will be interpreted as commands.
2667 *
2668 * return FAIL for failure, OK otherwise
2669 */
2670 static int
2671cmdline_paste(regname, literally)
2672 int regname;
2673 int literally; /* Insert text literally instead of "as typed" */
2674{
2675 long i;
2676 char_u *arg;
2677 int allocated;
2678 struct cmdline_info save_ccline;
2679
2680 /* check for valid regname; also accept special characters for CTRL-R in
2681 * the command line */
2682 if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
2683 && regname != Ctrl_A && !valid_yank_reg(regname, FALSE))
2684 return FAIL;
2685
2686 /* A register containing CTRL-R can cause an endless loop. Allow using
2687 * CTRL-C to break the loop. */
2688 line_breakcheck();
2689 if (got_int)
2690 return FAIL;
2691
2692#ifdef FEAT_CLIPBOARD
2693 regname = may_get_selection(regname);
2694#endif
2695
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00002696 /* Need to save and restore ccline. */
2697 save_cmdline(&save_ccline);
Bram Moolenaar8299df92004-07-10 09:47:34 +00002698 i = get_spec_reg(regname, &arg, &allocated, TRUE);
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00002699 restore_cmdline(&save_ccline);
Bram Moolenaar8299df92004-07-10 09:47:34 +00002700
2701 if (i)
2702 {
2703 /* Got the value of a special register in "arg". */
2704 if (arg == NULL)
2705 return FAIL;
2706 cmdline_paste_str(arg, literally);
2707 if (allocated)
2708 vim_free(arg);
2709 return OK;
2710 }
2711
2712 return cmdline_paste_reg(regname, literally);
2713}
2714
2715/*
2716 * Put a string on the command line.
2717 * When "literally" is TRUE, insert literally.
2718 * When "literally" is FALSE, insert as typed, but don't leave the command
2719 * line.
2720 */
2721 void
2722cmdline_paste_str(s, literally)
2723 char_u *s;
2724 int literally;
2725{
2726 int c, cv;
2727
2728 if (literally)
2729 put_on_cmdline(s, -1, TRUE);
2730 else
2731 while (*s != NUL)
2732 {
2733 cv = *s;
2734 if (cv == Ctrl_V && s[1])
2735 ++s;
2736#ifdef FEAT_MBYTE
2737 if (has_mbyte)
2738 {
2739 c = mb_ptr2char(s);
2740 s += mb_char2len(c);
2741 }
2742 else
2743#endif
2744 c = *s++;
2745 if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL
2746#ifdef UNIX
2747 || c == intr_char
2748#endif
2749 || (c == Ctrl_BSL && *s == Ctrl_N))
2750 stuffcharReadbuff(Ctrl_V);
2751 stuffcharReadbuff(c);
2752 }
2753}
2754
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755#ifdef FEAT_WILDMENU
2756/*
2757 * Delete characters on the command line, from "from" to the current
2758 * position.
2759 */
2760 static void
2761cmdline_del(from)
2762 int from;
2763{
2764 mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
2765 (size_t)(ccline.cmdlen - ccline.cmdpos + 1));
2766 ccline.cmdlen -= ccline.cmdpos - from;
2767 ccline.cmdpos = from;
2768}
2769#endif
2770
2771/*
2772 * this fuction is called when the screen size changes and with incremental
2773 * search
2774 */
2775 void
2776redrawcmdline()
2777{
2778 if (cmd_silent)
2779 return;
2780 need_wait_return = FALSE;
2781 compute_cmdrow();
2782 redrawcmd();
2783 cursorcmd();
2784}
2785
2786 static void
2787redrawcmdprompt()
2788{
2789 int i;
2790
2791 if (cmd_silent)
2792 return;
2793 if (ccline.cmdfirstc)
2794 msg_putchar(ccline.cmdfirstc);
2795 if (ccline.cmdprompt != NULL)
2796 {
2797 msg_puts_attr(ccline.cmdprompt, ccline.cmdattr);
2798 ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
2799 /* do the reverse of set_cmdspos() */
2800 if (ccline.cmdfirstc)
2801 --ccline.cmdindent;
2802 }
2803 else
2804 for (i = ccline.cmdindent; i > 0; --i)
2805 msg_putchar(' ');
2806}
2807
2808/*
2809 * Redraw what is currently on the command line.
2810 */
2811 void
2812redrawcmd()
2813{
2814 if (cmd_silent)
2815 return;
2816
2817 msg_start();
2818 redrawcmdprompt();
2819
2820 /* Don't use more prompt, truncate the cmdline if it doesn't fit. */
2821 msg_no_more = TRUE;
2822 draw_cmdline(0, ccline.cmdlen);
2823 msg_clr_eos();
2824 msg_no_more = FALSE;
2825
2826 set_cmdspos_cursor();
2827
2828 /*
2829 * An emsg() before may have set msg_scroll. This is used in normal mode,
2830 * in cmdline mode we can reset them now.
2831 */
2832 msg_scroll = FALSE; /* next message overwrites cmdline */
2833
2834 /* Typing ':' at the more prompt may set skip_redraw. We don't want this
2835 * in cmdline mode */
2836 skip_redraw = FALSE;
2837}
2838
2839 void
2840compute_cmdrow()
2841{
2842 if (exmode_active || msg_scrolled)
2843 cmdline_row = Rows - 1;
2844 else
2845 cmdline_row = W_WINROW(lastwin) + lastwin->w_height
2846 + W_STATUS_HEIGHT(lastwin);
2847}
2848
2849 static void
2850cursorcmd()
2851{
2852 if (cmd_silent)
2853 return;
2854
2855#ifdef FEAT_RIGHTLEFT
2856 if (cmdmsg_rl)
2857 {
2858 msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
2859 msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
2860 if (msg_row <= 0)
2861 msg_row = Rows - 1;
2862 }
2863 else
2864#endif
2865 {
2866 msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
2867 msg_col = ccline.cmdspos % (int)Columns;
2868 if (msg_row >= Rows)
2869 msg_row = Rows - 1;
2870 }
2871
2872 windgoto(msg_row, msg_col);
2873#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2874 redrawcmd_preedit();
2875#endif
2876#ifdef MCH_CURSOR_SHAPE
2877 mch_update_cursor();
2878#endif
2879}
2880
2881 void
2882gotocmdline(clr)
2883 int clr;
2884{
2885 msg_start();
2886#ifdef FEAT_RIGHTLEFT
2887 if (cmdmsg_rl)
2888 msg_col = Columns - 1;
2889 else
2890#endif
2891 msg_col = 0; /* always start in column 0 */
2892 if (clr) /* clear the bottom line(s) */
2893 msg_clr_eos(); /* will reset clear_cmdline */
2894 windgoto(cmdline_row, 0);
2895}
2896
2897/*
2898 * Check the word in front of the cursor for an abbreviation.
2899 * Called when the non-id character "c" has been entered.
2900 * When an abbreviation is recognized it is removed from the text with
2901 * backspaces and the replacement string is inserted, followed by "c".
2902 */
2903 static int
2904ccheck_abbr(c)
2905 int c;
2906{
2907 if (p_paste || no_abbr) /* no abbreviations or in paste mode */
2908 return FALSE;
2909
2910 return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0);
2911}
2912
2913/*
2914 * Return FAIL if this is not an appropriate context in which to do
2915 * completion of anything, return OK if it is (even if there are no matches).
2916 * For the caller, this means that the character is just passed through like a
2917 * normal character (instead of being expanded). This allows :s/^I^D etc.
2918 */
2919 static int
2920nextwild(xp, type, options)
2921 expand_T *xp;
2922 int type;
2923 int options; /* extra options for ExpandOne() */
2924{
2925 int i, j;
2926 char_u *p1;
2927 char_u *p2;
2928 int oldlen;
2929 int difflen;
2930 int v;
2931
2932 if (xp->xp_numfiles == -1)
2933 {
2934 set_expand_context(xp);
2935 cmd_showtail = expand_showtail(xp);
2936 }
2937
2938 if (xp->xp_context == EXPAND_UNSUCCESSFUL)
2939 {
2940 beep_flush();
2941 return OK; /* Something illegal on command line */
2942 }
2943 if (xp->xp_context == EXPAND_NOTHING)
2944 {
2945 /* Caller can use the character as a normal char instead */
2946 return FAIL;
2947 }
2948
2949 MSG_PUTS("..."); /* show that we are busy */
2950 out_flush();
2951
2952 i = (int)(xp->xp_pattern - ccline.cmdbuff);
2953 oldlen = ccline.cmdpos - i;
2954
2955 if (type == WILD_NEXT || type == WILD_PREV)
2956 {
2957 /*
2958 * Get next/previous match for a previous expanded pattern.
2959 */
2960 p2 = ExpandOne(xp, NULL, NULL, 0, type);
2961 }
2962 else
2963 {
2964 /*
2965 * Translate string into pattern and expand it.
2966 */
2967 if ((p1 = addstar(&ccline.cmdbuff[i], oldlen, xp->xp_context)) == NULL)
2968 p2 = NULL;
2969 else
2970 {
2971 p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], oldlen),
2972 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT|WILD_ESCAPE
2973 |options, type);
2974 vim_free(p1);
2975 /* longest match: make sure it is not shorter (happens with :help */
2976 if (p2 != NULL && type == WILD_LONGEST)
2977 {
2978 for (j = 0; j < oldlen; ++j)
2979 if (ccline.cmdbuff[i + j] == '*'
2980 || ccline.cmdbuff[i + j] == '?')
2981 break;
2982 if ((int)STRLEN(p2) < j)
2983 {
2984 vim_free(p2);
2985 p2 = NULL;
2986 }
2987 }
2988 }
2989 }
2990
2991 if (p2 != NULL && !got_int)
2992 {
2993 difflen = (int)STRLEN(p2) - oldlen;
2994 if (ccline.cmdlen + difflen > ccline.cmdbufflen - 4)
2995 {
2996 v = realloc_cmdbuff(ccline.cmdlen + difflen);
2997 xp->xp_pattern = ccline.cmdbuff + i;
2998 }
2999 else
3000 v = OK;
3001 if (v == OK)
3002 {
3003 vim_strncpy(&ccline.cmdbuff[ccline.cmdpos + difflen],
3004 &ccline.cmdbuff[ccline.cmdpos],
3005 ccline.cmdlen - ccline.cmdpos + 1);
3006 STRNCPY(&ccline.cmdbuff[i], p2, STRLEN(p2));
3007 ccline.cmdlen += difflen;
3008 ccline.cmdpos += difflen;
3009 }
3010 }
3011 vim_free(p2);
3012
3013 redrawcmd();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003014 cursorcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015
3016 /* When expanding a ":map" command and no matches are found, assume that
3017 * the key is supposed to be inserted literally */
3018 if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL)
3019 return FAIL;
3020
3021 if (xp->xp_numfiles <= 0 && p2 == NULL)
3022 beep_flush();
3023 else if (xp->xp_numfiles == 1)
3024 /* free expanded pattern */
3025 (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
3026
3027 return OK;
3028}
3029
3030/*
3031 * Do wildcard expansion on the string 'str'.
3032 * Chars that should not be expanded must be preceded with a backslash.
3033 * Return a pointer to alloced memory containing the new string.
3034 * Return NULL for failure.
3035 *
3036 * Results are cached in xp->xp_files and xp->xp_numfiles.
3037 *
3038 * mode = WILD_FREE: just free previously expanded matches
3039 * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
3040 * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
3041 * mode = WILD_NEXT: use next match in multiple match, wrap to first
3042 * mode = WILD_PREV: use previous match in multiple match, wrap to first
3043 * mode = WILD_ALL: return all matches concatenated
3044 * mode = WILD_LONGEST: return longest matched part
3045 *
3046 * options = WILD_LIST_NOTFOUND: list entries without a match
3047 * options = WILD_HOME_REPLACE: do home_replace() for buffer names
3048 * options = WILD_USE_NL: Use '\n' for WILD_ALL
3049 * options = WILD_NO_BEEP: Don't beep for multiple matches
3050 * options = WILD_ADD_SLASH: add a slash after directory names
3051 * options = WILD_KEEP_ALL: don't remove 'wildignore' entries
3052 * options = WILD_SILENT: don't print warning messages
3053 * options = WILD_ESCAPE: put backslash before special chars
3054 *
3055 * The variables xp->xp_context and xp->xp_backslash must have been set!
3056 */
3057 char_u *
3058ExpandOne(xp, str, orig, options, mode)
3059 expand_T *xp;
3060 char_u *str;
3061 char_u *orig; /* allocated copy of original of expanded string */
3062 int options;
3063 int mode;
3064{
3065 char_u *ss = NULL;
3066 static int findex;
3067 static char_u *orig_save = NULL; /* kept value of orig */
3068 int i;
3069 long_u len;
3070 int non_suf_match; /* number without matching suffix */
3071
3072 /*
3073 * first handle the case of using an old match
3074 */
3075 if (mode == WILD_NEXT || mode == WILD_PREV)
3076 {
3077 if (xp->xp_numfiles > 0)
3078 {
3079 if (mode == WILD_PREV)
3080 {
3081 if (findex == -1)
3082 findex = xp->xp_numfiles;
3083 --findex;
3084 }
3085 else /* mode == WILD_NEXT */
3086 ++findex;
3087
3088 /*
3089 * When wrapping around, return the original string, set findex to
3090 * -1.
3091 */
3092 if (findex < 0)
3093 {
3094 if (orig_save == NULL)
3095 findex = xp->xp_numfiles - 1;
3096 else
3097 findex = -1;
3098 }
3099 if (findex >= xp->xp_numfiles)
3100 {
3101 if (orig_save == NULL)
3102 findex = 0;
3103 else
3104 findex = -1;
3105 }
3106#ifdef FEAT_WILDMENU
3107 if (p_wmnu)
3108 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
3109 findex, cmd_showtail);
3110#endif
3111 if (findex == -1)
3112 return vim_strsave(orig_save);
3113 return vim_strsave(xp->xp_files[findex]);
3114 }
3115 else
3116 return NULL;
3117 }
3118
3119/* free old names */
3120 if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
3121 {
3122 FreeWild(xp->xp_numfiles, xp->xp_files);
3123 xp->xp_numfiles = -1;
3124 vim_free(orig_save);
3125 orig_save = NULL;
3126 }
3127 findex = 0;
3128
3129 if (mode == WILD_FREE) /* only release file name */
3130 return NULL;
3131
3132 if (xp->xp_numfiles == -1)
3133 {
3134 vim_free(orig_save);
3135 orig_save = orig;
3136
3137 /*
3138 * Do the expansion.
3139 */
3140 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
3141 options) == FAIL)
3142 {
3143#ifdef FNAME_ILLEGAL
3144 /* Illegal file name has been silently skipped. But when there
3145 * are wildcards, the real problem is that there was no match,
3146 * causing the pattern to be added, which has illegal characters.
3147 */
3148 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
3149 EMSG2(_(e_nomatch2), str);
3150#endif
3151 }
3152 else if (xp->xp_numfiles == 0)
3153 {
3154 if (!(options & WILD_SILENT))
3155 EMSG2(_(e_nomatch2), str);
3156 }
3157 else
3158 {
3159 /* Escape the matches for use on the command line. */
3160 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
3161
3162 /*
3163 * Check for matching suffixes in file names.
3164 */
3165 if (mode != WILD_ALL && mode != WILD_LONGEST)
3166 {
3167 if (xp->xp_numfiles)
3168 non_suf_match = xp->xp_numfiles;
3169 else
3170 non_suf_match = 1;
3171 if ((xp->xp_context == EXPAND_FILES
3172 || xp->xp_context == EXPAND_DIRECTORIES)
3173 && xp->xp_numfiles > 1)
3174 {
3175 /*
3176 * More than one match; check suffix.
3177 * The files will have been sorted on matching suffix in
3178 * expand_wildcards, only need to check the first two.
3179 */
3180 non_suf_match = 0;
3181 for (i = 0; i < 2; ++i)
3182 if (match_suffix(xp->xp_files[i]))
3183 ++non_suf_match;
3184 }
3185 if (non_suf_match != 1)
3186 {
3187 /* Can we ever get here unless it's while expanding
3188 * interactively? If not, we can get rid of this all
3189 * together. Don't really want to wait for this message
3190 * (and possibly have to hit return to continue!).
3191 */
3192 if (!(options & WILD_SILENT))
3193 EMSG(_(e_toomany));
3194 else if (!(options & WILD_NO_BEEP))
3195 beep_flush();
3196 }
3197 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
3198 ss = vim_strsave(xp->xp_files[0]);
3199 }
3200 }
3201 }
3202
3203 /* Find longest common part */
3204 if (mode == WILD_LONGEST && xp->xp_numfiles > 0)
3205 {
3206 for (len = 0; xp->xp_files[0][len]; ++len)
3207 {
3208 for (i = 0; i < xp->xp_numfiles; ++i)
3209 {
3210#ifdef CASE_INSENSITIVE_FILENAME
3211 if (xp->xp_context == EXPAND_DIRECTORIES
3212 || xp->xp_context == EXPAND_FILES
3213 || xp->xp_context == EXPAND_BUFFERS)
3214 {
3215 if (TOLOWER_LOC(xp->xp_files[i][len]) !=
3216 TOLOWER_LOC(xp->xp_files[0][len]))
3217 break;
3218 }
3219 else
3220#endif
3221 if (xp->xp_files[i][len] != xp->xp_files[0][len])
3222 break;
3223 }
3224 if (i < xp->xp_numfiles)
3225 {
3226 if (!(options & WILD_NO_BEEP))
3227 vim_beep();
3228 break;
3229 }
3230 }
3231 ss = alloc((unsigned)len + 1);
3232 if (ss)
3233 {
3234 STRNCPY(ss, xp->xp_files[0], len);
3235 ss[len] = NUL;
3236 }
3237 findex = -1; /* next p_wc gets first one */
3238 }
3239
3240 /* Concatenate all matching names */
3241 if (mode == WILD_ALL && xp->xp_numfiles > 0)
3242 {
3243 len = 0;
3244 for (i = 0; i < xp->xp_numfiles; ++i)
3245 len += (long_u)STRLEN(xp->xp_files[i]) + 1;
3246 ss = lalloc(len, TRUE);
3247 if (ss != NULL)
3248 {
3249 *ss = NUL;
3250 for (i = 0; i < xp->xp_numfiles; ++i)
3251 {
3252 STRCAT(ss, xp->xp_files[i]);
3253 if (i != xp->xp_numfiles - 1)
3254 STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " ");
3255 }
3256 }
3257 }
3258
3259 if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
3260 ExpandCleanup(xp);
3261
3262 return ss;
3263}
3264
3265/*
3266 * Prepare an expand structure for use.
3267 */
3268 void
3269ExpandInit(xp)
3270 expand_T *xp;
3271{
3272 xp->xp_backslash = XP_BS_NONE;
3273 xp->xp_numfiles = -1;
3274 xp->xp_files = NULL;
3275}
3276
3277/*
3278 * Cleanup an expand structure after use.
3279 */
3280 void
3281ExpandCleanup(xp)
3282 expand_T *xp;
3283{
3284 if (xp->xp_numfiles >= 0)
3285 {
3286 FreeWild(xp->xp_numfiles, xp->xp_files);
3287 xp->xp_numfiles = -1;
3288 }
3289}
3290
3291 void
3292ExpandEscape(xp, str, numfiles, files, options)
3293 expand_T *xp;
3294 char_u *str;
3295 int numfiles;
3296 char_u **files;
3297 int options;
3298{
3299 int i;
3300 char_u *p;
3301
3302 /*
3303 * May change home directory back to "~"
3304 */
3305 if (options & WILD_HOME_REPLACE)
3306 tilde_replace(str, numfiles, files);
3307
3308 if (options & WILD_ESCAPE)
3309 {
3310 if (xp->xp_context == EXPAND_FILES
3311 || xp->xp_context == EXPAND_BUFFERS
3312 || xp->xp_context == EXPAND_DIRECTORIES)
3313 {
3314 /*
3315 * Insert a backslash into a file name before a space, \, %, #
3316 * and wildmatch characters, except '~'.
3317 */
3318 for (i = 0; i < numfiles; ++i)
3319 {
3320 /* for ":set path=" we need to escape spaces twice */
3321 if (xp->xp_backslash == XP_BS_THREE)
3322 {
3323 p = vim_strsave_escaped(files[i], (char_u *)" ");
3324 if (p != NULL)
3325 {
3326 vim_free(files[i]);
3327 files[i] = p;
3328#if defined(BACKSLASH_IN_FILENAME) || defined(COLON_AS_PATHSEP)
3329 p = vim_strsave_escaped(files[i], (char_u *)" ");
3330 if (p != NULL)
3331 {
3332 vim_free(files[i]);
3333 files[i] = p;
3334 }
3335#endif
3336 }
3337 }
3338#ifdef BACKSLASH_IN_FILENAME
3339 {
3340 char_u buf[20];
3341 int j = 0;
3342
3343 /* Don't escape '[' and '{' if they are in 'isfname'. */
3344 for (p = PATH_ESC_CHARS; *p != NUL; ++p)
3345 if ((*p != '[' && *p != '{') || !vim_isfilec(*p))
3346 buf[j++] = *p;
3347 buf[j] = NUL;
3348 p = vim_strsave_escaped(files[i], buf);
3349 }
3350#else
3351 p = vim_strsave_escaped(files[i], PATH_ESC_CHARS);
3352#endif
3353 if (p != NULL)
3354 {
3355 vim_free(files[i]);
3356 files[i] = p;
3357 }
3358
3359 /* If 'str' starts with "\~", replace "~" at start of
3360 * files[i] with "\~". */
3361 if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~')
3362 {
3363 p = alloc((unsigned)(STRLEN(files[i]) + 2));
3364 if (p != NULL)
3365 {
3366 p[0] = '\\';
3367 STRCPY(p + 1, files[i]);
3368 vim_free(files[i]);
3369 files[i] = p;
3370 }
3371 }
3372 }
3373 xp->xp_backslash = XP_BS_NONE;
3374 }
3375 else if (xp->xp_context == EXPAND_TAGS)
3376 {
3377 /*
3378 * Insert a backslash before characters in a tag name that
3379 * would terminate the ":tag" command.
3380 */
3381 for (i = 0; i < numfiles; ++i)
3382 {
3383 p = vim_strsave_escaped(files[i], (char_u *)"\\|\"");
3384 if (p != NULL)
3385 {
3386 vim_free(files[i]);
3387 files[i] = p;
3388 }
3389 }
3390 }
3391 }
3392}
3393
3394/*
3395 * For each file name in files[num_files]:
3396 * If 'orig_pat' starts with "~/", replace the home directory with "~".
3397 */
3398 void
3399tilde_replace(orig_pat, num_files, files)
3400 char_u *orig_pat;
3401 int num_files;
3402 char_u **files;
3403{
3404 int i;
3405 char_u *p;
3406
3407 if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
3408 {
3409 for (i = 0; i < num_files; ++i)
3410 {
3411 p = home_replace_save(NULL, files[i]);
3412 if (p != NULL)
3413 {
3414 vim_free(files[i]);
3415 files[i] = p;
3416 }
3417 }
3418 }
3419}
3420
3421/*
3422 * Show all matches for completion on the command line.
3423 * Returns EXPAND_NOTHING when the character that triggered expansion should
3424 * be inserted like a normal character.
3425 */
3426/*ARGSUSED*/
3427 static int
3428showmatches(xp, wildmenu)
3429 expand_T *xp;
3430 int wildmenu;
3431{
3432#define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m])
3433 int num_files;
3434 char_u **files_found;
3435 int i, j, k;
3436 int maxlen;
3437 int lines;
3438 int columns;
3439 char_u *p;
3440 int lastlen;
3441 int attr;
3442 int showtail;
3443
3444 if (xp->xp_numfiles == -1)
3445 {
3446 set_expand_context(xp);
3447 i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos,
3448 &num_files, &files_found);
3449 showtail = expand_showtail(xp);
3450 if (i != EXPAND_OK)
3451 return i;
3452
3453 }
3454 else
3455 {
3456 num_files = xp->xp_numfiles;
3457 files_found = xp->xp_files;
3458 showtail = cmd_showtail;
3459 }
3460
3461#ifdef FEAT_WILDMENU
3462 if (!wildmenu)
3463 {
3464#endif
3465 msg_didany = FALSE; /* lines_left will be set */
3466 msg_start(); /* prepare for paging */
3467 msg_putchar('\n');
3468 out_flush();
3469 cmdline_row = msg_row;
3470 msg_didany = FALSE; /* lines_left will be set again */
3471 msg_start(); /* prepare for paging */
3472#ifdef FEAT_WILDMENU
3473 }
3474#endif
3475
3476 if (got_int)
3477 got_int = FALSE; /* only int. the completion, not the cmd line */
3478#ifdef FEAT_WILDMENU
3479 else if (wildmenu)
3480 win_redr_status_matches(xp, num_files, files_found, 0, showtail);
3481#endif
3482 else
3483 {
3484 /* find the length of the longest file name */
3485 maxlen = 0;
3486 for (i = 0; i < num_files; ++i)
3487 {
3488 if (!showtail && (xp->xp_context == EXPAND_FILES
3489 || xp->xp_context == EXPAND_BUFFERS))
3490 {
3491 home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
3492 j = vim_strsize(NameBuff);
3493 }
3494 else
3495 j = vim_strsize(L_SHOWFILE(i));
3496 if (j > maxlen)
3497 maxlen = j;
3498 }
3499
3500 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3501 lines = num_files;
3502 else
3503 {
3504 /* compute the number of columns and lines for the listing */
3505 maxlen += 2; /* two spaces between file names */
3506 columns = ((int)Columns + 2) / maxlen;
3507 if (columns < 1)
3508 columns = 1;
3509 lines = (num_files + columns - 1) / columns;
3510 }
3511
3512 attr = hl_attr(HLF_D); /* find out highlighting for directories */
3513
3514 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3515 {
3516 MSG_PUTS_ATTR(_("tagname"), hl_attr(HLF_T));
3517 msg_clr_eos();
3518 msg_advance(maxlen - 3);
3519 MSG_PUTS_ATTR(_(" kind file\n"), hl_attr(HLF_T));
3520 }
3521
3522 /* list the files line by line */
3523 for (i = 0; i < lines; ++i)
3524 {
3525 lastlen = 999;
3526 for (k = i; k < num_files; k += lines)
3527 {
3528 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3529 {
3530 msg_outtrans_attr(files_found[k], hl_attr(HLF_D));
3531 p = files_found[k] + STRLEN(files_found[k]) + 1;
3532 msg_advance(maxlen + 1);
3533 msg_puts(p);
3534 msg_advance(maxlen + 3);
3535 msg_puts_long_attr(p + 2, hl_attr(HLF_D));
3536 break;
3537 }
3538 for (j = maxlen - lastlen; --j >= 0; )
3539 msg_putchar(' ');
3540 if (xp->xp_context == EXPAND_FILES
3541 || xp->xp_context == EXPAND_BUFFERS)
3542 {
3543 /* highlight directories */
3544 j = (mch_isdir(files_found[k]));
3545 if (showtail)
3546 p = L_SHOWFILE(k);
3547 else
3548 {
3549 home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
3550 TRUE);
3551 p = NameBuff;
3552 }
3553 }
3554 else
3555 {
3556 j = FALSE;
3557 p = L_SHOWFILE(k);
3558 }
3559 lastlen = msg_outtrans_attr(p, j ? attr : 0);
3560 }
3561 if (msg_col > 0) /* when not wrapped around */
3562 {
3563 msg_clr_eos();
3564 msg_putchar('\n');
3565 }
3566 out_flush(); /* show one line at a time */
3567 if (got_int)
3568 {
3569 got_int = FALSE;
3570 break;
3571 }
3572 }
3573
3574 /*
3575 * we redraw the command below the lines that we have just listed
3576 * This is a bit tricky, but it saves a lot of screen updating.
3577 */
3578 cmdline_row = msg_row; /* will put it back later */
3579 }
3580
3581 if (xp->xp_numfiles == -1)
3582 FreeWild(num_files, files_found);
3583
3584 return EXPAND_OK;
3585}
3586
3587/*
3588 * Private gettail for showmatches() (and win_redr_status_matches()):
3589 * Find tail of file name path, but ignore trailing "/".
3590 */
3591 char_u *
3592sm_gettail(s)
3593 char_u *s;
3594{
3595 char_u *p;
3596 char_u *t = s;
3597 int had_sep = FALSE;
3598
3599 for (p = s; *p != NUL; )
3600 {
3601 if (vim_ispathsep(*p)
3602#ifdef BACKSLASH_IN_FILENAME
3603 && !rem_backslash(p)
3604#endif
3605 )
3606 had_sep = TRUE;
3607 else if (had_sep)
3608 {
3609 t = p;
3610 had_sep = FALSE;
3611 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003612 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613 }
3614 return t;
3615}
3616
3617/*
3618 * Return TRUE if we only need to show the tail of completion matches.
3619 * When not completing file names or there is a wildcard in the path FALSE is
3620 * returned.
3621 */
3622 static int
3623expand_showtail(xp)
3624 expand_T *xp;
3625{
3626 char_u *s;
3627 char_u *end;
3628
3629 /* When not completing file names a "/" may mean something different. */
3630 if (xp->xp_context != EXPAND_FILES && xp->xp_context != EXPAND_DIRECTORIES)
3631 return FALSE;
3632
3633 end = gettail(xp->xp_pattern);
3634 if (end == xp->xp_pattern) /* there is no path separator */
3635 return FALSE;
3636
3637 for (s = xp->xp_pattern; s < end; s++)
3638 {
3639 /* Skip escaped wildcards. Only when the backslash is not a path
3640 * separator, on DOS the '*' "path\*\file" must not be skipped. */
3641 if (rem_backslash(s))
3642 ++s;
3643 else if (vim_strchr((char_u *)"*?[", *s) != NULL)
3644 return FALSE;
3645 }
3646 return TRUE;
3647}
3648
3649/*
3650 * Prepare a string for expansion.
3651 * When expanding file names: The string will be used with expand_wildcards().
3652 * Copy the file name into allocated memory and add a '*' at the end.
3653 * When expanding other names: The string will be used with regcomp(). Copy
3654 * the name into allocated memory and prepend "^".
3655 */
3656 char_u *
3657addstar(fname, len, context)
3658 char_u *fname;
3659 int len;
3660 int context; /* EXPAND_FILES etc. */
3661{
3662 char_u *retval;
3663 int i, j;
3664 int new_len;
3665 char_u *tail;
3666
3667 if (context != EXPAND_FILES && context != EXPAND_DIRECTORIES)
3668 {
3669 /*
3670 * Matching will be done internally (on something other than files).
3671 * So we convert the file-matching-type wildcards into our kind for
3672 * use with vim_regcomp(). First work out how long it will be:
3673 */
3674
3675 /* For help tags the translation is done in find_help_tags().
3676 * For a tag pattern starting with "/" no translation is needed. */
3677 if (context == EXPAND_HELP
3678 || context == EXPAND_COLORS
3679 || context == EXPAND_COMPILER
3680 || (context == EXPAND_TAGS && fname[0] == '/'))
3681 retval = vim_strnsave(fname, len);
3682 else
3683 {
3684 new_len = len + 2; /* +2 for '^' at start, NUL at end */
3685 for (i = 0; i < len; i++)
3686 {
3687 if (fname[i] == '*' || fname[i] == '~')
3688 new_len++; /* '*' needs to be replaced by ".*"
3689 '~' needs to be replaced by "\~" */
3690
3691 /* Buffer names are like file names. "." should be literal */
3692 if (context == EXPAND_BUFFERS && fname[i] == '.')
3693 new_len++; /* "." becomes "\." */
3694
3695 /* Custom expansion takes care of special things, match
3696 * backslashes literally (perhaps also for other types?) */
3697 if (context == EXPAND_USER_DEFINED && fname[i] == '\\')
3698 new_len++; /* '\' becomes "\\" */
3699 }
3700 retval = alloc(new_len);
3701 if (retval != NULL)
3702 {
3703 retval[0] = '^';
3704 j = 1;
3705 for (i = 0; i < len; i++, j++)
3706 {
3707 /* Skip backslash. But why? At least keep it for custom
3708 * expansion. */
3709 if (context != EXPAND_USER_DEFINED
3710 && fname[i] == '\\' && ++i == len)
3711 break;
3712
3713 switch (fname[i])
3714 {
3715 case '*': retval[j++] = '.';
3716 break;
3717 case '~': retval[j++] = '\\';
3718 break;
3719 case '?': retval[j] = '.';
3720 continue;
3721 case '.': if (context == EXPAND_BUFFERS)
3722 retval[j++] = '\\';
3723 break;
3724 case '\\': if (context == EXPAND_USER_DEFINED)
3725 retval[j++] = '\\';
3726 break;
3727 }
3728 retval[j] = fname[i];
3729 }
3730 retval[j] = NUL;
3731 }
3732 }
3733 }
3734 else
3735 {
3736 retval = alloc(len + 4);
3737 if (retval != NULL)
3738 {
3739 STRNCPY(retval, fname, len);
3740 retval[len] = NUL;
3741
3742 /*
3743 * Don't add a star to ~, ~user, $var or `cmd`.
3744 * ~ would be at the start of the file name, but not the tail.
3745 * $ could be anywhere in the tail.
3746 * ` could be anywhere in the file name.
3747 */
3748 tail = gettail(retval);
3749 if ((*retval != '~' || tail != retval)
3750 && vim_strchr(tail, '$') == NULL
3751 && vim_strchr(retval, '`') == NULL)
3752 retval[len++] = '*';
3753 retval[len] = NUL;
3754 }
3755 }
3756 return retval;
3757}
3758
3759/*
3760 * Must parse the command line so far to work out what context we are in.
3761 * Completion can then be done based on that context.
3762 * This routine sets the variables:
3763 * xp->xp_pattern The start of the pattern to be expanded within
3764 * the command line (ends at the cursor).
3765 * xp->xp_context The type of thing to expand. Will be one of:
3766 *
3767 * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
3768 * the command line, like an unknown command. Caller
3769 * should beep.
3770 * EXPAND_NOTHING Unrecognised context for completion, use char like
3771 * a normal char, rather than for completion. eg
3772 * :s/^I/
3773 * EXPAND_COMMANDS Cursor is still touching the command, so complete
3774 * it.
3775 * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
3776 * EXPAND_FILES After command with XFILE set, or after setting
3777 * with P_EXPAND set. eg :e ^I, :w>>^I
3778 * EXPAND_DIRECTORIES In some cases this is used instead of the latter
3779 * when we know only directories are of interest. eg
3780 * :set dir=^I
3781 * EXPAND_SETTINGS Complete variable names. eg :set d^I
3782 * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
3783 * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
3784 * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect
3785 * EXPAND_HELP Complete tags from the file 'helpfile'/tags
3786 * EXPAND_EVENTS Complete event names
3787 * EXPAND_SYNTAX Complete :syntax command arguments
3788 * EXPAND_HIGHLIGHT Complete highlight (syntax) group names
3789 * EXPAND_AUGROUP Complete autocommand group names
3790 * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I
3791 * EXPAND_MAPPINGS Complete mapping and abbreviation names,
3792 * eg :unmap a^I , :cunab x^I
3793 * EXPAND_FUNCTIONS Complete internal or user defined function names,
3794 * eg :call sub^I
3795 * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I
3796 * EXPAND_EXPRESSION Complete internal or user defined function/variable
3797 * names in expressions, eg :while s^I
3798 * EXPAND_ENV_VARS Complete environment variable names
3799 */
3800 static void
3801set_expand_context(xp)
3802 expand_T *xp;
3803{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003804 /* only expansion for ':', '>' and '=' command-lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805 if (ccline.cmdfirstc != ':'
3806#ifdef FEAT_EVAL
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003807 && ccline.cmdfirstc != '>' && ccline.cmdfirstc != '='
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808#endif
3809 )
3810 {
3811 xp->xp_context = EXPAND_NOTHING;
3812 return;
3813 }
3814 set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos);
3815}
3816
3817 void
3818set_cmd_context(xp, str, len, col)
3819 expand_T *xp;
3820 char_u *str; /* start of command line */
3821 int len; /* length of command line (excl. NUL) */
3822 int col; /* position of cursor */
3823{
3824 int old_char = NUL;
3825 char_u *nextcomm;
3826
3827 /*
3828 * Avoid a UMR warning from Purify, only save the character if it has been
3829 * written before.
3830 */
3831 if (col < len)
3832 old_char = str[col];
3833 str[col] = NUL;
3834 nextcomm = str;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003835
3836#ifdef FEAT_EVAL
3837 if (ccline.cmdfirstc == '=')
3838 /* pass CMD_SIZE because there is no real command */
3839 set_context_for_expression(xp, str, CMD_SIZE);
3840 else
3841#endif
3842 while (nextcomm != NULL)
3843 nextcomm = set_one_cmd_context(xp, nextcomm);
3844
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845 str[col] = old_char;
3846}
3847
3848/*
3849 * Expand the command line "str" from context "xp".
3850 * "xp" must have been set by set_cmd_context().
3851 * xp->xp_pattern points into "str", to where the text that is to be expanded
3852 * starts.
3853 * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the
3854 * cursor.
3855 * Returns EXPAND_NOTHING when there is nothing to expand, might insert the
3856 * key that triggered expansion literally.
3857 * Returns EXPAND_OK otherwise.
3858 */
3859 int
3860expand_cmdline(xp, str, col, matchcount, matches)
3861 expand_T *xp;
3862 char_u *str; /* start of command line */
3863 int col; /* position of cursor */
3864 int *matchcount; /* return: nr of matches */
3865 char_u ***matches; /* return: array of pointers to matches */
3866{
3867 char_u *file_str = NULL;
3868
3869 if (xp->xp_context == EXPAND_UNSUCCESSFUL)
3870 {
3871 beep_flush();
3872 return EXPAND_UNSUCCESSFUL; /* Something illegal on command line */
3873 }
3874 if (xp->xp_context == EXPAND_NOTHING)
3875 {
3876 /* Caller can use the character as a normal char instead */
3877 return EXPAND_NOTHING;
3878 }
3879
3880 /* add star to file name, or convert to regexp if not exp. files. */
3881 file_str = addstar(xp->xp_pattern,
3882 (int)(str + col - xp->xp_pattern), xp->xp_context);
3883 if (file_str == NULL)
3884 return EXPAND_UNSUCCESSFUL;
3885
3886 /* find all files that match the description */
3887 if (ExpandFromContext(xp, file_str, matchcount, matches,
3888 WILD_ADD_SLASH|WILD_SILENT) == FAIL)
3889 {
3890 *matchcount = 0;
3891 *matches = NULL;
3892 }
3893 vim_free(file_str);
3894
3895 return EXPAND_OK;
3896}
3897
3898#ifdef FEAT_MULTI_LANG
3899/*
3900 * Cleanup matches for help tags: remove "@en" if "en" is the only language.
3901 */
3902static void cleanup_help_tags __ARGS((int num_file, char_u **file));
3903
3904 static void
3905cleanup_help_tags(num_file, file)
3906 int num_file;
3907 char_u **file;
3908{
3909 int i, j;
3910 int len;
3911
3912 for (i = 0; i < num_file; ++i)
3913 {
3914 len = (int)STRLEN(file[i]) - 3;
3915 if (len > 0 && STRCMP(file[i] + len, "@en") == 0)
3916 {
3917 /* Sorting on priority means the same item in another language may
3918 * be anywhere. Search all items for a match up to the "@en". */
3919 for (j = 0; j < num_file; ++j)
3920 if (j != i
3921 && (int)STRLEN(file[j]) == len + 3
3922 && STRNCMP(file[i], file[j], len + 1) == 0)
3923 break;
3924 if (j == num_file)
3925 file[i][len] = NUL;
3926 }
3927 }
3928}
3929#endif
3930
3931/*
3932 * Do the expansion based on xp->xp_context and "pat".
3933 */
3934 static int
3935ExpandFromContext(xp, pat, num_file, file, options)
3936 expand_T *xp;
3937 char_u *pat;
3938 int *num_file;
3939 char_u ***file;
3940 int options;
3941{
3942#ifdef FEAT_CMDL_COMPL
3943 regmatch_T regmatch;
3944#endif
3945 int ret;
3946 int flags;
3947
3948 flags = EW_DIR; /* include directories */
3949 if (options & WILD_LIST_NOTFOUND)
3950 flags |= EW_NOTFOUND;
3951 if (options & WILD_ADD_SLASH)
3952 flags |= EW_ADDSLASH;
3953 if (options & WILD_KEEP_ALL)
3954 flags |= EW_KEEPALL;
3955 if (options & WILD_SILENT)
3956 flags |= EW_SILENT;
3957
3958 if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES)
3959 {
3960 /*
3961 * Expand file or directory names.
3962 */
3963 int free_pat = FALSE;
3964 int i;
3965
3966 /* for ":set path=" and ":set tags=" halve backslashes for escaped
3967 * space */
3968 if (xp->xp_backslash != XP_BS_NONE)
3969 {
3970 free_pat = TRUE;
3971 pat = vim_strsave(pat);
3972 for (i = 0; pat[i]; ++i)
3973 if (pat[i] == '\\')
3974 {
3975 if (xp->xp_backslash == XP_BS_THREE
3976 && pat[i + 1] == '\\'
3977 && pat[i + 2] == '\\'
3978 && pat[i + 3] == ' ')
3979 STRCPY(pat + i, pat + i + 3);
3980 if (xp->xp_backslash == XP_BS_ONE
3981 && pat[i + 1] == ' ')
3982 STRCPY(pat + i, pat + i + 1);
3983 }
3984 }
3985
3986 if (xp->xp_context == EXPAND_FILES)
3987 flags |= EW_FILE;
3988 else
3989 flags = (flags | EW_DIR) & ~EW_FILE;
3990 ret = expand_wildcards(1, &pat, num_file, file, flags);
3991 if (free_pat)
3992 vim_free(pat);
3993 return ret;
3994 }
3995
3996 *file = (char_u **)"";
3997 *num_file = 0;
3998 if (xp->xp_context == EXPAND_HELP)
3999 {
4000 if (find_help_tags(pat, num_file, file, FALSE) == OK)
4001 {
4002#ifdef FEAT_MULTI_LANG
4003 cleanup_help_tags(*num_file, *file);
4004#endif
4005 return OK;
4006 }
4007 return FAIL;
4008 }
4009
4010#ifndef FEAT_CMDL_COMPL
4011 return FAIL;
4012#else
4013 if (xp->xp_context == EXPAND_OLD_SETTING)
4014 return ExpandOldSetting(num_file, file);
4015 if (xp->xp_context == EXPAND_BUFFERS)
4016 return ExpandBufnames(pat, num_file, file, options);
4017 if (xp->xp_context == EXPAND_TAGS
4018 || xp->xp_context == EXPAND_TAGS_LISTFILES)
4019 return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
4020 if (xp->xp_context == EXPAND_COLORS)
4021 return ExpandRTDir(pat, num_file, file, "colors");
4022 if (xp->xp_context == EXPAND_COMPILER)
4023 return ExpandRTDir(pat, num_file, file, "compiler");
4024
4025 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
4026 if (regmatch.regprog == NULL)
4027 return FAIL;
4028
4029 /* set ignore-case according to p_ic, p_scs and pat */
4030 regmatch.rm_ic = ignorecase(pat);
4031
4032 if (xp->xp_context == EXPAND_SETTINGS
4033 || xp->xp_context == EXPAND_BOOL_SETTINGS)
4034 ret = ExpandSettings(xp, &regmatch, num_file, file);
4035 else if (xp->xp_context == EXPAND_MAPPINGS)
4036 ret = ExpandMappings(&regmatch, num_file, file);
4037# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
4038 else if (xp->xp_context == EXPAND_USER_DEFINED)
4039 ret = ExpandUserDefined(xp, &regmatch, num_file, file);
4040# endif
4041 else
4042 {
4043 static struct expgen
4044 {
4045 int context;
4046 char_u *((*func)__ARGS((expand_T *, int)));
4047 int ic;
4048 } tab[] =
4049 {
4050 {EXPAND_COMMANDS, get_command_name, FALSE},
4051#ifdef FEAT_USR_CMDS
4052 {EXPAND_USER_COMMANDS, get_user_commands, FALSE},
4053 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE},
4054 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE},
4055 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE},
4056#endif
4057#ifdef FEAT_EVAL
4058 {EXPAND_USER_VARS, get_user_var_name, FALSE},
4059 {EXPAND_FUNCTIONS, get_function_name, FALSE},
4060 {EXPAND_USER_FUNC, get_user_func_name, FALSE},
4061 {EXPAND_EXPRESSION, get_expr_name, FALSE},
4062#endif
4063#ifdef FEAT_MENU
4064 {EXPAND_MENUS, get_menu_name, FALSE},
4065 {EXPAND_MENUNAMES, get_menu_names, FALSE},
4066#endif
4067#ifdef FEAT_SYN_HL
4068 {EXPAND_SYNTAX, get_syntax_name, TRUE},
4069#endif
4070 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE},
4071#ifdef FEAT_AUTOCMD
4072 {EXPAND_EVENTS, get_event_name, TRUE},
4073 {EXPAND_AUGROUP, get_augroup_name, TRUE},
4074#endif
4075#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4076 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4077 {EXPAND_LANGUAGE, get_lang_arg, TRUE},
4078#endif
4079 {EXPAND_ENV_VARS, get_env_name, TRUE},
4080 };
4081 int i;
4082
4083 /*
4084 * Find a context in the table and call the ExpandGeneric() with the
4085 * right function to do the expansion.
4086 */
4087 ret = FAIL;
4088 for (i = 0; i < sizeof(tab) / sizeof(struct expgen); ++i)
4089 if (xp->xp_context == tab[i].context)
4090 {
4091 if (tab[i].ic)
4092 regmatch.rm_ic = TRUE;
4093 ret = ExpandGeneric(xp, &regmatch, num_file, file, tab[i].func);
4094 break;
4095 }
4096 }
4097
4098 vim_free(regmatch.regprog);
4099
4100 return ret;
4101#endif /* FEAT_CMDL_COMPL */
4102}
4103
4104#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
4105/*
4106 * Expand a list of names.
4107 *
4108 * Generic function for command line completion. It calls a function to
4109 * obtain strings, one by one. The strings are matched against a regexp
4110 * program. Matching strings are copied into an array, which is returned.
4111 *
4112 * Returns OK when no problems encountered, FAIL for error (out of memory).
4113 */
4114 int
4115ExpandGeneric(xp, regmatch, num_file, file, func)
4116 expand_T *xp;
4117 regmatch_T *regmatch;
4118 int *num_file;
4119 char_u ***file;
4120 char_u *((*func)__ARGS((expand_T *, int)));
4121 /* returns a string from the list */
4122{
4123 int i;
4124 int count = 0;
4125 int loop;
4126 char_u *str;
4127
4128 /* do this loop twice:
4129 * loop == 0: count the number of matching names
4130 * loop == 1: copy the matching names into allocated memory
4131 */
4132 for (loop = 0; loop <= 1; ++loop)
4133 {
4134 for (i = 0; ; ++i)
4135 {
4136 str = (*func)(xp, i);
4137 if (str == NULL) /* end of list */
4138 break;
4139 if (*str == NUL) /* skip empty strings */
4140 continue;
4141
4142 if (vim_regexec(regmatch, str, (colnr_T)0))
4143 {
4144 if (loop)
4145 {
4146 str = vim_strsave_escaped(str, (char_u *)" \t\\.");
4147 (*file)[count] = str;
4148#ifdef FEAT_MENU
4149 if (func == get_menu_names && str != NULL)
4150 {
4151 /* test for separator added by get_menu_names() */
4152 str += STRLEN(str) - 1;
4153 if (*str == '\001')
4154 *str = '.';
4155 }
4156#endif
4157 }
4158 ++count;
4159 }
4160 }
4161 if (loop == 0)
4162 {
4163 if (count == 0)
4164 return OK;
4165 *num_file = count;
4166 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
4167 if (*file == NULL)
4168 {
4169 *file = (char_u **)"";
4170 return FAIL;
4171 }
4172 count = 0;
4173 }
4174 }
4175 return OK;
4176}
4177
4178# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
4179/*
4180 * Expand names with a function defined by the user.
4181 */
4182 static int
4183ExpandUserDefined(xp, regmatch, num_file, file)
4184 expand_T *xp;
4185 regmatch_T *regmatch;
4186 int *num_file;
4187 char_u ***file;
4188{
4189 char_u *args[3];
4190 char_u *all;
4191 char_u *s;
4192 char_u *e;
4193 char_u keep;
4194 char_u num[50];
4195 garray_T ga;
4196 int save_current_SID = current_SID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004197 struct cmdline_info save_ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198
4199 if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0')
4200 return FAIL;
4201 *num_file = 0;
4202 *file = NULL;
4203
4204 keep = ccline.cmdbuff[ccline.cmdlen];
4205 ccline.cmdbuff[ccline.cmdlen] = 0;
4206 sprintf((char *)num, "%d", ccline.cmdpos);
4207 args[0] = xp->xp_pattern;
4208 args[1] = ccline.cmdbuff;
4209 args[2] = num;
4210
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004211 /* Save the cmdline, we don't know what the function may do. */
4212 save_ccline = ccline;
4213 ccline.cmdbuff = NULL;
4214 ccline.cmdprompt = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215 current_SID = xp->xp_scriptID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004216
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217 all = call_vim_function(xp->xp_arg, 3, args, FALSE);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004218
4219 ccline = save_ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 current_SID = save_current_SID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004221
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 ccline.cmdbuff[ccline.cmdlen] = keep;
4223 if (all == NULL)
4224 return FAIL;
4225
4226 ga_init2(&ga, (int)sizeof(char *), 3);
4227 for (s = all; *s != NUL; s = e)
4228 {
4229 e = vim_strchr(s, '\n');
4230 if (e == NULL)
4231 e = s + STRLEN(s);
4232 keep = *e;
4233 *e = 0;
4234
4235 if (xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0)
4236 {
4237 *e = keep;
4238 if (*e != NUL)
4239 ++e;
4240 continue;
4241 }
4242
4243 if (ga_grow(&ga, 1) == FAIL)
4244 break;
4245
4246 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s));
4247 ++ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248
4249 *e = keep;
4250 if (*e != NUL)
4251 ++e;
4252 }
4253 vim_free(all);
4254 *file = ga.ga_data;
4255 *num_file = ga.ga_len;
4256 return OK;
4257}
4258#endif
4259
4260/*
4261 * Expand color scheme names: 'runtimepath'/colors/{pat}.vim
4262 * or compiler names.
4263 */
4264 static int
4265ExpandRTDir(pat, num_file, file, dirname)
4266 char_u *pat;
4267 int *num_file;
4268 char_u ***file;
4269 char *dirname; /* "colors" or "compiler" */
4270{
4271 char_u *all;
4272 char_u *s;
4273 char_u *e;
4274 garray_T ga;
4275
4276 *num_file = 0;
4277 *file = NULL;
4278 s = alloc((unsigned)(STRLEN(pat) + STRLEN(dirname) + 7));
4279 if (s == NULL)
4280 return FAIL;
4281 sprintf((char *)s, "%s/%s*.vim", dirname, pat);
4282 all = globpath(p_rtp, s);
4283 vim_free(s);
4284 if (all == NULL)
4285 return FAIL;
4286
4287 ga_init2(&ga, (int)sizeof(char *), 3);
4288 for (s = all; *s != NUL; s = e)
4289 {
4290 e = vim_strchr(s, '\n');
4291 if (e == NULL)
4292 e = s + STRLEN(s);
4293 if (ga_grow(&ga, 1) == FAIL)
4294 break;
4295 if (e - 4 > s && STRNICMP(e - 4, ".vim", 4) == 0)
4296 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004297 for (s = e - 4; s > all; mb_ptr_back(all, s))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 if (*s == '\n' || vim_ispathsep(*s))
4299 break;
4300 ++s;
4301 ((char_u **)ga.ga_data)[ga.ga_len] =
4302 vim_strnsave(s, (int)(e - s - 4));
4303 ++ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304 }
4305 if (*e != NUL)
4306 ++e;
4307 }
4308 vim_free(all);
4309 *file = ga.ga_data;
4310 *num_file = ga.ga_len;
4311 return OK;
4312}
4313
4314#endif
4315
4316#if defined(FEAT_CMDL_COMPL) || defined(FEAT_EVAL) || defined(PROTO)
4317/*
4318 * Expand "file" for all comma-separated directories in "path".
4319 * Returns an allocated string with all matches concatenated, separated by
4320 * newlines. Returns NULL for an error or no matches.
4321 */
4322 char_u *
4323globpath(path, file)
4324 char_u *path;
4325 char_u *file;
4326{
4327 expand_T xpc;
4328 char_u *buf;
4329 garray_T ga;
4330 int i;
4331 int len;
4332 int num_p;
4333 char_u **p;
4334 char_u *cur = NULL;
4335
4336 buf = alloc(MAXPATHL);
4337 if (buf == NULL)
4338 return NULL;
4339
4340 xpc.xp_context = EXPAND_FILES;
4341 xpc.xp_backslash = XP_BS_NONE;
4342 ga_init2(&ga, 1, 100);
4343
4344 /* Loop over all entries in {path}. */
4345 while (*path != NUL)
4346 {
4347 /* Copy one item of the path to buf[] and concatenate the file name. */
4348 copy_option_part(&path, buf, MAXPATHL, ",");
4349 if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL)
4350 {
4351 add_pathsep(buf);
4352 STRCAT(buf, file);
4353 if (ExpandFromContext(&xpc, buf, &num_p, &p, WILD_SILENT) != FAIL
4354 && num_p > 0)
4355 {
4356 ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT);
4357 for (len = 0, i = 0; i < num_p; ++i)
4358 len += (long_u)STRLEN(p[i]) + 1;
4359
4360 /* Concatenate new results to previous ones. */
4361 if (ga_grow(&ga, len) == OK)
4362 {
4363 cur = (char_u *)ga.ga_data + ga.ga_len;
4364 for (i = 0; i < num_p; ++i)
4365 {
4366 STRCPY(cur, p[i]);
4367 cur += STRLEN(p[i]);
4368 *cur++ = '\n';
4369 }
4370 ga.ga_len += len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004371 }
4372 FreeWild(num_p, p);
4373 }
4374 }
4375 }
4376 if (cur != NULL)
4377 *--cur = 0; /* Replace trailing newline with NUL */
4378
4379 vim_free(buf);
4380 return (char_u *)ga.ga_data;
4381}
4382
4383#endif
4384
4385#if defined(FEAT_CMDHIST) || defined(PROTO)
4386
4387/*********************************
4388 * Command line history stuff *
4389 *********************************/
4390
4391/*
4392 * Translate a history character to the associated type number.
4393 */
4394 static int
4395hist_char2type(c)
4396 int c;
4397{
4398 if (c == ':')
4399 return HIST_CMD;
4400 if (c == '=')
4401 return HIST_EXPR;
4402 if (c == '@')
4403 return HIST_INPUT;
4404 if (c == '>')
4405 return HIST_DEBUG;
4406 return HIST_SEARCH; /* must be '?' or '/' */
4407}
4408
4409/*
4410 * Table of history names.
4411 * These names are used in :history and various hist...() functions.
4412 * It is sufficient to give the significant prefix of a history name.
4413 */
4414
4415static char *(history_names[]) =
4416{
4417 "cmd",
4418 "search",
4419 "expr",
4420 "input",
4421 "debug",
4422 NULL
4423};
4424
4425/*
4426 * init_history() - Initialize the command line history.
4427 * Also used to re-allocate the history when the size changes.
4428 */
4429 static void
4430init_history()
4431{
4432 int newlen; /* new length of history table */
4433 histentry_T *temp;
4434 int i;
4435 int j;
4436 int type;
4437
4438 /*
4439 * If size of history table changed, reallocate it
4440 */
4441 newlen = (int)p_hi;
4442 if (newlen != hislen) /* history length changed */
4443 {
4444 for (type = 0; type < HIST_COUNT; ++type) /* adjust the tables */
4445 {
4446 if (newlen)
4447 {
4448 temp = (histentry_T *)lalloc(
4449 (long_u)(newlen * sizeof(histentry_T)), TRUE);
4450 if (temp == NULL) /* out of memory! */
4451 {
4452 if (type == 0) /* first one: just keep the old length */
4453 {
4454 newlen = hislen;
4455 break;
4456 }
4457 /* Already changed one table, now we can only have zero
4458 * length for all tables. */
4459 newlen = 0;
4460 type = -1;
4461 continue;
4462 }
4463 }
4464 else
4465 temp = NULL;
4466 if (newlen == 0 || temp != NULL)
4467 {
4468 if (hisidx[type] < 0) /* there are no entries yet */
4469 {
4470 for (i = 0; i < newlen; ++i)
4471 {
4472 temp[i].hisnum = 0;
4473 temp[i].hisstr = NULL;
4474 }
4475 }
4476 else if (newlen > hislen) /* array becomes bigger */
4477 {
4478 for (i = 0; i <= hisidx[type]; ++i)
4479 temp[i] = history[type][i];
4480 j = i;
4481 for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
4482 {
4483 temp[i].hisnum = 0;
4484 temp[i].hisstr = NULL;
4485 }
4486 for ( ; j < hislen; ++i, ++j)
4487 temp[i] = history[type][j];
4488 }
4489 else /* array becomes smaller or 0 */
4490 {
4491 j = hisidx[type];
4492 for (i = newlen - 1; ; --i)
4493 {
4494 if (i >= 0) /* copy newest entries */
4495 temp[i] = history[type][j];
4496 else /* remove older entries */
4497 vim_free(history[type][j].hisstr);
4498 if (--j < 0)
4499 j = hislen - 1;
4500 if (j == hisidx[type])
4501 break;
4502 }
4503 hisidx[type] = newlen - 1;
4504 }
4505 vim_free(history[type]);
4506 history[type] = temp;
4507 }
4508 }
4509 hislen = newlen;
4510 }
4511}
4512
4513/*
4514 * Check if command line 'str' is already in history.
4515 * If 'move_to_front' is TRUE, matching entry is moved to end of history.
4516 */
4517 static int
4518in_history(type, str, move_to_front)
4519 int type;
4520 char_u *str;
4521 int move_to_front; /* Move the entry to the front if it exists */
4522{
4523 int i;
4524 int last_i = -1;
4525
4526 if (hisidx[type] < 0)
4527 return FALSE;
4528 i = hisidx[type];
4529 do
4530 {
4531 if (history[type][i].hisstr == NULL)
4532 return FALSE;
4533 if (STRCMP(str, history[type][i].hisstr) == 0)
4534 {
4535 if (!move_to_front)
4536 return TRUE;
4537 last_i = i;
4538 break;
4539 }
4540 if (--i < 0)
4541 i = hislen - 1;
4542 } while (i != hisidx[type]);
4543
4544 if (last_i >= 0)
4545 {
4546 str = history[type][i].hisstr;
4547 while (i != hisidx[type])
4548 {
4549 if (++i >= hislen)
4550 i = 0;
4551 history[type][last_i] = history[type][i];
4552 last_i = i;
4553 }
4554 history[type][i].hisstr = str;
4555 history[type][i].hisnum = ++hisnum[type];
4556 return TRUE;
4557 }
4558 return FALSE;
4559}
4560
4561/*
4562 * Convert history name (from table above) to its HIST_ equivalent.
4563 * When "name" is empty, return "cmd" history.
4564 * Returns -1 for unknown history name.
4565 */
4566 int
4567get_histtype(name)
4568 char_u *name;
4569{
4570 int i;
4571 int len = (int)STRLEN(name);
4572
4573 /* No argument: use current history. */
4574 if (len == 0)
4575 return hist_char2type(ccline.cmdfirstc);
4576
4577 for (i = 0; history_names[i] != NULL; ++i)
4578 if (STRNICMP(name, history_names[i], len) == 0)
4579 return i;
4580
4581 if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
4582 return hist_char2type(name[0]);
4583
4584 return -1;
4585}
4586
4587static int last_maptick = -1; /* last seen maptick */
4588
4589/*
4590 * Add the given string to the given history. If the string is already in the
4591 * history then it is moved to the front. "histype" may be one of he HIST_
4592 * values.
4593 */
4594 void
4595add_to_history(histype, new_entry, in_map, sep)
4596 int histype;
4597 char_u *new_entry;
4598 int in_map; /* consider maptick when inside a mapping */
4599 int sep; /* separator character used (search hist) */
4600{
4601 histentry_T *hisptr;
4602 int len;
4603
4604 if (hislen == 0) /* no history */
4605 return;
4606
4607 /*
4608 * Searches inside the same mapping overwrite each other, so that only
4609 * the last line is kept. Be careful not to remove a line that was moved
4610 * down, only lines that were added.
4611 */
4612 if (histype == HIST_SEARCH && in_map)
4613 {
4614 if (maptick == last_maptick)
4615 {
4616 /* Current line is from the same mapping, remove it */
4617 hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
4618 vim_free(hisptr->hisstr);
4619 hisptr->hisstr = NULL;
4620 hisptr->hisnum = 0;
4621 --hisnum[histype];
4622 if (--hisidx[HIST_SEARCH] < 0)
4623 hisidx[HIST_SEARCH] = hislen - 1;
4624 }
4625 last_maptick = -1;
4626 }
4627 if (!in_history(histype, new_entry, TRUE))
4628 {
4629 if (++hisidx[histype] == hislen)
4630 hisidx[histype] = 0;
4631 hisptr = &history[histype][hisidx[histype]];
4632 vim_free(hisptr->hisstr);
4633
4634 /* Store the separator after the NUL of the string. */
4635 len = STRLEN(new_entry);
4636 hisptr->hisstr = vim_strnsave(new_entry, len + 2);
4637 if (hisptr->hisstr != NULL)
4638 hisptr->hisstr[len + 1] = sep;
4639
4640 hisptr->hisnum = ++hisnum[histype];
4641 if (histype == HIST_SEARCH && in_map)
4642 last_maptick = maptick;
4643 }
4644}
4645
4646#if defined(FEAT_EVAL) || defined(PROTO)
4647
4648/*
4649 * Get identifier of newest history entry.
4650 * "histype" may be one of the HIST_ values.
4651 */
4652 int
4653get_history_idx(histype)
4654 int histype;
4655{
4656 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
4657 || hisidx[histype] < 0)
4658 return -1;
4659
4660 return history[histype][hisidx[histype]].hisnum;
4661}
4662
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004663static struct cmdline_info *get_ccline_ptr __ARGS((void));
4664
4665/*
4666 * Get pointer to the command line info to use. cmdline_paste() may clear
4667 * ccline and put the previous value in prev_ccline.
4668 */
4669 static struct cmdline_info *
4670get_ccline_ptr()
4671{
4672 if ((State & CMDLINE) == 0)
4673 return NULL;
4674 if (ccline.cmdbuff != NULL)
4675 return &ccline;
4676 if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
4677 return &prev_ccline;
4678 return NULL;
4679}
4680
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681/*
4682 * Get the current command line in allocated memory.
4683 * Only works when the command line is being edited.
4684 * Returns NULL when something is wrong.
4685 */
4686 char_u *
4687get_cmdline_str()
4688{
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004689 struct cmdline_info *p = get_ccline_ptr();
4690
4691 if (p == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 return NULL;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004693 return vim_strnsave(p->cmdbuff, p->cmdlen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694}
4695
4696/*
4697 * Get the current command line position, counted in bytes.
4698 * Zero is the first position.
4699 * Only works when the command line is being edited.
4700 * Returns -1 when something is wrong.
4701 */
4702 int
4703get_cmdline_pos()
4704{
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004705 struct cmdline_info *p = get_ccline_ptr();
4706
4707 if (p == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 return -1;
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004709 return p->cmdpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710}
4711
4712/*
4713 * Set the command line byte position to "pos". Zero is the first position.
4714 * Only works when the command line is being edited.
4715 * Returns 1 when failed, 0 when OK.
4716 */
4717 int
4718set_cmdline_pos(pos)
4719 int pos;
4720{
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00004721 struct cmdline_info *p = get_ccline_ptr();
4722
4723 if (p == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724 return 1;
4725
4726 /* The position is not set directly but after CTRL-\ e or CTRL-R = has
4727 * changed the command line. */
4728 if (pos < 0)
4729 new_cmdpos = 0;
4730 else
4731 new_cmdpos = pos;
4732 return 0;
4733}
4734
4735/*
4736 * Calculate history index from a number:
4737 * num > 0: seen as identifying number of a history entry
4738 * num < 0: relative position in history wrt newest entry
4739 * "histype" may be one of the HIST_ values.
4740 */
4741 static int
4742calc_hist_idx(histype, num)
4743 int histype;
4744 int num;
4745{
4746 int i;
4747 histentry_T *hist;
4748 int wrapped = FALSE;
4749
4750 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
4751 || (i = hisidx[histype]) < 0 || num == 0)
4752 return -1;
4753
4754 hist = history[histype];
4755 if (num > 0)
4756 {
4757 while (hist[i].hisnum > num)
4758 if (--i < 0)
4759 {
4760 if (wrapped)
4761 break;
4762 i += hislen;
4763 wrapped = TRUE;
4764 }
4765 if (hist[i].hisnum == num && hist[i].hisstr != NULL)
4766 return i;
4767 }
4768 else if (-num <= hislen)
4769 {
4770 i += num + 1;
4771 if (i < 0)
4772 i += hislen;
4773 if (hist[i].hisstr != NULL)
4774 return i;
4775 }
4776 return -1;
4777}
4778
4779/*
4780 * Get a history entry by its index.
4781 * "histype" may be one of the HIST_ values.
4782 */
4783 char_u *
4784get_history_entry(histype, idx)
4785 int histype;
4786 int idx;
4787{
4788 idx = calc_hist_idx(histype, idx);
4789 if (idx >= 0)
4790 return history[histype][idx].hisstr;
4791 else
4792 return (char_u *)"";
4793}
4794
4795/*
4796 * Clear all entries of a history.
4797 * "histype" may be one of the HIST_ values.
4798 */
4799 int
4800clr_history(histype)
4801 int histype;
4802{
4803 int i;
4804 histentry_T *hisptr;
4805
4806 if (hislen != 0 && histype >= 0 && histype < HIST_COUNT)
4807 {
4808 hisptr = history[histype];
4809 for (i = hislen; i--;)
4810 {
4811 vim_free(hisptr->hisstr);
4812 hisptr->hisnum = 0;
4813 hisptr++->hisstr = NULL;
4814 }
4815 hisidx[histype] = -1; /* mark history as cleared */
4816 hisnum[histype] = 0; /* reset identifier counter */
4817 return OK;
4818 }
4819 return FAIL;
4820}
4821
4822/*
4823 * Remove all entries matching {str} from a history.
4824 * "histype" may be one of the HIST_ values.
4825 */
4826 int
4827del_history_entry(histype, str)
4828 int histype;
4829 char_u *str;
4830{
4831 regmatch_T regmatch;
4832 histentry_T *hisptr;
4833 int idx;
4834 int i;
4835 int last;
4836 int found = FALSE;
4837
4838 regmatch.regprog = NULL;
4839 regmatch.rm_ic = FALSE; /* always match case */
4840 if (hislen != 0
4841 && histype >= 0
4842 && histype < HIST_COUNT
4843 && *str != NUL
4844 && (idx = hisidx[histype]) >= 0
4845 && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING))
4846 != NULL)
4847 {
4848 i = last = idx;
4849 do
4850 {
4851 hisptr = &history[histype][i];
4852 if (hisptr->hisstr == NULL)
4853 break;
4854 if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0))
4855 {
4856 found = TRUE;
4857 vim_free(hisptr->hisstr);
4858 hisptr->hisstr = NULL;
4859 hisptr->hisnum = 0;
4860 }
4861 else
4862 {
4863 if (i != last)
4864 {
4865 history[histype][last] = *hisptr;
4866 hisptr->hisstr = NULL;
4867 hisptr->hisnum = 0;
4868 }
4869 if (--last < 0)
4870 last += hislen;
4871 }
4872 if (--i < 0)
4873 i += hislen;
4874 } while (i != idx);
4875 if (history[histype][idx].hisstr == NULL)
4876 hisidx[histype] = -1;
4877 }
4878 vim_free(regmatch.regprog);
4879 return found;
4880}
4881
4882/*
4883 * Remove an indexed entry from a history.
4884 * "histype" may be one of the HIST_ values.
4885 */
4886 int
4887del_history_idx(histype, idx)
4888 int histype;
4889 int idx;
4890{
4891 int i, j;
4892
4893 i = calc_hist_idx(histype, idx);
4894 if (i < 0)
4895 return FALSE;
4896 idx = hisidx[histype];
4897 vim_free(history[histype][i].hisstr);
4898
4899 /* When deleting the last added search string in a mapping, reset
4900 * last_maptick, so that the last added search string isn't deleted again.
4901 */
4902 if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
4903 last_maptick = -1;
4904
4905 while (i != idx)
4906 {
4907 j = (i + 1) % hislen;
4908 history[histype][i] = history[histype][j];
4909 i = j;
4910 }
4911 history[histype][i].hisstr = NULL;
4912 history[histype][i].hisnum = 0;
4913 if (--i < 0)
4914 i += hislen;
4915 hisidx[histype] = i;
4916 return TRUE;
4917}
4918
4919#endif /* FEAT_EVAL */
4920
4921#if defined(FEAT_CRYPT) || defined(PROTO)
4922/*
4923 * Very specific function to remove the value in ":set key=val" from the
4924 * history.
4925 */
4926 void
4927remove_key_from_history()
4928{
4929 char_u *p;
4930 int i;
4931
4932 i = hisidx[HIST_CMD];
4933 if (i < 0)
4934 return;
4935 p = history[HIST_CMD][i].hisstr;
4936 if (p != NULL)
4937 for ( ; *p; ++p)
4938 if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3]))
4939 {
4940 p = vim_strchr(p + 3, '=');
4941 if (p == NULL)
4942 break;
4943 ++p;
4944 for (i = 0; p[i] && !vim_iswhite(p[i]); ++i)
4945 if (p[i] == '\\' && p[i + 1])
4946 ++i;
4947 mch_memmove(p, p + i, STRLEN(p + i) + 1);
4948 --p;
4949 }
4950}
4951#endif
4952
4953#endif /* FEAT_CMDHIST */
4954
4955#if defined(FEAT_QUICKFIX) || defined(FEAT_CMDHIST) || defined(PROTO)
4956/*
4957 * Get indices "num1,num2" that specify a range within a list (not a range of
4958 * text lines in a buffer!) from a string. Used for ":history" and ":clist".
4959 * Returns OK if parsed successfully, otherwise FAIL.
4960 */
4961 int
4962get_list_range(str, num1, num2)
4963 char_u **str;
4964 int *num1;
4965 int *num2;
4966{
4967 int len;
4968 int first = FALSE;
4969 long num;
4970
4971 *str = skipwhite(*str);
4972 if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */
4973 {
4974 vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
4975 *str += len;
4976 *num1 = (int)num;
4977 first = TRUE;
4978 }
4979 *str = skipwhite(*str);
4980 if (**str == ',') /* parse "to" part of range */
4981 {
4982 *str = skipwhite(*str + 1);
4983 vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
4984 if (len > 0)
4985 {
4986 *num2 = (int)num;
4987 *str = skipwhite(*str + len);
4988 }
4989 else if (!first) /* no number given at all */
4990 return FAIL;
4991 }
4992 else if (first) /* only one number given */
4993 *num2 = *num1;
4994 return OK;
4995}
4996#endif
4997
4998#if defined(FEAT_CMDHIST) || defined(PROTO)
4999/*
5000 * :history command - print a history
5001 */
5002 void
5003ex_history(eap)
5004 exarg_T *eap;
5005{
5006 histentry_T *hist;
5007 int histype1 = HIST_CMD;
5008 int histype2 = HIST_CMD;
5009 int hisidx1 = 1;
5010 int hisidx2 = -1;
5011 int idx;
5012 int i, j, k;
5013 char_u *end;
5014 char_u *arg = eap->arg;
5015
5016 if (hislen == 0)
5017 {
5018 MSG(_("'history' option is zero"));
5019 return;
5020 }
5021
5022 if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ','))
5023 {
5024 end = arg;
5025 while (ASCII_ISALPHA(*end)
5026 || vim_strchr((char_u *)":=@>/?", *end) != NULL)
5027 end++;
5028 i = *end;
5029 *end = NUL;
5030 histype1 = get_histtype(arg);
5031 if (histype1 == -1)
5032 {
5033 if (STRICMP(arg, "all") == 0)
5034 {
5035 histype1 = 0;
5036 histype2 = HIST_COUNT-1;
5037 }
5038 else
5039 {
5040 *end = i;
5041 EMSG(_(e_trailing));
5042 return;
5043 }
5044 }
5045 else
5046 histype2 = histype1;
5047 *end = i;
5048 }
5049 else
5050 end = arg;
5051 if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL)
5052 {
5053 EMSG(_(e_trailing));
5054 return;
5055 }
5056
5057 for (; !got_int && histype1 <= histype2; ++histype1)
5058 {
5059 STRCPY(IObuff, "\n # ");
5060 STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
5061 MSG_PUTS_TITLE(IObuff);
5062 idx = hisidx[histype1];
5063 hist = history[histype1];
5064 j = hisidx1;
5065 k = hisidx2;
5066 if (j < 0)
5067 j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
5068 if (k < 0)
5069 k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
5070 if (idx >= 0 && j <= k)
5071 for (i = idx + 1; !got_int; ++i)
5072 {
5073 if (i == hislen)
5074 i = 0;
5075 if (hist[i].hisstr != NULL
5076 && hist[i].hisnum >= j && hist[i].hisnum <= k)
5077 {
5078 msg_putchar('\n');
5079 sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ',
5080 hist[i].hisnum);
5081 if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
5082 trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
5083 (int)Columns - 10);
5084 else
5085 STRCAT(IObuff, hist[i].hisstr);
5086 msg_outtrans(IObuff);
5087 out_flush();
5088 }
5089 if (i == idx)
5090 break;
5091 }
5092 }
5093}
5094#endif
5095
5096#if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
5097static char_u **viminfo_history[HIST_COUNT] = {NULL, NULL, NULL, NULL};
5098static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0};
5099static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0};
5100static int viminfo_add_at_front = FALSE;
5101
5102static int hist_type2char __ARGS((int type, int use_question));
5103
5104/*
5105 * Translate a history type number to the associated character.
5106 */
5107 static int
5108hist_type2char(type, use_question)
5109 int type;
5110 int use_question; /* use '?' instead of '/' */
5111{
5112 if (type == HIST_CMD)
5113 return ':';
5114 if (type == HIST_SEARCH)
5115 {
5116 if (use_question)
5117 return '?';
5118 else
5119 return '/';
5120 }
5121 if (type == HIST_EXPR)
5122 return '=';
5123 return '@';
5124}
5125
5126/*
5127 * Prepare for reading the history from the viminfo file.
5128 * This allocates history arrays to store the read history lines.
5129 */
5130 void
5131prepare_viminfo_history(asklen)
5132 int asklen;
5133{
5134 int i;
5135 int num;
5136 int type;
5137 int len;
5138
5139 init_history();
5140 viminfo_add_at_front = (asklen != 0);
5141 if (asklen > hislen)
5142 asklen = hislen;
5143
5144 for (type = 0; type < HIST_COUNT; ++type)
5145 {
5146 /*
5147 * Count the number of empty spaces in the history list. If there are
5148 * more spaces available than we request, then fill them up.
5149 */
5150 for (i = 0, num = 0; i < hislen; i++)
5151 if (history[type][i].hisstr == NULL)
5152 num++;
5153 len = asklen;
5154 if (num > len)
5155 len = num;
5156 if (len <= 0)
5157 viminfo_history[type] = NULL;
5158 else
5159 viminfo_history[type] =
5160 (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE);
5161 if (viminfo_history[type] == NULL)
5162 len = 0;
5163 viminfo_hislen[type] = len;
5164 viminfo_hisidx[type] = 0;
5165 }
5166}
5167
5168/*
5169 * Accept a line from the viminfo, store it in the history array when it's
5170 * new.
5171 */
5172 int
5173read_viminfo_history(virp)
5174 vir_T *virp;
5175{
5176 int type;
5177 long_u len;
5178 char_u *val;
5179 char_u *p;
5180
5181 type = hist_char2type(virp->vir_line[0]);
5182 if (viminfo_hisidx[type] < viminfo_hislen[type])
5183 {
5184 val = viminfo_readstring(virp, 1, TRUE);
5185 if (val != NULL && *val != NUL)
5186 {
5187 if (!in_history(type, val + (type == HIST_SEARCH),
5188 viminfo_add_at_front))
5189 {
5190 /* Need to re-allocate to append the separator byte. */
5191 len = STRLEN(val);
5192 p = lalloc(len + 2, TRUE);
5193 if (p != NULL)
5194 {
5195 if (type == HIST_SEARCH)
5196 {
5197 /* Search entry: Move the separator from the first
5198 * column to after the NUL. */
5199 mch_memmove(p, val + 1, (size_t)len);
5200 p[len] = (*val == ' ' ? NUL : *val);
5201 }
5202 else
5203 {
5204 /* Not a search entry: No separator in the viminfo
5205 * file, add a NUL separator. */
5206 mch_memmove(p, val, (size_t)len + 1);
5207 p[len + 1] = NUL;
5208 }
5209 viminfo_history[type][viminfo_hisidx[type]++] = p;
5210 }
5211 }
5212 }
5213 vim_free(val);
5214 }
5215 return viminfo_readline(virp);
5216}
5217
5218 void
5219finish_viminfo_history()
5220{
5221 int idx;
5222 int i;
5223 int type;
5224
5225 for (type = 0; type < HIST_COUNT; ++type)
5226 {
5227 if (history[type] == NULL)
5228 return;
5229 idx = hisidx[type] + viminfo_hisidx[type];
5230 if (idx >= hislen)
5231 idx -= hislen;
5232 else if (idx < 0)
5233 idx = hislen - 1;
5234 if (viminfo_add_at_front)
5235 hisidx[type] = idx;
5236 else
5237 {
5238 if (hisidx[type] == -1)
5239 hisidx[type] = hislen - 1;
5240 do
5241 {
5242 if (history[type][idx].hisstr != NULL)
5243 break;
5244 if (++idx == hislen)
5245 idx = 0;
5246 } while (idx != hisidx[type]);
5247 if (idx != hisidx[type] && --idx < 0)
5248 idx = hislen - 1;
5249 }
5250 for (i = 0; i < viminfo_hisidx[type]; i++)
5251 {
5252 vim_free(history[type][idx].hisstr);
5253 history[type][idx].hisstr = viminfo_history[type][i];
5254 if (--idx < 0)
5255 idx = hislen - 1;
5256 }
5257 idx += 1;
5258 idx %= hislen;
5259 for (i = 0; i < viminfo_hisidx[type]; i++)
5260 {
5261 history[type][idx++].hisnum = ++hisnum[type];
5262 idx %= hislen;
5263 }
5264 vim_free(viminfo_history[type]);
5265 viminfo_history[type] = NULL;
5266 }
5267}
5268
5269 void
5270write_viminfo_history(fp)
5271 FILE *fp;
5272{
5273 int i;
5274 int type;
5275 int num_saved;
5276 char_u *p;
5277 int c;
5278
5279 init_history();
5280 if (hislen == 0)
5281 return;
5282 for (type = 0; type < HIST_COUNT; ++type)
5283 {
5284 num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
5285 if (num_saved == 0)
5286 continue;
5287 if (num_saved < 0) /* Use default */
5288 num_saved = hislen;
5289 fprintf(fp, _("\n# %s History (newest to oldest):\n"),
5290 type == HIST_CMD ? _("Command Line") :
5291 type == HIST_SEARCH ? _("Search String") :
5292 type == HIST_EXPR ? _("Expression") :
5293 _("Input Line"));
5294 if (num_saved > hislen)
5295 num_saved = hislen;
5296 i = hisidx[type];
5297 if (i >= 0)
5298 while (num_saved--)
5299 {
5300 p = history[type][i].hisstr;
5301 if (p != NULL)
5302 {
5303 putc(hist_type2char(type, TRUE), fp);
5304 /* For the search history: put the separator in the second
5305 * column; use a space if there isn't one. */
5306 if (type == HIST_SEARCH)
5307 {
5308 c = p[STRLEN(p) + 1];
5309 putc(c == NUL ? ' ' : c, fp);
5310 }
5311 viminfo_writestring(fp, p);
5312 }
5313 if (--i < 0)
5314 i = hislen - 1;
5315 }
5316 }
5317}
5318#endif /* FEAT_VIMINFO */
5319
5320#if defined(FEAT_FKMAP) || defined(PROTO)
5321/*
5322 * Write a character at the current cursor+offset position.
5323 * It is directly written into the command buffer block.
5324 */
5325 void
5326cmd_pchar(c, offset)
5327 int c, offset;
5328{
5329 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
5330 {
5331 EMSG(_("E198: cmd_pchar beyond the command length"));
5332 return;
5333 }
5334 ccline.cmdbuff[ccline.cmdpos + offset] = (char_u)c;
5335 ccline.cmdbuff[ccline.cmdlen] = NUL;
5336}
5337
5338 int
5339cmd_gchar(offset)
5340 int offset;
5341{
5342 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
5343 {
5344 /* EMSG(_("cmd_gchar beyond the command length")); */
5345 return NUL;
5346 }
5347 return (int)ccline.cmdbuff[ccline.cmdpos + offset];
5348}
5349#endif
5350
5351#if defined(FEAT_CMDWIN) || defined(PROTO)
5352/*
5353 * Open a window on the current command line and history. Allow editing in
5354 * the window. Returns when the window is closed.
5355 * Returns:
5356 * CR if the command is to be executed
5357 * Ctrl_C if it is to be abandoned
5358 * K_IGNORE if editing continues
5359 */
5360 static int
5361ex_window()
5362{
5363 struct cmdline_info save_ccline;
5364 buf_T *old_curbuf = curbuf;
5365 win_T *old_curwin = curwin;
5366 buf_T *bp;
5367 win_T *wp;
5368 int i;
5369 linenr_T lnum;
5370 int histtype;
5371 garray_T winsizes;
5372 char_u typestr[2];
5373 int save_restart_edit = restart_edit;
5374 int save_State = State;
5375 int save_exmode = exmode_active;
5376
5377 /* Can't do this recursively. Can't do it when typing a password. */
5378 if (cmdwin_type != 0
5379# if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
5380 || cmdline_star > 0
5381# endif
5382 )
5383 {
5384 beep_flush();
5385 return K_IGNORE;
5386 }
5387
5388 /* Save current window sizes. */
5389 win_size_save(&winsizes);
5390
5391# ifdef FEAT_AUTOCMD
5392 /* Don't execute autocommands while creating the window. */
5393 ++autocmd_block;
5394# endif
5395 /* Create a window for the command-line buffer. */
5396 if (win_split((int)p_cwh, WSP_BOT) == FAIL)
5397 {
5398 beep_flush();
5399 return K_IGNORE;
5400 }
5401 cmdwin_type = ccline.cmdfirstc;
5402 if (cmdwin_type == NUL)
5403 cmdwin_type = '-';
5404
5405 /* Create the command-line buffer empty. */
5406 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE);
5407 (void)setfname(curbuf, (char_u *)"command-line", NULL, TRUE);
5408 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
5409 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
5410 curbuf->b_p_ma = TRUE;
5411# ifdef FEAT_RIGHTLEFT
5412 curwin->w_p_rl = FALSE;
5413# endif
5414# ifdef FEAT_SCROLLBIND
5415 curwin->w_p_scb = FALSE;
5416# endif
5417
5418# ifdef FEAT_AUTOCMD
5419 /* Do execute autocommands for setting the filetype (load syntax). */
5420 --autocmd_block;
5421# endif
5422
5423 histtype = hist_char2type(ccline.cmdfirstc);
5424 if (histtype == HIST_CMD || histtype == HIST_DEBUG)
5425 {
5426 if (p_wc == TAB)
5427 {
5428 add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
5429 add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
5430 }
5431 set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
5432 }
5433
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005434 /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
5435 * sets 'textwidth' to 78). */
5436 curbuf->b_p_tw = 0;
5437
Bram Moolenaar071d4272004-06-13 20:20:40 +00005438 /* Fill the buffer with the history. */
5439 init_history();
5440 if (hislen > 0)
5441 {
5442 i = hisidx[histtype];
5443 if (i >= 0)
5444 {
5445 lnum = 0;
5446 do
5447 {
5448 if (++i == hislen)
5449 i = 0;
5450 if (history[histtype][i].hisstr != NULL)
5451 ml_append(lnum++, history[histtype][i].hisstr,
5452 (colnr_T)0, FALSE);
5453 }
5454 while (i != hisidx[histtype]);
5455 }
5456 }
5457
5458 /* Replace the empty last line with the current command-line and put the
5459 * cursor there. */
5460 ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE);
5461 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5462 curwin->w_cursor.col = ccline.cmdpos;
5463 redraw_later(NOT_VALID);
5464
5465 /* Save the command line info, can be used recursively. */
5466 save_ccline = ccline;
5467 ccline.cmdbuff = NULL;
5468 ccline.cmdprompt = NULL;
5469
5470 /* No Ex mode here! */
5471 exmode_active = 0;
5472
5473 State = NORMAL;
5474# ifdef FEAT_MOUSE
5475 setmouse();
5476# endif
5477
5478# ifdef FEAT_AUTOCMD
5479 /* Trigger CmdwinEnter autocommands. */
5480 typestr[0] = cmdwin_type;
5481 typestr[1] = NUL;
5482 apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, FALSE, curbuf);
5483# endif
5484
5485 i = RedrawingDisabled;
5486 RedrawingDisabled = 0;
5487
5488 /*
5489 * Call the main loop until <CR> or CTRL-C is typed.
5490 */
5491 cmdwin_result = 0;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005492 main_loop(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005493
5494 RedrawingDisabled = i;
5495
5496# ifdef FEAT_AUTOCMD
5497 /* Trigger CmdwinLeave autocommands. */
5498 apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, FALSE, curbuf);
5499# endif
5500
5501 /* Restore the comand line info. */
5502 ccline = save_ccline;
5503 cmdwin_type = 0;
5504
5505 exmode_active = save_exmode;
5506
5507 /* Safety check: The old window or buffer was deleted: It's a a bug when
5508 * this happens! */
5509 if (!win_valid(old_curwin) || !buf_valid(old_curbuf))
5510 {
5511 cmdwin_result = Ctrl_C;
5512 EMSG(_("E199: Active window or buffer deleted"));
5513 }
5514 else
5515 {
5516# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5517 /* autocmds may abort script processing */
5518 if (aborting() && cmdwin_result != K_IGNORE)
5519 cmdwin_result = Ctrl_C;
5520# endif
5521 /* Set the new command line from the cmdline buffer. */
5522 vim_free(ccline.cmdbuff);
5523 if (cmdwin_result == K_XF1) /* :qa! typed */
5524 {
5525 ccline.cmdbuff = vim_strsave((char_u *)"qa!");
5526 cmdwin_result = CAR;
5527 }
5528 else if (cmdwin_result == K_XF2) /* :qa typed */
5529 {
5530 ccline.cmdbuff = vim_strsave((char_u *)"qa");
5531 cmdwin_result = CAR;
5532 }
5533 else
5534 ccline.cmdbuff = vim_strsave(ml_get_curline());
5535 if (ccline.cmdbuff == NULL)
5536 cmdwin_result = Ctrl_C;
5537 else
5538 {
5539 ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
5540 ccline.cmdbufflen = ccline.cmdlen + 1;
5541 ccline.cmdpos = curwin->w_cursor.col;
5542 if (ccline.cmdpos > ccline.cmdlen)
5543 ccline.cmdpos = ccline.cmdlen;
5544 if (cmdwin_result == K_IGNORE)
5545 {
5546 set_cmdspos_cursor();
5547 redrawcmd();
5548 }
5549 }
5550
5551# ifdef FEAT_AUTOCMD
5552 /* Don't execute autocommands while deleting the window. */
5553 ++autocmd_block;
5554# endif
5555 wp = curwin;
5556 bp = curbuf;
5557 win_goto(old_curwin);
5558 win_close(wp, TRUE);
5559 close_buffer(NULL, bp, DOBUF_WIPE);
5560
5561 /* Restore window sizes. */
5562 win_size_restore(&winsizes);
5563
5564# ifdef FEAT_AUTOCMD
5565 --autocmd_block;
5566# endif
5567 }
5568
5569 ga_clear(&winsizes);
5570 restart_edit = save_restart_edit;
5571
5572 State = save_State;
5573# ifdef FEAT_MOUSE
5574 setmouse();
5575# endif
5576
5577 return cmdwin_result;
5578}
5579#endif /* FEAT_CMDWIN */
5580
5581/*
5582 * Used for commands that either take a simple command string argument, or:
5583 * cmd << endmarker
5584 * {script}
5585 * endmarker
5586 * Returns a pointer to allocated memory with {script} or NULL.
5587 */
5588 char_u *
5589script_get(eap, cmd)
5590 exarg_T *eap;
5591 char_u *cmd;
5592{
5593 char_u *theline;
5594 char *end_pattern = NULL;
5595 char dot[] = ".";
5596 garray_T ga;
5597
5598 if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL)
5599 return NULL;
5600
5601 ga_init2(&ga, 1, 0x400);
5602
5603 if (cmd[2] != NUL)
5604 end_pattern = (char *)skipwhite(cmd + 2);
5605 else
5606 end_pattern = dot;
5607
5608 for (;;)
5609 {
5610 theline = eap->getline(
5611#ifdef FEAT_EVAL
Bram Moolenaar12805862005-01-05 22:16:17 +00005612 eap->cstack->cs_looplevel > 0 ? -1 :
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613#endif
5614 NUL, eap->cookie, 0);
5615
5616 if (theline == NULL || STRCMP(end_pattern, theline) == 0)
5617 break;
5618
5619 ga_concat(&ga, theline);
5620 ga_append(&ga, '\n');
5621 vim_free(theline);
5622 }
Bram Moolenaar269ec652004-07-29 08:43:53 +00005623 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624
5625 return (char_u *)ga.ga_data;
5626}