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