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