blob: 8c153021a9ea86f3ca50aa71e3aa46e06422888f [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;
1967 ++line_ga.ga_room;
1968 /* compute column that cursor should be in */
1969 v = 0;
1970 q = ((char_u *)line_ga.ga_data);
1971 for (i = 0; i < line_ga.ga_len; ++i)
1972 {
1973 if (*q == TAB)
1974 v += 8 - v % 8;
1975 else
1976 v += ptr2cells(q);
1977 ++q;
1978 }
1979 /* erase characters to position cursor */
1980 while (vcol > v)
1981 {
1982 msg_putchar('\b');
1983 msg_putchar(' ');
1984 msg_putchar('\b');
1985 --vcol;
1986 }
1987 }
1988 continue;
1989 }
1990
1991 if (c1 == Ctrl_U)
1992 {
1993 msg_col = startcol;
1994 msg_clr_eos();
1995 line_ga.ga_room += line_ga.ga_len;
1996 line_ga.ga_len = 0;
1997 continue;
1998 }
1999
2000 if (c1 == Ctrl_V)
2001 {
2002 escaped = TRUE;
2003 continue;
2004 }
2005 }
2006
2007 if (IS_SPECIAL(c1))
2008 c1 = '?';
2009 ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1;
2010 if (c1 == '\n')
2011 msg_putchar('\n');
2012 else if (c1 == TAB)
2013 {
2014 /* Don't use chartabsize(), 'ts' can be different */
2015 do
2016 {
2017 msg_putchar(' ');
2018 } while (++vcol % 8);
2019 }
2020 else
2021 {
2022 msg_outtrans_len(
2023 ((char_u *)line_ga.ga_data) + line_ga.ga_len, 1);
2024 vcol += char2cells(c1);
2025 }
2026 ++line_ga.ga_len;
2027 --line_ga.ga_room;
2028 escaped = FALSE;
2029 }
2030 windgoto(msg_row, msg_col);
2031 }
2032# ifndef NO_COOKED_INPUT
2033 else
2034# endif
2035#endif
2036#ifndef NO_COOKED_INPUT
2037 {
2038 line_ga.ga_len += len;
2039 line_ga.ga_room -= len;
2040 }
2041#endif
2042 p = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
2043 if (line_ga.ga_len && p[-1] == '\n')
2044 {
2045 finished = TRUE;
2046 --line_ga.ga_len;
2047 --p;
2048 *p = NUL;
2049 }
2050 }
2051
2052 /* note that cursor has moved, because of the echoed <CR> */
2053 screen_down();
2054 /* make following messages go to the next line */
2055 msg_didout = FALSE;
2056 msg_col = 0;
2057 if (msg_row < Rows - 1)
2058 ++msg_row;
2059 emsg_on_display = FALSE; /* don't want ui_delay() */
2060
2061 if (got_int)
2062 ga_clear(&line_ga);
2063
2064 return (char_u *)line_ga.ga_data;
2065}
2066
2067#ifdef CURSOR_SHAPE
2068/*
2069 * Return TRUE if ccline.overstrike is on.
2070 */
2071 int
2072cmdline_overstrike()
2073{
2074 return ccline.overstrike;
2075}
2076
2077/*
2078 * Return TRUE if the cursor is at the end of the cmdline.
2079 */
2080 int
2081cmdline_at_end()
2082{
2083 return (ccline.cmdpos >= ccline.cmdlen);
2084}
2085#endif
2086
2087#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
2088/*
2089 * Return the virtual column number at the current cursor position.
2090 * This is used by the IM code to obtain the start of the preedit string.
2091 */
2092 colnr_T
2093cmdline_getvcol_cursor()
2094{
2095 if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen)
2096 return MAXCOL;
2097
2098# ifdef FEAT_MBYTE
2099 if (has_mbyte)
2100 {
2101 colnr_T col;
2102 int i = 0;
2103
2104 for (col = 0; i < ccline.cmdpos; ++col)
2105 i += (*mb_ptr2len_check)(ccline.cmdbuff + i);
2106
2107 return col;
2108 }
2109 else
2110# endif
2111 return ccline.cmdpos;
2112}
2113#endif
2114
2115#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2116/*
2117 * If part of the command line is an IM preedit string, redraw it with
2118 * IM feedback attributes. The cursor position is restored after drawing.
2119 */
2120 static void
2121redrawcmd_preedit()
2122{
2123 if ((State & CMDLINE)
2124 && xic != NULL
2125 && im_get_status()
2126 && !p_imdisable
2127 && im_is_preediting())
2128 {
2129 int cmdpos = 0;
2130 int cmdspos;
2131 int old_row;
2132 int old_col;
2133 colnr_T col;
2134
2135 old_row = msg_row;
2136 old_col = msg_col;
2137 cmdspos = ((ccline.cmdfirstc) ? 1 : 0) + ccline.cmdindent;
2138
2139# ifdef FEAT_MBYTE
2140 if (has_mbyte)
2141 {
2142 for (col = 0; col < preedit_start_col
2143 && cmdpos < ccline.cmdlen; ++col)
2144 {
2145 cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos);
2146 cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff + cmdpos);
2147 }
2148 }
2149 else
2150# endif
2151 {
2152 cmdspos += preedit_start_col;
2153 cmdpos += preedit_start_col;
2154 }
2155
2156 msg_row = cmdline_row + (cmdspos / (int)Columns);
2157 msg_col = cmdspos % (int)Columns;
2158 if (msg_row >= Rows)
2159 msg_row = Rows - 1;
2160
2161 for (col = 0; cmdpos < ccline.cmdlen; ++col)
2162 {
2163 int char_len;
2164 int char_attr;
2165
2166 char_attr = im_get_feedback_attr(col);
2167 if (char_attr < 0)
2168 break; /* end of preedit string */
2169
2170# ifdef FEAT_MBYTE
2171 if (has_mbyte)
2172 char_len = (*mb_ptr2len_check)(ccline.cmdbuff + cmdpos);
2173 else
2174# endif
2175 char_len = 1;
2176
2177 msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr);
2178 cmdpos += char_len;
2179 }
2180
2181 msg_row = old_row;
2182 msg_col = old_col;
2183 }
2184}
2185#endif /* FEAT_XIM && FEAT_GUI_GTK */
2186
2187/*
2188 * Allocate a new command line buffer.
2189 * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
2190 * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
2191 */
2192 static void
2193alloc_cmdbuff(len)
2194 int len;
2195{
2196 /*
2197 * give some extra space to avoid having to allocate all the time
2198 */
2199 if (len < 80)
2200 len = 100;
2201 else
2202 len += 20;
2203
2204 ccline.cmdbuff = alloc(len); /* caller should check for out-of-memory */
2205 ccline.cmdbufflen = len;
2206}
2207
2208/*
2209 * Re-allocate the command line to length len + something extra.
2210 * return FAIL for failure, OK otherwise
2211 */
2212 static int
2213realloc_cmdbuff(len)
2214 int len;
2215{
2216 char_u *p;
2217
2218 p = ccline.cmdbuff;
2219 alloc_cmdbuff(len); /* will get some more */
2220 if (ccline.cmdbuff == NULL) /* out of memory */
2221 {
2222 ccline.cmdbuff = p; /* keep the old one */
2223 return FAIL;
2224 }
2225 mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen + 1);
2226 vim_free(p);
2227 return OK;
2228}
2229
2230/*
2231 * Draw part of the cmdline at the current cursor position. But draw stars
2232 * when cmdline_star is TRUE.
2233 */
2234 static void
2235draw_cmdline(start, len)
2236 int start;
2237 int len;
2238{
2239#if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
2240 int i;
2241
2242 if (cmdline_star > 0)
2243 for (i = 0; i < len; ++i)
2244 {
2245 msg_putchar('*');
2246# ifdef FEAT_MBYTE
2247 if (has_mbyte)
2248 i += (*mb_ptr2len_check)(ccline.cmdbuff + start + i) - 1;
2249# endif
2250 }
2251 else
2252#endif
2253#ifdef FEAT_ARABIC
2254 if (p_arshape && !p_tbidi && enc_utf8 && len > 0)
2255 {
2256 static char_u *buf;
2257 static int buflen = 0;
2258 char_u *p;
2259 int j;
2260 int newlen = 0;
2261 int mb_l;
2262 int pc, pc1;
2263 int prev_c = 0;
2264 int prev_c1 = 0;
2265 int u8c, u8c_c1, u8c_c2;
2266 int nc = 0;
2267 int dummy;
2268
2269 /*
2270 * Do arabic shaping into a temporary buffer. This is very
2271 * inefficient!
2272 */
2273 if (len * 2 > buflen)
2274 {
2275 /* Re-allocate the buffer. We keep it around to avoid a lot of
2276 * alloc()/free() calls. */
2277 vim_free(buf);
2278 buflen = len * 2;
2279 buf = alloc(buflen);
2280 if (buf == NULL)
2281 return; /* out of memory */
2282 }
2283
2284 for (j = start; j < start + len; j += mb_l)
2285 {
2286 p = ccline.cmdbuff + j;
2287 u8c = utfc_ptr2char_len(p, &u8c_c1, &u8c_c2, start + len - j);
2288 mb_l = utfc_ptr2len_check_len(p, start + len - j);
2289 if (ARABIC_CHAR(u8c))
2290 {
2291 /* Do Arabic shaping. */
2292 if (cmdmsg_rl)
2293 {
2294 /* displaying from right to left */
2295 pc = prev_c;
2296 pc1 = prev_c1;
2297 prev_c1 = u8c_c1;
2298 if (j + mb_l >= start + len)
2299 nc = NUL;
2300 else
2301 nc = utf_ptr2char(p + mb_l);
2302 }
2303 else
2304 {
2305 /* displaying from left to right */
2306 if (j + mb_l >= start + len)
2307 pc = NUL;
2308 else
2309 pc = utfc_ptr2char_len(p + mb_l, &pc1, &dummy,
2310 start + len - j - mb_l);
2311 nc = prev_c;
2312 }
2313 prev_c = u8c;
2314
2315 u8c = arabic_shape(u8c, NULL, &u8c_c1, pc, pc1, nc);
2316
2317 newlen += (*mb_char2bytes)(u8c, buf + newlen);
2318 if (u8c_c1 != 0)
2319 {
2320 newlen += (*mb_char2bytes)(u8c_c1, buf + newlen);
2321 if (u8c_c2 != 0)
2322 newlen += (*mb_char2bytes)(u8c_c2, buf + newlen);
2323 }
2324 }
2325 else
2326 {
2327 prev_c = u8c;
2328 mch_memmove(buf + newlen, p, mb_l);
2329 newlen += mb_l;
2330 }
2331 }
2332
2333 msg_outtrans_len(buf, newlen);
2334 }
2335 else
2336#endif
2337 msg_outtrans_len(ccline.cmdbuff + start, len);
2338}
2339
2340/*
2341 * Put a character on the command line. Shifts the following text to the
2342 * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
2343 * "c" must be printable (fit in one display cell)!
2344 */
2345 void
2346putcmdline(c, shift)
2347 int c;
2348 int shift;
2349{
2350 if (cmd_silent)
2351 return;
2352 msg_no_more = TRUE;
2353 msg_putchar(c);
2354 if (shift)
2355 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
2356 msg_no_more = FALSE;
2357 cursorcmd();
2358}
2359
2360/*
2361 * Undo a putcmdline(c, FALSE).
2362 */
2363 void
2364unputcmdline()
2365{
2366 if (cmd_silent)
2367 return;
2368 msg_no_more = TRUE;
2369 if (ccline.cmdlen == ccline.cmdpos)
2370 msg_putchar(' ');
2371 else
2372 draw_cmdline(ccline.cmdpos, 1);
2373 msg_no_more = FALSE;
2374 cursorcmd();
2375}
2376
2377/*
2378 * Put the given string, of the given length, onto the command line.
2379 * If len is -1, then STRLEN() is used to calculate the length.
2380 * If 'redraw' is TRUE then the new part of the command line, and the remaining
2381 * part will be redrawn, otherwise it will not. If this function is called
2382 * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
2383 * called afterwards.
2384 */
2385 int
2386put_on_cmdline(str, len, redraw)
2387 char_u *str;
2388 int len;
2389 int redraw;
2390{
2391 int retval;
2392 int i;
2393 int m;
2394 int c;
2395
2396 if (len < 0)
2397 len = (int)STRLEN(str);
2398
2399 /* Check if ccline.cmdbuff needs to be longer */
2400 if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen)
2401 retval = realloc_cmdbuff(ccline.cmdlen + len);
2402 else
2403 retval = OK;
2404 if (retval == OK)
2405 {
2406 if (!ccline.overstrike)
2407 {
2408 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
2409 ccline.cmdbuff + ccline.cmdpos,
2410 (size_t)(ccline.cmdlen - ccline.cmdpos));
2411 ccline.cmdlen += len;
2412 }
2413 else
2414 {
2415#ifdef FEAT_MBYTE
2416 if (has_mbyte)
2417 {
2418 /* Count nr of characters in the new string. */
2419 m = 0;
2420 for (i = 0; i < len; i += (*mb_ptr2len_check)(str + i))
2421 ++m;
2422 /* Count nr of bytes in cmdline that are overwritten by these
2423 * characters. */
2424 for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0;
2425 i += (*mb_ptr2len_check)(ccline.cmdbuff + i))
2426 --m;
2427 if (i < ccline.cmdlen)
2428 {
2429 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len,
2430 ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i));
2431 ccline.cmdlen += ccline.cmdpos + len - i;
2432 }
2433 else
2434 ccline.cmdlen = ccline.cmdpos + len;
2435 }
2436 else
2437#endif
2438 if (ccline.cmdpos + len > ccline.cmdlen)
2439 ccline.cmdlen = ccline.cmdpos + len;
2440 }
2441 mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len);
2442 ccline.cmdbuff[ccline.cmdlen] = NUL;
2443
2444#ifdef FEAT_MBYTE
2445 if (enc_utf8)
2446 {
2447 /* When the inserted text starts with a composing character,
2448 * backup to the character before it. There could be two of them.
2449 */
2450 i = 0;
2451 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
2452 while (ccline.cmdpos > 0 && utf_iscomposing(c))
2453 {
2454 i = (*mb_head_off)(ccline.cmdbuff,
2455 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
2456 ccline.cmdpos -= i;
2457 len += i;
2458 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos);
2459 }
2460# ifdef FEAT_ARABIC
2461 if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c))
2462 {
2463 /* Check the previous character for Arabic combining pair. */
2464 i = (*mb_head_off)(ccline.cmdbuff,
2465 ccline.cmdbuff + ccline.cmdpos - 1) + 1;
2466 if (arabic_combine(utf_ptr2char(ccline.cmdbuff
2467 + ccline.cmdpos - i), c))
2468 {
2469 ccline.cmdpos -= i;
2470 len += i;
2471 }
2472 else
2473 i = 0;
2474 }
2475# endif
2476 if (i != 0)
2477 {
2478 /* Also backup the cursor position. */
2479 i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
2480 ccline.cmdspos -= i;
2481 msg_col -= i;
2482 if (msg_col < 0)
2483 {
2484 msg_col += Columns;
2485 --msg_row;
2486 }
2487 }
2488 }
2489#endif
2490
2491 if (redraw && !cmd_silent)
2492 {
2493 msg_no_more = TRUE;
2494 i = cmdline_row;
2495 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
2496 /* Avoid clearing the rest of the line too often. */
2497 if (cmdline_row != i || ccline.overstrike)
2498 msg_clr_eos();
2499 msg_no_more = FALSE;
2500 }
2501#ifdef FEAT_FKMAP
2502 /*
2503 * If we are in Farsi command mode, the character input must be in
2504 * Insert mode. So do not advance the cmdpos.
2505 */
2506 if (!cmd_fkmap)
2507#endif
2508 {
2509 if (KeyTyped)
2510 m = Columns * Rows;
2511 else
2512 m = MAXCOL;
2513 for (i = 0; i < len; ++i)
2514 {
2515 c = cmdline_charsize(ccline.cmdpos);
2516#ifdef FEAT_MBYTE
2517 /* count ">" for a double-wide char that doesn't fit. */
2518 if (has_mbyte)
2519 correct_cmdspos(ccline.cmdpos, c);
2520#endif
2521 /* Stop cursor at the end of the screen */
2522 if (ccline.cmdspos + c >= m)
2523 break;
2524 ccline.cmdspos += c;
2525#ifdef FEAT_MBYTE
2526 if (has_mbyte)
2527 {
2528 c = (*mb_ptr2len_check)(ccline.cmdbuff + ccline.cmdpos) - 1;
2529 if (c > len - i - 1)
2530 c = len - i - 1;
2531 ccline.cmdpos += c;
2532 i += c;
2533 }
2534#endif
2535 ++ccline.cmdpos;
2536 }
2537 }
2538 }
2539 if (redraw)
2540 msg_check();
2541 return retval;
2542}
2543
Bram Moolenaar8299df92004-07-10 09:47:34 +00002544/*
2545 * paste a yank register into the command line.
2546 * used by CTRL-R command in command-line mode
2547 * insert_reg() can't be used here, because special characters from the
2548 * register contents will be interpreted as commands.
2549 *
2550 * return FAIL for failure, OK otherwise
2551 */
2552 static int
2553cmdline_paste(regname, literally)
2554 int regname;
2555 int literally; /* Insert text literally instead of "as typed" */
2556{
2557 long i;
2558 char_u *arg;
2559 int allocated;
2560 struct cmdline_info save_ccline;
2561
2562 /* check for valid regname; also accept special characters for CTRL-R in
2563 * the command line */
2564 if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
2565 && regname != Ctrl_A && !valid_yank_reg(regname, FALSE))
2566 return FAIL;
2567
2568 /* A register containing CTRL-R can cause an endless loop. Allow using
2569 * CTRL-C to break the loop. */
2570 line_breakcheck();
2571 if (got_int)
2572 return FAIL;
2573
2574#ifdef FEAT_CLIPBOARD
2575 regname = may_get_selection(regname);
2576#endif
2577
2578 /* Need to save and restore ccline, because obtaining the "=" register may
2579 * execute "normal :cmd" and overwrite it. */
2580 save_ccline = ccline;
2581 ccline.cmdbuff = NULL;
2582 ccline.cmdprompt = NULL;
2583 i = get_spec_reg(regname, &arg, &allocated, TRUE);
2584 ccline = save_ccline;
2585
2586 if (i)
2587 {
2588 /* Got the value of a special register in "arg". */
2589 if (arg == NULL)
2590 return FAIL;
2591 cmdline_paste_str(arg, literally);
2592 if (allocated)
2593 vim_free(arg);
2594 return OK;
2595 }
2596
2597 return cmdline_paste_reg(regname, literally);
2598}
2599
2600/*
2601 * Put a string on the command line.
2602 * When "literally" is TRUE, insert literally.
2603 * When "literally" is FALSE, insert as typed, but don't leave the command
2604 * line.
2605 */
2606 void
2607cmdline_paste_str(s, literally)
2608 char_u *s;
2609 int literally;
2610{
2611 int c, cv;
2612
2613 if (literally)
2614 put_on_cmdline(s, -1, TRUE);
2615 else
2616 while (*s != NUL)
2617 {
2618 cv = *s;
2619 if (cv == Ctrl_V && s[1])
2620 ++s;
2621#ifdef FEAT_MBYTE
2622 if (has_mbyte)
2623 {
2624 c = mb_ptr2char(s);
2625 s += mb_char2len(c);
2626 }
2627 else
2628#endif
2629 c = *s++;
2630 if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL
2631#ifdef UNIX
2632 || c == intr_char
2633#endif
2634 || (c == Ctrl_BSL && *s == Ctrl_N))
2635 stuffcharReadbuff(Ctrl_V);
2636 stuffcharReadbuff(c);
2637 }
2638}
2639
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640#ifdef FEAT_WILDMENU
2641/*
2642 * Delete characters on the command line, from "from" to the current
2643 * position.
2644 */
2645 static void
2646cmdline_del(from)
2647 int from;
2648{
2649 mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
2650 (size_t)(ccline.cmdlen - ccline.cmdpos + 1));
2651 ccline.cmdlen -= ccline.cmdpos - from;
2652 ccline.cmdpos = from;
2653}
2654#endif
2655
2656/*
2657 * this fuction is called when the screen size changes and with incremental
2658 * search
2659 */
2660 void
2661redrawcmdline()
2662{
2663 if (cmd_silent)
2664 return;
2665 need_wait_return = FALSE;
2666 compute_cmdrow();
2667 redrawcmd();
2668 cursorcmd();
2669}
2670
2671 static void
2672redrawcmdprompt()
2673{
2674 int i;
2675
2676 if (cmd_silent)
2677 return;
2678 if (ccline.cmdfirstc)
2679 msg_putchar(ccline.cmdfirstc);
2680 if (ccline.cmdprompt != NULL)
2681 {
2682 msg_puts_attr(ccline.cmdprompt, ccline.cmdattr);
2683 ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
2684 /* do the reverse of set_cmdspos() */
2685 if (ccline.cmdfirstc)
2686 --ccline.cmdindent;
2687 }
2688 else
2689 for (i = ccline.cmdindent; i > 0; --i)
2690 msg_putchar(' ');
2691}
2692
2693/*
2694 * Redraw what is currently on the command line.
2695 */
2696 void
2697redrawcmd()
2698{
2699 if (cmd_silent)
2700 return;
2701
2702 msg_start();
2703 redrawcmdprompt();
2704
2705 /* Don't use more prompt, truncate the cmdline if it doesn't fit. */
2706 msg_no_more = TRUE;
2707 draw_cmdline(0, ccline.cmdlen);
2708 msg_clr_eos();
2709 msg_no_more = FALSE;
2710
2711 set_cmdspos_cursor();
2712
2713 /*
2714 * An emsg() before may have set msg_scroll. This is used in normal mode,
2715 * in cmdline mode we can reset them now.
2716 */
2717 msg_scroll = FALSE; /* next message overwrites cmdline */
2718
2719 /* Typing ':' at the more prompt may set skip_redraw. We don't want this
2720 * in cmdline mode */
2721 skip_redraw = FALSE;
2722}
2723
2724 void
2725compute_cmdrow()
2726{
2727 if (exmode_active || msg_scrolled)
2728 cmdline_row = Rows - 1;
2729 else
2730 cmdline_row = W_WINROW(lastwin) + lastwin->w_height
2731 + W_STATUS_HEIGHT(lastwin);
2732}
2733
2734 static void
2735cursorcmd()
2736{
2737 if (cmd_silent)
2738 return;
2739
2740#ifdef FEAT_RIGHTLEFT
2741 if (cmdmsg_rl)
2742 {
2743 msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
2744 msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
2745 if (msg_row <= 0)
2746 msg_row = Rows - 1;
2747 }
2748 else
2749#endif
2750 {
2751 msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
2752 msg_col = ccline.cmdspos % (int)Columns;
2753 if (msg_row >= Rows)
2754 msg_row = Rows - 1;
2755 }
2756
2757 windgoto(msg_row, msg_col);
2758#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
2759 redrawcmd_preedit();
2760#endif
2761#ifdef MCH_CURSOR_SHAPE
2762 mch_update_cursor();
2763#endif
2764}
2765
2766 void
2767gotocmdline(clr)
2768 int clr;
2769{
2770 msg_start();
2771#ifdef FEAT_RIGHTLEFT
2772 if (cmdmsg_rl)
2773 msg_col = Columns - 1;
2774 else
2775#endif
2776 msg_col = 0; /* always start in column 0 */
2777 if (clr) /* clear the bottom line(s) */
2778 msg_clr_eos(); /* will reset clear_cmdline */
2779 windgoto(cmdline_row, 0);
2780}
2781
2782/*
2783 * Check the word in front of the cursor for an abbreviation.
2784 * Called when the non-id character "c" has been entered.
2785 * When an abbreviation is recognized it is removed from the text with
2786 * backspaces and the replacement string is inserted, followed by "c".
2787 */
2788 static int
2789ccheck_abbr(c)
2790 int c;
2791{
2792 if (p_paste || no_abbr) /* no abbreviations or in paste mode */
2793 return FALSE;
2794
2795 return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0);
2796}
2797
2798/*
2799 * Return FAIL if this is not an appropriate context in which to do
2800 * completion of anything, return OK if it is (even if there are no matches).
2801 * For the caller, this means that the character is just passed through like a
2802 * normal character (instead of being expanded). This allows :s/^I^D etc.
2803 */
2804 static int
2805nextwild(xp, type, options)
2806 expand_T *xp;
2807 int type;
2808 int options; /* extra options for ExpandOne() */
2809{
2810 int i, j;
2811 char_u *p1;
2812 char_u *p2;
2813 int oldlen;
2814 int difflen;
2815 int v;
2816
2817 if (xp->xp_numfiles == -1)
2818 {
2819 set_expand_context(xp);
2820 cmd_showtail = expand_showtail(xp);
2821 }
2822
2823 if (xp->xp_context == EXPAND_UNSUCCESSFUL)
2824 {
2825 beep_flush();
2826 return OK; /* Something illegal on command line */
2827 }
2828 if (xp->xp_context == EXPAND_NOTHING)
2829 {
2830 /* Caller can use the character as a normal char instead */
2831 return FAIL;
2832 }
2833
2834 MSG_PUTS("..."); /* show that we are busy */
2835 out_flush();
2836
2837 i = (int)(xp->xp_pattern - ccline.cmdbuff);
2838 oldlen = ccline.cmdpos - i;
2839
2840 if (type == WILD_NEXT || type == WILD_PREV)
2841 {
2842 /*
2843 * Get next/previous match for a previous expanded pattern.
2844 */
2845 p2 = ExpandOne(xp, NULL, NULL, 0, type);
2846 }
2847 else
2848 {
2849 /*
2850 * Translate string into pattern and expand it.
2851 */
2852 if ((p1 = addstar(&ccline.cmdbuff[i], oldlen, xp->xp_context)) == NULL)
2853 p2 = NULL;
2854 else
2855 {
2856 p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], oldlen),
2857 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT|WILD_ESCAPE
2858 |options, type);
2859 vim_free(p1);
2860 /* longest match: make sure it is not shorter (happens with :help */
2861 if (p2 != NULL && type == WILD_LONGEST)
2862 {
2863 for (j = 0; j < oldlen; ++j)
2864 if (ccline.cmdbuff[i + j] == '*'
2865 || ccline.cmdbuff[i + j] == '?')
2866 break;
2867 if ((int)STRLEN(p2) < j)
2868 {
2869 vim_free(p2);
2870 p2 = NULL;
2871 }
2872 }
2873 }
2874 }
2875
2876 if (p2 != NULL && !got_int)
2877 {
2878 difflen = (int)STRLEN(p2) - oldlen;
2879 if (ccline.cmdlen + difflen > ccline.cmdbufflen - 4)
2880 {
2881 v = realloc_cmdbuff(ccline.cmdlen + difflen);
2882 xp->xp_pattern = ccline.cmdbuff + i;
2883 }
2884 else
2885 v = OK;
2886 if (v == OK)
2887 {
2888 vim_strncpy(&ccline.cmdbuff[ccline.cmdpos + difflen],
2889 &ccline.cmdbuff[ccline.cmdpos],
2890 ccline.cmdlen - ccline.cmdpos + 1);
2891 STRNCPY(&ccline.cmdbuff[i], p2, STRLEN(p2));
2892 ccline.cmdlen += difflen;
2893 ccline.cmdpos += difflen;
2894 }
2895 }
2896 vim_free(p2);
2897
2898 redrawcmd();
Bram Moolenaar009b2592004-10-24 19:18:58 +00002899 cursorcmd();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
2901 /* When expanding a ":map" command and no matches are found, assume that
2902 * the key is supposed to be inserted literally */
2903 if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL)
2904 return FAIL;
2905
2906 if (xp->xp_numfiles <= 0 && p2 == NULL)
2907 beep_flush();
2908 else if (xp->xp_numfiles == 1)
2909 /* free expanded pattern */
2910 (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
2911
2912 return OK;
2913}
2914
2915/*
2916 * Do wildcard expansion on the string 'str'.
2917 * Chars that should not be expanded must be preceded with a backslash.
2918 * Return a pointer to alloced memory containing the new string.
2919 * Return NULL for failure.
2920 *
2921 * Results are cached in xp->xp_files and xp->xp_numfiles.
2922 *
2923 * mode = WILD_FREE: just free previously expanded matches
2924 * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
2925 * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
2926 * mode = WILD_NEXT: use next match in multiple match, wrap to first
2927 * mode = WILD_PREV: use previous match in multiple match, wrap to first
2928 * mode = WILD_ALL: return all matches concatenated
2929 * mode = WILD_LONGEST: return longest matched part
2930 *
2931 * options = WILD_LIST_NOTFOUND: list entries without a match
2932 * options = WILD_HOME_REPLACE: do home_replace() for buffer names
2933 * options = WILD_USE_NL: Use '\n' for WILD_ALL
2934 * options = WILD_NO_BEEP: Don't beep for multiple matches
2935 * options = WILD_ADD_SLASH: add a slash after directory names
2936 * options = WILD_KEEP_ALL: don't remove 'wildignore' entries
2937 * options = WILD_SILENT: don't print warning messages
2938 * options = WILD_ESCAPE: put backslash before special chars
2939 *
2940 * The variables xp->xp_context and xp->xp_backslash must have been set!
2941 */
2942 char_u *
2943ExpandOne(xp, str, orig, options, mode)
2944 expand_T *xp;
2945 char_u *str;
2946 char_u *orig; /* allocated copy of original of expanded string */
2947 int options;
2948 int mode;
2949{
2950 char_u *ss = NULL;
2951 static int findex;
2952 static char_u *orig_save = NULL; /* kept value of orig */
2953 int i;
2954 long_u len;
2955 int non_suf_match; /* number without matching suffix */
2956
2957 /*
2958 * first handle the case of using an old match
2959 */
2960 if (mode == WILD_NEXT || mode == WILD_PREV)
2961 {
2962 if (xp->xp_numfiles > 0)
2963 {
2964 if (mode == WILD_PREV)
2965 {
2966 if (findex == -1)
2967 findex = xp->xp_numfiles;
2968 --findex;
2969 }
2970 else /* mode == WILD_NEXT */
2971 ++findex;
2972
2973 /*
2974 * When wrapping around, return the original string, set findex to
2975 * -1.
2976 */
2977 if (findex < 0)
2978 {
2979 if (orig_save == NULL)
2980 findex = xp->xp_numfiles - 1;
2981 else
2982 findex = -1;
2983 }
2984 if (findex >= xp->xp_numfiles)
2985 {
2986 if (orig_save == NULL)
2987 findex = 0;
2988 else
2989 findex = -1;
2990 }
2991#ifdef FEAT_WILDMENU
2992 if (p_wmnu)
2993 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
2994 findex, cmd_showtail);
2995#endif
2996 if (findex == -1)
2997 return vim_strsave(orig_save);
2998 return vim_strsave(xp->xp_files[findex]);
2999 }
3000 else
3001 return NULL;
3002 }
3003
3004/* free old names */
3005 if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
3006 {
3007 FreeWild(xp->xp_numfiles, xp->xp_files);
3008 xp->xp_numfiles = -1;
3009 vim_free(orig_save);
3010 orig_save = NULL;
3011 }
3012 findex = 0;
3013
3014 if (mode == WILD_FREE) /* only release file name */
3015 return NULL;
3016
3017 if (xp->xp_numfiles == -1)
3018 {
3019 vim_free(orig_save);
3020 orig_save = orig;
3021
3022 /*
3023 * Do the expansion.
3024 */
3025 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
3026 options) == FAIL)
3027 {
3028#ifdef FNAME_ILLEGAL
3029 /* Illegal file name has been silently skipped. But when there
3030 * are wildcards, the real problem is that there was no match,
3031 * causing the pattern to be added, which has illegal characters.
3032 */
3033 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
3034 EMSG2(_(e_nomatch2), str);
3035#endif
3036 }
3037 else if (xp->xp_numfiles == 0)
3038 {
3039 if (!(options & WILD_SILENT))
3040 EMSG2(_(e_nomatch2), str);
3041 }
3042 else
3043 {
3044 /* Escape the matches for use on the command line. */
3045 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
3046
3047 /*
3048 * Check for matching suffixes in file names.
3049 */
3050 if (mode != WILD_ALL && mode != WILD_LONGEST)
3051 {
3052 if (xp->xp_numfiles)
3053 non_suf_match = xp->xp_numfiles;
3054 else
3055 non_suf_match = 1;
3056 if ((xp->xp_context == EXPAND_FILES
3057 || xp->xp_context == EXPAND_DIRECTORIES)
3058 && xp->xp_numfiles > 1)
3059 {
3060 /*
3061 * More than one match; check suffix.
3062 * The files will have been sorted on matching suffix in
3063 * expand_wildcards, only need to check the first two.
3064 */
3065 non_suf_match = 0;
3066 for (i = 0; i < 2; ++i)
3067 if (match_suffix(xp->xp_files[i]))
3068 ++non_suf_match;
3069 }
3070 if (non_suf_match != 1)
3071 {
3072 /* Can we ever get here unless it's while expanding
3073 * interactively? If not, we can get rid of this all
3074 * together. Don't really want to wait for this message
3075 * (and possibly have to hit return to continue!).
3076 */
3077 if (!(options & WILD_SILENT))
3078 EMSG(_(e_toomany));
3079 else if (!(options & WILD_NO_BEEP))
3080 beep_flush();
3081 }
3082 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
3083 ss = vim_strsave(xp->xp_files[0]);
3084 }
3085 }
3086 }
3087
3088 /* Find longest common part */
3089 if (mode == WILD_LONGEST && xp->xp_numfiles > 0)
3090 {
3091 for (len = 0; xp->xp_files[0][len]; ++len)
3092 {
3093 for (i = 0; i < xp->xp_numfiles; ++i)
3094 {
3095#ifdef CASE_INSENSITIVE_FILENAME
3096 if (xp->xp_context == EXPAND_DIRECTORIES
3097 || xp->xp_context == EXPAND_FILES
3098 || xp->xp_context == EXPAND_BUFFERS)
3099 {
3100 if (TOLOWER_LOC(xp->xp_files[i][len]) !=
3101 TOLOWER_LOC(xp->xp_files[0][len]))
3102 break;
3103 }
3104 else
3105#endif
3106 if (xp->xp_files[i][len] != xp->xp_files[0][len])
3107 break;
3108 }
3109 if (i < xp->xp_numfiles)
3110 {
3111 if (!(options & WILD_NO_BEEP))
3112 vim_beep();
3113 break;
3114 }
3115 }
3116 ss = alloc((unsigned)len + 1);
3117 if (ss)
3118 {
3119 STRNCPY(ss, xp->xp_files[0], len);
3120 ss[len] = NUL;
3121 }
3122 findex = -1; /* next p_wc gets first one */
3123 }
3124
3125 /* Concatenate all matching names */
3126 if (mode == WILD_ALL && xp->xp_numfiles > 0)
3127 {
3128 len = 0;
3129 for (i = 0; i < xp->xp_numfiles; ++i)
3130 len += (long_u)STRLEN(xp->xp_files[i]) + 1;
3131 ss = lalloc(len, TRUE);
3132 if (ss != NULL)
3133 {
3134 *ss = NUL;
3135 for (i = 0; i < xp->xp_numfiles; ++i)
3136 {
3137 STRCAT(ss, xp->xp_files[i]);
3138 if (i != xp->xp_numfiles - 1)
3139 STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " ");
3140 }
3141 }
3142 }
3143
3144 if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
3145 ExpandCleanup(xp);
3146
3147 return ss;
3148}
3149
3150/*
3151 * Prepare an expand structure for use.
3152 */
3153 void
3154ExpandInit(xp)
3155 expand_T *xp;
3156{
3157 xp->xp_backslash = XP_BS_NONE;
3158 xp->xp_numfiles = -1;
3159 xp->xp_files = NULL;
3160}
3161
3162/*
3163 * Cleanup an expand structure after use.
3164 */
3165 void
3166ExpandCleanup(xp)
3167 expand_T *xp;
3168{
3169 if (xp->xp_numfiles >= 0)
3170 {
3171 FreeWild(xp->xp_numfiles, xp->xp_files);
3172 xp->xp_numfiles = -1;
3173 }
3174}
3175
3176 void
3177ExpandEscape(xp, str, numfiles, files, options)
3178 expand_T *xp;
3179 char_u *str;
3180 int numfiles;
3181 char_u **files;
3182 int options;
3183{
3184 int i;
3185 char_u *p;
3186
3187 /*
3188 * May change home directory back to "~"
3189 */
3190 if (options & WILD_HOME_REPLACE)
3191 tilde_replace(str, numfiles, files);
3192
3193 if (options & WILD_ESCAPE)
3194 {
3195 if (xp->xp_context == EXPAND_FILES
3196 || xp->xp_context == EXPAND_BUFFERS
3197 || xp->xp_context == EXPAND_DIRECTORIES)
3198 {
3199 /*
3200 * Insert a backslash into a file name before a space, \, %, #
3201 * and wildmatch characters, except '~'.
3202 */
3203 for (i = 0; i < numfiles; ++i)
3204 {
3205 /* for ":set path=" we need to escape spaces twice */
3206 if (xp->xp_backslash == XP_BS_THREE)
3207 {
3208 p = vim_strsave_escaped(files[i], (char_u *)" ");
3209 if (p != NULL)
3210 {
3211 vim_free(files[i]);
3212 files[i] = p;
3213#if defined(BACKSLASH_IN_FILENAME) || defined(COLON_AS_PATHSEP)
3214 p = vim_strsave_escaped(files[i], (char_u *)" ");
3215 if (p != NULL)
3216 {
3217 vim_free(files[i]);
3218 files[i] = p;
3219 }
3220#endif
3221 }
3222 }
3223#ifdef BACKSLASH_IN_FILENAME
3224 {
3225 char_u buf[20];
3226 int j = 0;
3227
3228 /* Don't escape '[' and '{' if they are in 'isfname'. */
3229 for (p = PATH_ESC_CHARS; *p != NUL; ++p)
3230 if ((*p != '[' && *p != '{') || !vim_isfilec(*p))
3231 buf[j++] = *p;
3232 buf[j] = NUL;
3233 p = vim_strsave_escaped(files[i], buf);
3234 }
3235#else
3236 p = vim_strsave_escaped(files[i], PATH_ESC_CHARS);
3237#endif
3238 if (p != NULL)
3239 {
3240 vim_free(files[i]);
3241 files[i] = p;
3242 }
3243
3244 /* If 'str' starts with "\~", replace "~" at start of
3245 * files[i] with "\~". */
3246 if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~')
3247 {
3248 p = alloc((unsigned)(STRLEN(files[i]) + 2));
3249 if (p != NULL)
3250 {
3251 p[0] = '\\';
3252 STRCPY(p + 1, files[i]);
3253 vim_free(files[i]);
3254 files[i] = p;
3255 }
3256 }
3257 }
3258 xp->xp_backslash = XP_BS_NONE;
3259 }
3260 else if (xp->xp_context == EXPAND_TAGS)
3261 {
3262 /*
3263 * Insert a backslash before characters in a tag name that
3264 * would terminate the ":tag" command.
3265 */
3266 for (i = 0; i < numfiles; ++i)
3267 {
3268 p = vim_strsave_escaped(files[i], (char_u *)"\\|\"");
3269 if (p != NULL)
3270 {
3271 vim_free(files[i]);
3272 files[i] = p;
3273 }
3274 }
3275 }
3276 }
3277}
3278
3279/*
3280 * For each file name in files[num_files]:
3281 * If 'orig_pat' starts with "~/", replace the home directory with "~".
3282 */
3283 void
3284tilde_replace(orig_pat, num_files, files)
3285 char_u *orig_pat;
3286 int num_files;
3287 char_u **files;
3288{
3289 int i;
3290 char_u *p;
3291
3292 if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1]))
3293 {
3294 for (i = 0; i < num_files; ++i)
3295 {
3296 p = home_replace_save(NULL, files[i]);
3297 if (p != NULL)
3298 {
3299 vim_free(files[i]);
3300 files[i] = p;
3301 }
3302 }
3303 }
3304}
3305
3306/*
3307 * Show all matches for completion on the command line.
3308 * Returns EXPAND_NOTHING when the character that triggered expansion should
3309 * be inserted like a normal character.
3310 */
3311/*ARGSUSED*/
3312 static int
3313showmatches(xp, wildmenu)
3314 expand_T *xp;
3315 int wildmenu;
3316{
3317#define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m])
3318 int num_files;
3319 char_u **files_found;
3320 int i, j, k;
3321 int maxlen;
3322 int lines;
3323 int columns;
3324 char_u *p;
3325 int lastlen;
3326 int attr;
3327 int showtail;
3328
3329 if (xp->xp_numfiles == -1)
3330 {
3331 set_expand_context(xp);
3332 i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos,
3333 &num_files, &files_found);
3334 showtail = expand_showtail(xp);
3335 if (i != EXPAND_OK)
3336 return i;
3337
3338 }
3339 else
3340 {
3341 num_files = xp->xp_numfiles;
3342 files_found = xp->xp_files;
3343 showtail = cmd_showtail;
3344 }
3345
3346#ifdef FEAT_WILDMENU
3347 if (!wildmenu)
3348 {
3349#endif
3350 msg_didany = FALSE; /* lines_left will be set */
3351 msg_start(); /* prepare for paging */
3352 msg_putchar('\n');
3353 out_flush();
3354 cmdline_row = msg_row;
3355 msg_didany = FALSE; /* lines_left will be set again */
3356 msg_start(); /* prepare for paging */
3357#ifdef FEAT_WILDMENU
3358 }
3359#endif
3360
3361 if (got_int)
3362 got_int = FALSE; /* only int. the completion, not the cmd line */
3363#ifdef FEAT_WILDMENU
3364 else if (wildmenu)
3365 win_redr_status_matches(xp, num_files, files_found, 0, showtail);
3366#endif
3367 else
3368 {
3369 /* find the length of the longest file name */
3370 maxlen = 0;
3371 for (i = 0; i < num_files; ++i)
3372 {
3373 if (!showtail && (xp->xp_context == EXPAND_FILES
3374 || xp->xp_context == EXPAND_BUFFERS))
3375 {
3376 home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
3377 j = vim_strsize(NameBuff);
3378 }
3379 else
3380 j = vim_strsize(L_SHOWFILE(i));
3381 if (j > maxlen)
3382 maxlen = j;
3383 }
3384
3385 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3386 lines = num_files;
3387 else
3388 {
3389 /* compute the number of columns and lines for the listing */
3390 maxlen += 2; /* two spaces between file names */
3391 columns = ((int)Columns + 2) / maxlen;
3392 if (columns < 1)
3393 columns = 1;
3394 lines = (num_files + columns - 1) / columns;
3395 }
3396
3397 attr = hl_attr(HLF_D); /* find out highlighting for directories */
3398
3399 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3400 {
3401 MSG_PUTS_ATTR(_("tagname"), hl_attr(HLF_T));
3402 msg_clr_eos();
3403 msg_advance(maxlen - 3);
3404 MSG_PUTS_ATTR(_(" kind file\n"), hl_attr(HLF_T));
3405 }
3406
3407 /* list the files line by line */
3408 for (i = 0; i < lines; ++i)
3409 {
3410 lastlen = 999;
3411 for (k = i; k < num_files; k += lines)
3412 {
3413 if (xp->xp_context == EXPAND_TAGS_LISTFILES)
3414 {
3415 msg_outtrans_attr(files_found[k], hl_attr(HLF_D));
3416 p = files_found[k] + STRLEN(files_found[k]) + 1;
3417 msg_advance(maxlen + 1);
3418 msg_puts(p);
3419 msg_advance(maxlen + 3);
3420 msg_puts_long_attr(p + 2, hl_attr(HLF_D));
3421 break;
3422 }
3423 for (j = maxlen - lastlen; --j >= 0; )
3424 msg_putchar(' ');
3425 if (xp->xp_context == EXPAND_FILES
3426 || xp->xp_context == EXPAND_BUFFERS)
3427 {
3428 /* highlight directories */
3429 j = (mch_isdir(files_found[k]));
3430 if (showtail)
3431 p = L_SHOWFILE(k);
3432 else
3433 {
3434 home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
3435 TRUE);
3436 p = NameBuff;
3437 }
3438 }
3439 else
3440 {
3441 j = FALSE;
3442 p = L_SHOWFILE(k);
3443 }
3444 lastlen = msg_outtrans_attr(p, j ? attr : 0);
3445 }
3446 if (msg_col > 0) /* when not wrapped around */
3447 {
3448 msg_clr_eos();
3449 msg_putchar('\n');
3450 }
3451 out_flush(); /* show one line at a time */
3452 if (got_int)
3453 {
3454 got_int = FALSE;
3455 break;
3456 }
3457 }
3458
3459 /*
3460 * we redraw the command below the lines that we have just listed
3461 * This is a bit tricky, but it saves a lot of screen updating.
3462 */
3463 cmdline_row = msg_row; /* will put it back later */
3464 }
3465
3466 if (xp->xp_numfiles == -1)
3467 FreeWild(num_files, files_found);
3468
3469 return EXPAND_OK;
3470}
3471
3472/*
3473 * Private gettail for showmatches() (and win_redr_status_matches()):
3474 * Find tail of file name path, but ignore trailing "/".
3475 */
3476 char_u *
3477sm_gettail(s)
3478 char_u *s;
3479{
3480 char_u *p;
3481 char_u *t = s;
3482 int had_sep = FALSE;
3483
3484 for (p = s; *p != NUL; )
3485 {
3486 if (vim_ispathsep(*p)
3487#ifdef BACKSLASH_IN_FILENAME
3488 && !rem_backslash(p)
3489#endif
3490 )
3491 had_sep = TRUE;
3492 else if (had_sep)
3493 {
3494 t = p;
3495 had_sep = FALSE;
3496 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003497 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 }
3499 return t;
3500}
3501
3502/*
3503 * Return TRUE if we only need to show the tail of completion matches.
3504 * When not completing file names or there is a wildcard in the path FALSE is
3505 * returned.
3506 */
3507 static int
3508expand_showtail(xp)
3509 expand_T *xp;
3510{
3511 char_u *s;
3512 char_u *end;
3513
3514 /* When not completing file names a "/" may mean something different. */
3515 if (xp->xp_context != EXPAND_FILES && xp->xp_context != EXPAND_DIRECTORIES)
3516 return FALSE;
3517
3518 end = gettail(xp->xp_pattern);
3519 if (end == xp->xp_pattern) /* there is no path separator */
3520 return FALSE;
3521
3522 for (s = xp->xp_pattern; s < end; s++)
3523 {
3524 /* Skip escaped wildcards. Only when the backslash is not a path
3525 * separator, on DOS the '*' "path\*\file" must not be skipped. */
3526 if (rem_backslash(s))
3527 ++s;
3528 else if (vim_strchr((char_u *)"*?[", *s) != NULL)
3529 return FALSE;
3530 }
3531 return TRUE;
3532}
3533
3534/*
3535 * Prepare a string for expansion.
3536 * When expanding file names: The string will be used with expand_wildcards().
3537 * Copy the file name into allocated memory and add a '*' at the end.
3538 * When expanding other names: The string will be used with regcomp(). Copy
3539 * the name into allocated memory and prepend "^".
3540 */
3541 char_u *
3542addstar(fname, len, context)
3543 char_u *fname;
3544 int len;
3545 int context; /* EXPAND_FILES etc. */
3546{
3547 char_u *retval;
3548 int i, j;
3549 int new_len;
3550 char_u *tail;
3551
3552 if (context != EXPAND_FILES && context != EXPAND_DIRECTORIES)
3553 {
3554 /*
3555 * Matching will be done internally (on something other than files).
3556 * So we convert the file-matching-type wildcards into our kind for
3557 * use with vim_regcomp(). First work out how long it will be:
3558 */
3559
3560 /* For help tags the translation is done in find_help_tags().
3561 * For a tag pattern starting with "/" no translation is needed. */
3562 if (context == EXPAND_HELP
3563 || context == EXPAND_COLORS
3564 || context == EXPAND_COMPILER
3565 || (context == EXPAND_TAGS && fname[0] == '/'))
3566 retval = vim_strnsave(fname, len);
3567 else
3568 {
3569 new_len = len + 2; /* +2 for '^' at start, NUL at end */
3570 for (i = 0; i < len; i++)
3571 {
3572 if (fname[i] == '*' || fname[i] == '~')
3573 new_len++; /* '*' needs to be replaced by ".*"
3574 '~' needs to be replaced by "\~" */
3575
3576 /* Buffer names are like file names. "." should be literal */
3577 if (context == EXPAND_BUFFERS && fname[i] == '.')
3578 new_len++; /* "." becomes "\." */
3579
3580 /* Custom expansion takes care of special things, match
3581 * backslashes literally (perhaps also for other types?) */
3582 if (context == EXPAND_USER_DEFINED && fname[i] == '\\')
3583 new_len++; /* '\' becomes "\\" */
3584 }
3585 retval = alloc(new_len);
3586 if (retval != NULL)
3587 {
3588 retval[0] = '^';
3589 j = 1;
3590 for (i = 0; i < len; i++, j++)
3591 {
3592 /* Skip backslash. But why? At least keep it for custom
3593 * expansion. */
3594 if (context != EXPAND_USER_DEFINED
3595 && fname[i] == '\\' && ++i == len)
3596 break;
3597
3598 switch (fname[i])
3599 {
3600 case '*': retval[j++] = '.';
3601 break;
3602 case '~': retval[j++] = '\\';
3603 break;
3604 case '?': retval[j] = '.';
3605 continue;
3606 case '.': if (context == EXPAND_BUFFERS)
3607 retval[j++] = '\\';
3608 break;
3609 case '\\': if (context == EXPAND_USER_DEFINED)
3610 retval[j++] = '\\';
3611 break;
3612 }
3613 retval[j] = fname[i];
3614 }
3615 retval[j] = NUL;
3616 }
3617 }
3618 }
3619 else
3620 {
3621 retval = alloc(len + 4);
3622 if (retval != NULL)
3623 {
3624 STRNCPY(retval, fname, len);
3625 retval[len] = NUL;
3626
3627 /*
3628 * Don't add a star to ~, ~user, $var or `cmd`.
3629 * ~ would be at the start of the file name, but not the tail.
3630 * $ could be anywhere in the tail.
3631 * ` could be anywhere in the file name.
3632 */
3633 tail = gettail(retval);
3634 if ((*retval != '~' || tail != retval)
3635 && vim_strchr(tail, '$') == NULL
3636 && vim_strchr(retval, '`') == NULL)
3637 retval[len++] = '*';
3638 retval[len] = NUL;
3639 }
3640 }
3641 return retval;
3642}
3643
3644/*
3645 * Must parse the command line so far to work out what context we are in.
3646 * Completion can then be done based on that context.
3647 * This routine sets the variables:
3648 * xp->xp_pattern The start of the pattern to be expanded within
3649 * the command line (ends at the cursor).
3650 * xp->xp_context The type of thing to expand. Will be one of:
3651 *
3652 * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
3653 * the command line, like an unknown command. Caller
3654 * should beep.
3655 * EXPAND_NOTHING Unrecognised context for completion, use char like
3656 * a normal char, rather than for completion. eg
3657 * :s/^I/
3658 * EXPAND_COMMANDS Cursor is still touching the command, so complete
3659 * it.
3660 * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
3661 * EXPAND_FILES After command with XFILE set, or after setting
3662 * with P_EXPAND set. eg :e ^I, :w>>^I
3663 * EXPAND_DIRECTORIES In some cases this is used instead of the latter
3664 * when we know only directories are of interest. eg
3665 * :set dir=^I
3666 * EXPAND_SETTINGS Complete variable names. eg :set d^I
3667 * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
3668 * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
3669 * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect
3670 * EXPAND_HELP Complete tags from the file 'helpfile'/tags
3671 * EXPAND_EVENTS Complete event names
3672 * EXPAND_SYNTAX Complete :syntax command arguments
3673 * EXPAND_HIGHLIGHT Complete highlight (syntax) group names
3674 * EXPAND_AUGROUP Complete autocommand group names
3675 * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I
3676 * EXPAND_MAPPINGS Complete mapping and abbreviation names,
3677 * eg :unmap a^I , :cunab x^I
3678 * EXPAND_FUNCTIONS Complete internal or user defined function names,
3679 * eg :call sub^I
3680 * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I
3681 * EXPAND_EXPRESSION Complete internal or user defined function/variable
3682 * names in expressions, eg :while s^I
3683 * EXPAND_ENV_VARS Complete environment variable names
3684 */
3685 static void
3686set_expand_context(xp)
3687 expand_T *xp;
3688{
3689 /* only expansion for ':' and '>' commands */
3690 if (ccline.cmdfirstc != ':'
3691#ifdef FEAT_EVAL
3692 && ccline.cmdfirstc != '>'
3693#endif
3694 )
3695 {
3696 xp->xp_context = EXPAND_NOTHING;
3697 return;
3698 }
3699 set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos);
3700}
3701
3702 void
3703set_cmd_context(xp, str, len, col)
3704 expand_T *xp;
3705 char_u *str; /* start of command line */
3706 int len; /* length of command line (excl. NUL) */
3707 int col; /* position of cursor */
3708{
3709 int old_char = NUL;
3710 char_u *nextcomm;
3711
3712 /*
3713 * Avoid a UMR warning from Purify, only save the character if it has been
3714 * written before.
3715 */
3716 if (col < len)
3717 old_char = str[col];
3718 str[col] = NUL;
3719 nextcomm = str;
3720 while (nextcomm != NULL)
3721 nextcomm = set_one_cmd_context(xp, nextcomm);
3722 str[col] = old_char;
3723}
3724
3725/*
3726 * Expand the command line "str" from context "xp".
3727 * "xp" must have been set by set_cmd_context().
3728 * xp->xp_pattern points into "str", to where the text that is to be expanded
3729 * starts.
3730 * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the
3731 * cursor.
3732 * Returns EXPAND_NOTHING when there is nothing to expand, might insert the
3733 * key that triggered expansion literally.
3734 * Returns EXPAND_OK otherwise.
3735 */
3736 int
3737expand_cmdline(xp, str, col, matchcount, matches)
3738 expand_T *xp;
3739 char_u *str; /* start of command line */
3740 int col; /* position of cursor */
3741 int *matchcount; /* return: nr of matches */
3742 char_u ***matches; /* return: array of pointers to matches */
3743{
3744 char_u *file_str = NULL;
3745
3746 if (xp->xp_context == EXPAND_UNSUCCESSFUL)
3747 {
3748 beep_flush();
3749 return EXPAND_UNSUCCESSFUL; /* Something illegal on command line */
3750 }
3751 if (xp->xp_context == EXPAND_NOTHING)
3752 {
3753 /* Caller can use the character as a normal char instead */
3754 return EXPAND_NOTHING;
3755 }
3756
3757 /* add star to file name, or convert to regexp if not exp. files. */
3758 file_str = addstar(xp->xp_pattern,
3759 (int)(str + col - xp->xp_pattern), xp->xp_context);
3760 if (file_str == NULL)
3761 return EXPAND_UNSUCCESSFUL;
3762
3763 /* find all files that match the description */
3764 if (ExpandFromContext(xp, file_str, matchcount, matches,
3765 WILD_ADD_SLASH|WILD_SILENT) == FAIL)
3766 {
3767 *matchcount = 0;
3768 *matches = NULL;
3769 }
3770 vim_free(file_str);
3771
3772 return EXPAND_OK;
3773}
3774
3775#ifdef FEAT_MULTI_LANG
3776/*
3777 * Cleanup matches for help tags: remove "@en" if "en" is the only language.
3778 */
3779static void cleanup_help_tags __ARGS((int num_file, char_u **file));
3780
3781 static void
3782cleanup_help_tags(num_file, file)
3783 int num_file;
3784 char_u **file;
3785{
3786 int i, j;
3787 int len;
3788
3789 for (i = 0; i < num_file; ++i)
3790 {
3791 len = (int)STRLEN(file[i]) - 3;
3792 if (len > 0 && STRCMP(file[i] + len, "@en") == 0)
3793 {
3794 /* Sorting on priority means the same item in another language may
3795 * be anywhere. Search all items for a match up to the "@en". */
3796 for (j = 0; j < num_file; ++j)
3797 if (j != i
3798 && (int)STRLEN(file[j]) == len + 3
3799 && STRNCMP(file[i], file[j], len + 1) == 0)
3800 break;
3801 if (j == num_file)
3802 file[i][len] = NUL;
3803 }
3804 }
3805}
3806#endif
3807
3808/*
3809 * Do the expansion based on xp->xp_context and "pat".
3810 */
3811 static int
3812ExpandFromContext(xp, pat, num_file, file, options)
3813 expand_T *xp;
3814 char_u *pat;
3815 int *num_file;
3816 char_u ***file;
3817 int options;
3818{
3819#ifdef FEAT_CMDL_COMPL
3820 regmatch_T regmatch;
3821#endif
3822 int ret;
3823 int flags;
3824
3825 flags = EW_DIR; /* include directories */
3826 if (options & WILD_LIST_NOTFOUND)
3827 flags |= EW_NOTFOUND;
3828 if (options & WILD_ADD_SLASH)
3829 flags |= EW_ADDSLASH;
3830 if (options & WILD_KEEP_ALL)
3831 flags |= EW_KEEPALL;
3832 if (options & WILD_SILENT)
3833 flags |= EW_SILENT;
3834
3835 if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES)
3836 {
3837 /*
3838 * Expand file or directory names.
3839 */
3840 int free_pat = FALSE;
3841 int i;
3842
3843 /* for ":set path=" and ":set tags=" halve backslashes for escaped
3844 * space */
3845 if (xp->xp_backslash != XP_BS_NONE)
3846 {
3847 free_pat = TRUE;
3848 pat = vim_strsave(pat);
3849 for (i = 0; pat[i]; ++i)
3850 if (pat[i] == '\\')
3851 {
3852 if (xp->xp_backslash == XP_BS_THREE
3853 && pat[i + 1] == '\\'
3854 && pat[i + 2] == '\\'
3855 && pat[i + 3] == ' ')
3856 STRCPY(pat + i, pat + i + 3);
3857 if (xp->xp_backslash == XP_BS_ONE
3858 && pat[i + 1] == ' ')
3859 STRCPY(pat + i, pat + i + 1);
3860 }
3861 }
3862
3863 if (xp->xp_context == EXPAND_FILES)
3864 flags |= EW_FILE;
3865 else
3866 flags = (flags | EW_DIR) & ~EW_FILE;
3867 ret = expand_wildcards(1, &pat, num_file, file, flags);
3868 if (free_pat)
3869 vim_free(pat);
3870 return ret;
3871 }
3872
3873 *file = (char_u **)"";
3874 *num_file = 0;
3875 if (xp->xp_context == EXPAND_HELP)
3876 {
3877 if (find_help_tags(pat, num_file, file, FALSE) == OK)
3878 {
3879#ifdef FEAT_MULTI_LANG
3880 cleanup_help_tags(*num_file, *file);
3881#endif
3882 return OK;
3883 }
3884 return FAIL;
3885 }
3886
3887#ifndef FEAT_CMDL_COMPL
3888 return FAIL;
3889#else
3890 if (xp->xp_context == EXPAND_OLD_SETTING)
3891 return ExpandOldSetting(num_file, file);
3892 if (xp->xp_context == EXPAND_BUFFERS)
3893 return ExpandBufnames(pat, num_file, file, options);
3894 if (xp->xp_context == EXPAND_TAGS
3895 || xp->xp_context == EXPAND_TAGS_LISTFILES)
3896 return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
3897 if (xp->xp_context == EXPAND_COLORS)
3898 return ExpandRTDir(pat, num_file, file, "colors");
3899 if (xp->xp_context == EXPAND_COMPILER)
3900 return ExpandRTDir(pat, num_file, file, "compiler");
3901
3902 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
3903 if (regmatch.regprog == NULL)
3904 return FAIL;
3905
3906 /* set ignore-case according to p_ic, p_scs and pat */
3907 regmatch.rm_ic = ignorecase(pat);
3908
3909 if (xp->xp_context == EXPAND_SETTINGS
3910 || xp->xp_context == EXPAND_BOOL_SETTINGS)
3911 ret = ExpandSettings(xp, &regmatch, num_file, file);
3912 else if (xp->xp_context == EXPAND_MAPPINGS)
3913 ret = ExpandMappings(&regmatch, num_file, file);
3914# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
3915 else if (xp->xp_context == EXPAND_USER_DEFINED)
3916 ret = ExpandUserDefined(xp, &regmatch, num_file, file);
3917# endif
3918 else
3919 {
3920 static struct expgen
3921 {
3922 int context;
3923 char_u *((*func)__ARGS((expand_T *, int)));
3924 int ic;
3925 } tab[] =
3926 {
3927 {EXPAND_COMMANDS, get_command_name, FALSE},
3928#ifdef FEAT_USR_CMDS
3929 {EXPAND_USER_COMMANDS, get_user_commands, FALSE},
3930 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE},
3931 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE},
3932 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE},
3933#endif
3934#ifdef FEAT_EVAL
3935 {EXPAND_USER_VARS, get_user_var_name, FALSE},
3936 {EXPAND_FUNCTIONS, get_function_name, FALSE},
3937 {EXPAND_USER_FUNC, get_user_func_name, FALSE},
3938 {EXPAND_EXPRESSION, get_expr_name, FALSE},
3939#endif
3940#ifdef FEAT_MENU
3941 {EXPAND_MENUS, get_menu_name, FALSE},
3942 {EXPAND_MENUNAMES, get_menu_names, FALSE},
3943#endif
3944#ifdef FEAT_SYN_HL
3945 {EXPAND_SYNTAX, get_syntax_name, TRUE},
3946#endif
3947 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE},
3948#ifdef FEAT_AUTOCMD
3949 {EXPAND_EVENTS, get_event_name, TRUE},
3950 {EXPAND_AUGROUP, get_augroup_name, TRUE},
3951#endif
3952#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3953 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
3954 {EXPAND_LANGUAGE, get_lang_arg, TRUE},
3955#endif
3956 {EXPAND_ENV_VARS, get_env_name, TRUE},
3957 };
3958 int i;
3959
3960 /*
3961 * Find a context in the table and call the ExpandGeneric() with the
3962 * right function to do the expansion.
3963 */
3964 ret = FAIL;
3965 for (i = 0; i < sizeof(tab) / sizeof(struct expgen); ++i)
3966 if (xp->xp_context == tab[i].context)
3967 {
3968 if (tab[i].ic)
3969 regmatch.rm_ic = TRUE;
3970 ret = ExpandGeneric(xp, &regmatch, num_file, file, tab[i].func);
3971 break;
3972 }
3973 }
3974
3975 vim_free(regmatch.regprog);
3976
3977 return ret;
3978#endif /* FEAT_CMDL_COMPL */
3979}
3980
3981#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
3982/*
3983 * Expand a list of names.
3984 *
3985 * Generic function for command line completion. It calls a function to
3986 * obtain strings, one by one. The strings are matched against a regexp
3987 * program. Matching strings are copied into an array, which is returned.
3988 *
3989 * Returns OK when no problems encountered, FAIL for error (out of memory).
3990 */
3991 int
3992ExpandGeneric(xp, regmatch, num_file, file, func)
3993 expand_T *xp;
3994 regmatch_T *regmatch;
3995 int *num_file;
3996 char_u ***file;
3997 char_u *((*func)__ARGS((expand_T *, int)));
3998 /* returns a string from the list */
3999{
4000 int i;
4001 int count = 0;
4002 int loop;
4003 char_u *str;
4004
4005 /* do this loop twice:
4006 * loop == 0: count the number of matching names
4007 * loop == 1: copy the matching names into allocated memory
4008 */
4009 for (loop = 0; loop <= 1; ++loop)
4010 {
4011 for (i = 0; ; ++i)
4012 {
4013 str = (*func)(xp, i);
4014 if (str == NULL) /* end of list */
4015 break;
4016 if (*str == NUL) /* skip empty strings */
4017 continue;
4018
4019 if (vim_regexec(regmatch, str, (colnr_T)0))
4020 {
4021 if (loop)
4022 {
4023 str = vim_strsave_escaped(str, (char_u *)" \t\\.");
4024 (*file)[count] = str;
4025#ifdef FEAT_MENU
4026 if (func == get_menu_names && str != NULL)
4027 {
4028 /* test for separator added by get_menu_names() */
4029 str += STRLEN(str) - 1;
4030 if (*str == '\001')
4031 *str = '.';
4032 }
4033#endif
4034 }
4035 ++count;
4036 }
4037 }
4038 if (loop == 0)
4039 {
4040 if (count == 0)
4041 return OK;
4042 *num_file = count;
4043 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
4044 if (*file == NULL)
4045 {
4046 *file = (char_u **)"";
4047 return FAIL;
4048 }
4049 count = 0;
4050 }
4051 }
4052 return OK;
4053}
4054
4055# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
4056/*
4057 * Expand names with a function defined by the user.
4058 */
4059 static int
4060ExpandUserDefined(xp, regmatch, num_file, file)
4061 expand_T *xp;
4062 regmatch_T *regmatch;
4063 int *num_file;
4064 char_u ***file;
4065{
4066 char_u *args[3];
4067 char_u *all;
4068 char_u *s;
4069 char_u *e;
4070 char_u keep;
4071 char_u num[50];
4072 garray_T ga;
4073 int save_current_SID = current_SID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004074 struct cmdline_info save_ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075
4076 if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0')
4077 return FAIL;
4078 *num_file = 0;
4079 *file = NULL;
4080
4081 keep = ccline.cmdbuff[ccline.cmdlen];
4082 ccline.cmdbuff[ccline.cmdlen] = 0;
4083 sprintf((char *)num, "%d", ccline.cmdpos);
4084 args[0] = xp->xp_pattern;
4085 args[1] = ccline.cmdbuff;
4086 args[2] = num;
4087
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004088 /* Save the cmdline, we don't know what the function may do. */
4089 save_ccline = ccline;
4090 ccline.cmdbuff = NULL;
4091 ccline.cmdprompt = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 current_SID = xp->xp_scriptID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004093
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 all = call_vim_function(xp->xp_arg, 3, args, FALSE);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004095
4096 ccline = save_ccline;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 current_SID = save_current_SID;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00004098
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 ccline.cmdbuff[ccline.cmdlen] = keep;
4100 if (all == NULL)
4101 return FAIL;
4102
4103 ga_init2(&ga, (int)sizeof(char *), 3);
4104 for (s = all; *s != NUL; s = e)
4105 {
4106 e = vim_strchr(s, '\n');
4107 if (e == NULL)
4108 e = s + STRLEN(s);
4109 keep = *e;
4110 *e = 0;
4111
4112 if (xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0)
4113 {
4114 *e = keep;
4115 if (*e != NUL)
4116 ++e;
4117 continue;
4118 }
4119
4120 if (ga_grow(&ga, 1) == FAIL)
4121 break;
4122
4123 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s));
4124 ++ga.ga_len;
4125 --ga.ga_room;
4126
4127 *e = keep;
4128 if (*e != NUL)
4129 ++e;
4130 }
4131 vim_free(all);
4132 *file = ga.ga_data;
4133 *num_file = ga.ga_len;
4134 return OK;
4135}
4136#endif
4137
4138/*
4139 * Expand color scheme names: 'runtimepath'/colors/{pat}.vim
4140 * or compiler names.
4141 */
4142 static int
4143ExpandRTDir(pat, num_file, file, dirname)
4144 char_u *pat;
4145 int *num_file;
4146 char_u ***file;
4147 char *dirname; /* "colors" or "compiler" */
4148{
4149 char_u *all;
4150 char_u *s;
4151 char_u *e;
4152 garray_T ga;
4153
4154 *num_file = 0;
4155 *file = NULL;
4156 s = alloc((unsigned)(STRLEN(pat) + STRLEN(dirname) + 7));
4157 if (s == NULL)
4158 return FAIL;
4159 sprintf((char *)s, "%s/%s*.vim", dirname, pat);
4160 all = globpath(p_rtp, s);
4161 vim_free(s);
4162 if (all == NULL)
4163 return FAIL;
4164
4165 ga_init2(&ga, (int)sizeof(char *), 3);
4166 for (s = all; *s != NUL; s = e)
4167 {
4168 e = vim_strchr(s, '\n');
4169 if (e == NULL)
4170 e = s + STRLEN(s);
4171 if (ga_grow(&ga, 1) == FAIL)
4172 break;
4173 if (e - 4 > s && STRNICMP(e - 4, ".vim", 4) == 0)
4174 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004175 for (s = e - 4; s > all; mb_ptr_back(all, s))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 if (*s == '\n' || vim_ispathsep(*s))
4177 break;
4178 ++s;
4179 ((char_u **)ga.ga_data)[ga.ga_len] =
4180 vim_strnsave(s, (int)(e - s - 4));
4181 ++ga.ga_len;
4182 --ga.ga_room;
4183 }
4184 if (*e != NUL)
4185 ++e;
4186 }
4187 vim_free(all);
4188 *file = ga.ga_data;
4189 *num_file = ga.ga_len;
4190 return OK;
4191}
4192
4193#endif
4194
4195#if defined(FEAT_CMDL_COMPL) || defined(FEAT_EVAL) || defined(PROTO)
4196/*
4197 * Expand "file" for all comma-separated directories in "path".
4198 * Returns an allocated string with all matches concatenated, separated by
4199 * newlines. Returns NULL for an error or no matches.
4200 */
4201 char_u *
4202globpath(path, file)
4203 char_u *path;
4204 char_u *file;
4205{
4206 expand_T xpc;
4207 char_u *buf;
4208 garray_T ga;
4209 int i;
4210 int len;
4211 int num_p;
4212 char_u **p;
4213 char_u *cur = NULL;
4214
4215 buf = alloc(MAXPATHL);
4216 if (buf == NULL)
4217 return NULL;
4218
4219 xpc.xp_context = EXPAND_FILES;
4220 xpc.xp_backslash = XP_BS_NONE;
4221 ga_init2(&ga, 1, 100);
4222
4223 /* Loop over all entries in {path}. */
4224 while (*path != NUL)
4225 {
4226 /* Copy one item of the path to buf[] and concatenate the file name. */
4227 copy_option_part(&path, buf, MAXPATHL, ",");
4228 if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL)
4229 {
4230 add_pathsep(buf);
4231 STRCAT(buf, file);
4232 if (ExpandFromContext(&xpc, buf, &num_p, &p, WILD_SILENT) != FAIL
4233 && num_p > 0)
4234 {
4235 ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT);
4236 for (len = 0, i = 0; i < num_p; ++i)
4237 len += (long_u)STRLEN(p[i]) + 1;
4238
4239 /* Concatenate new results to previous ones. */
4240 if (ga_grow(&ga, len) == OK)
4241 {
4242 cur = (char_u *)ga.ga_data + ga.ga_len;
4243 for (i = 0; i < num_p; ++i)
4244 {
4245 STRCPY(cur, p[i]);
4246 cur += STRLEN(p[i]);
4247 *cur++ = '\n';
4248 }
4249 ga.ga_len += len;
4250 ga.ga_room -= len;
4251 }
4252 FreeWild(num_p, p);
4253 }
4254 }
4255 }
4256 if (cur != NULL)
4257 *--cur = 0; /* Replace trailing newline with NUL */
4258
4259 vim_free(buf);
4260 return (char_u *)ga.ga_data;
4261}
4262
4263#endif
4264
4265#if defined(FEAT_CMDHIST) || defined(PROTO)
4266
4267/*********************************
4268 * Command line history stuff *
4269 *********************************/
4270
4271/*
4272 * Translate a history character to the associated type number.
4273 */
4274 static int
4275hist_char2type(c)
4276 int c;
4277{
4278 if (c == ':')
4279 return HIST_CMD;
4280 if (c == '=')
4281 return HIST_EXPR;
4282 if (c == '@')
4283 return HIST_INPUT;
4284 if (c == '>')
4285 return HIST_DEBUG;
4286 return HIST_SEARCH; /* must be '?' or '/' */
4287}
4288
4289/*
4290 * Table of history names.
4291 * These names are used in :history and various hist...() functions.
4292 * It is sufficient to give the significant prefix of a history name.
4293 */
4294
4295static char *(history_names[]) =
4296{
4297 "cmd",
4298 "search",
4299 "expr",
4300 "input",
4301 "debug",
4302 NULL
4303};
4304
4305/*
4306 * init_history() - Initialize the command line history.
4307 * Also used to re-allocate the history when the size changes.
4308 */
4309 static void
4310init_history()
4311{
4312 int newlen; /* new length of history table */
4313 histentry_T *temp;
4314 int i;
4315 int j;
4316 int type;
4317
4318 /*
4319 * If size of history table changed, reallocate it
4320 */
4321 newlen = (int)p_hi;
4322 if (newlen != hislen) /* history length changed */
4323 {
4324 for (type = 0; type < HIST_COUNT; ++type) /* adjust the tables */
4325 {
4326 if (newlen)
4327 {
4328 temp = (histentry_T *)lalloc(
4329 (long_u)(newlen * sizeof(histentry_T)), TRUE);
4330 if (temp == NULL) /* out of memory! */
4331 {
4332 if (type == 0) /* first one: just keep the old length */
4333 {
4334 newlen = hislen;
4335 break;
4336 }
4337 /* Already changed one table, now we can only have zero
4338 * length for all tables. */
4339 newlen = 0;
4340 type = -1;
4341 continue;
4342 }
4343 }
4344 else
4345 temp = NULL;
4346 if (newlen == 0 || temp != NULL)
4347 {
4348 if (hisidx[type] < 0) /* there are no entries yet */
4349 {
4350 for (i = 0; i < newlen; ++i)
4351 {
4352 temp[i].hisnum = 0;
4353 temp[i].hisstr = NULL;
4354 }
4355 }
4356 else if (newlen > hislen) /* array becomes bigger */
4357 {
4358 for (i = 0; i <= hisidx[type]; ++i)
4359 temp[i] = history[type][i];
4360 j = i;
4361 for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
4362 {
4363 temp[i].hisnum = 0;
4364 temp[i].hisstr = NULL;
4365 }
4366 for ( ; j < hislen; ++i, ++j)
4367 temp[i] = history[type][j];
4368 }
4369 else /* array becomes smaller or 0 */
4370 {
4371 j = hisidx[type];
4372 for (i = newlen - 1; ; --i)
4373 {
4374 if (i >= 0) /* copy newest entries */
4375 temp[i] = history[type][j];
4376 else /* remove older entries */
4377 vim_free(history[type][j].hisstr);
4378 if (--j < 0)
4379 j = hislen - 1;
4380 if (j == hisidx[type])
4381 break;
4382 }
4383 hisidx[type] = newlen - 1;
4384 }
4385 vim_free(history[type]);
4386 history[type] = temp;
4387 }
4388 }
4389 hislen = newlen;
4390 }
4391}
4392
4393/*
4394 * Check if command line 'str' is already in history.
4395 * If 'move_to_front' is TRUE, matching entry is moved to end of history.
4396 */
4397 static int
4398in_history(type, str, move_to_front)
4399 int type;
4400 char_u *str;
4401 int move_to_front; /* Move the entry to the front if it exists */
4402{
4403 int i;
4404 int last_i = -1;
4405
4406 if (hisidx[type] < 0)
4407 return FALSE;
4408 i = hisidx[type];
4409 do
4410 {
4411 if (history[type][i].hisstr == NULL)
4412 return FALSE;
4413 if (STRCMP(str, history[type][i].hisstr) == 0)
4414 {
4415 if (!move_to_front)
4416 return TRUE;
4417 last_i = i;
4418 break;
4419 }
4420 if (--i < 0)
4421 i = hislen - 1;
4422 } while (i != hisidx[type]);
4423
4424 if (last_i >= 0)
4425 {
4426 str = history[type][i].hisstr;
4427 while (i != hisidx[type])
4428 {
4429 if (++i >= hislen)
4430 i = 0;
4431 history[type][last_i] = history[type][i];
4432 last_i = i;
4433 }
4434 history[type][i].hisstr = str;
4435 history[type][i].hisnum = ++hisnum[type];
4436 return TRUE;
4437 }
4438 return FALSE;
4439}
4440
4441/*
4442 * Convert history name (from table above) to its HIST_ equivalent.
4443 * When "name" is empty, return "cmd" history.
4444 * Returns -1 for unknown history name.
4445 */
4446 int
4447get_histtype(name)
4448 char_u *name;
4449{
4450 int i;
4451 int len = (int)STRLEN(name);
4452
4453 /* No argument: use current history. */
4454 if (len == 0)
4455 return hist_char2type(ccline.cmdfirstc);
4456
4457 for (i = 0; history_names[i] != NULL; ++i)
4458 if (STRNICMP(name, history_names[i], len) == 0)
4459 return i;
4460
4461 if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
4462 return hist_char2type(name[0]);
4463
4464 return -1;
4465}
4466
4467static int last_maptick = -1; /* last seen maptick */
4468
4469/*
4470 * Add the given string to the given history. If the string is already in the
4471 * history then it is moved to the front. "histype" may be one of he HIST_
4472 * values.
4473 */
4474 void
4475add_to_history(histype, new_entry, in_map, sep)
4476 int histype;
4477 char_u *new_entry;
4478 int in_map; /* consider maptick when inside a mapping */
4479 int sep; /* separator character used (search hist) */
4480{
4481 histentry_T *hisptr;
4482 int len;
4483
4484 if (hislen == 0) /* no history */
4485 return;
4486
4487 /*
4488 * Searches inside the same mapping overwrite each other, so that only
4489 * the last line is kept. Be careful not to remove a line that was moved
4490 * down, only lines that were added.
4491 */
4492 if (histype == HIST_SEARCH && in_map)
4493 {
4494 if (maptick == last_maptick)
4495 {
4496 /* Current line is from the same mapping, remove it */
4497 hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
4498 vim_free(hisptr->hisstr);
4499 hisptr->hisstr = NULL;
4500 hisptr->hisnum = 0;
4501 --hisnum[histype];
4502 if (--hisidx[HIST_SEARCH] < 0)
4503 hisidx[HIST_SEARCH] = hislen - 1;
4504 }
4505 last_maptick = -1;
4506 }
4507 if (!in_history(histype, new_entry, TRUE))
4508 {
4509 if (++hisidx[histype] == hislen)
4510 hisidx[histype] = 0;
4511 hisptr = &history[histype][hisidx[histype]];
4512 vim_free(hisptr->hisstr);
4513
4514 /* Store the separator after the NUL of the string. */
4515 len = STRLEN(new_entry);
4516 hisptr->hisstr = vim_strnsave(new_entry, len + 2);
4517 if (hisptr->hisstr != NULL)
4518 hisptr->hisstr[len + 1] = sep;
4519
4520 hisptr->hisnum = ++hisnum[histype];
4521 if (histype == HIST_SEARCH && in_map)
4522 last_maptick = maptick;
4523 }
4524}
4525
4526#if defined(FEAT_EVAL) || defined(PROTO)
4527
4528/*
4529 * Get identifier of newest history entry.
4530 * "histype" may be one of the HIST_ values.
4531 */
4532 int
4533get_history_idx(histype)
4534 int histype;
4535{
4536 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
4537 || hisidx[histype] < 0)
4538 return -1;
4539
4540 return history[histype][hisidx[histype]].hisnum;
4541}
4542
4543/*
4544 * Get the current command line in allocated memory.
4545 * Only works when the command line is being edited.
4546 * Returns NULL when something is wrong.
4547 */
4548 char_u *
4549get_cmdline_str()
4550{
4551 if (ccline.cmdbuff == NULL || (State & CMDLINE) == 0)
4552 return NULL;
4553 return vim_strnsave(ccline.cmdbuff, ccline.cmdlen);
4554}
4555
4556/*
4557 * Get the current command line position, counted in bytes.
4558 * Zero is the first position.
4559 * Only works when the command line is being edited.
4560 * Returns -1 when something is wrong.
4561 */
4562 int
4563get_cmdline_pos()
4564{
4565 if (ccline.cmdbuff == NULL || (State & CMDLINE) == 0)
4566 return -1;
4567 return ccline.cmdpos;
4568}
4569
4570/*
4571 * Set the command line byte position to "pos". Zero is the first position.
4572 * Only works when the command line is being edited.
4573 * Returns 1 when failed, 0 when OK.
4574 */
4575 int
4576set_cmdline_pos(pos)
4577 int pos;
4578{
4579 if (ccline.cmdbuff == NULL || (State & CMDLINE) == 0)
4580 return 1;
4581
4582 /* The position is not set directly but after CTRL-\ e or CTRL-R = has
4583 * changed the command line. */
4584 if (pos < 0)
4585 new_cmdpos = 0;
4586 else
4587 new_cmdpos = pos;
4588 return 0;
4589}
4590
4591/*
4592 * Calculate history index from a number:
4593 * num > 0: seen as identifying number of a history entry
4594 * num < 0: relative position in history wrt newest entry
4595 * "histype" may be one of the HIST_ values.
4596 */
4597 static int
4598calc_hist_idx(histype, num)
4599 int histype;
4600 int num;
4601{
4602 int i;
4603 histentry_T *hist;
4604 int wrapped = FALSE;
4605
4606 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
4607 || (i = hisidx[histype]) < 0 || num == 0)
4608 return -1;
4609
4610 hist = history[histype];
4611 if (num > 0)
4612 {
4613 while (hist[i].hisnum > num)
4614 if (--i < 0)
4615 {
4616 if (wrapped)
4617 break;
4618 i += hislen;
4619 wrapped = TRUE;
4620 }
4621 if (hist[i].hisnum == num && hist[i].hisstr != NULL)
4622 return i;
4623 }
4624 else if (-num <= hislen)
4625 {
4626 i += num + 1;
4627 if (i < 0)
4628 i += hislen;
4629 if (hist[i].hisstr != NULL)
4630 return i;
4631 }
4632 return -1;
4633}
4634
4635/*
4636 * Get a history entry by its index.
4637 * "histype" may be one of the HIST_ values.
4638 */
4639 char_u *
4640get_history_entry(histype, idx)
4641 int histype;
4642 int idx;
4643{
4644 idx = calc_hist_idx(histype, idx);
4645 if (idx >= 0)
4646 return history[histype][idx].hisstr;
4647 else
4648 return (char_u *)"";
4649}
4650
4651/*
4652 * Clear all entries of a history.
4653 * "histype" may be one of the HIST_ values.
4654 */
4655 int
4656clr_history(histype)
4657 int histype;
4658{
4659 int i;
4660 histentry_T *hisptr;
4661
4662 if (hislen != 0 && histype >= 0 && histype < HIST_COUNT)
4663 {
4664 hisptr = history[histype];
4665 for (i = hislen; i--;)
4666 {
4667 vim_free(hisptr->hisstr);
4668 hisptr->hisnum = 0;
4669 hisptr++->hisstr = NULL;
4670 }
4671 hisidx[histype] = -1; /* mark history as cleared */
4672 hisnum[histype] = 0; /* reset identifier counter */
4673 return OK;
4674 }
4675 return FAIL;
4676}
4677
4678/*
4679 * Remove all entries matching {str} from a history.
4680 * "histype" may be one of the HIST_ values.
4681 */
4682 int
4683del_history_entry(histype, str)
4684 int histype;
4685 char_u *str;
4686{
4687 regmatch_T regmatch;
4688 histentry_T *hisptr;
4689 int idx;
4690 int i;
4691 int last;
4692 int found = FALSE;
4693
4694 regmatch.regprog = NULL;
4695 regmatch.rm_ic = FALSE; /* always match case */
4696 if (hislen != 0
4697 && histype >= 0
4698 && histype < HIST_COUNT
4699 && *str != NUL
4700 && (idx = hisidx[histype]) >= 0
4701 && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING))
4702 != NULL)
4703 {
4704 i = last = idx;
4705 do
4706 {
4707 hisptr = &history[histype][i];
4708 if (hisptr->hisstr == NULL)
4709 break;
4710 if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0))
4711 {
4712 found = TRUE;
4713 vim_free(hisptr->hisstr);
4714 hisptr->hisstr = NULL;
4715 hisptr->hisnum = 0;
4716 }
4717 else
4718 {
4719 if (i != last)
4720 {
4721 history[histype][last] = *hisptr;
4722 hisptr->hisstr = NULL;
4723 hisptr->hisnum = 0;
4724 }
4725 if (--last < 0)
4726 last += hislen;
4727 }
4728 if (--i < 0)
4729 i += hislen;
4730 } while (i != idx);
4731 if (history[histype][idx].hisstr == NULL)
4732 hisidx[histype] = -1;
4733 }
4734 vim_free(regmatch.regprog);
4735 return found;
4736}
4737
4738/*
4739 * Remove an indexed entry from a history.
4740 * "histype" may be one of the HIST_ values.
4741 */
4742 int
4743del_history_idx(histype, idx)
4744 int histype;
4745 int idx;
4746{
4747 int i, j;
4748
4749 i = calc_hist_idx(histype, idx);
4750 if (i < 0)
4751 return FALSE;
4752 idx = hisidx[histype];
4753 vim_free(history[histype][i].hisstr);
4754
4755 /* When deleting the last added search string in a mapping, reset
4756 * last_maptick, so that the last added search string isn't deleted again.
4757 */
4758 if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
4759 last_maptick = -1;
4760
4761 while (i != idx)
4762 {
4763 j = (i + 1) % hislen;
4764 history[histype][i] = history[histype][j];
4765 i = j;
4766 }
4767 history[histype][i].hisstr = NULL;
4768 history[histype][i].hisnum = 0;
4769 if (--i < 0)
4770 i += hislen;
4771 hisidx[histype] = i;
4772 return TRUE;
4773}
4774
4775#endif /* FEAT_EVAL */
4776
4777#if defined(FEAT_CRYPT) || defined(PROTO)
4778/*
4779 * Very specific function to remove the value in ":set key=val" from the
4780 * history.
4781 */
4782 void
4783remove_key_from_history()
4784{
4785 char_u *p;
4786 int i;
4787
4788 i = hisidx[HIST_CMD];
4789 if (i < 0)
4790 return;
4791 p = history[HIST_CMD][i].hisstr;
4792 if (p != NULL)
4793 for ( ; *p; ++p)
4794 if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3]))
4795 {
4796 p = vim_strchr(p + 3, '=');
4797 if (p == NULL)
4798 break;
4799 ++p;
4800 for (i = 0; p[i] && !vim_iswhite(p[i]); ++i)
4801 if (p[i] == '\\' && p[i + 1])
4802 ++i;
4803 mch_memmove(p, p + i, STRLEN(p + i) + 1);
4804 --p;
4805 }
4806}
4807#endif
4808
4809#endif /* FEAT_CMDHIST */
4810
4811#if defined(FEAT_QUICKFIX) || defined(FEAT_CMDHIST) || defined(PROTO)
4812/*
4813 * Get indices "num1,num2" that specify a range within a list (not a range of
4814 * text lines in a buffer!) from a string. Used for ":history" and ":clist".
4815 * Returns OK if parsed successfully, otherwise FAIL.
4816 */
4817 int
4818get_list_range(str, num1, num2)
4819 char_u **str;
4820 int *num1;
4821 int *num2;
4822{
4823 int len;
4824 int first = FALSE;
4825 long num;
4826
4827 *str = skipwhite(*str);
4828 if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */
4829 {
4830 vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
4831 *str += len;
4832 *num1 = (int)num;
4833 first = TRUE;
4834 }
4835 *str = skipwhite(*str);
4836 if (**str == ',') /* parse "to" part of range */
4837 {
4838 *str = skipwhite(*str + 1);
4839 vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
4840 if (len > 0)
4841 {
4842 *num2 = (int)num;
4843 *str = skipwhite(*str + len);
4844 }
4845 else if (!first) /* no number given at all */
4846 return FAIL;
4847 }
4848 else if (first) /* only one number given */
4849 *num2 = *num1;
4850 return OK;
4851}
4852#endif
4853
4854#if defined(FEAT_CMDHIST) || defined(PROTO)
4855/*
4856 * :history command - print a history
4857 */
4858 void
4859ex_history(eap)
4860 exarg_T *eap;
4861{
4862 histentry_T *hist;
4863 int histype1 = HIST_CMD;
4864 int histype2 = HIST_CMD;
4865 int hisidx1 = 1;
4866 int hisidx2 = -1;
4867 int idx;
4868 int i, j, k;
4869 char_u *end;
4870 char_u *arg = eap->arg;
4871
4872 if (hislen == 0)
4873 {
4874 MSG(_("'history' option is zero"));
4875 return;
4876 }
4877
4878 if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ','))
4879 {
4880 end = arg;
4881 while (ASCII_ISALPHA(*end)
4882 || vim_strchr((char_u *)":=@>/?", *end) != NULL)
4883 end++;
4884 i = *end;
4885 *end = NUL;
4886 histype1 = get_histtype(arg);
4887 if (histype1 == -1)
4888 {
4889 if (STRICMP(arg, "all") == 0)
4890 {
4891 histype1 = 0;
4892 histype2 = HIST_COUNT-1;
4893 }
4894 else
4895 {
4896 *end = i;
4897 EMSG(_(e_trailing));
4898 return;
4899 }
4900 }
4901 else
4902 histype2 = histype1;
4903 *end = i;
4904 }
4905 else
4906 end = arg;
4907 if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL)
4908 {
4909 EMSG(_(e_trailing));
4910 return;
4911 }
4912
4913 for (; !got_int && histype1 <= histype2; ++histype1)
4914 {
4915 STRCPY(IObuff, "\n # ");
4916 STRCAT(STRCAT(IObuff, history_names[histype1]), " history");
4917 MSG_PUTS_TITLE(IObuff);
4918 idx = hisidx[histype1];
4919 hist = history[histype1];
4920 j = hisidx1;
4921 k = hisidx2;
4922 if (j < 0)
4923 j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
4924 if (k < 0)
4925 k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
4926 if (idx >= 0 && j <= k)
4927 for (i = idx + 1; !got_int; ++i)
4928 {
4929 if (i == hislen)
4930 i = 0;
4931 if (hist[i].hisstr != NULL
4932 && hist[i].hisnum >= j && hist[i].hisnum <= k)
4933 {
4934 msg_putchar('\n');
4935 sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ',
4936 hist[i].hisnum);
4937 if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
4938 trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
4939 (int)Columns - 10);
4940 else
4941 STRCAT(IObuff, hist[i].hisstr);
4942 msg_outtrans(IObuff);
4943 out_flush();
4944 }
4945 if (i == idx)
4946 break;
4947 }
4948 }
4949}
4950#endif
4951
4952#if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO)
4953static char_u **viminfo_history[HIST_COUNT] = {NULL, NULL, NULL, NULL};
4954static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0};
4955static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0};
4956static int viminfo_add_at_front = FALSE;
4957
4958static int hist_type2char __ARGS((int type, int use_question));
4959
4960/*
4961 * Translate a history type number to the associated character.
4962 */
4963 static int
4964hist_type2char(type, use_question)
4965 int type;
4966 int use_question; /* use '?' instead of '/' */
4967{
4968 if (type == HIST_CMD)
4969 return ':';
4970 if (type == HIST_SEARCH)
4971 {
4972 if (use_question)
4973 return '?';
4974 else
4975 return '/';
4976 }
4977 if (type == HIST_EXPR)
4978 return '=';
4979 return '@';
4980}
4981
4982/*
4983 * Prepare for reading the history from the viminfo file.
4984 * This allocates history arrays to store the read history lines.
4985 */
4986 void
4987prepare_viminfo_history(asklen)
4988 int asklen;
4989{
4990 int i;
4991 int num;
4992 int type;
4993 int len;
4994
4995 init_history();
4996 viminfo_add_at_front = (asklen != 0);
4997 if (asklen > hislen)
4998 asklen = hislen;
4999
5000 for (type = 0; type < HIST_COUNT; ++type)
5001 {
5002 /*
5003 * Count the number of empty spaces in the history list. If there are
5004 * more spaces available than we request, then fill them up.
5005 */
5006 for (i = 0, num = 0; i < hislen; i++)
5007 if (history[type][i].hisstr == NULL)
5008 num++;
5009 len = asklen;
5010 if (num > len)
5011 len = num;
5012 if (len <= 0)
5013 viminfo_history[type] = NULL;
5014 else
5015 viminfo_history[type] =
5016 (char_u **)lalloc((long_u)(len * sizeof(char_u *)), FALSE);
5017 if (viminfo_history[type] == NULL)
5018 len = 0;
5019 viminfo_hislen[type] = len;
5020 viminfo_hisidx[type] = 0;
5021 }
5022}
5023
5024/*
5025 * Accept a line from the viminfo, store it in the history array when it's
5026 * new.
5027 */
5028 int
5029read_viminfo_history(virp)
5030 vir_T *virp;
5031{
5032 int type;
5033 long_u len;
5034 char_u *val;
5035 char_u *p;
5036
5037 type = hist_char2type(virp->vir_line[0]);
5038 if (viminfo_hisidx[type] < viminfo_hislen[type])
5039 {
5040 val = viminfo_readstring(virp, 1, TRUE);
5041 if (val != NULL && *val != NUL)
5042 {
5043 if (!in_history(type, val + (type == HIST_SEARCH),
5044 viminfo_add_at_front))
5045 {
5046 /* Need to re-allocate to append the separator byte. */
5047 len = STRLEN(val);
5048 p = lalloc(len + 2, TRUE);
5049 if (p != NULL)
5050 {
5051 if (type == HIST_SEARCH)
5052 {
5053 /* Search entry: Move the separator from the first
5054 * column to after the NUL. */
5055 mch_memmove(p, val + 1, (size_t)len);
5056 p[len] = (*val == ' ' ? NUL : *val);
5057 }
5058 else
5059 {
5060 /* Not a search entry: No separator in the viminfo
5061 * file, add a NUL separator. */
5062 mch_memmove(p, val, (size_t)len + 1);
5063 p[len + 1] = NUL;
5064 }
5065 viminfo_history[type][viminfo_hisidx[type]++] = p;
5066 }
5067 }
5068 }
5069 vim_free(val);
5070 }
5071 return viminfo_readline(virp);
5072}
5073
5074 void
5075finish_viminfo_history()
5076{
5077 int idx;
5078 int i;
5079 int type;
5080
5081 for (type = 0; type < HIST_COUNT; ++type)
5082 {
5083 if (history[type] == NULL)
5084 return;
5085 idx = hisidx[type] + viminfo_hisidx[type];
5086 if (idx >= hislen)
5087 idx -= hislen;
5088 else if (idx < 0)
5089 idx = hislen - 1;
5090 if (viminfo_add_at_front)
5091 hisidx[type] = idx;
5092 else
5093 {
5094 if (hisidx[type] == -1)
5095 hisidx[type] = hislen - 1;
5096 do
5097 {
5098 if (history[type][idx].hisstr != NULL)
5099 break;
5100 if (++idx == hislen)
5101 idx = 0;
5102 } while (idx != hisidx[type]);
5103 if (idx != hisidx[type] && --idx < 0)
5104 idx = hislen - 1;
5105 }
5106 for (i = 0; i < viminfo_hisidx[type]; i++)
5107 {
5108 vim_free(history[type][idx].hisstr);
5109 history[type][idx].hisstr = viminfo_history[type][i];
5110 if (--idx < 0)
5111 idx = hislen - 1;
5112 }
5113 idx += 1;
5114 idx %= hislen;
5115 for (i = 0; i < viminfo_hisidx[type]; i++)
5116 {
5117 history[type][idx++].hisnum = ++hisnum[type];
5118 idx %= hislen;
5119 }
5120 vim_free(viminfo_history[type]);
5121 viminfo_history[type] = NULL;
5122 }
5123}
5124
5125 void
5126write_viminfo_history(fp)
5127 FILE *fp;
5128{
5129 int i;
5130 int type;
5131 int num_saved;
5132 char_u *p;
5133 int c;
5134
5135 init_history();
5136 if (hislen == 0)
5137 return;
5138 for (type = 0; type < HIST_COUNT; ++type)
5139 {
5140 num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
5141 if (num_saved == 0)
5142 continue;
5143 if (num_saved < 0) /* Use default */
5144 num_saved = hislen;
5145 fprintf(fp, _("\n# %s History (newest to oldest):\n"),
5146 type == HIST_CMD ? _("Command Line") :
5147 type == HIST_SEARCH ? _("Search String") :
5148 type == HIST_EXPR ? _("Expression") :
5149 _("Input Line"));
5150 if (num_saved > hislen)
5151 num_saved = hislen;
5152 i = hisidx[type];
5153 if (i >= 0)
5154 while (num_saved--)
5155 {
5156 p = history[type][i].hisstr;
5157 if (p != NULL)
5158 {
5159 putc(hist_type2char(type, TRUE), fp);
5160 /* For the search history: put the separator in the second
5161 * column; use a space if there isn't one. */
5162 if (type == HIST_SEARCH)
5163 {
5164 c = p[STRLEN(p) + 1];
5165 putc(c == NUL ? ' ' : c, fp);
5166 }
5167 viminfo_writestring(fp, p);
5168 }
5169 if (--i < 0)
5170 i = hislen - 1;
5171 }
5172 }
5173}
5174#endif /* FEAT_VIMINFO */
5175
5176#if defined(FEAT_FKMAP) || defined(PROTO)
5177/*
5178 * Write a character at the current cursor+offset position.
5179 * It is directly written into the command buffer block.
5180 */
5181 void
5182cmd_pchar(c, offset)
5183 int c, offset;
5184{
5185 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
5186 {
5187 EMSG(_("E198: cmd_pchar beyond the command length"));
5188 return;
5189 }
5190 ccline.cmdbuff[ccline.cmdpos + offset] = (char_u)c;
5191 ccline.cmdbuff[ccline.cmdlen] = NUL;
5192}
5193
5194 int
5195cmd_gchar(offset)
5196 int offset;
5197{
5198 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0)
5199 {
5200 /* EMSG(_("cmd_gchar beyond the command length")); */
5201 return NUL;
5202 }
5203 return (int)ccline.cmdbuff[ccline.cmdpos + offset];
5204}
5205#endif
5206
5207#if defined(FEAT_CMDWIN) || defined(PROTO)
5208/*
5209 * Open a window on the current command line and history. Allow editing in
5210 * the window. Returns when the window is closed.
5211 * Returns:
5212 * CR if the command is to be executed
5213 * Ctrl_C if it is to be abandoned
5214 * K_IGNORE if editing continues
5215 */
5216 static int
5217ex_window()
5218{
5219 struct cmdline_info save_ccline;
5220 buf_T *old_curbuf = curbuf;
5221 win_T *old_curwin = curwin;
5222 buf_T *bp;
5223 win_T *wp;
5224 int i;
5225 linenr_T lnum;
5226 int histtype;
5227 garray_T winsizes;
5228 char_u typestr[2];
5229 int save_restart_edit = restart_edit;
5230 int save_State = State;
5231 int save_exmode = exmode_active;
5232
5233 /* Can't do this recursively. Can't do it when typing a password. */
5234 if (cmdwin_type != 0
5235# if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
5236 || cmdline_star > 0
5237# endif
5238 )
5239 {
5240 beep_flush();
5241 return K_IGNORE;
5242 }
5243
5244 /* Save current window sizes. */
5245 win_size_save(&winsizes);
5246
5247# ifdef FEAT_AUTOCMD
5248 /* Don't execute autocommands while creating the window. */
5249 ++autocmd_block;
5250# endif
5251 /* Create a window for the command-line buffer. */
5252 if (win_split((int)p_cwh, WSP_BOT) == FAIL)
5253 {
5254 beep_flush();
5255 return K_IGNORE;
5256 }
5257 cmdwin_type = ccline.cmdfirstc;
5258 if (cmdwin_type == NUL)
5259 cmdwin_type = '-';
5260
5261 /* Create the command-line buffer empty. */
5262 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE);
5263 (void)setfname(curbuf, (char_u *)"command-line", NULL, TRUE);
5264 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
5265 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
5266 curbuf->b_p_ma = TRUE;
5267# ifdef FEAT_RIGHTLEFT
5268 curwin->w_p_rl = FALSE;
5269# endif
5270# ifdef FEAT_SCROLLBIND
5271 curwin->w_p_scb = FALSE;
5272# endif
5273
5274# ifdef FEAT_AUTOCMD
5275 /* Do execute autocommands for setting the filetype (load syntax). */
5276 --autocmd_block;
5277# endif
5278
5279 histtype = hist_char2type(ccline.cmdfirstc);
5280 if (histtype == HIST_CMD || histtype == HIST_DEBUG)
5281 {
5282 if (p_wc == TAB)
5283 {
5284 add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
5285 add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
5286 }
5287 set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
5288 }
5289
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00005290 /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
5291 * sets 'textwidth' to 78). */
5292 curbuf->b_p_tw = 0;
5293
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294 /* Fill the buffer with the history. */
5295 init_history();
5296 if (hislen > 0)
5297 {
5298 i = hisidx[histtype];
5299 if (i >= 0)
5300 {
5301 lnum = 0;
5302 do
5303 {
5304 if (++i == hislen)
5305 i = 0;
5306 if (history[histtype][i].hisstr != NULL)
5307 ml_append(lnum++, history[histtype][i].hisstr,
5308 (colnr_T)0, FALSE);
5309 }
5310 while (i != hisidx[histtype]);
5311 }
5312 }
5313
5314 /* Replace the empty last line with the current command-line and put the
5315 * cursor there. */
5316 ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE);
5317 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5318 curwin->w_cursor.col = ccline.cmdpos;
5319 redraw_later(NOT_VALID);
5320
5321 /* Save the command line info, can be used recursively. */
5322 save_ccline = ccline;
5323 ccline.cmdbuff = NULL;
5324 ccline.cmdprompt = NULL;
5325
5326 /* No Ex mode here! */
5327 exmode_active = 0;
5328
5329 State = NORMAL;
5330# ifdef FEAT_MOUSE
5331 setmouse();
5332# endif
5333
5334# ifdef FEAT_AUTOCMD
5335 /* Trigger CmdwinEnter autocommands. */
5336 typestr[0] = cmdwin_type;
5337 typestr[1] = NUL;
5338 apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, FALSE, curbuf);
5339# endif
5340
5341 i = RedrawingDisabled;
5342 RedrawingDisabled = 0;
5343
5344 /*
5345 * Call the main loop until <CR> or CTRL-C is typed.
5346 */
5347 cmdwin_result = 0;
5348 main_loop(TRUE);
5349
5350 RedrawingDisabled = i;
5351
5352# ifdef FEAT_AUTOCMD
5353 /* Trigger CmdwinLeave autocommands. */
5354 apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, FALSE, curbuf);
5355# endif
5356
5357 /* Restore the comand line info. */
5358 ccline = save_ccline;
5359 cmdwin_type = 0;
5360
5361 exmode_active = save_exmode;
5362
5363 /* Safety check: The old window or buffer was deleted: It's a a bug when
5364 * this happens! */
5365 if (!win_valid(old_curwin) || !buf_valid(old_curbuf))
5366 {
5367 cmdwin_result = Ctrl_C;
5368 EMSG(_("E199: Active window or buffer deleted"));
5369 }
5370 else
5371 {
5372# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5373 /* autocmds may abort script processing */
5374 if (aborting() && cmdwin_result != K_IGNORE)
5375 cmdwin_result = Ctrl_C;
5376# endif
5377 /* Set the new command line from the cmdline buffer. */
5378 vim_free(ccline.cmdbuff);
5379 if (cmdwin_result == K_XF1) /* :qa! typed */
5380 {
5381 ccline.cmdbuff = vim_strsave((char_u *)"qa!");
5382 cmdwin_result = CAR;
5383 }
5384 else if (cmdwin_result == K_XF2) /* :qa typed */
5385 {
5386 ccline.cmdbuff = vim_strsave((char_u *)"qa");
5387 cmdwin_result = CAR;
5388 }
5389 else
5390 ccline.cmdbuff = vim_strsave(ml_get_curline());
5391 if (ccline.cmdbuff == NULL)
5392 cmdwin_result = Ctrl_C;
5393 else
5394 {
5395 ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
5396 ccline.cmdbufflen = ccline.cmdlen + 1;
5397 ccline.cmdpos = curwin->w_cursor.col;
5398 if (ccline.cmdpos > ccline.cmdlen)
5399 ccline.cmdpos = ccline.cmdlen;
5400 if (cmdwin_result == K_IGNORE)
5401 {
5402 set_cmdspos_cursor();
5403 redrawcmd();
5404 }
5405 }
5406
5407# ifdef FEAT_AUTOCMD
5408 /* Don't execute autocommands while deleting the window. */
5409 ++autocmd_block;
5410# endif
5411 wp = curwin;
5412 bp = curbuf;
5413 win_goto(old_curwin);
5414 win_close(wp, TRUE);
5415 close_buffer(NULL, bp, DOBUF_WIPE);
5416
5417 /* Restore window sizes. */
5418 win_size_restore(&winsizes);
5419
5420# ifdef FEAT_AUTOCMD
5421 --autocmd_block;
5422# endif
5423 }
5424
5425 ga_clear(&winsizes);
5426 restart_edit = save_restart_edit;
5427
5428 State = save_State;
5429# ifdef FEAT_MOUSE
5430 setmouse();
5431# endif
5432
5433 return cmdwin_result;
5434}
5435#endif /* FEAT_CMDWIN */
5436
5437/*
5438 * Used for commands that either take a simple command string argument, or:
5439 * cmd << endmarker
5440 * {script}
5441 * endmarker
5442 * Returns a pointer to allocated memory with {script} or NULL.
5443 */
5444 char_u *
5445script_get(eap, cmd)
5446 exarg_T *eap;
5447 char_u *cmd;
5448{
5449 char_u *theline;
5450 char *end_pattern = NULL;
5451 char dot[] = ".";
5452 garray_T ga;
5453
5454 if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL)
5455 return NULL;
5456
5457 ga_init2(&ga, 1, 0x400);
5458
5459 if (cmd[2] != NUL)
5460 end_pattern = (char *)skipwhite(cmd + 2);
5461 else
5462 end_pattern = dot;
5463
5464 for (;;)
5465 {
5466 theline = eap->getline(
5467#ifdef FEAT_EVAL
5468 eap->cstack->cs_whilelevel > 0 ? -1 :
5469#endif
5470 NUL, eap->cookie, 0);
5471
5472 if (theline == NULL || STRCMP(end_pattern, theline) == 0)
5473 break;
5474
5475 ga_concat(&ga, theline);
5476 ga_append(&ga, '\n');
5477 vim_free(theline);
5478 }
Bram Moolenaar269ec652004-07-29 08:43:53 +00005479 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005480
5481 return (char_u *)ga.ga_data;
5482}