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