1 /* vi:set ts=8 sts=4 sw=4 noet: 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 */ 21 struct cmdline_info 22 { 23 char_u *cmdbuff; /* pointer to command line buffer */ 24 int cmdbufflen; /* length of cmdbuff */ 25 int cmdlen; /* number of chars in command line */ 26 int cmdpos; /* current cursor position */ 27 int cmdspos; /* cursor column on screen */ 28 int cmdfirstc; /* ':', '/', '?', '=', '>' or NUL */ 29 int cmdindent; /* number of spaces before cmdline */ 30 char_u *cmdprompt; /* message in front of cmdline */ 31 int cmdattr; /* attributes for prompt */ 32 int overstrike; /* Typing mode on the command line. Shared by 33 getcmdline() and put_on_cmdline(). */ 34 expand_T *xpc; /* struct being used for expansion, xp_pattern 35 may point into cmdbuff */ 36 int xp_context; /* type of expansion */ 37 # ifdef FEAT_EVAL 38 char_u *xp_arg; /* user-defined expansion arg */ 39 int input_fn; /* when TRUE Invoked for input() function */ 40 # endif 41 }; 42 43 /* The current cmdline_info. It is initialized in getcmdline() and after that 44 * used by other functions. When invoking getcmdline() recursively it needs 45 * to be saved with save_cmdline() and restored with restore_cmdline(). 46 * TODO: make it local to getcmdline() and pass it around. */ 47 static struct cmdline_info ccline; 48 49 static int cmd_showtail; /* Only show path tail in lists ? */ 50 51 #ifdef FEAT_EVAL 52 static int new_cmdpos; /* position set by set_cmdline_pos() */ 53 #endif 54 55 static int extra_char = NUL; /* extra character to display when redrawing 56 * the command line */ 57 static int extra_char_shift; 58 59 #ifdef FEAT_CMDHIST 60 typedef struct hist_entry 61 { 62 int hisnum; /* identifying number */ 63 int viminfo; /* when TRUE hisstr comes from viminfo */ 64 char_u *hisstr; /* actual entry, separator char after the NUL */ 65 time_t time_set; /* when it was typed, zero if unknown */ 66 } histentry_T; 67 68 static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL}; 69 static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */ 70 static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0}; 71 /* identifying (unique) number of newest history entry */ 72 static int hislen = 0; /* actual length of history tables */ 73 74 static int hist_char2type(int c); 75 76 static int in_history(int, char_u *, int, int, int); 77 # ifdef FEAT_EVAL 78 static int calc_hist_idx(int histype, int num); 79 # endif 80 #endif 81 82 #ifdef FEAT_RIGHTLEFT 83 static int cmd_hkmap = 0; /* Hebrew mapping during command line */ 84 #endif 85 86 #ifdef FEAT_FKMAP 87 static int cmd_fkmap = 0; /* Farsi mapping during command line */ 88 #endif 89 90 static int cmdline_charsize(int idx); 91 static void set_cmdspos(void); 92 static void set_cmdspos_cursor(void); 93 #ifdef FEAT_MBYTE 94 static void correct_cmdspos(int idx, int cells); 95 #endif 96 static void alloc_cmdbuff(int len); 97 static int realloc_cmdbuff(int len); 98 static void draw_cmdline(int start, int len); 99 static void save_cmdline(struct cmdline_info *ccp); 100 static void restore_cmdline(struct cmdline_info *ccp); 101 static int cmdline_paste(int regname, int literally, int remcr); 102 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 103 static void redrawcmd_preedit(void); 104 #endif 105 #ifdef FEAT_WILDMENU 106 static void cmdline_del(int from); 107 #endif 108 static void redrawcmdprompt(void); 109 static void cursorcmd(void); 110 static int ccheck_abbr(int); 111 static int nextwild(expand_T *xp, int type, int options, int escape); 112 static void escape_fname(char_u **pp); 113 static int showmatches(expand_T *xp, int wildmenu); 114 static void set_expand_context(expand_T *xp); 115 static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int); 116 static int expand_showtail(expand_T *xp); 117 #ifdef FEAT_CMDL_COMPL 118 static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg); 119 static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]); 120 static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); 121 # ifdef FEAT_CMDHIST 122 static char_u *get_history_arg(expand_T *xp, int idx); 123 # endif 124 # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) 125 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); 126 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); 127 # endif 128 #endif 129 #ifdef FEAT_CMDHIST 130 static void clear_hist_entry(histentry_T *hisptr); 131 #endif 132 133 #ifdef FEAT_CMDWIN 134 static int open_cmdwin(void); 135 #endif 136 137 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 138 static int 139 #ifdef __BORLANDC__ 140 _RTLENTRYF 141 #endif 142 sort_func_compare(const void *s1, const void *s2); 143 #endif 144 #ifdef FEAT_SEARCH_EXTRA 145 static void set_search_match(pos_T *t); 146 #endif 147 148 /* 149 * getcmdline() - accept a command line starting with firstc. 150 * 151 * firstc == ':' get ":" command line. 152 * firstc == '/' or '?' get search pattern 153 * firstc == '=' get expression 154 * firstc == '@' get text for input() function 155 * firstc == '>' get text for debug mode 156 * firstc == NUL get text for :insert command 157 * firstc == -1 like NUL, and break on CTRL-C 158 * 159 * The line is collected in ccline.cmdbuff, which is reallocated to fit the 160 * command line. 161 * 162 * Careful: getcmdline() can be called recursively! 163 * 164 * Return pointer to allocated string if there is a commandline, NULL 165 * otherwise. 166 */ 167 char_u * 168 getcmdline( 169 int firstc, 170 long count UNUSED, /* only used for incremental search */ 171 int indent) /* indent for inside conditionals */ 172 { 173 int c; 174 int i; 175 int j; 176 int gotesc = FALSE; /* TRUE when <ESC> just typed */ 177 int do_abbr; /* when TRUE check for abbr. */ 178 #ifdef FEAT_CMDHIST 179 char_u *lookfor = NULL; /* string to match */ 180 int hiscnt; /* current history line in use */ 181 int histype; /* history type to be used */ 182 #endif 183 #ifdef FEAT_SEARCH_EXTRA 184 pos_T search_start; /* where 'incsearch' starts searching */ 185 pos_T save_cursor; 186 colnr_T old_curswant; 187 colnr_T init_curswant = curwin->w_curswant; 188 colnr_T old_leftcol; 189 colnr_T init_leftcol = curwin->w_leftcol; 190 linenr_T old_topline; 191 linenr_T init_topline = curwin->w_topline; 192 pos_T match_start = curwin->w_cursor; 193 pos_T match_end; 194 # ifdef FEAT_DIFF 195 int old_topfill; 196 int init_topfill = curwin->w_topfill; 197 # endif 198 linenr_T old_botline; 199 linenr_T init_botline = curwin->w_botline; 200 int did_incsearch = FALSE; 201 int incsearch_postponed = FALSE; 202 #endif 203 int did_wild_list = FALSE; /* did wild_list() recently */ 204 int wim_index = 0; /* index in wim_flags[] */ 205 int res; 206 int save_msg_scroll = msg_scroll; 207 int save_State = State; /* remember State when called */ 208 int some_key_typed = FALSE; /* one of the keys was typed */ 209 #ifdef FEAT_MOUSE 210 /* mouse drag and release events are ignored, unless they are 211 * preceded with a mouse down event */ 212 int ignore_drag_release = TRUE; 213 #endif 214 #ifdef FEAT_EVAL 215 int break_ctrl_c = FALSE; 216 #endif 217 expand_T xpc; 218 long *b_im_ptr = NULL; 219 #if defined(FEAT_WILDMENU) || defined(FEAT_EVAL) || defined(FEAT_SEARCH_EXTRA) 220 /* Everything that may work recursively should save and restore the 221 * current command line in save_ccline. That includes update_screen(), a 222 * custom status line may invoke ":normal". */ 223 struct cmdline_info save_ccline; 224 #endif 225 226 #ifdef FEAT_EVAL 227 if (firstc == -1) 228 { 229 firstc = NUL; 230 break_ctrl_c = TRUE; 231 } 232 #endif 233 #ifdef FEAT_RIGHTLEFT 234 /* start without Hebrew mapping for a command line */ 235 if (firstc == ':' || firstc == '=' || firstc == '>') 236 cmd_hkmap = 0; 237 #endif 238 239 ccline.overstrike = FALSE; /* always start in insert mode */ 240 #ifdef FEAT_SEARCH_EXTRA 241 CLEAR_POS(&match_end); 242 save_cursor = curwin->w_cursor; /* may be restored later */ 243 search_start = curwin->w_cursor; 244 old_curswant = curwin->w_curswant; 245 old_leftcol = curwin->w_leftcol; 246 old_topline = curwin->w_topline; 247 # ifdef FEAT_DIFF 248 old_topfill = curwin->w_topfill; 249 # endif 250 old_botline = curwin->w_botline; 251 #endif 252 253 /* 254 * set some variables for redrawcmd() 255 */ 256 ccline.cmdfirstc = (firstc == '@' ? 0 : firstc); 257 ccline.cmdindent = (firstc > 0 ? indent : 0); 258 259 /* alloc initial ccline.cmdbuff */ 260 alloc_cmdbuff(exmode_active ? 250 : indent + 1); 261 if (ccline.cmdbuff == NULL) 262 return NULL; /* out of memory */ 263 ccline.cmdlen = ccline.cmdpos = 0; 264 ccline.cmdbuff[0] = NUL; 265 sb_text_start_cmdline(); 266 267 /* autoindent for :insert and :append */ 268 if (firstc <= 0) 269 { 270 vim_memset(ccline.cmdbuff, ' ', indent); 271 ccline.cmdbuff[indent] = NUL; 272 ccline.cmdpos = indent; 273 ccline.cmdspos = indent; 274 ccline.cmdlen = indent; 275 } 276 277 ExpandInit(&xpc); 278 ccline.xpc = &xpc; 279 280 #ifdef FEAT_RIGHTLEFT 281 if (curwin->w_p_rl && *curwin->w_p_rlc == 's' 282 && (firstc == '/' || firstc == '?')) 283 cmdmsg_rl = TRUE; 284 else 285 cmdmsg_rl = FALSE; 286 #endif 287 288 redir_off = TRUE; /* don't redirect the typed command */ 289 if (!cmd_silent) 290 { 291 i = msg_scrolled; 292 msg_scrolled = 0; /* avoid wait_return message */ 293 gotocmdline(TRUE); 294 msg_scrolled += i; 295 redrawcmdprompt(); /* draw prompt or indent */ 296 set_cmdspos(); 297 } 298 xpc.xp_context = EXPAND_NOTHING; 299 xpc.xp_backslash = XP_BS_NONE; 300 #ifndef BACKSLASH_IN_FILENAME 301 xpc.xp_shell = FALSE; 302 #endif 303 304 #if defined(FEAT_EVAL) 305 if (ccline.input_fn) 306 { 307 xpc.xp_context = ccline.xp_context; 308 xpc.xp_pattern = ccline.cmdbuff; 309 # if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) 310 xpc.xp_arg = ccline.xp_arg; 311 # endif 312 } 313 #endif 314 315 /* 316 * Avoid scrolling when called by a recursive do_cmdline(), e.g. when 317 * doing ":@0" when register 0 doesn't contain a CR. 318 */ 319 msg_scroll = FALSE; 320 321 State = CMDLINE; 322 323 if (firstc == '/' || firstc == '?' || firstc == '@') 324 { 325 /* Use ":lmap" mappings for search pattern and input(). */ 326 if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT) 327 b_im_ptr = &curbuf->b_p_iminsert; 328 else 329 b_im_ptr = &curbuf->b_p_imsearch; 330 if (*b_im_ptr == B_IMODE_LMAP) 331 State |= LANGMAP; 332 #ifdef USE_IM_CONTROL 333 im_set_active(*b_im_ptr == B_IMODE_IM); 334 #endif 335 } 336 #ifdef USE_IM_CONTROL 337 else if (p_imcmdline) 338 im_set_active(TRUE); 339 #endif 340 341 #ifdef FEAT_MOUSE 342 setmouse(); 343 #endif 344 #ifdef CURSOR_SHAPE 345 ui_cursor_shape(); /* may show different cursor shape */ 346 #endif 347 348 /* When inside an autocommand for writing "exiting" may be set and 349 * terminal mode set to cooked. Need to set raw mode here then. */ 350 settmode(TMODE_RAW); 351 352 #ifdef FEAT_CMDHIST 353 init_history(); 354 hiscnt = hislen; /* set hiscnt to impossible history value */ 355 histype = hist_char2type(firstc); 356 #endif 357 358 #ifdef FEAT_DIGRAPHS 359 do_digraph(-1); /* init digraph typeahead */ 360 #endif 361 362 /* If something above caused an error, reset the flags, we do want to type 363 * and execute commands. Display may be messed up a bit. */ 364 if (did_emsg) 365 redrawcmd(); 366 did_emsg = FALSE; 367 got_int = FALSE; 368 369 /* 370 * Collect the command string, handling editing keys. 371 */ 372 for (;;) 373 { 374 redir_off = TRUE; /* Don't redirect the typed command. 375 Repeated, because a ":redir" inside 376 completion may switch it on. */ 377 #ifdef USE_ON_FLY_SCROLL 378 dont_scroll = FALSE; /* allow scrolling here */ 379 #endif 380 quit_more = FALSE; /* reset after CTRL-D which had a more-prompt */ 381 382 cursorcmd(); /* set the cursor on the right spot */ 383 384 /* Get a character. Ignore K_IGNORE, it should not do anything, such 385 * as stop completion. */ 386 do 387 { 388 c = safe_vgetc(); 389 } while (c == K_IGNORE); 390 391 if (KeyTyped) 392 { 393 some_key_typed = TRUE; 394 #ifdef FEAT_RIGHTLEFT 395 if (cmd_hkmap) 396 c = hkmap(c); 397 # ifdef FEAT_FKMAP 398 if (cmd_fkmap) 399 c = cmdl_fkmap(c); 400 # endif 401 if (cmdmsg_rl && !KeyStuffed) 402 { 403 /* Invert horizontal movements and operations. Only when 404 * typed by the user directly, not when the result of a 405 * mapping. */ 406 switch (c) 407 { 408 case K_RIGHT: c = K_LEFT; break; 409 case K_S_RIGHT: c = K_S_LEFT; break; 410 case K_C_RIGHT: c = K_C_LEFT; break; 411 case K_LEFT: c = K_RIGHT; break; 412 case K_S_LEFT: c = K_S_RIGHT; break; 413 case K_C_LEFT: c = K_C_RIGHT; break; 414 } 415 } 416 #endif 417 } 418 419 /* 420 * Ignore got_int when CTRL-C was typed here. 421 * Don't ignore it in :global, we really need to break then, e.g., for 422 * ":g/pat/normal /pat" (without the <CR>). 423 * Don't ignore it for the input() function. 424 */ 425 if ((c == Ctrl_C 426 #ifdef UNIX 427 || c == intr_char 428 #endif 429 ) 430 #if defined(FEAT_EVAL) || defined(FEAT_CRYPT) 431 && firstc != '@' 432 #endif 433 #ifdef FEAT_EVAL 434 && !break_ctrl_c 435 #endif 436 && !global_busy) 437 got_int = FALSE; 438 439 #ifdef FEAT_CMDHIST 440 /* free old command line when finished moving around in the history 441 * list */ 442 if (lookfor != NULL 443 && c != K_S_DOWN && c != K_S_UP 444 && c != K_DOWN && c != K_UP 445 && c != K_PAGEDOWN && c != K_PAGEUP 446 && c != K_KPAGEDOWN && c != K_KPAGEUP 447 && c != K_LEFT && c != K_RIGHT 448 && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N))) 449 { 450 vim_free(lookfor); 451 lookfor = NULL; 452 } 453 #endif 454 455 /* 456 * When there are matching completions to select <S-Tab> works like 457 * CTRL-P (unless 'wc' is <S-Tab>). 458 */ 459 if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles > 0) 460 c = Ctrl_P; 461 462 #ifdef FEAT_WILDMENU 463 /* Special translations for 'wildmenu' */ 464 if (did_wild_list && p_wmnu) 465 { 466 if (c == K_LEFT) 467 c = Ctrl_P; 468 else if (c == K_RIGHT) 469 c = Ctrl_N; 470 } 471 /* Hitting CR after "emenu Name.": complete submenu */ 472 if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu 473 && ccline.cmdpos > 1 474 && ccline.cmdbuff[ccline.cmdpos - 1] == '.' 475 && ccline.cmdbuff[ccline.cmdpos - 2] != '\\' 476 && (c == '\n' || c == '\r' || c == K_KENTER)) 477 c = K_DOWN; 478 #endif 479 480 /* free expanded names when finished walking through matches */ 481 if (xpc.xp_numfiles != -1 482 && !(c == p_wc && KeyTyped) && c != p_wcm 483 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A 484 && c != Ctrl_L) 485 { 486 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); 487 did_wild_list = FALSE; 488 #ifdef FEAT_WILDMENU 489 if (!p_wmnu || (c != K_UP && c != K_DOWN)) 490 #endif 491 xpc.xp_context = EXPAND_NOTHING; 492 wim_index = 0; 493 #ifdef FEAT_WILDMENU 494 if (p_wmnu && wild_menu_showing != 0) 495 { 496 int skt = KeyTyped; 497 int old_RedrawingDisabled = RedrawingDisabled; 498 499 if (ccline.input_fn) 500 RedrawingDisabled = 0; 501 502 if (wild_menu_showing == WM_SCROLLED) 503 { 504 /* Entered command line, move it up */ 505 cmdline_row--; 506 redrawcmd(); 507 } 508 else if (save_p_ls != -1) 509 { 510 /* restore 'laststatus' and 'winminheight' */ 511 p_ls = save_p_ls; 512 p_wmh = save_p_wmh; 513 last_status(FALSE); 514 save_cmdline(&save_ccline); 515 update_screen(VALID); /* redraw the screen NOW */ 516 restore_cmdline(&save_ccline); 517 redrawcmd(); 518 save_p_ls = -1; 519 } 520 else 521 { 522 win_redraw_last_status(topframe); 523 redraw_statuslines(); 524 } 525 KeyTyped = skt; 526 wild_menu_showing = 0; 527 if (ccline.input_fn) 528 RedrawingDisabled = old_RedrawingDisabled; 529 } 530 #endif 531 } 532 533 #ifdef FEAT_WILDMENU 534 /* Special translations for 'wildmenu' */ 535 if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) 536 { 537 /* Hitting <Down> after "emenu Name.": complete submenu */ 538 if (c == K_DOWN && ccline.cmdpos > 0 539 && ccline.cmdbuff[ccline.cmdpos - 1] == '.') 540 c = p_wc; 541 else if (c == K_UP) 542 { 543 /* Hitting <Up>: Remove one submenu name in front of the 544 * cursor */ 545 int found = FALSE; 546 547 j = (int)(xpc.xp_pattern - ccline.cmdbuff); 548 i = 0; 549 while (--j > 0) 550 { 551 /* check for start of menu name */ 552 if (ccline.cmdbuff[j] == ' ' 553 && ccline.cmdbuff[j - 1] != '\\') 554 { 555 i = j + 1; 556 break; 557 } 558 /* check for start of submenu name */ 559 if (ccline.cmdbuff[j] == '.' 560 && ccline.cmdbuff[j - 1] != '\\') 561 { 562 if (found) 563 { 564 i = j + 1; 565 break; 566 } 567 else 568 found = TRUE; 569 } 570 } 571 if (i > 0) 572 cmdline_del(i); 573 c = p_wc; 574 xpc.xp_context = EXPAND_NOTHING; 575 } 576 } 577 if ((xpc.xp_context == EXPAND_FILES 578 || xpc.xp_context == EXPAND_DIRECTORIES 579 || xpc.xp_context == EXPAND_SHELLCMD) && p_wmnu) 580 { 581 char_u upseg[5]; 582 583 upseg[0] = PATHSEP; 584 upseg[1] = '.'; 585 upseg[2] = '.'; 586 upseg[3] = PATHSEP; 587 upseg[4] = NUL; 588 589 if (c == K_DOWN 590 && ccline.cmdpos > 0 591 && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP 592 && (ccline.cmdpos < 3 593 || ccline.cmdbuff[ccline.cmdpos - 2] != '.' 594 || ccline.cmdbuff[ccline.cmdpos - 3] != '.')) 595 { 596 /* go down a directory */ 597 c = p_wc; 598 } 599 else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) 600 { 601 /* If in a direct ancestor, strip off one ../ to go down */ 602 int found = FALSE; 603 604 j = ccline.cmdpos; 605 i = (int)(xpc.xp_pattern - ccline.cmdbuff); 606 while (--j > i) 607 { 608 #ifdef FEAT_MBYTE 609 if (has_mbyte) 610 j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j); 611 #endif 612 if (vim_ispathsep(ccline.cmdbuff[j])) 613 { 614 found = TRUE; 615 break; 616 } 617 } 618 if (found 619 && ccline.cmdbuff[j - 1] == '.' 620 && ccline.cmdbuff[j - 2] == '.' 621 && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2)) 622 { 623 cmdline_del(j - 2); 624 c = p_wc; 625 } 626 } 627 else if (c == K_UP) 628 { 629 /* go up a directory */ 630 int found = FALSE; 631 632 j = ccline.cmdpos - 1; 633 i = (int)(xpc.xp_pattern - ccline.cmdbuff); 634 while (--j > i) 635 { 636 #ifdef FEAT_MBYTE 637 if (has_mbyte) 638 j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j); 639 #endif 640 if (vim_ispathsep(ccline.cmdbuff[j]) 641 #ifdef BACKSLASH_IN_FILENAME 642 && vim_strchr((char_u *)" *?[{`$%#", 643 ccline.cmdbuff[j + 1]) == NULL 644 #endif 645 ) 646 { 647 if (found) 648 { 649 i = j + 1; 650 break; 651 } 652 else 653 found = TRUE; 654 } 655 } 656 657 if (!found) 658 j = i; 659 else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0) 660 j += 4; 661 else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0 662 && j == i) 663 j += 3; 664 else 665 j = 0; 666 if (j > 0) 667 { 668 /* TODO this is only for DOS/UNIX systems - need to put in 669 * machine-specific stuff here and in upseg init */ 670 cmdline_del(j); 671 put_on_cmdline(upseg + 1, 3, FALSE); 672 } 673 else if (ccline.cmdpos > i) 674 cmdline_del(i); 675 676 /* Now complete in the new directory. Set KeyTyped in case the 677 * Up key came from a mapping. */ 678 c = p_wc; 679 KeyTyped = TRUE; 680 } 681 } 682 683 #endif /* FEAT_WILDMENU */ 684 685 /* CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert 686 * mode when 'insertmode' is set, CTRL-\ e prompts for an expression. */ 687 if (c == Ctrl_BSL) 688 { 689 ++no_mapping; 690 ++allow_keys; 691 c = plain_vgetc(); 692 --no_mapping; 693 --allow_keys; 694 /* CTRL-\ e doesn't work when obtaining an expression, unless it 695 * is in a mapping. */ 696 if (c != Ctrl_N && c != Ctrl_G && (c != 'e' 697 || (ccline.cmdfirstc == '=' && KeyTyped))) 698 { 699 vungetc(c); 700 c = Ctrl_BSL; 701 } 702 #ifdef FEAT_EVAL 703 else if (c == 'e') 704 { 705 char_u *p = NULL; 706 int len; 707 708 /* 709 * Replace the command line with the result of an expression. 710 * Need to save and restore the current command line, to be 711 * able to enter a new one... 712 */ 713 if (ccline.cmdpos == ccline.cmdlen) 714 new_cmdpos = 99999; /* keep it at the end */ 715 else 716 new_cmdpos = ccline.cmdpos; 717 718 save_cmdline(&save_ccline); 719 c = get_expr_register(); 720 restore_cmdline(&save_ccline); 721 if (c == '=') 722 { 723 /* Need to save and restore ccline. And set "textlock" 724 * to avoid nasty things like going to another buffer when 725 * evaluating an expression. */ 726 save_cmdline(&save_ccline); 727 ++textlock; 728 p = get_expr_line(); 729 --textlock; 730 restore_cmdline(&save_ccline); 731 732 if (p != NULL) 733 { 734 len = (int)STRLEN(p); 735 if (realloc_cmdbuff(len + 1) == OK) 736 { 737 ccline.cmdlen = len; 738 STRCPY(ccline.cmdbuff, p); 739 vim_free(p); 740 741 /* Restore the cursor or use the position set with 742 * set_cmdline_pos(). */ 743 if (new_cmdpos > ccline.cmdlen) 744 ccline.cmdpos = ccline.cmdlen; 745 else 746 ccline.cmdpos = new_cmdpos; 747 748 KeyTyped = FALSE; /* Don't do p_wc completion. */ 749 redrawcmd(); 750 goto cmdline_changed; 751 } 752 } 753 } 754 beep_flush(); 755 got_int = FALSE; /* don't abandon the command line */ 756 did_emsg = FALSE; 757 emsg_on_display = FALSE; 758 redrawcmd(); 759 goto cmdline_not_changed; 760 } 761 #endif 762 else 763 { 764 if (c == Ctrl_G && p_im && restart_edit == 0) 765 restart_edit = 'a'; 766 gotesc = TRUE; /* will free ccline.cmdbuff after putting it 767 in history */ 768 goto returncmd; /* back to Normal mode */ 769 } 770 } 771 772 #ifdef FEAT_CMDWIN 773 if (c == cedit_key || c == K_CMDWIN) 774 { 775 if (ex_normal_busy == 0 && got_int == FALSE) 776 { 777 /* 778 * Open a window to edit the command line (and history). 779 */ 780 c = open_cmdwin(); 781 some_key_typed = TRUE; 782 } 783 } 784 # ifdef FEAT_DIGRAPHS 785 else 786 # endif 787 #endif 788 #ifdef FEAT_DIGRAPHS 789 c = do_digraph(c); 790 #endif 791 792 if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC 793 && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL))) 794 { 795 /* In Ex mode a backslash escapes a newline. */ 796 if (exmode_active 797 && c != ESC 798 && ccline.cmdpos == ccline.cmdlen 799 && ccline.cmdpos > 0 800 && ccline.cmdbuff[ccline.cmdpos - 1] == '\\') 801 { 802 if (c == K_KENTER) 803 c = '\n'; 804 } 805 else 806 { 807 gotesc = FALSE; /* Might have typed ESC previously, don't 808 truncate the cmdline now. */ 809 if (ccheck_abbr(c + ABBR_OFF)) 810 goto cmdline_changed; 811 if (!cmd_silent) 812 { 813 windgoto(msg_row, 0); 814 out_flush(); 815 } 816 break; 817 } 818 } 819 820 /* 821 * Completion for 'wildchar' or 'wildcharm' key. 822 * - hitting <ESC> twice means: abandon command line. 823 * - wildcard expansion is only done when the 'wildchar' key is really 824 * typed, not when it comes from a macro 825 */ 826 if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm) 827 { 828 if (xpc.xp_numfiles > 0) /* typed p_wc at least twice */ 829 { 830 /* if 'wildmode' contains "list" may still need to list */ 831 if (xpc.xp_numfiles > 1 832 && !did_wild_list 833 && (wim_flags[wim_index] & WIM_LIST)) 834 { 835 (void)showmatches(&xpc, FALSE); 836 redrawcmd(); 837 did_wild_list = TRUE; 838 } 839 if (wim_flags[wim_index] & WIM_LONGEST) 840 res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP, 841 firstc != '@'); 842 else if (wim_flags[wim_index] & WIM_FULL) 843 res = nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP, 844 firstc != '@'); 845 else 846 res = OK; /* don't insert 'wildchar' now */ 847 } 848 else /* typed p_wc first time */ 849 { 850 wim_index = 0; 851 j = ccline.cmdpos; 852 /* if 'wildmode' first contains "longest", get longest 853 * common part */ 854 if (wim_flags[0] & WIM_LONGEST) 855 res = nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP, 856 firstc != '@'); 857 else 858 res = nextwild(&xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP, 859 firstc != '@'); 860 861 /* if interrupted while completing, behave like it failed */ 862 if (got_int) 863 { 864 (void)vpeekc(); /* remove <C-C> from input stream */ 865 got_int = FALSE; /* don't abandon the command line */ 866 (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); 867 #ifdef FEAT_WILDMENU 868 xpc.xp_context = EXPAND_NOTHING; 869 #endif 870 goto cmdline_changed; 871 } 872 873 /* when more than one match, and 'wildmode' first contains 874 * "list", or no change and 'wildmode' contains "longest,list", 875 * list all matches */ 876 if (res == OK && xpc.xp_numfiles > 1) 877 { 878 /* a "longest" that didn't do anything is skipped (but not 879 * "list:longest") */ 880 if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j) 881 wim_index = 1; 882 if ((wim_flags[wim_index] & WIM_LIST) 883 #ifdef FEAT_WILDMENU 884 || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0) 885 #endif 886 ) 887 { 888 if (!(wim_flags[0] & WIM_LONGEST)) 889 { 890 #ifdef FEAT_WILDMENU 891 int p_wmnu_save = p_wmnu; 892 p_wmnu = 0; 893 #endif 894 /* remove match */ 895 nextwild(&xpc, WILD_PREV, 0, firstc != '@'); 896 #ifdef FEAT_WILDMENU 897 p_wmnu = p_wmnu_save; 898 #endif 899 } 900 #ifdef FEAT_WILDMENU 901 (void)showmatches(&xpc, p_wmnu 902 && ((wim_flags[wim_index] & WIM_LIST) == 0)); 903 #else 904 (void)showmatches(&xpc, FALSE); 905 #endif 906 redrawcmd(); 907 did_wild_list = TRUE; 908 if (wim_flags[wim_index] & WIM_LONGEST) 909 nextwild(&xpc, WILD_LONGEST, WILD_NO_BEEP, 910 firstc != '@'); 911 else if (wim_flags[wim_index] & WIM_FULL) 912 nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP, 913 firstc != '@'); 914 } 915 else 916 vim_beep(BO_WILD); 917 } 918 #ifdef FEAT_WILDMENU 919 else if (xpc.xp_numfiles == -1) 920 xpc.xp_context = EXPAND_NOTHING; 921 #endif 922 } 923 if (wim_index < 3) 924 ++wim_index; 925 if (c == ESC) 926 gotesc = TRUE; 927 if (res == OK) 928 goto cmdline_changed; 929 } 930 931 gotesc = FALSE; 932 933 /* <S-Tab> goes to last match, in a clumsy way */ 934 if (c == K_S_TAB && KeyTyped) 935 { 936 if (nextwild(&xpc, WILD_EXPAND_KEEP, 0, firstc != '@') == OK 937 && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK 938 && nextwild(&xpc, WILD_PREV, 0, firstc != '@') == OK) 939 goto cmdline_changed; 940 } 941 942 if (c == NUL || c == K_ZERO) /* NUL is stored as NL */ 943 c = NL; 944 945 do_abbr = TRUE; /* default: check for abbreviation */ 946 947 /* 948 * Big switch for a typed command line character. 949 */ 950 switch (c) 951 { 952 case K_BS: 953 case Ctrl_H: 954 case K_DEL: 955 case K_KDEL: 956 case Ctrl_W: 957 #ifdef FEAT_FKMAP 958 if (cmd_fkmap && c == K_BS) 959 c = K_DEL; 960 #endif 961 if (c == K_KDEL) 962 c = K_DEL; 963 964 /* 965 * delete current character is the same as backspace on next 966 * character, except at end of line 967 */ 968 if (c == K_DEL && ccline.cmdpos != ccline.cmdlen) 969 ++ccline.cmdpos; 970 #ifdef FEAT_MBYTE 971 if (has_mbyte && c == K_DEL) 972 ccline.cmdpos += mb_off_next(ccline.cmdbuff, 973 ccline.cmdbuff + ccline.cmdpos); 974 #endif 975 if (ccline.cmdpos > 0) 976 { 977 char_u *p; 978 979 j = ccline.cmdpos; 980 p = ccline.cmdbuff + j; 981 #ifdef FEAT_MBYTE 982 if (has_mbyte) 983 { 984 p = mb_prevptr(ccline.cmdbuff, p); 985 if (c == Ctrl_W) 986 { 987 while (p > ccline.cmdbuff && vim_isspace(*p)) 988 p = mb_prevptr(ccline.cmdbuff, p); 989 i = mb_get_class(p); 990 while (p > ccline.cmdbuff && mb_get_class(p) == i) 991 p = mb_prevptr(ccline.cmdbuff, p); 992 if (mb_get_class(p) != i) 993 p += (*mb_ptr2len)(p); 994 } 995 } 996 else 997 #endif 998 if (c == Ctrl_W) 999 { 1000 while (p > ccline.cmdbuff && vim_isspace(p[-1])) 1001 --p; 1002 i = vim_iswordc(p[-1]); 1003 while (p > ccline.cmdbuff && !vim_isspace(p[-1]) 1004 && vim_iswordc(p[-1]) == i) 1005 --p; 1006 } 1007 else 1008 --p; 1009 ccline.cmdpos = (int)(p - ccline.cmdbuff); 1010 ccline.cmdlen -= j - ccline.cmdpos; 1011 i = ccline.cmdpos; 1012 while (i < ccline.cmdlen) 1013 ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; 1014 1015 /* Truncate at the end, required for multi-byte chars. */ 1016 ccline.cmdbuff[ccline.cmdlen] = NUL; 1017 #ifdef FEAT_SEARCH_EXTRA 1018 if (ccline.cmdlen == 0) 1019 { 1020 search_start = save_cursor; 1021 /* save view settings, so that the screen 1022 * won't be restored at the wrong position */ 1023 old_curswant = init_curswant; 1024 old_leftcol = init_leftcol; 1025 old_topline = init_topline; 1026 # ifdef FEAT_DIFF 1027 old_topfill = init_topfill; 1028 # endif 1029 old_botline = init_botline; 1030 } 1031 #endif 1032 redrawcmd(); 1033 } 1034 else if (ccline.cmdlen == 0 && c != Ctrl_W 1035 && ccline.cmdprompt == NULL && indent == 0) 1036 { 1037 /* In ex and debug mode it doesn't make sense to return. */ 1038 if (exmode_active 1039 #ifdef FEAT_EVAL 1040 || ccline.cmdfirstc == '>' 1041 #endif 1042 ) 1043 goto cmdline_not_changed; 1044 1045 vim_free(ccline.cmdbuff); /* no commandline to return */ 1046 ccline.cmdbuff = NULL; 1047 if (!cmd_silent) 1048 { 1049 #ifdef FEAT_RIGHTLEFT 1050 if (cmdmsg_rl) 1051 msg_col = Columns; 1052 else 1053 #endif 1054 msg_col = 0; 1055 msg_putchar(' '); /* delete ':' */ 1056 } 1057 #ifdef FEAT_SEARCH_EXTRA 1058 if (ccline.cmdlen == 0) 1059 search_start = save_cursor; 1060 #endif 1061 redraw_cmdline = TRUE; 1062 goto returncmd; /* back to cmd mode */ 1063 } 1064 goto cmdline_changed; 1065 1066 case K_INS: 1067 case K_KINS: 1068 #ifdef FEAT_FKMAP 1069 /* if Farsi mode set, we are in reverse insert mode - 1070 Do not change the mode */ 1071 if (cmd_fkmap) 1072 beep_flush(); 1073 else 1074 #endif 1075 ccline.overstrike = !ccline.overstrike; 1076 #ifdef CURSOR_SHAPE 1077 ui_cursor_shape(); /* may show different cursor shape */ 1078 #endif 1079 goto cmdline_not_changed; 1080 1081 case Ctrl_HAT: 1082 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) 1083 { 1084 /* ":lmap" mappings exists, toggle use of mappings. */ 1085 State ^= LANGMAP; 1086 #ifdef USE_IM_CONTROL 1087 im_set_active(FALSE); /* Disable input method */ 1088 #endif 1089 if (b_im_ptr != NULL) 1090 { 1091 if (State & LANGMAP) 1092 *b_im_ptr = B_IMODE_LMAP; 1093 else 1094 *b_im_ptr = B_IMODE_NONE; 1095 } 1096 } 1097 #ifdef USE_IM_CONTROL 1098 else 1099 { 1100 /* There are no ":lmap" mappings, toggle IM. When 1101 * 'imdisable' is set don't try getting the status, it's 1102 * always off. */ 1103 if ((p_imdisable && b_im_ptr != NULL) 1104 ? *b_im_ptr == B_IMODE_IM : im_get_status()) 1105 { 1106 im_set_active(FALSE); /* Disable input method */ 1107 if (b_im_ptr != NULL) 1108 *b_im_ptr = B_IMODE_NONE; 1109 } 1110 else 1111 { 1112 im_set_active(TRUE); /* Enable input method */ 1113 if (b_im_ptr != NULL) 1114 *b_im_ptr = B_IMODE_IM; 1115 } 1116 } 1117 #endif 1118 if (b_im_ptr != NULL) 1119 { 1120 if (b_im_ptr == &curbuf->b_p_iminsert) 1121 set_iminsert_global(); 1122 else 1123 set_imsearch_global(); 1124 } 1125 #ifdef CURSOR_SHAPE 1126 ui_cursor_shape(); /* may show different cursor shape */ 1127 #endif 1128 #if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP) 1129 /* Show/unshow value of 'keymap' in status lines later. */ 1130 status_redraw_curbuf(); 1131 #endif 1132 goto cmdline_not_changed; 1133 1134 /* case '@': only in very old vi */ 1135 case Ctrl_U: 1136 /* delete all characters left of the cursor */ 1137 j = ccline.cmdpos; 1138 ccline.cmdlen -= j; 1139 i = ccline.cmdpos = 0; 1140 while (i < ccline.cmdlen) 1141 ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; 1142 /* Truncate at the end, required for multi-byte chars. */ 1143 ccline.cmdbuff[ccline.cmdlen] = NUL; 1144 #ifdef FEAT_SEARCH_EXTRA 1145 if (ccline.cmdlen == 0) 1146 search_start = save_cursor; 1147 #endif 1148 redrawcmd(); 1149 goto cmdline_changed; 1150 1151 #ifdef FEAT_CLIPBOARD 1152 case Ctrl_Y: 1153 /* Copy the modeless selection, if there is one. */ 1154 if (clip_star.state != SELECT_CLEARED) 1155 { 1156 if (clip_star.state == SELECT_DONE) 1157 clip_copy_modeless_selection(TRUE); 1158 goto cmdline_not_changed; 1159 } 1160 break; 1161 #endif 1162 1163 case ESC: /* get here if p_wc != ESC or when ESC typed twice */ 1164 case Ctrl_C: 1165 /* In exmode it doesn't make sense to return. Except when 1166 * ":normal" runs out of characters. */ 1167 if (exmode_active 1168 && (ex_normal_busy == 0 || typebuf.tb_len > 0)) 1169 goto cmdline_not_changed; 1170 1171 gotesc = TRUE; /* will free ccline.cmdbuff after 1172 putting it in history */ 1173 goto returncmd; /* back to cmd mode */ 1174 1175 case Ctrl_R: /* insert register */ 1176 #ifdef USE_ON_FLY_SCROLL 1177 dont_scroll = TRUE; /* disallow scrolling here */ 1178 #endif 1179 putcmdline('"', TRUE); 1180 ++no_mapping; 1181 i = c = plain_vgetc(); /* CTRL-R <char> */ 1182 if (i == Ctrl_O) 1183 i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */ 1184 if (i == Ctrl_R) 1185 c = plain_vgetc(); /* CTRL-R CTRL-R <char> */ 1186 extra_char = NUL; 1187 --no_mapping; 1188 #ifdef FEAT_EVAL 1189 /* 1190 * Insert the result of an expression. 1191 * Need to save the current command line, to be able to enter 1192 * a new one... 1193 */ 1194 new_cmdpos = -1; 1195 if (c == '=') 1196 { 1197 if (ccline.cmdfirstc == '=')/* can't do this recursively */ 1198 { 1199 beep_flush(); 1200 c = ESC; 1201 } 1202 else 1203 { 1204 save_cmdline(&save_ccline); 1205 c = get_expr_register(); 1206 restore_cmdline(&save_ccline); 1207 } 1208 } 1209 #endif 1210 if (c != ESC) /* use ESC to cancel inserting register */ 1211 { 1212 cmdline_paste(c, i == Ctrl_R, FALSE); 1213 1214 #ifdef FEAT_EVAL 1215 /* When there was a serious error abort getting the 1216 * command line. */ 1217 if (aborting()) 1218 { 1219 gotesc = TRUE; /* will free ccline.cmdbuff after 1220 putting it in history */ 1221 goto returncmd; /* back to cmd mode */ 1222 } 1223 #endif 1224 KeyTyped = FALSE; /* Don't do p_wc completion. */ 1225 #ifdef FEAT_EVAL 1226 if (new_cmdpos >= 0) 1227 { 1228 /* set_cmdline_pos() was used */ 1229 if (new_cmdpos > ccline.cmdlen) 1230 ccline.cmdpos = ccline.cmdlen; 1231 else 1232 ccline.cmdpos = new_cmdpos; 1233 } 1234 #endif 1235 } 1236 redrawcmd(); 1237 goto cmdline_changed; 1238 1239 case Ctrl_D: 1240 if (showmatches(&xpc, FALSE) == EXPAND_NOTHING) 1241 break; /* Use ^D as normal char instead */ 1242 1243 redrawcmd(); 1244 continue; /* don't do incremental search now */ 1245 1246 case K_RIGHT: 1247 case K_S_RIGHT: 1248 case K_C_RIGHT: 1249 do 1250 { 1251 if (ccline.cmdpos >= ccline.cmdlen) 1252 break; 1253 i = cmdline_charsize(ccline.cmdpos); 1254 if (KeyTyped && ccline.cmdspos + i >= Columns * Rows) 1255 break; 1256 ccline.cmdspos += i; 1257 #ifdef FEAT_MBYTE 1258 if (has_mbyte) 1259 ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff 1260 + ccline.cmdpos); 1261 else 1262 #endif 1263 ++ccline.cmdpos; 1264 } 1265 while ((c == K_S_RIGHT || c == K_C_RIGHT 1266 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))) 1267 && ccline.cmdbuff[ccline.cmdpos] != ' '); 1268 #ifdef FEAT_MBYTE 1269 if (has_mbyte) 1270 set_cmdspos_cursor(); 1271 #endif 1272 goto cmdline_not_changed; 1273 1274 case K_LEFT: 1275 case K_S_LEFT: 1276 case K_C_LEFT: 1277 if (ccline.cmdpos == 0) 1278 goto cmdline_not_changed; 1279 do 1280 { 1281 --ccline.cmdpos; 1282 #ifdef FEAT_MBYTE 1283 if (has_mbyte) /* move to first byte of char */ 1284 ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff, 1285 ccline.cmdbuff + ccline.cmdpos); 1286 #endif 1287 ccline.cmdspos -= cmdline_charsize(ccline.cmdpos); 1288 } 1289 while (ccline.cmdpos > 0 1290 && (c == K_S_LEFT || c == K_C_LEFT 1291 || (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))) 1292 && ccline.cmdbuff[ccline.cmdpos - 1] != ' '); 1293 #ifdef FEAT_MBYTE 1294 if (has_mbyte) 1295 set_cmdspos_cursor(); 1296 #endif 1297 goto cmdline_not_changed; 1298 1299 case K_IGNORE: 1300 /* Ignore mouse event or open_cmdwin() result. */ 1301 goto cmdline_not_changed; 1302 1303 #ifdef FEAT_GUI_W32 1304 /* On Win32 ignore <M-F4>, we get it when closing the window was 1305 * cancelled. */ 1306 case K_F4: 1307 if (mod_mask == MOD_MASK_ALT) 1308 { 1309 redrawcmd(); /* somehow the cmdline is cleared */ 1310 goto cmdline_not_changed; 1311 } 1312 break; 1313 #endif 1314 1315 #ifdef FEAT_MOUSE 1316 case K_MIDDLEDRAG: 1317 case K_MIDDLERELEASE: 1318 goto cmdline_not_changed; /* Ignore mouse */ 1319 1320 case K_MIDDLEMOUSE: 1321 # ifdef FEAT_GUI 1322 /* When GUI is active, also paste when 'mouse' is empty */ 1323 if (!gui.in_use) 1324 # endif 1325 if (!mouse_has(MOUSE_COMMAND)) 1326 goto cmdline_not_changed; /* Ignore mouse */ 1327 # ifdef FEAT_CLIPBOARD 1328 if (clip_star.available) 1329 cmdline_paste('*', TRUE, TRUE); 1330 else 1331 # endif 1332 cmdline_paste(0, TRUE, TRUE); 1333 redrawcmd(); 1334 goto cmdline_changed; 1335 1336 # ifdef FEAT_DND 1337 case K_DROP: 1338 cmdline_paste('~', TRUE, FALSE); 1339 redrawcmd(); 1340 goto cmdline_changed; 1341 # endif 1342 1343 case K_LEFTDRAG: 1344 case K_LEFTRELEASE: 1345 case K_RIGHTDRAG: 1346 case K_RIGHTRELEASE: 1347 /* Ignore drag and release events when the button-down wasn't 1348 * seen before. */ 1349 if (ignore_drag_release) 1350 goto cmdline_not_changed; 1351 /* FALLTHROUGH */ 1352 case K_LEFTMOUSE: 1353 case K_RIGHTMOUSE: 1354 if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE) 1355 ignore_drag_release = TRUE; 1356 else 1357 ignore_drag_release = FALSE; 1358 # ifdef FEAT_GUI 1359 /* When GUI is active, also move when 'mouse' is empty */ 1360 if (!gui.in_use) 1361 # endif 1362 if (!mouse_has(MOUSE_COMMAND)) 1363 goto cmdline_not_changed; /* Ignore mouse */ 1364 # ifdef FEAT_CLIPBOARD 1365 if (mouse_row < cmdline_row && clip_star.available) 1366 { 1367 int button, is_click, is_drag; 1368 1369 /* 1370 * Handle modeless selection. 1371 */ 1372 button = get_mouse_button(KEY2TERMCAP1(c), 1373 &is_click, &is_drag); 1374 if (mouse_model_popup() && button == MOUSE_LEFT 1375 && (mod_mask & MOD_MASK_SHIFT)) 1376 { 1377 /* Translate shift-left to right button. */ 1378 button = MOUSE_RIGHT; 1379 mod_mask &= ~MOD_MASK_SHIFT; 1380 } 1381 clip_modeless(button, is_click, is_drag); 1382 goto cmdline_not_changed; 1383 } 1384 # endif 1385 1386 set_cmdspos(); 1387 for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; 1388 ++ccline.cmdpos) 1389 { 1390 i = cmdline_charsize(ccline.cmdpos); 1391 if (mouse_row <= cmdline_row + ccline.cmdspos / Columns 1392 && mouse_col < ccline.cmdspos % Columns + i) 1393 break; 1394 # ifdef FEAT_MBYTE 1395 if (has_mbyte) 1396 { 1397 /* Count ">" for double-wide char that doesn't fit. */ 1398 correct_cmdspos(ccline.cmdpos, i); 1399 ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff 1400 + ccline.cmdpos) - 1; 1401 } 1402 # endif 1403 ccline.cmdspos += i; 1404 } 1405 goto cmdline_not_changed; 1406 1407 /* Mouse scroll wheel: ignored here */ 1408 case K_MOUSEDOWN: 1409 case K_MOUSEUP: 1410 case K_MOUSELEFT: 1411 case K_MOUSERIGHT: 1412 /* Alternate buttons ignored here */ 1413 case K_X1MOUSE: 1414 case K_X1DRAG: 1415 case K_X1RELEASE: 1416 case K_X2MOUSE: 1417 case K_X2DRAG: 1418 case K_X2RELEASE: 1419 goto cmdline_not_changed; 1420 1421 #endif /* FEAT_MOUSE */ 1422 1423 #ifdef FEAT_GUI 1424 case K_LEFTMOUSE_NM: /* mousefocus click, ignored */ 1425 case K_LEFTRELEASE_NM: 1426 goto cmdline_not_changed; 1427 1428 case K_VER_SCROLLBAR: 1429 if (msg_scrolled == 0) 1430 { 1431 gui_do_scroll(); 1432 redrawcmd(); 1433 } 1434 goto cmdline_not_changed; 1435 1436 case K_HOR_SCROLLBAR: 1437 if (msg_scrolled == 0) 1438 { 1439 gui_do_horiz_scroll(scrollbar_value, FALSE); 1440 redrawcmd(); 1441 } 1442 goto cmdline_not_changed; 1443 #endif 1444 #ifdef FEAT_GUI_TABLINE 1445 case K_TABLINE: 1446 case K_TABMENU: 1447 /* Don't want to change any tabs here. Make sure the same tab 1448 * is still selected. */ 1449 if (gui_use_tabline()) 1450 gui_mch_set_curtab(tabpage_index(curtab)); 1451 goto cmdline_not_changed; 1452 #endif 1453 1454 case K_SELECT: /* end of Select mode mapping - ignore */ 1455 goto cmdline_not_changed; 1456 1457 case Ctrl_B: /* begin of command line */ 1458 case K_HOME: 1459 case K_KHOME: 1460 case K_S_HOME: 1461 case K_C_HOME: 1462 ccline.cmdpos = 0; 1463 set_cmdspos(); 1464 goto cmdline_not_changed; 1465 1466 case Ctrl_E: /* end of command line */ 1467 case K_END: 1468 case K_KEND: 1469 case K_S_END: 1470 case K_C_END: 1471 ccline.cmdpos = ccline.cmdlen; 1472 set_cmdspos_cursor(); 1473 goto cmdline_not_changed; 1474 1475 case Ctrl_A: /* all matches */ 1476 if (nextwild(&xpc, WILD_ALL, 0, firstc != '@') == FAIL) 1477 break; 1478 goto cmdline_changed; 1479 1480 case Ctrl_L: 1481 #ifdef FEAT_SEARCH_EXTRA 1482 if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) 1483 { 1484 /* Add a character from under the cursor for 'incsearch' */ 1485 if (did_incsearch) 1486 { 1487 curwin->w_cursor = match_end; 1488 if (!EQUAL_POS(curwin->w_cursor, search_start)) 1489 { 1490 c = gchar_cursor(); 1491 /* If 'ignorecase' and 'smartcase' are set and the 1492 * command line has no uppercase characters, convert 1493 * the character to lowercase */ 1494 if (p_ic && p_scs 1495 && !pat_has_uppercase(ccline.cmdbuff)) 1496 c = MB_TOLOWER(c); 1497 if (c != NUL) 1498 { 1499 if (c == firstc || vim_strchr((char_u *)( 1500 p_magic ? "\\~^$.*[" : "\\^$"), c) 1501 != NULL) 1502 { 1503 /* put a backslash before special 1504 * characters */ 1505 stuffcharReadbuff(c); 1506 c = '\\'; 1507 } 1508 break; 1509 } 1510 } 1511 } 1512 goto cmdline_not_changed; 1513 } 1514 #endif 1515 1516 /* completion: longest common part */ 1517 if (nextwild(&xpc, WILD_LONGEST, 0, firstc != '@') == FAIL) 1518 break; 1519 goto cmdline_changed; 1520 1521 case Ctrl_N: /* next match */ 1522 case Ctrl_P: /* previous match */ 1523 if (xpc.xp_numfiles > 0) 1524 { 1525 if (nextwild(&xpc, (c == Ctrl_P) ? WILD_PREV : WILD_NEXT, 1526 0, firstc != '@') == FAIL) 1527 break; 1528 goto cmdline_not_changed; 1529 } 1530 /* FALLTHROUGH */ 1531 1532 #ifdef FEAT_CMDHIST 1533 case K_UP: 1534 case K_DOWN: 1535 case K_S_UP: 1536 case K_S_DOWN: 1537 case K_PAGEUP: 1538 case K_KPAGEUP: 1539 case K_PAGEDOWN: 1540 case K_KPAGEDOWN: 1541 if (hislen == 0 || firstc == NUL) /* no history */ 1542 goto cmdline_not_changed; 1543 1544 i = hiscnt; 1545 1546 /* save current command string so it can be restored later */ 1547 if (lookfor == NULL) 1548 { 1549 if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL) 1550 goto cmdline_not_changed; 1551 lookfor[ccline.cmdpos] = NUL; 1552 } 1553 1554 j = (int)STRLEN(lookfor); 1555 for (;;) 1556 { 1557 /* one step backwards */ 1558 if (c == K_UP|| c == K_S_UP || c == Ctrl_P 1559 || c == K_PAGEUP || c == K_KPAGEUP) 1560 { 1561 if (hiscnt == hislen) /* first time */ 1562 hiscnt = hisidx[histype]; 1563 else if (hiscnt == 0 && hisidx[histype] != hislen - 1) 1564 hiscnt = hislen - 1; 1565 else if (hiscnt != hisidx[histype] + 1) 1566 --hiscnt; 1567 else /* at top of list */ 1568 { 1569 hiscnt = i; 1570 break; 1571 } 1572 } 1573 else /* one step forwards */ 1574 { 1575 /* on last entry, clear the line */ 1576 if (hiscnt == hisidx[histype]) 1577 { 1578 hiscnt = hislen; 1579 break; 1580 } 1581 1582 /* not on a history line, nothing to do */ 1583 if (hiscnt == hislen) 1584 break; 1585 if (hiscnt == hislen - 1) /* wrap around */ 1586 hiscnt = 0; 1587 else 1588 ++hiscnt; 1589 } 1590 if (hiscnt < 0 || history[histype][hiscnt].hisstr == NULL) 1591 { 1592 hiscnt = i; 1593 break; 1594 } 1595 if ((c != K_UP && c != K_DOWN) 1596 || hiscnt == i 1597 || STRNCMP(history[histype][hiscnt].hisstr, 1598 lookfor, (size_t)j) == 0) 1599 break; 1600 } 1601 1602 if (hiscnt != i) /* jumped to other entry */ 1603 { 1604 char_u *p; 1605 int len; 1606 int old_firstc; 1607 1608 vim_free(ccline.cmdbuff); 1609 xpc.xp_context = EXPAND_NOTHING; 1610 if (hiscnt == hislen) 1611 p = lookfor; /* back to the old one */ 1612 else 1613 p = history[histype][hiscnt].hisstr; 1614 1615 if (histype == HIST_SEARCH 1616 && p != lookfor 1617 && (old_firstc = p[STRLEN(p) + 1]) != firstc) 1618 { 1619 /* Correct for the separator character used when 1620 * adding the history entry vs the one used now. 1621 * First loop: count length. 1622 * Second loop: copy the characters. */ 1623 for (i = 0; i <= 1; ++i) 1624 { 1625 len = 0; 1626 for (j = 0; p[j] != NUL; ++j) 1627 { 1628 /* Replace old sep with new sep, unless it is 1629 * escaped. */ 1630 if (p[j] == old_firstc 1631 && (j == 0 || p[j - 1] != '\\')) 1632 { 1633 if (i > 0) 1634 ccline.cmdbuff[len] = firstc; 1635 } 1636 else 1637 { 1638 /* Escape new sep, unless it is already 1639 * escaped. */ 1640 if (p[j] == firstc 1641 && (j == 0 || p[j - 1] != '\\')) 1642 { 1643 if (i > 0) 1644 ccline.cmdbuff[len] = '\\'; 1645 ++len; 1646 } 1647 if (i > 0) 1648 ccline.cmdbuff[len] = p[j]; 1649 } 1650 ++len; 1651 } 1652 if (i == 0) 1653 { 1654 alloc_cmdbuff(len); 1655 if (ccline.cmdbuff == NULL) 1656 goto returncmd; 1657 } 1658 } 1659 ccline.cmdbuff[len] = NUL; 1660 } 1661 else 1662 { 1663 alloc_cmdbuff((int)STRLEN(p)); 1664 if (ccline.cmdbuff == NULL) 1665 goto returncmd; 1666 STRCPY(ccline.cmdbuff, p); 1667 } 1668 1669 ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); 1670 redrawcmd(); 1671 goto cmdline_changed; 1672 } 1673 beep_flush(); 1674 #endif 1675 goto cmdline_not_changed; 1676 1677 #ifdef FEAT_SEARCH_EXTRA 1678 case Ctrl_G: /* next match */ 1679 case Ctrl_T: /* previous match */ 1680 if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) 1681 { 1682 pos_T t; 1683 int search_flags = SEARCH_KEEP + SEARCH_NOOF 1684 + SEARCH_PEEK; 1685 1686 if (char_avail()) 1687 continue; 1688 cursor_off(); 1689 out_flush(); 1690 if (c == Ctrl_G) 1691 { 1692 t = match_end; 1693 search_flags += SEARCH_COL; 1694 } 1695 else 1696 t = match_start; 1697 ++emsg_off; 1698 i = searchit(curwin, curbuf, &t, 1699 c == Ctrl_G ? FORWARD : BACKWARD, 1700 ccline.cmdbuff, count, search_flags, 1701 RE_SEARCH, 0, NULL, NULL); 1702 --emsg_off; 1703 if (i) 1704 { 1705 search_start = match_start; 1706 match_end = t; 1707 match_start = t; 1708 if (c == Ctrl_T && firstc == '/') 1709 { 1710 /* move just before the current match, so that 1711 * when nv_search finishes the cursor will be 1712 * put back on the match */ 1713 search_start = t; 1714 (void)decl(&search_start); 1715 } 1716 else if (c == Ctrl_G && firstc == '?') 1717 { 1718 /* move just after the current match, so that 1719 * when nv_search finishes the cursor will be 1720 * put back on the match */ 1721 search_start = t; 1722 (void)incl(&search_start); 1723 } 1724 if (LT_POS(t, search_start) && c == Ctrl_G) 1725 { 1726 /* wrap around */ 1727 search_start = t; 1728 if (firstc == '?') 1729 (void)incl(&search_start); 1730 else 1731 (void)decl(&search_start); 1732 } 1733 1734 set_search_match(&match_end); 1735 curwin->w_cursor = match_start; 1736 changed_cline_bef_curs(); 1737 update_topline(); 1738 validate_cursor(); 1739 highlight_match = TRUE; 1740 old_curswant = curwin->w_curswant; 1741 old_leftcol = curwin->w_leftcol; 1742 old_topline = curwin->w_topline; 1743 # ifdef FEAT_DIFF 1744 old_topfill = curwin->w_topfill; 1745 # endif 1746 old_botline = curwin->w_botline; 1747 update_screen(NOT_VALID); 1748 redrawcmdline(); 1749 } 1750 else 1751 vim_beep(BO_ERROR); 1752 goto cmdline_not_changed; 1753 } 1754 break; 1755 #endif 1756 1757 case Ctrl_V: 1758 case Ctrl_Q: 1759 #ifdef FEAT_MOUSE 1760 ignore_drag_release = TRUE; 1761 #endif 1762 putcmdline('^', TRUE); 1763 c = get_literal(); /* get next (two) character(s) */ 1764 do_abbr = FALSE; /* don't do abbreviation now */ 1765 extra_char = NUL; 1766 #ifdef FEAT_MBYTE 1767 /* may need to remove ^ when composing char was typed */ 1768 if (enc_utf8 && utf_iscomposing(c) && !cmd_silent) 1769 { 1770 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); 1771 msg_putchar(' '); 1772 cursorcmd(); 1773 } 1774 #endif 1775 break; 1776 1777 #ifdef FEAT_DIGRAPHS 1778 case Ctrl_K: 1779 #ifdef FEAT_MOUSE 1780 ignore_drag_release = TRUE; 1781 #endif 1782 putcmdline('?', TRUE); 1783 #ifdef USE_ON_FLY_SCROLL 1784 dont_scroll = TRUE; /* disallow scrolling here */ 1785 #endif 1786 c = get_digraph(TRUE); 1787 extra_char = NUL; 1788 if (c != NUL) 1789 break; 1790 1791 redrawcmd(); 1792 goto cmdline_not_changed; 1793 #endif /* FEAT_DIGRAPHS */ 1794 1795 #ifdef FEAT_RIGHTLEFT 1796 case Ctrl__: /* CTRL-_: switch language mode */ 1797 if (!p_ari) 1798 break; 1799 # ifdef FEAT_FKMAP 1800 if (p_altkeymap) 1801 { 1802 cmd_fkmap = !cmd_fkmap; 1803 if (cmd_fkmap) /* in Farsi always in Insert mode */ 1804 ccline.overstrike = FALSE; 1805 } 1806 else /* Hebrew is default */ 1807 # endif 1808 cmd_hkmap = !cmd_hkmap; 1809 goto cmdline_not_changed; 1810 #endif 1811 1812 case K_PS: 1813 bracketed_paste(PASTE_CMDLINE, FALSE, NULL); 1814 goto cmdline_changed; 1815 1816 default: 1817 #ifdef UNIX 1818 if (c == intr_char) 1819 { 1820 gotesc = TRUE; /* will free ccline.cmdbuff after 1821 putting it in history */ 1822 goto returncmd; /* back to Normal mode */ 1823 } 1824 #endif 1825 /* 1826 * Normal character with no special meaning. Just set mod_mask 1827 * to 0x0 so that typing Shift-Space in the GUI doesn't enter 1828 * the string <S-Space>. This should only happen after ^V. 1829 */ 1830 if (!IS_SPECIAL(c)) 1831 mod_mask = 0x0; 1832 break; 1833 } 1834 /* 1835 * End of switch on command line character. 1836 * We come here if we have a normal character. 1837 */ 1838 1839 if (do_abbr && (IS_SPECIAL(c) || !vim_iswordc(c)) && (ccheck_abbr( 1840 #ifdef FEAT_MBYTE 1841 /* Add ABBR_OFF for characters above 0x100, this is 1842 * what check_abbr() expects. */ 1843 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : 1844 #endif 1845 c) || c == Ctrl_RSB)) 1846 goto cmdline_changed; 1847 1848 /* 1849 * put the character in the command line 1850 */ 1851 if (IS_SPECIAL(c) || mod_mask != 0) 1852 put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE); 1853 else 1854 { 1855 #ifdef FEAT_MBYTE 1856 if (has_mbyte) 1857 { 1858 j = (*mb_char2bytes)(c, IObuff); 1859 IObuff[j] = NUL; /* exclude composing chars */ 1860 put_on_cmdline(IObuff, j, TRUE); 1861 } 1862 else 1863 #endif 1864 { 1865 IObuff[0] = c; 1866 put_on_cmdline(IObuff, 1, TRUE); 1867 } 1868 } 1869 goto cmdline_changed; 1870 1871 /* 1872 * This part implements incremental searches for "/" and "?" 1873 * Jump to cmdline_not_changed when a character has been read but the command 1874 * line did not change. Then we only search and redraw if something changed in 1875 * the past. 1876 * Jump to cmdline_changed when the command line did change. 1877 * (Sorry for the goto's, I know it is ugly). 1878 */ 1879 cmdline_not_changed: 1880 #ifdef FEAT_SEARCH_EXTRA 1881 if (!incsearch_postponed) 1882 continue; 1883 #endif 1884 1885 cmdline_changed: 1886 #ifdef FEAT_SEARCH_EXTRA 1887 /* 1888 * 'incsearch' highlighting. 1889 */ 1890 if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) 1891 { 1892 pos_T end_pos; 1893 #ifdef FEAT_RELTIME 1894 proftime_T tm; 1895 #endif 1896 1897 /* if there is a character waiting, search and redraw later */ 1898 if (char_avail()) 1899 { 1900 incsearch_postponed = TRUE; 1901 continue; 1902 } 1903 incsearch_postponed = FALSE; 1904 curwin->w_cursor = search_start; /* start at old position */ 1905 1906 /* If there is no command line, don't do anything */ 1907 if (ccline.cmdlen == 0) 1908 i = 0; 1909 else 1910 { 1911 cursor_off(); /* so the user knows we're busy */ 1912 out_flush(); 1913 ++emsg_off; /* So it doesn't beep if bad expr */ 1914 #ifdef FEAT_RELTIME 1915 /* Set the time limit to half a second. */ 1916 profile_setlimit(500L, &tm); 1917 #endif 1918 i = do_search(NULL, firstc, ccline.cmdbuff, count, 1919 SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK, 1920 #ifdef FEAT_RELTIME 1921 &tm, NULL 1922 #else 1923 NULL, NULL 1924 #endif 1925 ); 1926 --emsg_off; 1927 /* if interrupted while searching, behave like it failed */ 1928 if (got_int) 1929 { 1930 (void)vpeekc(); /* remove <C-C> from input stream */ 1931 got_int = FALSE; /* don't abandon the command line */ 1932 i = 0; 1933 } 1934 else if (char_avail()) 1935 /* cancelled searching because a char was typed */ 1936 incsearch_postponed = TRUE; 1937 } 1938 if (i != 0) 1939 highlight_match = TRUE; /* highlight position */ 1940 else 1941 highlight_match = FALSE; /* remove highlight */ 1942 1943 /* first restore the old curwin values, so the screen is 1944 * positioned in the same way as the actual search command */ 1945 curwin->w_leftcol = old_leftcol; 1946 curwin->w_topline = old_topline; 1947 # ifdef FEAT_DIFF 1948 curwin->w_topfill = old_topfill; 1949 # endif 1950 curwin->w_botline = old_botline; 1951 changed_cline_bef_curs(); 1952 update_topline(); 1953 1954 if (i != 0) 1955 { 1956 pos_T save_pos = curwin->w_cursor; 1957 1958 match_start = curwin->w_cursor; 1959 set_search_match(&curwin->w_cursor); 1960 validate_cursor(); 1961 end_pos = curwin->w_cursor; 1962 match_end = end_pos; 1963 curwin->w_cursor = save_pos; 1964 } 1965 else 1966 end_pos = curwin->w_cursor; /* shutup gcc 4 */ 1967 1968 validate_cursor(); 1969 # ifdef FEAT_WINDOWS 1970 /* May redraw the status line to show the cursor position. */ 1971 if (p_ru && curwin->w_status_height > 0) 1972 curwin->w_redr_status = TRUE; 1973 # endif 1974 1975 save_cmdline(&save_ccline); 1976 update_screen(SOME_VALID); 1977 restore_cmdline(&save_ccline); 1978 1979 /* Leave it at the end to make CTRL-R CTRL-W work. */ 1980 if (i != 0) 1981 curwin->w_cursor = end_pos; 1982 1983 msg_starthere(); 1984 redrawcmdline(); 1985 did_incsearch = TRUE; 1986 } 1987 #else /* FEAT_SEARCH_EXTRA */ 1988 ; 1989 #endif 1990 1991 #ifdef FEAT_RIGHTLEFT 1992 if (cmdmsg_rl 1993 # ifdef FEAT_ARABIC 1994 || (p_arshape && !p_tbidi && enc_utf8) 1995 # endif 1996 ) 1997 /* Always redraw the whole command line to fix shaping and 1998 * right-left typing. Not efficient, but it works. 1999 * Do it only when there are no characters left to read 2000 * to avoid useless intermediate redraws. */ 2001 if (vpeekc() == NUL) 2002 redrawcmd(); 2003 #endif 2004 } 2005 2006 returncmd: 2007 2008 #ifdef FEAT_RIGHTLEFT 2009 cmdmsg_rl = FALSE; 2010 #endif 2011 2012 #ifdef FEAT_FKMAP 2013 cmd_fkmap = 0; 2014 #endif 2015 2016 ExpandCleanup(&xpc); 2017 ccline.xpc = NULL; 2018 2019 #ifdef FEAT_SEARCH_EXTRA 2020 if (did_incsearch) 2021 { 2022 if (gotesc) 2023 curwin->w_cursor = save_cursor; 2024 else 2025 { 2026 if (!EQUAL_POS(save_cursor, search_start)) 2027 { 2028 /* put the '" mark at the original position */ 2029 curwin->w_cursor = save_cursor; 2030 setpcmark(); 2031 } 2032 curwin->w_cursor = search_start; 2033 } 2034 curwin->w_curswant = old_curswant; 2035 curwin->w_leftcol = old_leftcol; 2036 curwin->w_topline = old_topline; 2037 # ifdef FEAT_DIFF 2038 curwin->w_topfill = old_topfill; 2039 # endif 2040 curwin->w_botline = old_botline; 2041 highlight_match = FALSE; 2042 validate_cursor(); /* needed for TAB */ 2043 redraw_later(SOME_VALID); 2044 } 2045 #endif 2046 2047 if (ccline.cmdbuff != NULL) 2048 { 2049 /* 2050 * Put line in history buffer (":" and "=" only when it was typed). 2051 */ 2052 #ifdef FEAT_CMDHIST 2053 if (ccline.cmdlen && firstc != NUL 2054 && (some_key_typed || histype == HIST_SEARCH)) 2055 { 2056 add_to_history(histype, ccline.cmdbuff, TRUE, 2057 histype == HIST_SEARCH ? firstc : NUL); 2058 if (firstc == ':') 2059 { 2060 vim_free(new_last_cmdline); 2061 new_last_cmdline = vim_strsave(ccline.cmdbuff); 2062 } 2063 } 2064 #endif 2065 2066 if (gotesc) /* abandon command line */ 2067 { 2068 vim_free(ccline.cmdbuff); 2069 ccline.cmdbuff = NULL; 2070 if (msg_scrolled == 0) 2071 compute_cmdrow(); 2072 MSG(""); 2073 redraw_cmdline = TRUE; 2074 } 2075 } 2076 2077 /* 2078 * If the screen was shifted up, redraw the whole screen (later). 2079 * If the line is too long, clear it, so ruler and shown command do 2080 * not get printed in the middle of it. 2081 */ 2082 msg_check(); 2083 msg_scroll = save_msg_scroll; 2084 redir_off = FALSE; 2085 2086 /* When the command line was typed, no need for a wait-return prompt. */ 2087 if (some_key_typed) 2088 need_wait_return = FALSE; 2089 2090 State = save_State; 2091 #ifdef USE_IM_CONTROL 2092 if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP) 2093 im_save_status(b_im_ptr); 2094 im_set_active(FALSE); 2095 #endif 2096 #ifdef FEAT_MOUSE 2097 setmouse(); 2098 #endif 2099 #ifdef CURSOR_SHAPE 2100 ui_cursor_shape(); /* may show different cursor shape */ 2101 #endif 2102 sb_text_end_cmdline(); 2103 2104 { 2105 char_u *p = ccline.cmdbuff; 2106 2107 /* Make ccline empty, getcmdline() may try to use it. */ 2108 ccline.cmdbuff = NULL; 2109 return p; 2110 } 2111 } 2112 2113 #if (defined(FEAT_CRYPT) || defined(FEAT_EVAL)) || defined(PROTO) 2114 /* 2115 * Get a command line with a prompt. 2116 * This is prepared to be called recursively from getcmdline() (e.g. by 2117 * f_input() when evaluating an expression from CTRL-R =). 2118 * Returns the command line in allocated memory, or NULL. 2119 */ 2120 char_u * 2121 getcmdline_prompt( 2122 int firstc, 2123 char_u *prompt, /* command line prompt */ 2124 int attr, /* attributes for prompt */ 2125 int xp_context, /* type of expansion */ 2126 char_u *xp_arg) /* user-defined expansion argument */ 2127 { 2128 char_u *s; 2129 struct cmdline_info save_ccline; 2130 int msg_col_save = msg_col; 2131 int msg_silent_save = msg_silent; 2132 2133 save_cmdline(&save_ccline); 2134 ccline.cmdprompt = prompt; 2135 ccline.cmdattr = attr; 2136 # ifdef FEAT_EVAL 2137 ccline.xp_context = xp_context; 2138 ccline.xp_arg = xp_arg; 2139 ccline.input_fn = (firstc == '@'); 2140 # endif 2141 msg_silent = 0; 2142 s = getcmdline(firstc, 1L, 0); 2143 restore_cmdline(&save_ccline); 2144 msg_silent = msg_silent_save; 2145 /* Restore msg_col, the prompt from input() may have changed it. 2146 * But only if called recursively and the commandline is therefore being 2147 * restored to an old one; if not, the input() prompt stays on the screen, 2148 * so we need its modified msg_col left intact. */ 2149 if (ccline.cmdbuff != NULL) 2150 msg_col = msg_col_save; 2151 2152 return s; 2153 } 2154 #endif 2155 2156 /* 2157 * Return TRUE when the text must not be changed and we can't switch to 2158 * another window or buffer. Used when editing the command line, evaluating 2159 * 'balloonexpr', etc. 2160 */ 2161 int 2162 text_locked(void) 2163 { 2164 #ifdef FEAT_CMDWIN 2165 if (cmdwin_type != 0) 2166 return TRUE; 2167 #endif 2168 return textlock != 0; 2169 } 2170 2171 /* 2172 * Give an error message for a command that isn't allowed while the cmdline 2173 * window is open or editing the cmdline in another way. 2174 */ 2175 void 2176 text_locked_msg(void) 2177 { 2178 EMSG(_(get_text_locked_msg())); 2179 } 2180 2181 char_u * 2182 get_text_locked_msg(void) 2183 { 2184 #ifdef FEAT_CMDWIN 2185 if (cmdwin_type != 0) 2186 return e_cmdwin; 2187 #endif 2188 return e_secure; 2189 } 2190 2191 #if defined(FEAT_AUTOCMD) || defined(PROTO) 2192 /* 2193 * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is 2194 * and give an error message. 2195 */ 2196 int 2197 curbuf_locked(void) 2198 { 2199 if (curbuf_lock > 0) 2200 { 2201 EMSG(_("E788: Not allowed to edit another buffer now")); 2202 return TRUE; 2203 } 2204 return allbuf_locked(); 2205 } 2206 2207 /* 2208 * Check if "allbuf_lock" is set and return TRUE when it is and give an error 2209 * message. 2210 */ 2211 int 2212 allbuf_locked(void) 2213 { 2214 if (allbuf_lock > 0) 2215 { 2216 EMSG(_("E811: Not allowed to change buffer information now")); 2217 return TRUE; 2218 } 2219 return FALSE; 2220 } 2221 #endif 2222 2223 static int 2224 cmdline_charsize(int idx) 2225 { 2226 #if defined(FEAT_CRYPT) || defined(FEAT_EVAL) 2227 if (cmdline_star > 0) /* showing '*', always 1 position */ 2228 return 1; 2229 #endif 2230 return ptr2cells(ccline.cmdbuff + idx); 2231 } 2232 2233 /* 2234 * Compute the offset of the cursor on the command line for the prompt and 2235 * indent. 2236 */ 2237 static void 2238 set_cmdspos(void) 2239 { 2240 if (ccline.cmdfirstc != NUL) 2241 ccline.cmdspos = 1 + ccline.cmdindent; 2242 else 2243 ccline.cmdspos = 0 + ccline.cmdindent; 2244 } 2245 2246 /* 2247 * Compute the screen position for the cursor on the command line. 2248 */ 2249 static void 2250 set_cmdspos_cursor(void) 2251 { 2252 int i, m, c; 2253 2254 set_cmdspos(); 2255 if (KeyTyped) 2256 { 2257 m = Columns * Rows; 2258 if (m < 0) /* overflow, Columns or Rows at weird value */ 2259 m = MAXCOL; 2260 } 2261 else 2262 m = MAXCOL; 2263 for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i) 2264 { 2265 c = cmdline_charsize(i); 2266 #ifdef FEAT_MBYTE 2267 /* Count ">" for double-wide multi-byte char that doesn't fit. */ 2268 if (has_mbyte) 2269 correct_cmdspos(i, c); 2270 #endif 2271 /* If the cmdline doesn't fit, show cursor on last visible char. 2272 * Don't move the cursor itself, so we can still append. */ 2273 if ((ccline.cmdspos += c) >= m) 2274 { 2275 ccline.cmdspos -= c; 2276 break; 2277 } 2278 #ifdef FEAT_MBYTE 2279 if (has_mbyte) 2280 i += (*mb_ptr2len)(ccline.cmdbuff + i) - 1; 2281 #endif 2282 } 2283 } 2284 2285 #ifdef FEAT_MBYTE 2286 /* 2287 * Check if the character at "idx", which is "cells" wide, is a multi-byte 2288 * character that doesn't fit, so that a ">" must be displayed. 2289 */ 2290 static void 2291 correct_cmdspos(int idx, int cells) 2292 { 2293 if ((*mb_ptr2len)(ccline.cmdbuff + idx) > 1 2294 && (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1 2295 && ccline.cmdspos % Columns + cells > Columns) 2296 ccline.cmdspos++; 2297 } 2298 #endif 2299 2300 /* 2301 * Get an Ex command line for the ":" command. 2302 */ 2303 char_u * 2304 getexline( 2305 int c, /* normally ':', NUL for ":append" */ 2306 void *cookie UNUSED, 2307 int indent) /* indent for inside conditionals */ 2308 { 2309 /* When executing a register, remove ':' that's in front of each line. */ 2310 if (exec_from_reg && vpeekc() == ':') 2311 (void)vgetc(); 2312 return getcmdline(c, 1L, indent); 2313 } 2314 2315 /* 2316 * Get an Ex command line for Ex mode. 2317 * In Ex mode we only use the OS supplied line editing features and no 2318 * mappings or abbreviations. 2319 * Returns a string in allocated memory or NULL. 2320 */ 2321 char_u * 2322 getexmodeline( 2323 int promptc, /* normally ':', NUL for ":append" and '?' for 2324 :s prompt */ 2325 void *cookie UNUSED, 2326 int indent) /* indent for inside conditionals */ 2327 { 2328 garray_T line_ga; 2329 char_u *pend; 2330 int startcol = 0; 2331 int c1 = 0; 2332 int escaped = FALSE; /* CTRL-V typed */ 2333 int vcol = 0; 2334 char_u *p; 2335 int prev_char; 2336 int len; 2337 2338 /* Switch cursor on now. This avoids that it happens after the "\n", which 2339 * confuses the system function that computes tabstops. */ 2340 cursor_on(); 2341 2342 /* always start in column 0; write a newline if necessary */ 2343 compute_cmdrow(); 2344 if ((msg_col || msg_didout) && promptc != '?') 2345 msg_putchar('\n'); 2346 if (promptc == ':') 2347 { 2348 /* indent that is only displayed, not in the line itself */ 2349 if (p_prompt) 2350 msg_putchar(':'); 2351 while (indent-- > 0) 2352 msg_putchar(' '); 2353 startcol = msg_col; 2354 } 2355 2356 ga_init2(&line_ga, 1, 30); 2357 2358 /* autoindent for :insert and :append is in the line itself */ 2359 if (promptc <= 0) 2360 { 2361 vcol = indent; 2362 while (indent >= 8) 2363 { 2364 ga_append(&line_ga, TAB); 2365 msg_puts((char_u *)" "); 2366 indent -= 8; 2367 } 2368 while (indent-- > 0) 2369 { 2370 ga_append(&line_ga, ' '); 2371 msg_putchar(' '); 2372 } 2373 } 2374 ++no_mapping; 2375 ++allow_keys; 2376 2377 /* 2378 * Get the line, one character at a time. 2379 */ 2380 got_int = FALSE; 2381 while (!got_int) 2382 { 2383 long sw; 2384 char_u *s; 2385 2386 if (ga_grow(&line_ga, 40) == FAIL) 2387 break; 2388 2389 /* 2390 * Get one character at a time. 2391 */ 2392 prev_char = c1; 2393 2394 /* Check for a ":normal" command and no more characters left. */ 2395 if (ex_normal_busy > 0 && typebuf.tb_len == 0) 2396 c1 = '\n'; 2397 else 2398 c1 = vgetc(); 2399 2400 /* 2401 * Handle line editing. 2402 * Previously this was left to the system, putting the terminal in 2403 * cooked mode, but then CTRL-D and CTRL-T can't be used properly. 2404 */ 2405 if (got_int) 2406 { 2407 msg_putchar('\n'); 2408 break; 2409 } 2410 2411 if (c1 == K_PS) 2412 { 2413 bracketed_paste(PASTE_EX, FALSE, &line_ga); 2414 goto redraw; 2415 } 2416 2417 if (!escaped) 2418 { 2419 /* CR typed means "enter", which is NL */ 2420 if (c1 == '\r') 2421 c1 = '\n'; 2422 2423 if (c1 == BS || c1 == K_BS 2424 || c1 == DEL || c1 == K_DEL || c1 == K_KDEL) 2425 { 2426 if (line_ga.ga_len > 0) 2427 { 2428 #ifdef FEAT_MBYTE 2429 if (has_mbyte) 2430 { 2431 p = (char_u *)line_ga.ga_data; 2432 p[line_ga.ga_len] = NUL; 2433 len = (*mb_head_off)(p, p + line_ga.ga_len - 1) + 1; 2434 line_ga.ga_len -= len; 2435 } 2436 else 2437 #endif 2438 --line_ga.ga_len; 2439 goto redraw; 2440 } 2441 continue; 2442 } 2443 2444 if (c1 == Ctrl_U) 2445 { 2446 msg_col = startcol; 2447 msg_clr_eos(); 2448 line_ga.ga_len = 0; 2449 goto redraw; 2450 } 2451 2452 if (c1 == Ctrl_T) 2453 { 2454 sw = get_sw_value(curbuf); 2455 p = (char_u *)line_ga.ga_data; 2456 p[line_ga.ga_len] = NUL; 2457 indent = get_indent_str(p, 8, FALSE); 2458 indent += sw - indent % sw; 2459 add_indent: 2460 while (get_indent_str(p, 8, FALSE) < indent) 2461 { 2462 (void)ga_grow(&line_ga, 2); /* one more for the NUL */ 2463 p = (char_u *)line_ga.ga_data; 2464 s = skipwhite(p); 2465 mch_memmove(s + 1, s, line_ga.ga_len - (s - p) + 1); 2466 *s = ' '; 2467 ++line_ga.ga_len; 2468 } 2469 redraw: 2470 /* redraw the line */ 2471 msg_col = startcol; 2472 vcol = 0; 2473 p = (char_u *)line_ga.ga_data; 2474 p[line_ga.ga_len] = NUL; 2475 while (p < (char_u *)line_ga.ga_data + line_ga.ga_len) 2476 { 2477 if (*p == TAB) 2478 { 2479 do 2480 { 2481 msg_putchar(' '); 2482 } while (++vcol % 8); 2483 ++p; 2484 } 2485 else 2486 { 2487 len = MB_PTR2LEN(p); 2488 msg_outtrans_len(p, len); 2489 vcol += ptr2cells(p); 2490 p += len; 2491 } 2492 } 2493 msg_clr_eos(); 2494 windgoto(msg_row, msg_col); 2495 continue; 2496 } 2497 2498 if (c1 == Ctrl_D) 2499 { 2500 /* Delete one shiftwidth. */ 2501 p = (char_u *)line_ga.ga_data; 2502 if (prev_char == '0' || prev_char == '^') 2503 { 2504 if (prev_char == '^') 2505 ex_keep_indent = TRUE; 2506 indent = 0; 2507 p[--line_ga.ga_len] = NUL; 2508 } 2509 else 2510 { 2511 p[line_ga.ga_len] = NUL; 2512 indent = get_indent_str(p, 8, FALSE); 2513 if (indent > 0) 2514 { 2515 --indent; 2516 indent -= indent % get_sw_value(curbuf); 2517 } 2518 } 2519 while (get_indent_str(p, 8, FALSE) > indent) 2520 { 2521 s = skipwhite(p); 2522 mch_memmove(s - 1, s, line_ga.ga_len - (s - p) + 1); 2523 --line_ga.ga_len; 2524 } 2525 goto add_indent; 2526 } 2527 2528 if (c1 == Ctrl_V || c1 == Ctrl_Q) 2529 { 2530 escaped = TRUE; 2531 continue; 2532 } 2533 2534 /* Ignore special key codes: mouse movement, K_IGNORE, etc. */ 2535 if (IS_SPECIAL(c1)) 2536 continue; 2537 } 2538 2539 if (IS_SPECIAL(c1)) 2540 c1 = '?'; 2541 #ifdef FEAT_MBYTE 2542 if (has_mbyte) 2543 len = (*mb_char2bytes)(c1, 2544 (char_u *)line_ga.ga_data + line_ga.ga_len); 2545 else 2546 #endif 2547 { 2548 len = 1; 2549 ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1; 2550 } 2551 if (c1 == '\n') 2552 msg_putchar('\n'); 2553 else if (c1 == TAB) 2554 { 2555 /* Don't use chartabsize(), 'ts' can be different */ 2556 do 2557 { 2558 msg_putchar(' '); 2559 } while (++vcol % 8); 2560 } 2561 else 2562 { 2563 msg_outtrans_len( 2564 ((char_u *)line_ga.ga_data) + line_ga.ga_len, len); 2565 vcol += char2cells(c1); 2566 } 2567 line_ga.ga_len += len; 2568 escaped = FALSE; 2569 2570 windgoto(msg_row, msg_col); 2571 pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len; 2572 2573 /* We are done when a NL is entered, but not when it comes after an 2574 * odd number of backslashes, that results in a NUL. */ 2575 if (line_ga.ga_len > 0 && pend[-1] == '\n') 2576 { 2577 int bcount = 0; 2578 2579 while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\') 2580 ++bcount; 2581 2582 if (bcount > 0) 2583 { 2584 /* Halve the number of backslashes: "\NL" -> "NUL", "\\NL" -> 2585 * "\NL", etc. */ 2586 line_ga.ga_len -= (bcount + 1) / 2; 2587 pend -= (bcount + 1) / 2; 2588 pend[-1] = '\n'; 2589 } 2590 2591 if ((bcount & 1) == 0) 2592 { 2593 --line_ga.ga_len; 2594 --pend; 2595 *pend = NUL; 2596 break; 2597 } 2598 } 2599 } 2600 2601 --no_mapping; 2602 --allow_keys; 2603 2604 /* make following messages go to the next line */ 2605 msg_didout = FALSE; 2606 msg_col = 0; 2607 if (msg_row < Rows - 1) 2608 ++msg_row; 2609 emsg_on_display = FALSE; /* don't want ui_delay() */ 2610 2611 if (got_int) 2612 ga_clear(&line_ga); 2613 2614 return (char_u *)line_ga.ga_data; 2615 } 2616 2617 # if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \ 2618 || defined(FEAT_MOUSESHAPE) || defined(PROTO) 2619 /* 2620 * Return TRUE if ccline.overstrike is on. 2621 */ 2622 int 2623 cmdline_overstrike(void) 2624 { 2625 return ccline.overstrike; 2626 } 2627 2628 /* 2629 * Return TRUE if the cursor is at the end of the cmdline. 2630 */ 2631 int 2632 cmdline_at_end(void) 2633 { 2634 return (ccline.cmdpos >= ccline.cmdlen); 2635 } 2636 #endif 2637 2638 #if (defined(FEAT_XIM) && (defined(FEAT_GUI_GTK))) || defined(PROTO) 2639 /* 2640 * Return the virtual column number at the current cursor position. 2641 * This is used by the IM code to obtain the start of the preedit string. 2642 */ 2643 colnr_T 2644 cmdline_getvcol_cursor(void) 2645 { 2646 if (ccline.cmdbuff == NULL || ccline.cmdpos > ccline.cmdlen) 2647 return MAXCOL; 2648 2649 # ifdef FEAT_MBYTE 2650 if (has_mbyte) 2651 { 2652 colnr_T col; 2653 int i = 0; 2654 2655 for (col = 0; i < ccline.cmdpos; ++col) 2656 i += (*mb_ptr2len)(ccline.cmdbuff + i); 2657 2658 return col; 2659 } 2660 else 2661 # endif 2662 return ccline.cmdpos; 2663 } 2664 #endif 2665 2666 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 2667 /* 2668 * If part of the command line is an IM preedit string, redraw it with 2669 * IM feedback attributes. The cursor position is restored after drawing. 2670 */ 2671 static void 2672 redrawcmd_preedit(void) 2673 { 2674 if ((State & CMDLINE) 2675 && xic != NULL 2676 /* && im_get_status() doesn't work when using SCIM */ 2677 && !p_imdisable 2678 && im_is_preediting()) 2679 { 2680 int cmdpos = 0; 2681 int cmdspos; 2682 int old_row; 2683 int old_col; 2684 colnr_T col; 2685 2686 old_row = msg_row; 2687 old_col = msg_col; 2688 cmdspos = ((ccline.cmdfirstc != NUL) ? 1 : 0) + ccline.cmdindent; 2689 2690 # ifdef FEAT_MBYTE 2691 if (has_mbyte) 2692 { 2693 for (col = 0; col < preedit_start_col 2694 && cmdpos < ccline.cmdlen; ++col) 2695 { 2696 cmdspos += (*mb_ptr2cells)(ccline.cmdbuff + cmdpos); 2697 cmdpos += (*mb_ptr2len)(ccline.cmdbuff + cmdpos); 2698 } 2699 } 2700 else 2701 # endif 2702 { 2703 cmdspos += preedit_start_col; 2704 cmdpos += preedit_start_col; 2705 } 2706 2707 msg_row = cmdline_row + (cmdspos / (int)Columns); 2708 msg_col = cmdspos % (int)Columns; 2709 if (msg_row >= Rows) 2710 msg_row = Rows - 1; 2711 2712 for (col = 0; cmdpos < ccline.cmdlen; ++col) 2713 { 2714 int char_len; 2715 int char_attr; 2716 2717 char_attr = im_get_feedback_attr(col); 2718 if (char_attr < 0) 2719 break; /* end of preedit string */ 2720 2721 # ifdef FEAT_MBYTE 2722 if (has_mbyte) 2723 char_len = (*mb_ptr2len)(ccline.cmdbuff + cmdpos); 2724 else 2725 # endif 2726 char_len = 1; 2727 2728 msg_outtrans_len_attr(ccline.cmdbuff + cmdpos, char_len, char_attr); 2729 cmdpos += char_len; 2730 } 2731 2732 msg_row = old_row; 2733 msg_col = old_col; 2734 } 2735 } 2736 #endif /* FEAT_XIM && FEAT_GUI_GTK */ 2737 2738 /* 2739 * Allocate a new command line buffer. 2740 * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. 2741 * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen. 2742 */ 2743 static void 2744 alloc_cmdbuff(int len) 2745 { 2746 /* 2747 * give some extra space to avoid having to allocate all the time 2748 */ 2749 if (len < 80) 2750 len = 100; 2751 else 2752 len += 20; 2753 2754 ccline.cmdbuff = alloc(len); /* caller should check for out-of-memory */ 2755 ccline.cmdbufflen = len; 2756 } 2757 2758 /* 2759 * Re-allocate the command line to length len + something extra. 2760 * return FAIL for failure, OK otherwise 2761 */ 2762 static int 2763 realloc_cmdbuff(int len) 2764 { 2765 char_u *p; 2766 2767 if (len < ccline.cmdbufflen) 2768 return OK; /* no need to resize */ 2769 2770 p = ccline.cmdbuff; 2771 alloc_cmdbuff(len); /* will get some more */ 2772 if (ccline.cmdbuff == NULL) /* out of memory */ 2773 { 2774 ccline.cmdbuff = p; /* keep the old one */ 2775 return FAIL; 2776 } 2777 /* There isn't always a NUL after the command, but it may need to be 2778 * there, thus copy up to the NUL and add a NUL. */ 2779 mch_memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen); 2780 ccline.cmdbuff[ccline.cmdlen] = NUL; 2781 vim_free(p); 2782 2783 if (ccline.xpc != NULL 2784 && ccline.xpc->xp_pattern != NULL 2785 && ccline.xpc->xp_context != EXPAND_NOTHING 2786 && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL) 2787 { 2788 int i = (int)(ccline.xpc->xp_pattern - p); 2789 2790 /* If xp_pattern points inside the old cmdbuff it needs to be adjusted 2791 * to point into the newly allocated memory. */ 2792 if (i >= 0 && i <= ccline.cmdlen) 2793 ccline.xpc->xp_pattern = ccline.cmdbuff + i; 2794 } 2795 2796 return OK; 2797 } 2798 2799 #if defined(FEAT_ARABIC) || defined(PROTO) 2800 static char_u *arshape_buf = NULL; 2801 2802 # if defined(EXITFREE) || defined(PROTO) 2803 void 2804 free_cmdline_buf(void) 2805 { 2806 vim_free(arshape_buf); 2807 } 2808 # endif 2809 #endif 2810 2811 /* 2812 * Draw part of the cmdline at the current cursor position. But draw stars 2813 * when cmdline_star is TRUE. 2814 */ 2815 static void 2816 draw_cmdline(int start, int len) 2817 { 2818 #if defined(FEAT_CRYPT) || defined(FEAT_EVAL) 2819 int i; 2820 2821 if (cmdline_star > 0) 2822 for (i = 0; i < len; ++i) 2823 { 2824 msg_putchar('*'); 2825 # ifdef FEAT_MBYTE 2826 if (has_mbyte) 2827 i += (*mb_ptr2len)(ccline.cmdbuff + start + i) - 1; 2828 # endif 2829 } 2830 else 2831 #endif 2832 #ifdef FEAT_ARABIC 2833 if (p_arshape && !p_tbidi && enc_utf8 && len > 0) 2834 { 2835 static int buflen = 0; 2836 char_u *p; 2837 int j; 2838 int newlen = 0; 2839 int mb_l; 2840 int pc, pc1 = 0; 2841 int prev_c = 0; 2842 int prev_c1 = 0; 2843 int u8c; 2844 int u8cc[MAX_MCO]; 2845 int nc = 0; 2846 2847 /* 2848 * Do arabic shaping into a temporary buffer. This is very 2849 * inefficient! 2850 */ 2851 if (len * 2 + 2 > buflen) 2852 { 2853 /* Re-allocate the buffer. We keep it around to avoid a lot of 2854 * alloc()/free() calls. */ 2855 vim_free(arshape_buf); 2856 buflen = len * 2 + 2; 2857 arshape_buf = alloc(buflen); 2858 if (arshape_buf == NULL) 2859 return; /* out of memory */ 2860 } 2861 2862 if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start))) 2863 { 2864 /* Prepend a space to draw the leading composing char on. */ 2865 arshape_buf[0] = ' '; 2866 newlen = 1; 2867 } 2868 2869 for (j = start; j < start + len; j += mb_l) 2870 { 2871 p = ccline.cmdbuff + j; 2872 u8c = utfc_ptr2char_len(p, u8cc, start + len - j); 2873 mb_l = utfc_ptr2len_len(p, start + len - j); 2874 if (ARABIC_CHAR(u8c)) 2875 { 2876 /* Do Arabic shaping. */ 2877 if (cmdmsg_rl) 2878 { 2879 /* displaying from right to left */ 2880 pc = prev_c; 2881 pc1 = prev_c1; 2882 prev_c1 = u8cc[0]; 2883 if (j + mb_l >= start + len) 2884 nc = NUL; 2885 else 2886 nc = utf_ptr2char(p + mb_l); 2887 } 2888 else 2889 { 2890 /* displaying from left to right */ 2891 if (j + mb_l >= start + len) 2892 pc = NUL; 2893 else 2894 { 2895 int pcc[MAX_MCO]; 2896 2897 pc = utfc_ptr2char_len(p + mb_l, pcc, 2898 start + len - j - mb_l); 2899 pc1 = pcc[0]; 2900 } 2901 nc = prev_c; 2902 } 2903 prev_c = u8c; 2904 2905 u8c = arabic_shape(u8c, NULL, &u8cc[0], pc, pc1, nc); 2906 2907 newlen += (*mb_char2bytes)(u8c, arshape_buf + newlen); 2908 if (u8cc[0] != 0) 2909 { 2910 newlen += (*mb_char2bytes)(u8cc[0], arshape_buf + newlen); 2911 if (u8cc[1] != 0) 2912 newlen += (*mb_char2bytes)(u8cc[1], 2913 arshape_buf + newlen); 2914 } 2915 } 2916 else 2917 { 2918 prev_c = u8c; 2919 mch_memmove(arshape_buf + newlen, p, mb_l); 2920 newlen += mb_l; 2921 } 2922 } 2923 2924 msg_outtrans_len(arshape_buf, newlen); 2925 } 2926 else 2927 #endif 2928 msg_outtrans_len(ccline.cmdbuff + start, len); 2929 } 2930 2931 /* 2932 * Put a character on the command line. Shifts the following text to the 2933 * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. 2934 * "c" must be printable (fit in one display cell)! 2935 */ 2936 void 2937 putcmdline(int c, int shift) 2938 { 2939 if (cmd_silent) 2940 return; 2941 msg_no_more = TRUE; 2942 msg_putchar(c); 2943 if (shift) 2944 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); 2945 msg_no_more = FALSE; 2946 cursorcmd(); 2947 extra_char = c; 2948 extra_char_shift = shift; 2949 } 2950 2951 /* 2952 * Undo a putcmdline(c, FALSE). 2953 */ 2954 void 2955 unputcmdline(void) 2956 { 2957 if (cmd_silent) 2958 return; 2959 msg_no_more = TRUE; 2960 if (ccline.cmdlen == ccline.cmdpos) 2961 msg_putchar(' '); 2962 #ifdef FEAT_MBYTE 2963 else if (has_mbyte) 2964 draw_cmdline(ccline.cmdpos, 2965 (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos)); 2966 #endif 2967 else 2968 draw_cmdline(ccline.cmdpos, 1); 2969 msg_no_more = FALSE; 2970 cursorcmd(); 2971 extra_char = NUL; 2972 } 2973 2974 /* 2975 * Put the given string, of the given length, onto the command line. 2976 * If len is -1, then STRLEN() is used to calculate the length. 2977 * If 'redraw' is TRUE then the new part of the command line, and the remaining 2978 * part will be redrawn, otherwise it will not. If this function is called 2979 * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be 2980 * called afterwards. 2981 */ 2982 int 2983 put_on_cmdline(char_u *str, int len, int redraw) 2984 { 2985 int retval; 2986 int i; 2987 int m; 2988 int c; 2989 2990 if (len < 0) 2991 len = (int)STRLEN(str); 2992 2993 /* Check if ccline.cmdbuff needs to be longer */ 2994 if (ccline.cmdlen + len + 1 >= ccline.cmdbufflen) 2995 retval = realloc_cmdbuff(ccline.cmdlen + len + 1); 2996 else 2997 retval = OK; 2998 if (retval == OK) 2999 { 3000 if (!ccline.overstrike) 3001 { 3002 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len, 3003 ccline.cmdbuff + ccline.cmdpos, 3004 (size_t)(ccline.cmdlen - ccline.cmdpos)); 3005 ccline.cmdlen += len; 3006 } 3007 else 3008 { 3009 #ifdef FEAT_MBYTE 3010 if (has_mbyte) 3011 { 3012 /* Count nr of characters in the new string. */ 3013 m = 0; 3014 for (i = 0; i < len; i += (*mb_ptr2len)(str + i)) 3015 ++m; 3016 /* Count nr of bytes in cmdline that are overwritten by these 3017 * characters. */ 3018 for (i = ccline.cmdpos; i < ccline.cmdlen && m > 0; 3019 i += (*mb_ptr2len)(ccline.cmdbuff + i)) 3020 --m; 3021 if (i < ccline.cmdlen) 3022 { 3023 mch_memmove(ccline.cmdbuff + ccline.cmdpos + len, 3024 ccline.cmdbuff + i, (size_t)(ccline.cmdlen - i)); 3025 ccline.cmdlen += ccline.cmdpos + len - i; 3026 } 3027 else 3028 ccline.cmdlen = ccline.cmdpos + len; 3029 } 3030 else 3031 #endif 3032 if (ccline.cmdpos + len > ccline.cmdlen) 3033 ccline.cmdlen = ccline.cmdpos + len; 3034 } 3035 mch_memmove(ccline.cmdbuff + ccline.cmdpos, str, (size_t)len); 3036 ccline.cmdbuff[ccline.cmdlen] = NUL; 3037 3038 #ifdef FEAT_MBYTE 3039 if (enc_utf8) 3040 { 3041 /* When the inserted text starts with a composing character, 3042 * backup to the character before it. There could be two of them. 3043 */ 3044 i = 0; 3045 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); 3046 while (ccline.cmdpos > 0 && utf_iscomposing(c)) 3047 { 3048 i = (*mb_head_off)(ccline.cmdbuff, 3049 ccline.cmdbuff + ccline.cmdpos - 1) + 1; 3050 ccline.cmdpos -= i; 3051 len += i; 3052 c = utf_ptr2char(ccline.cmdbuff + ccline.cmdpos); 3053 } 3054 # ifdef FEAT_ARABIC 3055 if (i == 0 && ccline.cmdpos > 0 && arabic_maycombine(c)) 3056 { 3057 /* Check the previous character for Arabic combining pair. */ 3058 i = (*mb_head_off)(ccline.cmdbuff, 3059 ccline.cmdbuff + ccline.cmdpos - 1) + 1; 3060 if (arabic_combine(utf_ptr2char(ccline.cmdbuff 3061 + ccline.cmdpos - i), c)) 3062 { 3063 ccline.cmdpos -= i; 3064 len += i; 3065 } 3066 else 3067 i = 0; 3068 } 3069 # endif 3070 if (i != 0) 3071 { 3072 /* Also backup the cursor position. */ 3073 i = ptr2cells(ccline.cmdbuff + ccline.cmdpos); 3074 ccline.cmdspos -= i; 3075 msg_col -= i; 3076 if (msg_col < 0) 3077 { 3078 msg_col += Columns; 3079 --msg_row; 3080 } 3081 } 3082 } 3083 #endif 3084 3085 if (redraw && !cmd_silent) 3086 { 3087 msg_no_more = TRUE; 3088 i = cmdline_row; 3089 cursorcmd(); 3090 draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); 3091 /* Avoid clearing the rest of the line too often. */ 3092 if (cmdline_row != i || ccline.overstrike) 3093 msg_clr_eos(); 3094 msg_no_more = FALSE; 3095 } 3096 #ifdef FEAT_FKMAP 3097 /* 3098 * If we are in Farsi command mode, the character input must be in 3099 * Insert mode. So do not advance the cmdpos. 3100 */ 3101 if (!cmd_fkmap) 3102 #endif 3103 { 3104 if (KeyTyped) 3105 { 3106 m = Columns * Rows; 3107 if (m < 0) /* overflow, Columns or Rows at weird value */ 3108 m = MAXCOL; 3109 } 3110 else 3111 m = MAXCOL; 3112 for (i = 0; i < len; ++i) 3113 { 3114 c = cmdline_charsize(ccline.cmdpos); 3115 #ifdef FEAT_MBYTE 3116 /* count ">" for a double-wide char that doesn't fit. */ 3117 if (has_mbyte) 3118 correct_cmdspos(ccline.cmdpos, c); 3119 #endif 3120 /* Stop cursor at the end of the screen, but do increment the 3121 * insert position, so that entering a very long command 3122 * works, even though you can't see it. */ 3123 if (ccline.cmdspos + c < m) 3124 ccline.cmdspos += c; 3125 #ifdef FEAT_MBYTE 3126 if (has_mbyte) 3127 { 3128 c = (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos) - 1; 3129 if (c > len - i - 1) 3130 c = len - i - 1; 3131 ccline.cmdpos += c; 3132 i += c; 3133 } 3134 #endif 3135 ++ccline.cmdpos; 3136 } 3137 } 3138 } 3139 if (redraw) 3140 msg_check(); 3141 return retval; 3142 } 3143 3144 static struct cmdline_info prev_ccline; 3145 static int prev_ccline_used = FALSE; 3146 3147 /* 3148 * Save ccline, because obtaining the "=" register may execute "normal :cmd" 3149 * and overwrite it. But get_cmdline_str() may need it, thus make it 3150 * available globally in prev_ccline. 3151 */ 3152 static void 3153 save_cmdline(struct cmdline_info *ccp) 3154 { 3155 if (!prev_ccline_used) 3156 { 3157 vim_memset(&prev_ccline, 0, sizeof(struct cmdline_info)); 3158 prev_ccline_used = TRUE; 3159 } 3160 *ccp = prev_ccline; 3161 prev_ccline = ccline; 3162 ccline.cmdbuff = NULL; 3163 ccline.cmdprompt = NULL; 3164 ccline.xpc = NULL; 3165 } 3166 3167 /* 3168 * Restore ccline after it has been saved with save_cmdline(). 3169 */ 3170 static void 3171 restore_cmdline(struct cmdline_info *ccp) 3172 { 3173 ccline = prev_ccline; 3174 prev_ccline = *ccp; 3175 } 3176 3177 #if defined(FEAT_EVAL) || defined(PROTO) 3178 /* 3179 * Save the command line into allocated memory. Returns a pointer to be 3180 * passed to restore_cmdline_alloc() later. 3181 * Returns NULL when failed. 3182 */ 3183 char_u * 3184 save_cmdline_alloc(void) 3185 { 3186 struct cmdline_info *p; 3187 3188 p = (struct cmdline_info *)alloc((unsigned)sizeof(struct cmdline_info)); 3189 if (p != NULL) 3190 save_cmdline(p); 3191 return (char_u *)p; 3192 } 3193 3194 /* 3195 * Restore the command line from the return value of save_cmdline_alloc(). 3196 */ 3197 void 3198 restore_cmdline_alloc(char_u *p) 3199 { 3200 if (p != NULL) 3201 { 3202 restore_cmdline((struct cmdline_info *)p); 3203 vim_free(p); 3204 } 3205 } 3206 #endif 3207 3208 /* 3209 * Paste a yank register into the command line. 3210 * Used by CTRL-R command in command-line mode. 3211 * insert_reg() can't be used here, because special characters from the 3212 * register contents will be interpreted as commands. 3213 * 3214 * Return FAIL for failure, OK otherwise. 3215 */ 3216 static int 3217 cmdline_paste( 3218 int regname, 3219 int literally, /* Insert text literally instead of "as typed" */ 3220 int remcr) /* remove trailing CR */ 3221 { 3222 long i; 3223 char_u *arg; 3224 char_u *p; 3225 int allocated; 3226 struct cmdline_info save_ccline; 3227 3228 /* check for valid regname; also accept special characters for CTRL-R in 3229 * the command line */ 3230 if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W 3231 && regname != Ctrl_A && !valid_yank_reg(regname, FALSE)) 3232 return FAIL; 3233 3234 /* A register containing CTRL-R can cause an endless loop. Allow using 3235 * CTRL-C to break the loop. */ 3236 line_breakcheck(); 3237 if (got_int) 3238 return FAIL; 3239 3240 #ifdef FEAT_CLIPBOARD 3241 regname = may_get_selection(regname); 3242 #endif 3243 3244 /* Need to save and restore ccline. And set "textlock" to avoid nasty 3245 * things like going to another buffer when evaluating an expression. */ 3246 save_cmdline(&save_ccline); 3247 ++textlock; 3248 i = get_spec_reg(regname, &arg, &allocated, TRUE); 3249 --textlock; 3250 restore_cmdline(&save_ccline); 3251 3252 if (i) 3253 { 3254 /* Got the value of a special register in "arg". */ 3255 if (arg == NULL) 3256 return FAIL; 3257 3258 /* When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate 3259 * part of the word. */ 3260 p = arg; 3261 if (p_is && regname == Ctrl_W) 3262 { 3263 char_u *w; 3264 int len; 3265 3266 /* Locate start of last word in the cmd buffer. */ 3267 for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; ) 3268 { 3269 #ifdef FEAT_MBYTE 3270 if (has_mbyte) 3271 { 3272 len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1; 3273 if (!vim_iswordc(mb_ptr2char(w - len))) 3274 break; 3275 w -= len; 3276 } 3277 else 3278 #endif 3279 { 3280 if (!vim_iswordc(w[-1])) 3281 break; 3282 --w; 3283 } 3284 } 3285 len = (int)((ccline.cmdbuff + ccline.cmdpos) - w); 3286 if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0) 3287 p += len; 3288 } 3289 3290 cmdline_paste_str(p, literally); 3291 if (allocated) 3292 vim_free(arg); 3293 return OK; 3294 } 3295 3296 return cmdline_paste_reg(regname, literally, remcr); 3297 } 3298 3299 /* 3300 * Put a string on the command line. 3301 * When "literally" is TRUE, insert literally. 3302 * When "literally" is FALSE, insert as typed, but don't leave the command 3303 * line. 3304 */ 3305 void 3306 cmdline_paste_str(char_u *s, int literally) 3307 { 3308 int c, cv; 3309 3310 if (literally) 3311 put_on_cmdline(s, -1, TRUE); 3312 else 3313 while (*s != NUL) 3314 { 3315 cv = *s; 3316 if (cv == Ctrl_V && s[1]) 3317 ++s; 3318 #ifdef FEAT_MBYTE 3319 if (has_mbyte) 3320 c = mb_cptr2char_adv(&s); 3321 else 3322 #endif 3323 c = *s++; 3324 if (cv == Ctrl_V || c == ESC || c == Ctrl_C 3325 || c == CAR || c == NL || c == Ctrl_L 3326 #ifdef UNIX 3327 || c == intr_char 3328 #endif 3329 || (c == Ctrl_BSL && *s == Ctrl_N)) 3330 stuffcharReadbuff(Ctrl_V); 3331 stuffcharReadbuff(c); 3332 } 3333 } 3334 3335 #ifdef FEAT_WILDMENU 3336 /* 3337 * Delete characters on the command line, from "from" to the current 3338 * position. 3339 */ 3340 static void 3341 cmdline_del(int from) 3342 { 3343 mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos, 3344 (size_t)(ccline.cmdlen - ccline.cmdpos + 1)); 3345 ccline.cmdlen -= ccline.cmdpos - from; 3346 ccline.cmdpos = from; 3347 } 3348 #endif 3349 3350 /* 3351 * This function is called when the screen size changes and with incremental 3352 * search and in other situations where the command line may have been 3353 * overwritten. 3354 */ 3355 void 3356 redrawcmdline(void) 3357 { 3358 redrawcmdline_ex(TRUE); 3359 } 3360 3361 void 3362 redrawcmdline_ex(int do_compute_cmdrow) 3363 { 3364 if (cmd_silent) 3365 return; 3366 need_wait_return = FALSE; 3367 if (do_compute_cmdrow) 3368 compute_cmdrow(); 3369 redrawcmd(); 3370 cursorcmd(); 3371 } 3372 3373 static void 3374 redrawcmdprompt(void) 3375 { 3376 int i; 3377 3378 if (cmd_silent) 3379 return; 3380 if (ccline.cmdfirstc != NUL) 3381 msg_putchar(ccline.cmdfirstc); 3382 if (ccline.cmdprompt != NULL) 3383 { 3384 msg_puts_attr(ccline.cmdprompt, ccline.cmdattr); 3385 ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; 3386 /* do the reverse of set_cmdspos() */ 3387 if (ccline.cmdfirstc != NUL) 3388 --ccline.cmdindent; 3389 } 3390 else 3391 for (i = ccline.cmdindent; i > 0; --i) 3392 msg_putchar(' '); 3393 } 3394 3395 /* 3396 * Redraw what is currently on the command line. 3397 */ 3398 void 3399 redrawcmd(void) 3400 { 3401 if (cmd_silent) 3402 return; 3403 3404 /* when 'incsearch' is set there may be no command line while redrawing */ 3405 if (ccline.cmdbuff == NULL) 3406 { 3407 windgoto(cmdline_row, 0); 3408 msg_clr_eos(); 3409 return; 3410 } 3411 3412 msg_start(); 3413 redrawcmdprompt(); 3414 3415 /* Don't use more prompt, truncate the cmdline if it doesn't fit. */ 3416 msg_no_more = TRUE; 3417 draw_cmdline(0, ccline.cmdlen); 3418 msg_clr_eos(); 3419 msg_no_more = FALSE; 3420 3421 set_cmdspos_cursor(); 3422 if (extra_char != NUL) 3423 putcmdline(extra_char, extra_char_shift); 3424 3425 /* 3426 * An emsg() before may have set msg_scroll. This is used in normal mode, 3427 * in cmdline mode we can reset them now. 3428 */ 3429 msg_scroll = FALSE; /* next message overwrites cmdline */ 3430 3431 /* Typing ':' at the more prompt may set skip_redraw. We don't want this 3432 * in cmdline mode */ 3433 skip_redraw = FALSE; 3434 } 3435 3436 void 3437 compute_cmdrow(void) 3438 { 3439 if (exmode_active || msg_scrolled != 0) 3440 cmdline_row = Rows - 1; 3441 else 3442 cmdline_row = W_WINROW(lastwin) + lastwin->w_height 3443 + W_STATUS_HEIGHT(lastwin); 3444 } 3445 3446 static void 3447 cursorcmd(void) 3448 { 3449 if (cmd_silent) 3450 return; 3451 3452 #ifdef FEAT_RIGHTLEFT 3453 if (cmdmsg_rl) 3454 { 3455 msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1)); 3456 msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1; 3457 if (msg_row <= 0) 3458 msg_row = Rows - 1; 3459 } 3460 else 3461 #endif 3462 { 3463 msg_row = cmdline_row + (ccline.cmdspos / (int)Columns); 3464 msg_col = ccline.cmdspos % (int)Columns; 3465 if (msg_row >= Rows) 3466 msg_row = Rows - 1; 3467 } 3468 3469 windgoto(msg_row, msg_col); 3470 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 3471 redrawcmd_preedit(); 3472 #endif 3473 #ifdef MCH_CURSOR_SHAPE 3474 mch_update_cursor(); 3475 #endif 3476 } 3477 3478 void 3479 gotocmdline(int clr) 3480 { 3481 msg_start(); 3482 #ifdef FEAT_RIGHTLEFT 3483 if (cmdmsg_rl) 3484 msg_col = Columns - 1; 3485 else 3486 #endif 3487 msg_col = 0; /* always start in column 0 */ 3488 if (clr) /* clear the bottom line(s) */ 3489 msg_clr_eos(); /* will reset clear_cmdline */ 3490 windgoto(cmdline_row, 0); 3491 } 3492 3493 /* 3494 * Check the word in front of the cursor for an abbreviation. 3495 * Called when the non-id character "c" has been entered. 3496 * When an abbreviation is recognized it is removed from the text with 3497 * backspaces and the replacement string is inserted, followed by "c". 3498 */ 3499 static int 3500 ccheck_abbr(int c) 3501 { 3502 if (p_paste || no_abbr) /* no abbreviations or in paste mode */ 3503 return FALSE; 3504 3505 return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0); 3506 } 3507 3508 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 3509 static int 3510 #ifdef __BORLANDC__ 3511 _RTLENTRYF 3512 #endif 3513 sort_func_compare(const void *s1, const void *s2) 3514 { 3515 char_u *p1 = *(char_u **)s1; 3516 char_u *p2 = *(char_u **)s2; 3517 3518 if (*p1 != '<' && *p2 == '<') return -1; 3519 if (*p1 == '<' && *p2 != '<') return 1; 3520 return STRCMP(p1, p2); 3521 } 3522 #endif 3523 3524 /* 3525 * Return FAIL if this is not an appropriate context in which to do 3526 * completion of anything, return OK if it is (even if there are no matches). 3527 * For the caller, this means that the character is just passed through like a 3528 * normal character (instead of being expanded). This allows :s/^I^D etc. 3529 */ 3530 static int 3531 nextwild( 3532 expand_T *xp, 3533 int type, 3534 int options, /* extra options for ExpandOne() */ 3535 int escape) /* if TRUE, escape the returned matches */ 3536 { 3537 int i, j; 3538 char_u *p1; 3539 char_u *p2; 3540 int difflen; 3541 int v; 3542 3543 if (xp->xp_numfiles == -1) 3544 { 3545 set_expand_context(xp); 3546 cmd_showtail = expand_showtail(xp); 3547 } 3548 3549 if (xp->xp_context == EXPAND_UNSUCCESSFUL) 3550 { 3551 beep_flush(); 3552 return OK; /* Something illegal on command line */ 3553 } 3554 if (xp->xp_context == EXPAND_NOTHING) 3555 { 3556 /* Caller can use the character as a normal char instead */ 3557 return FAIL; 3558 } 3559 3560 MSG_PUTS("..."); /* show that we are busy */ 3561 out_flush(); 3562 3563 i = (int)(xp->xp_pattern - ccline.cmdbuff); 3564 xp->xp_pattern_len = ccline.cmdpos - i; 3565 3566 if (type == WILD_NEXT || type == WILD_PREV) 3567 { 3568 /* 3569 * Get next/previous match for a previous expanded pattern. 3570 */ 3571 p2 = ExpandOne(xp, NULL, NULL, 0, type); 3572 } 3573 else 3574 { 3575 /* 3576 * Translate string into pattern and expand it. 3577 */ 3578 if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, 3579 xp->xp_context)) == NULL) 3580 p2 = NULL; 3581 else 3582 { 3583 int use_options = options | 3584 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; 3585 if (escape) 3586 use_options |= WILD_ESCAPE; 3587 3588 if (p_wic) 3589 use_options += WILD_ICASE; 3590 p2 = ExpandOne(xp, p1, 3591 vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len), 3592 use_options, type); 3593 vim_free(p1); 3594 /* longest match: make sure it is not shorter, happens with :help */ 3595 if (p2 != NULL && type == WILD_LONGEST) 3596 { 3597 for (j = 0; j < xp->xp_pattern_len; ++j) 3598 if (ccline.cmdbuff[i + j] == '*' 3599 || ccline.cmdbuff[i + j] == '?') 3600 break; 3601 if ((int)STRLEN(p2) < j) 3602 { 3603 vim_free(p2); 3604 p2 = NULL; 3605 } 3606 } 3607 } 3608 } 3609 3610 if (p2 != NULL && !got_int) 3611 { 3612 difflen = (int)STRLEN(p2) - xp->xp_pattern_len; 3613 if (ccline.cmdlen + difflen + 4 > ccline.cmdbufflen) 3614 { 3615 v = realloc_cmdbuff(ccline.cmdlen + difflen + 4); 3616 xp->xp_pattern = ccline.cmdbuff + i; 3617 } 3618 else 3619 v = OK; 3620 if (v == OK) 3621 { 3622 mch_memmove(&ccline.cmdbuff[ccline.cmdpos + difflen], 3623 &ccline.cmdbuff[ccline.cmdpos], 3624 (size_t)(ccline.cmdlen - ccline.cmdpos + 1)); 3625 mch_memmove(&ccline.cmdbuff[i], p2, STRLEN(p2)); 3626 ccline.cmdlen += difflen; 3627 ccline.cmdpos += difflen; 3628 } 3629 } 3630 vim_free(p2); 3631 3632 redrawcmd(); 3633 cursorcmd(); 3634 3635 /* When expanding a ":map" command and no matches are found, assume that 3636 * the key is supposed to be inserted literally */ 3637 if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL) 3638 return FAIL; 3639 3640 if (xp->xp_numfiles <= 0 && p2 == NULL) 3641 beep_flush(); 3642 else if (xp->xp_numfiles == 1) 3643 /* free expanded pattern */ 3644 (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE); 3645 3646 return OK; 3647 } 3648 3649 /* 3650 * Do wildcard expansion on the string 'str'. 3651 * Chars that should not be expanded must be preceded with a backslash. 3652 * Return a pointer to allocated memory containing the new string. 3653 * Return NULL for failure. 3654 * 3655 * "orig" is the originally expanded string, copied to allocated memory. It 3656 * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or 3657 * WILD_PREV "orig" should be NULL. 3658 * 3659 * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode" 3660 * is WILD_EXPAND_FREE or WILD_ALL. 3661 * 3662 * mode = WILD_FREE: just free previously expanded matches 3663 * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches 3664 * mode = WILD_EXPAND_KEEP: normal expansion, keep matches 3665 * mode = WILD_NEXT: use next match in multiple match, wrap to first 3666 * mode = WILD_PREV: use previous match in multiple match, wrap to first 3667 * mode = WILD_ALL: return all matches concatenated 3668 * mode = WILD_LONGEST: return longest matched part 3669 * mode = WILD_ALL_KEEP: get all matches, keep matches 3670 * 3671 * options = WILD_LIST_NOTFOUND: list entries without a match 3672 * options = WILD_HOME_REPLACE: do home_replace() for buffer names 3673 * options = WILD_USE_NL: Use '\n' for WILD_ALL 3674 * options = WILD_NO_BEEP: Don't beep for multiple matches 3675 * options = WILD_ADD_SLASH: add a slash after directory names 3676 * options = WILD_KEEP_ALL: don't remove 'wildignore' entries 3677 * options = WILD_SILENT: don't print warning messages 3678 * options = WILD_ESCAPE: put backslash before special chars 3679 * options = WILD_ICASE: ignore case for files 3680 * 3681 * The variables xp->xp_context and xp->xp_backslash must have been set! 3682 */ 3683 char_u * 3684 ExpandOne( 3685 expand_T *xp, 3686 char_u *str, 3687 char_u *orig, /* allocated copy of original of expanded string */ 3688 int options, 3689 int mode) 3690 { 3691 char_u *ss = NULL; 3692 static int findex; 3693 static char_u *orig_save = NULL; /* kept value of orig */ 3694 int orig_saved = FALSE; 3695 int i; 3696 long_u len; 3697 int non_suf_match; /* number without matching suffix */ 3698 3699 /* 3700 * first handle the case of using an old match 3701 */ 3702 if (mode == WILD_NEXT || mode == WILD_PREV) 3703 { 3704 if (xp->xp_numfiles > 0) 3705 { 3706 if (mode == WILD_PREV) 3707 { 3708 if (findex == -1) 3709 findex = xp->xp_numfiles; 3710 --findex; 3711 } 3712 else /* mode == WILD_NEXT */ 3713 ++findex; 3714 3715 /* 3716 * When wrapping around, return the original string, set findex to 3717 * -1. 3718 */ 3719 if (findex < 0) 3720 { 3721 if (orig_save == NULL) 3722 findex = xp->xp_numfiles - 1; 3723 else 3724 findex = -1; 3725 } 3726 if (findex >= xp->xp_numfiles) 3727 { 3728 if (orig_save == NULL) 3729 findex = 0; 3730 else 3731 findex = -1; 3732 } 3733 #ifdef FEAT_WILDMENU 3734 if (p_wmnu) 3735 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, 3736 findex, cmd_showtail); 3737 #endif 3738 if (findex == -1) 3739 return vim_strsave(orig_save); 3740 return vim_strsave(xp->xp_files[findex]); 3741 } 3742 else 3743 return NULL; 3744 } 3745 3746 /* free old names */ 3747 if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) 3748 { 3749 FreeWild(xp->xp_numfiles, xp->xp_files); 3750 xp->xp_numfiles = -1; 3751 vim_free(orig_save); 3752 orig_save = NULL; 3753 } 3754 findex = 0; 3755 3756 if (mode == WILD_FREE) /* only release file name */ 3757 return NULL; 3758 3759 if (xp->xp_numfiles == -1) 3760 { 3761 vim_free(orig_save); 3762 orig_save = orig; 3763 orig_saved = TRUE; 3764 3765 /* 3766 * Do the expansion. 3767 */ 3768 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files, 3769 options) == FAIL) 3770 { 3771 #ifdef FNAME_ILLEGAL 3772 /* Illegal file name has been silently skipped. But when there 3773 * are wildcards, the real problem is that there was no match, 3774 * causing the pattern to be added, which has illegal characters. 3775 */ 3776 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) 3777 EMSG2(_(e_nomatch2), str); 3778 #endif 3779 } 3780 else if (xp->xp_numfiles == 0) 3781 { 3782 if (!(options & WILD_SILENT)) 3783 EMSG2(_(e_nomatch2), str); 3784 } 3785 else 3786 { 3787 /* Escape the matches for use on the command line. */ 3788 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options); 3789 3790 /* 3791 * Check for matching suffixes in file names. 3792 */ 3793 if (mode != WILD_ALL && mode != WILD_ALL_KEEP 3794 && mode != WILD_LONGEST) 3795 { 3796 if (xp->xp_numfiles) 3797 non_suf_match = xp->xp_numfiles; 3798 else 3799 non_suf_match = 1; 3800 if ((xp->xp_context == EXPAND_FILES 3801 || xp->xp_context == EXPAND_DIRECTORIES) 3802 && xp->xp_numfiles > 1) 3803 { 3804 /* 3805 * More than one match; check suffix. 3806 * The files will have been sorted on matching suffix in 3807 * expand_wildcards, only need to check the first two. 3808 */ 3809 non_suf_match = 0; 3810 for (i = 0; i < 2; ++i) 3811 if (match_suffix(xp->xp_files[i])) 3812 ++non_suf_match; 3813 } 3814 if (non_suf_match != 1) 3815 { 3816 /* Can we ever get here unless it's while expanding 3817 * interactively? If not, we can get rid of this all 3818 * together. Don't really want to wait for this message 3819 * (and possibly have to hit return to continue!). 3820 */ 3821 if (!(options & WILD_SILENT)) 3822 EMSG(_(e_toomany)); 3823 else if (!(options & WILD_NO_BEEP)) 3824 beep_flush(); 3825 } 3826 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) 3827 ss = vim_strsave(xp->xp_files[0]); 3828 } 3829 } 3830 } 3831 3832 /* Find longest common part */ 3833 if (mode == WILD_LONGEST && xp->xp_numfiles > 0) 3834 { 3835 int mb_len = 1; 3836 int c0, ci; 3837 3838 for (len = 0; xp->xp_files[0][len]; len += mb_len) 3839 { 3840 #ifdef FEAT_MBYTE 3841 if (has_mbyte) 3842 { 3843 mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]); 3844 c0 =(* mb_ptr2char)(&xp->xp_files[0][len]); 3845 } 3846 else 3847 #endif 3848 c0 = xp->xp_files[0][len]; 3849 for (i = 1; i < xp->xp_numfiles; ++i) 3850 { 3851 #ifdef FEAT_MBYTE 3852 if (has_mbyte) 3853 ci =(* mb_ptr2char)(&xp->xp_files[i][len]); 3854 else 3855 #endif 3856 ci = xp->xp_files[i][len]; 3857 if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES 3858 || xp->xp_context == EXPAND_FILES 3859 || xp->xp_context == EXPAND_SHELLCMD 3860 || xp->xp_context == EXPAND_BUFFERS)) 3861 { 3862 if (MB_TOLOWER(c0) != MB_TOLOWER(ci)) 3863 break; 3864 } 3865 else if (c0 != ci) 3866 break; 3867 } 3868 if (i < xp->xp_numfiles) 3869 { 3870 if (!(options & WILD_NO_BEEP)) 3871 vim_beep(BO_WILD); 3872 break; 3873 } 3874 } 3875 3876 ss = alloc((unsigned)len + 1); 3877 if (ss) 3878 vim_strncpy(ss, xp->xp_files[0], (size_t)len); 3879 findex = -1; /* next p_wc gets first one */ 3880 } 3881 3882 /* Concatenate all matching names */ 3883 if (mode == WILD_ALL && xp->xp_numfiles > 0) 3884 { 3885 len = 0; 3886 for (i = 0; i < xp->xp_numfiles; ++i) 3887 len += (long_u)STRLEN(xp->xp_files[i]) + 1; 3888 ss = lalloc(len, TRUE); 3889 if (ss != NULL) 3890 { 3891 *ss = NUL; 3892 for (i = 0; i < xp->xp_numfiles; ++i) 3893 { 3894 STRCAT(ss, xp->xp_files[i]); 3895 if (i != xp->xp_numfiles - 1) 3896 STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " "); 3897 } 3898 } 3899 } 3900 3901 if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) 3902 ExpandCleanup(xp); 3903 3904 /* Free "orig" if it wasn't stored in "orig_save". */ 3905 if (!orig_saved) 3906 vim_free(orig); 3907 3908 return ss; 3909 } 3910 3911 /* 3912 * Prepare an expand structure for use. 3913 */ 3914 void 3915 ExpandInit(expand_T *xp) 3916 { 3917 xp->xp_pattern = NULL; 3918 xp->xp_pattern_len = 0; 3919 xp->xp_backslash = XP_BS_NONE; 3920 #ifndef BACKSLASH_IN_FILENAME 3921 xp->xp_shell = FALSE; 3922 #endif 3923 xp->xp_numfiles = -1; 3924 xp->xp_files = NULL; 3925 #if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) 3926 xp->xp_arg = NULL; 3927 #endif 3928 xp->xp_line = NULL; 3929 } 3930 3931 /* 3932 * Cleanup an expand structure after use. 3933 */ 3934 void 3935 ExpandCleanup(expand_T *xp) 3936 { 3937 if (xp->xp_numfiles >= 0) 3938 { 3939 FreeWild(xp->xp_numfiles, xp->xp_files); 3940 xp->xp_numfiles = -1; 3941 } 3942 } 3943 3944 void 3945 ExpandEscape( 3946 expand_T *xp, 3947 char_u *str, 3948 int numfiles, 3949 char_u **files, 3950 int options) 3951 { 3952 int i; 3953 char_u *p; 3954 3955 /* 3956 * May change home directory back to "~" 3957 */ 3958 if (options & WILD_HOME_REPLACE) 3959 tilde_replace(str, numfiles, files); 3960 3961 if (options & WILD_ESCAPE) 3962 { 3963 if (xp->xp_context == EXPAND_FILES 3964 || xp->xp_context == EXPAND_FILES_IN_PATH 3965 || xp->xp_context == EXPAND_SHELLCMD 3966 || xp->xp_context == EXPAND_BUFFERS 3967 || xp->xp_context == EXPAND_DIRECTORIES) 3968 { 3969 /* 3970 * Insert a backslash into a file name before a space, \, %, # 3971 * and wildmatch characters, except '~'. 3972 */ 3973 for (i = 0; i < numfiles; ++i) 3974 { 3975 /* for ":set path=" we need to escape spaces twice */ 3976 if (xp->xp_backslash == XP_BS_THREE) 3977 { 3978 p = vim_strsave_escaped(files[i], (char_u *)" "); 3979 if (p != NULL) 3980 { 3981 vim_free(files[i]); 3982 files[i] = p; 3983 #if defined(BACKSLASH_IN_FILENAME) 3984 p = vim_strsave_escaped(files[i], (char_u *)" "); 3985 if (p != NULL) 3986 { 3987 vim_free(files[i]); 3988 files[i] = p; 3989 } 3990 #endif 3991 } 3992 } 3993 #ifdef BACKSLASH_IN_FILENAME 3994 p = vim_strsave_fnameescape(files[i], FALSE); 3995 #else 3996 p = vim_strsave_fnameescape(files[i], xp->xp_shell); 3997 #endif 3998 if (p != NULL) 3999 { 4000 vim_free(files[i]); 4001 files[i] = p; 4002 } 4003 4004 /* If 'str' starts with "\~", replace "~" at start of 4005 * files[i] with "\~". */ 4006 if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') 4007 escape_fname(&files[i]); 4008 } 4009 xp->xp_backslash = XP_BS_NONE; 4010 4011 /* If the first file starts with a '+' escape it. Otherwise it 4012 * could be seen as "+cmd". */ 4013 if (*files[0] == '+') 4014 escape_fname(&files[0]); 4015 } 4016 else if (xp->xp_context == EXPAND_TAGS) 4017 { 4018 /* 4019 * Insert a backslash before characters in a tag name that 4020 * would terminate the ":tag" command. 4021 */ 4022 for (i = 0; i < numfiles; ++i) 4023 { 4024 p = vim_strsave_escaped(files[i], (char_u *)"\\|\""); 4025 if (p != NULL) 4026 { 4027 vim_free(files[i]); 4028 files[i] = p; 4029 } 4030 } 4031 } 4032 } 4033 } 4034 4035 /* 4036 * Escape special characters in "fname" for when used as a file name argument 4037 * after a Vim command, or, when "shell" is non-zero, a shell command. 4038 * Returns the result in allocated memory. 4039 */ 4040 char_u * 4041 vim_strsave_fnameescape(char_u *fname, int shell) 4042 { 4043 char_u *p; 4044 #ifdef BACKSLASH_IN_FILENAME 4045 char_u buf[20]; 4046 int j = 0; 4047 4048 /* Don't escape '[', '{' and '!' if they are in 'isfname'. */ 4049 for (p = PATH_ESC_CHARS; *p != NUL; ++p) 4050 if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p)) 4051 buf[j++] = *p; 4052 buf[j] = NUL; 4053 p = vim_strsave_escaped(fname, buf); 4054 #else 4055 p = vim_strsave_escaped(fname, shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS); 4056 if (shell && csh_like_shell() && p != NULL) 4057 { 4058 char_u *s; 4059 4060 /* For csh and similar shells need to put two backslashes before '!'. 4061 * One is taken by Vim, one by the shell. */ 4062 s = vim_strsave_escaped(p, (char_u *)"!"); 4063 vim_free(p); 4064 p = s; 4065 } 4066 #endif 4067 4068 /* '>' and '+' are special at the start of some commands, e.g. ":edit" and 4069 * ":write". "cd -" has a special meaning. */ 4070 if (p != NULL && (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL))) 4071 escape_fname(&p); 4072 4073 return p; 4074 } 4075 4076 /* 4077 * Put a backslash before the file name in "pp", which is in allocated memory. 4078 */ 4079 static void 4080 escape_fname(char_u **pp) 4081 { 4082 char_u *p; 4083 4084 p = alloc((unsigned)(STRLEN(*pp) + 2)); 4085 if (p != NULL) 4086 { 4087 p[0] = '\\'; 4088 STRCPY(p + 1, *pp); 4089 vim_free(*pp); 4090 *pp = p; 4091 } 4092 } 4093 4094 /* 4095 * For each file name in files[num_files]: 4096 * If 'orig_pat' starts with "~/", replace the home directory with "~". 4097 */ 4098 void 4099 tilde_replace( 4100 char_u *orig_pat, 4101 int num_files, 4102 char_u **files) 4103 { 4104 int i; 4105 char_u *p; 4106 4107 if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1])) 4108 { 4109 for (i = 0; i < num_files; ++i) 4110 { 4111 p = home_replace_save(NULL, files[i]); 4112 if (p != NULL) 4113 { 4114 vim_free(files[i]); 4115 files[i] = p; 4116 } 4117 } 4118 } 4119 } 4120 4121 /* 4122 * Show all matches for completion on the command line. 4123 * Returns EXPAND_NOTHING when the character that triggered expansion should 4124 * be inserted like a normal character. 4125 */ 4126 static int 4127 showmatches(expand_T *xp, int wildmenu UNUSED) 4128 { 4129 #define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m]) 4130 int num_files; 4131 char_u **files_found; 4132 int i, j, k; 4133 int maxlen; 4134 int lines; 4135 int columns; 4136 char_u *p; 4137 int lastlen; 4138 int attr; 4139 int showtail; 4140 4141 if (xp->xp_numfiles == -1) 4142 { 4143 set_expand_context(xp); 4144 i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos, 4145 &num_files, &files_found); 4146 showtail = expand_showtail(xp); 4147 if (i != EXPAND_OK) 4148 return i; 4149 4150 } 4151 else 4152 { 4153 num_files = xp->xp_numfiles; 4154 files_found = xp->xp_files; 4155 showtail = cmd_showtail; 4156 } 4157 4158 #ifdef FEAT_WILDMENU 4159 if (!wildmenu) 4160 { 4161 #endif 4162 msg_didany = FALSE; /* lines_left will be set */ 4163 msg_start(); /* prepare for paging */ 4164 msg_putchar('\n'); 4165 out_flush(); 4166 cmdline_row = msg_row; 4167 msg_didany = FALSE; /* lines_left will be set again */ 4168 msg_start(); /* prepare for paging */ 4169 #ifdef FEAT_WILDMENU 4170 } 4171 #endif 4172 4173 if (got_int) 4174 got_int = FALSE; /* only int. the completion, not the cmd line */ 4175 #ifdef FEAT_WILDMENU 4176 else if (wildmenu) 4177 win_redr_status_matches(xp, num_files, files_found, -1, showtail); 4178 #endif 4179 else 4180 { 4181 /* find the length of the longest file name */ 4182 maxlen = 0; 4183 for (i = 0; i < num_files; ++i) 4184 { 4185 if (!showtail && (xp->xp_context == EXPAND_FILES 4186 || xp->xp_context == EXPAND_SHELLCMD 4187 || xp->xp_context == EXPAND_BUFFERS)) 4188 { 4189 home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE); 4190 j = vim_strsize(NameBuff); 4191 } 4192 else 4193 j = vim_strsize(L_SHOWFILE(i)); 4194 if (j > maxlen) 4195 maxlen = j; 4196 } 4197 4198 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 4199 lines = num_files; 4200 else 4201 { 4202 /* compute the number of columns and lines for the listing */ 4203 maxlen += 2; /* two spaces between file names */ 4204 columns = ((int)Columns + 2) / maxlen; 4205 if (columns < 1) 4206 columns = 1; 4207 lines = (num_files + columns - 1) / columns; 4208 } 4209 4210 attr = HL_ATTR(HLF_D); /* find out highlighting for directories */ 4211 4212 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 4213 { 4214 MSG_PUTS_ATTR(_("tagname"), HL_ATTR(HLF_T)); 4215 msg_clr_eos(); 4216 msg_advance(maxlen - 3); 4217 MSG_PUTS_ATTR(_(" kind file\n"), HL_ATTR(HLF_T)); 4218 } 4219 4220 /* list the files line by line */ 4221 for (i = 0; i < lines; ++i) 4222 { 4223 lastlen = 999; 4224 for (k = i; k < num_files; k += lines) 4225 { 4226 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 4227 { 4228 msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D)); 4229 p = files_found[k] + STRLEN(files_found[k]) + 1; 4230 msg_advance(maxlen + 1); 4231 msg_puts(p); 4232 msg_advance(maxlen + 3); 4233 msg_puts_long_attr(p + 2, HL_ATTR(HLF_D)); 4234 break; 4235 } 4236 for (j = maxlen - lastlen; --j >= 0; ) 4237 msg_putchar(' '); 4238 if (xp->xp_context == EXPAND_FILES 4239 || xp->xp_context == EXPAND_SHELLCMD 4240 || xp->xp_context == EXPAND_BUFFERS) 4241 { 4242 /* highlight directories */ 4243 if (xp->xp_numfiles != -1) 4244 { 4245 char_u *halved_slash; 4246 char_u *exp_path; 4247 4248 /* Expansion was done before and special characters 4249 * were escaped, need to halve backslashes. Also 4250 * $HOME has been replaced with ~/. */ 4251 exp_path = expand_env_save_opt(files_found[k], TRUE); 4252 halved_slash = backslash_halve_save( 4253 exp_path != NULL ? exp_path : files_found[k]); 4254 j = mch_isdir(halved_slash != NULL ? halved_slash 4255 : files_found[k]); 4256 vim_free(exp_path); 4257 vim_free(halved_slash); 4258 } 4259 else 4260 /* Expansion was done here, file names are literal. */ 4261 j = mch_isdir(files_found[k]); 4262 if (showtail) 4263 p = L_SHOWFILE(k); 4264 else 4265 { 4266 home_replace(NULL, files_found[k], NameBuff, MAXPATHL, 4267 TRUE); 4268 p = NameBuff; 4269 } 4270 } 4271 else 4272 { 4273 j = FALSE; 4274 p = L_SHOWFILE(k); 4275 } 4276 lastlen = msg_outtrans_attr(p, j ? attr : 0); 4277 } 4278 if (msg_col > 0) /* when not wrapped around */ 4279 { 4280 msg_clr_eos(); 4281 msg_putchar('\n'); 4282 } 4283 out_flush(); /* show one line at a time */ 4284 if (got_int) 4285 { 4286 got_int = FALSE; 4287 break; 4288 } 4289 } 4290 4291 /* 4292 * we redraw the command below the lines that we have just listed 4293 * This is a bit tricky, but it saves a lot of screen updating. 4294 */ 4295 cmdline_row = msg_row; /* will put it back later */ 4296 } 4297 4298 if (xp->xp_numfiles == -1) 4299 FreeWild(num_files, files_found); 4300 4301 return EXPAND_OK; 4302 } 4303 4304 /* 4305 * Private gettail for showmatches() (and win_redr_status_matches()): 4306 * Find tail of file name path, but ignore trailing "/". 4307 */ 4308 char_u * 4309 sm_gettail(char_u *s) 4310 { 4311 char_u *p; 4312 char_u *t = s; 4313 int had_sep = FALSE; 4314 4315 for (p = s; *p != NUL; ) 4316 { 4317 if (vim_ispathsep(*p) 4318 #ifdef BACKSLASH_IN_FILENAME 4319 && !rem_backslash(p) 4320 #endif 4321 ) 4322 had_sep = TRUE; 4323 else if (had_sep) 4324 { 4325 t = p; 4326 had_sep = FALSE; 4327 } 4328 MB_PTR_ADV(p); 4329 } 4330 return t; 4331 } 4332 4333 /* 4334 * Return TRUE if we only need to show the tail of completion matches. 4335 * When not completing file names or there is a wildcard in the path FALSE is 4336 * returned. 4337 */ 4338 static int 4339 expand_showtail(expand_T *xp) 4340 { 4341 char_u *s; 4342 char_u *end; 4343 4344 /* When not completing file names a "/" may mean something different. */ 4345 if (xp->xp_context != EXPAND_FILES 4346 && xp->xp_context != EXPAND_SHELLCMD 4347 && xp->xp_context != EXPAND_DIRECTORIES) 4348 return FALSE; 4349 4350 end = gettail(xp->xp_pattern); 4351 if (end == xp->xp_pattern) /* there is no path separator */ 4352 return FALSE; 4353 4354 for (s = xp->xp_pattern; s < end; s++) 4355 { 4356 /* Skip escaped wildcards. Only when the backslash is not a path 4357 * separator, on DOS the '*' "path\*\file" must not be skipped. */ 4358 if (rem_backslash(s)) 4359 ++s; 4360 else if (vim_strchr((char_u *)"*?[", *s) != NULL) 4361 return FALSE; 4362 } 4363 return TRUE; 4364 } 4365 4366 /* 4367 * Prepare a string for expansion. 4368 * When expanding file names: The string will be used with expand_wildcards(). 4369 * Copy "fname[len]" into allocated memory and add a '*' at the end. 4370 * When expanding other names: The string will be used with regcomp(). Copy 4371 * the name into allocated memory and prepend "^". 4372 */ 4373 char_u * 4374 addstar( 4375 char_u *fname, 4376 int len, 4377 int context) /* EXPAND_FILES etc. */ 4378 { 4379 char_u *retval; 4380 int i, j; 4381 int new_len; 4382 char_u *tail; 4383 int ends_in_star; 4384 4385 if (context != EXPAND_FILES 4386 && context != EXPAND_FILES_IN_PATH 4387 && context != EXPAND_SHELLCMD 4388 && context != EXPAND_DIRECTORIES) 4389 { 4390 /* 4391 * Matching will be done internally (on something other than files). 4392 * So we convert the file-matching-type wildcards into our kind for 4393 * use with vim_regcomp(). First work out how long it will be: 4394 */ 4395 4396 /* For help tags the translation is done in find_help_tags(). 4397 * For a tag pattern starting with "/" no translation is needed. */ 4398 if (context == EXPAND_HELP 4399 || context == EXPAND_COLORS 4400 || context == EXPAND_COMPILER 4401 || context == EXPAND_OWNSYNTAX 4402 || context == EXPAND_FILETYPE 4403 || context == EXPAND_PACKADD 4404 || ((context == EXPAND_TAGS_LISTFILES 4405 || context == EXPAND_TAGS) 4406 && fname[0] == '/')) 4407 retval = vim_strnsave(fname, len); 4408 else 4409 { 4410 new_len = len + 2; /* +2 for '^' at start, NUL at end */ 4411 for (i = 0; i < len; i++) 4412 { 4413 if (fname[i] == '*' || fname[i] == '~') 4414 new_len++; /* '*' needs to be replaced by ".*" 4415 '~' needs to be replaced by "\~" */ 4416 4417 /* Buffer names are like file names. "." should be literal */ 4418 if (context == EXPAND_BUFFERS && fname[i] == '.') 4419 new_len++; /* "." becomes "\." */ 4420 4421 /* Custom expansion takes care of special things, match 4422 * backslashes literally (perhaps also for other types?) */ 4423 if ((context == EXPAND_USER_DEFINED 4424 || context == EXPAND_USER_LIST) && fname[i] == '\\') 4425 new_len++; /* '\' becomes "\\" */ 4426 } 4427 retval = alloc(new_len); 4428 if (retval != NULL) 4429 { 4430 retval[0] = '^'; 4431 j = 1; 4432 for (i = 0; i < len; i++, j++) 4433 { 4434 /* Skip backslash. But why? At least keep it for custom 4435 * expansion. */ 4436 if (context != EXPAND_USER_DEFINED 4437 && context != EXPAND_USER_LIST 4438 && fname[i] == '\\' 4439 && ++i == len) 4440 break; 4441 4442 switch (fname[i]) 4443 { 4444 case '*': retval[j++] = '.'; 4445 break; 4446 case '~': retval[j++] = '\\'; 4447 break; 4448 case '?': retval[j] = '.'; 4449 continue; 4450 case '.': if (context == EXPAND_BUFFERS) 4451 retval[j++] = '\\'; 4452 break; 4453 case '\\': if (context == EXPAND_USER_DEFINED 4454 || context == EXPAND_USER_LIST) 4455 retval[j++] = '\\'; 4456 break; 4457 } 4458 retval[j] = fname[i]; 4459 } 4460 retval[j] = NUL; 4461 } 4462 } 4463 } 4464 else 4465 { 4466 retval = alloc(len + 4); 4467 if (retval != NULL) 4468 { 4469 vim_strncpy(retval, fname, len); 4470 4471 /* 4472 * Don't add a star to *, ~, ~user, $var or `cmd`. 4473 * * would become **, which walks the whole tree. 4474 * ~ would be at the start of the file name, but not the tail. 4475 * $ could be anywhere in the tail. 4476 * ` could be anywhere in the file name. 4477 * When the name ends in '$' don't add a star, remove the '$'. 4478 */ 4479 tail = gettail(retval); 4480 ends_in_star = (len > 0 && retval[len - 1] == '*'); 4481 #ifndef BACKSLASH_IN_FILENAME 4482 for (i = len - 2; i >= 0; --i) 4483 { 4484 if (retval[i] != '\\') 4485 break; 4486 ends_in_star = !ends_in_star; 4487 } 4488 #endif 4489 if ((*retval != '~' || tail != retval) 4490 && !ends_in_star 4491 && vim_strchr(tail, '$') == NULL 4492 && vim_strchr(retval, '`') == NULL) 4493 retval[len++] = '*'; 4494 else if (len > 0 && retval[len - 1] == '$') 4495 --len; 4496 retval[len] = NUL; 4497 } 4498 } 4499 return retval; 4500 } 4501 4502 /* 4503 * Must parse the command line so far to work out what context we are in. 4504 * Completion can then be done based on that context. 4505 * This routine sets the variables: 4506 * xp->xp_pattern The start of the pattern to be expanded within 4507 * the command line (ends at the cursor). 4508 * xp->xp_context The type of thing to expand. Will be one of: 4509 * 4510 * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on 4511 * the command line, like an unknown command. Caller 4512 * should beep. 4513 * EXPAND_NOTHING Unrecognised context for completion, use char like 4514 * a normal char, rather than for completion. eg 4515 * :s/^I/ 4516 * EXPAND_COMMANDS Cursor is still touching the command, so complete 4517 * it. 4518 * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. 4519 * EXPAND_FILES After command with XFILE set, or after setting 4520 * with P_EXPAND set. eg :e ^I, :w>>^I 4521 * EXPAND_DIRECTORIES In some cases this is used instead of the latter 4522 * when we know only directories are of interest. eg 4523 * :set dir=^I 4524 * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd". 4525 * EXPAND_SETTINGS Complete variable names. eg :set d^I 4526 * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I 4527 * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I 4528 * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect 4529 * EXPAND_HELP Complete tags from the file 'helpfile'/tags 4530 * EXPAND_EVENTS Complete event names 4531 * EXPAND_SYNTAX Complete :syntax command arguments 4532 * EXPAND_HIGHLIGHT Complete highlight (syntax) group names 4533 * EXPAND_AUGROUP Complete autocommand group names 4534 * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I 4535 * EXPAND_MAPPINGS Complete mapping and abbreviation names, 4536 * eg :unmap a^I , :cunab x^I 4537 * EXPAND_FUNCTIONS Complete internal or user defined function names, 4538 * eg :call sub^I 4539 * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I 4540 * EXPAND_EXPRESSION Complete internal or user defined function/variable 4541 * names in expressions, eg :while s^I 4542 * EXPAND_ENV_VARS Complete environment variable names 4543 * EXPAND_USER Complete user names 4544 */ 4545 static void 4546 set_expand_context(expand_T *xp) 4547 { 4548 /* only expansion for ':', '>' and '=' command-lines */ 4549 if (ccline.cmdfirstc != ':' 4550 #ifdef FEAT_EVAL 4551 && ccline.cmdfirstc != '>' && ccline.cmdfirstc != '=' 4552 && !ccline.input_fn 4553 #endif 4554 ) 4555 { 4556 xp->xp_context = EXPAND_NOTHING; 4557 return; 4558 } 4559 set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos, TRUE); 4560 } 4561 4562 void 4563 set_cmd_context( 4564 expand_T *xp, 4565 char_u *str, /* start of command line */ 4566 int len, /* length of command line (excl. NUL) */ 4567 int col, /* position of cursor */ 4568 int use_ccline UNUSED) /* use ccline for info */ 4569 { 4570 int old_char = NUL; 4571 char_u *nextcomm; 4572 4573 /* 4574 * Avoid a UMR warning from Purify, only save the character if it has been 4575 * written before. 4576 */ 4577 if (col < len) 4578 old_char = str[col]; 4579 str[col] = NUL; 4580 nextcomm = str; 4581 4582 #ifdef FEAT_EVAL 4583 if (use_ccline && ccline.cmdfirstc == '=') 4584 { 4585 # ifdef FEAT_CMDL_COMPL 4586 /* pass CMD_SIZE because there is no real command */ 4587 set_context_for_expression(xp, str, CMD_SIZE); 4588 # endif 4589 } 4590 else if (use_ccline && ccline.input_fn) 4591 { 4592 xp->xp_context = ccline.xp_context; 4593 xp->xp_pattern = ccline.cmdbuff; 4594 # if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) 4595 xp->xp_arg = ccline.xp_arg; 4596 # endif 4597 } 4598 else 4599 #endif 4600 while (nextcomm != NULL) 4601 nextcomm = set_one_cmd_context(xp, nextcomm); 4602 4603 /* Store the string here so that call_user_expand_func() can get to them 4604 * easily. */ 4605 xp->xp_line = str; 4606 xp->xp_col = col; 4607 4608 str[col] = old_char; 4609 } 4610 4611 /* 4612 * Expand the command line "str" from context "xp". 4613 * "xp" must have been set by set_cmd_context(). 4614 * xp->xp_pattern points into "str", to where the text that is to be expanded 4615 * starts. 4616 * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the 4617 * cursor. 4618 * Returns EXPAND_NOTHING when there is nothing to expand, might insert the 4619 * key that triggered expansion literally. 4620 * Returns EXPAND_OK otherwise. 4621 */ 4622 int 4623 expand_cmdline( 4624 expand_T *xp, 4625 char_u *str, /* start of command line */ 4626 int col, /* position of cursor */ 4627 int *matchcount, /* return: nr of matches */ 4628 char_u ***matches) /* return: array of pointers to matches */ 4629 { 4630 char_u *file_str = NULL; 4631 int options = WILD_ADD_SLASH|WILD_SILENT; 4632 4633 if (xp->xp_context == EXPAND_UNSUCCESSFUL) 4634 { 4635 beep_flush(); 4636 return EXPAND_UNSUCCESSFUL; /* Something illegal on command line */ 4637 } 4638 if (xp->xp_context == EXPAND_NOTHING) 4639 { 4640 /* Caller can use the character as a normal char instead */ 4641 return EXPAND_NOTHING; 4642 } 4643 4644 /* add star to file name, or convert to regexp if not exp. files. */ 4645 xp->xp_pattern_len = (int)(str + col - xp->xp_pattern); 4646 file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); 4647 if (file_str == NULL) 4648 return EXPAND_UNSUCCESSFUL; 4649 4650 if (p_wic) 4651 options += WILD_ICASE; 4652 4653 /* find all files that match the description */ 4654 if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL) 4655 { 4656 *matchcount = 0; 4657 *matches = NULL; 4658 } 4659 vim_free(file_str); 4660 4661 return EXPAND_OK; 4662 } 4663 4664 #ifdef FEAT_MULTI_LANG 4665 /* 4666 * Cleanup matches for help tags: 4667 * Remove "@ab" if the top of 'helplang' is "ab" and the language of the first 4668 * tag matches it. Otherwise remove "@en" if "en" is the only language. 4669 */ 4670 static void cleanup_help_tags(int num_file, char_u **file); 4671 4672 static void 4673 cleanup_help_tags(int num_file, char_u **file) 4674 { 4675 int i, j; 4676 int len; 4677 char_u buf[4]; 4678 char_u *p = buf; 4679 4680 if (p_hlg[0] != NUL && (p_hlg[0] != 'e' || p_hlg[1] != 'n')) 4681 { 4682 *p++ = '@'; 4683 *p++ = p_hlg[0]; 4684 *p++ = p_hlg[1]; 4685 } 4686 *p = NUL; 4687 4688 for (i = 0; i < num_file; ++i) 4689 { 4690 len = (int)STRLEN(file[i]) - 3; 4691 if (len <= 0) 4692 continue; 4693 if (STRCMP(file[i] + len, "@en") == 0) 4694 { 4695 /* Sorting on priority means the same item in another language may 4696 * be anywhere. Search all items for a match up to the "@en". */ 4697 for (j = 0; j < num_file; ++j) 4698 if (j != i && (int)STRLEN(file[j]) == len + 3 4699 && STRNCMP(file[i], file[j], len + 1) == 0) 4700 break; 4701 if (j == num_file) 4702 /* item only exists with @en, remove it */ 4703 file[i][len] = NUL; 4704 } 4705 } 4706 4707 if (*buf != NUL) 4708 for (i = 0; i < num_file; ++i) 4709 { 4710 len = (int)STRLEN(file[i]) - 3; 4711 if (len <= 0) 4712 continue; 4713 if (STRCMP(file[i] + len, buf) == 0) 4714 { 4715 /* remove the default language */ 4716 file[i][len] = NUL; 4717 } 4718 } 4719 } 4720 #endif 4721 4722 /* 4723 * Do the expansion based on xp->xp_context and "pat". 4724 */ 4725 static int 4726 ExpandFromContext( 4727 expand_T *xp, 4728 char_u *pat, 4729 int *num_file, 4730 char_u ***file, 4731 int options) /* EW_ flags */ 4732 { 4733 #ifdef FEAT_CMDL_COMPL 4734 regmatch_T regmatch; 4735 #endif 4736 int ret; 4737 int flags; 4738 4739 flags = EW_DIR; /* include directories */ 4740 if (options & WILD_LIST_NOTFOUND) 4741 flags |= EW_NOTFOUND; 4742 if (options & WILD_ADD_SLASH) 4743 flags |= EW_ADDSLASH; 4744 if (options & WILD_KEEP_ALL) 4745 flags |= EW_KEEPALL; 4746 if (options & WILD_SILENT) 4747 flags |= EW_SILENT; 4748 if (options & WILD_ALLLINKS) 4749 flags |= EW_ALLLINKS; 4750 4751 if (xp->xp_context == EXPAND_FILES 4752 || xp->xp_context == EXPAND_DIRECTORIES 4753 || xp->xp_context == EXPAND_FILES_IN_PATH) 4754 { 4755 /* 4756 * Expand file or directory names. 4757 */ 4758 int free_pat = FALSE; 4759 int i; 4760 4761 /* for ":set path=" and ":set tags=" halve backslashes for escaped 4762 * space */ 4763 if (xp->xp_backslash != XP_BS_NONE) 4764 { 4765 free_pat = TRUE; 4766 pat = vim_strsave(pat); 4767 for (i = 0; pat[i]; ++i) 4768 if (pat[i] == '\\') 4769 { 4770 if (xp->xp_backslash == XP_BS_THREE 4771 && pat[i + 1] == '\\' 4772 && pat[i + 2] == '\\' 4773 && pat[i + 3] == ' ') 4774 STRMOVE(pat + i, pat + i + 3); 4775 if (xp->xp_backslash == XP_BS_ONE 4776 && pat[i + 1] == ' ') 4777 STRMOVE(pat + i, pat + i + 1); 4778 } 4779 } 4780 4781 if (xp->xp_context == EXPAND_FILES) 4782 flags |= EW_FILE; 4783 else if (xp->xp_context == EXPAND_FILES_IN_PATH) 4784 flags |= (EW_FILE | EW_PATH); 4785 else 4786 flags = (flags | EW_DIR) & ~EW_FILE; 4787 if (options & WILD_ICASE) 4788 flags |= EW_ICASE; 4789 4790 /* Expand wildcards, supporting %:h and the like. */ 4791 ret = expand_wildcards_eval(&pat, num_file, file, flags); 4792 if (free_pat) 4793 vim_free(pat); 4794 return ret; 4795 } 4796 4797 *file = (char_u **)""; 4798 *num_file = 0; 4799 if (xp->xp_context == EXPAND_HELP) 4800 { 4801 /* With an empty argument we would get all the help tags, which is 4802 * very slow. Get matches for "help" instead. */ 4803 if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat, 4804 num_file, file, FALSE) == OK) 4805 { 4806 #ifdef FEAT_MULTI_LANG 4807 cleanup_help_tags(*num_file, *file); 4808 #endif 4809 return OK; 4810 } 4811 return FAIL; 4812 } 4813 4814 #ifndef FEAT_CMDL_COMPL 4815 return FAIL; 4816 #else 4817 if (xp->xp_context == EXPAND_SHELLCMD) 4818 return expand_shellcmd(pat, num_file, file, flags); 4819 if (xp->xp_context == EXPAND_OLD_SETTING) 4820 return ExpandOldSetting(num_file, file); 4821 if (xp->xp_context == EXPAND_BUFFERS) 4822 return ExpandBufnames(pat, num_file, file, options); 4823 if (xp->xp_context == EXPAND_TAGS 4824 || xp->xp_context == EXPAND_TAGS_LISTFILES) 4825 return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file); 4826 if (xp->xp_context == EXPAND_COLORS) 4827 { 4828 char *directories[] = {"colors", NULL}; 4829 return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, 4830 directories); 4831 } 4832 if (xp->xp_context == EXPAND_COMPILER) 4833 { 4834 char *directories[] = {"compiler", NULL}; 4835 return ExpandRTDir(pat, 0, num_file, file, directories); 4836 } 4837 if (xp->xp_context == EXPAND_OWNSYNTAX) 4838 { 4839 char *directories[] = {"syntax", NULL}; 4840 return ExpandRTDir(pat, 0, num_file, file, directories); 4841 } 4842 if (xp->xp_context == EXPAND_FILETYPE) 4843 { 4844 char *directories[] = {"syntax", "indent", "ftplugin", NULL}; 4845 return ExpandRTDir(pat, 0, num_file, file, directories); 4846 } 4847 # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) 4848 if (xp->xp_context == EXPAND_USER_LIST) 4849 return ExpandUserList(xp, num_file, file); 4850 # endif 4851 if (xp->xp_context == EXPAND_PACKADD) 4852 return ExpandPackAddDir(pat, num_file, file); 4853 4854 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); 4855 if (regmatch.regprog == NULL) 4856 return FAIL; 4857 4858 /* set ignore-case according to p_ic, p_scs and pat */ 4859 regmatch.rm_ic = ignorecase(pat); 4860 4861 if (xp->xp_context == EXPAND_SETTINGS 4862 || xp->xp_context == EXPAND_BOOL_SETTINGS) 4863 ret = ExpandSettings(xp, ®match, num_file, file); 4864 else if (xp->xp_context == EXPAND_MAPPINGS) 4865 ret = ExpandMappings(®match, num_file, file); 4866 # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) 4867 else if (xp->xp_context == EXPAND_USER_DEFINED) 4868 ret = ExpandUserDefined(xp, ®match, num_file, file); 4869 # endif 4870 else 4871 { 4872 static struct expgen 4873 { 4874 int context; 4875 char_u *((*func)(expand_T *, int)); 4876 int ic; 4877 int escaped; 4878 } tab[] = 4879 { 4880 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE}, 4881 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE}, 4882 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE}, 4883 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE}, 4884 #ifdef FEAT_CMDHIST 4885 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE}, 4886 #endif 4887 #ifdef FEAT_USR_CMDS 4888 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE}, 4889 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE}, 4890 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE}, 4891 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE}, 4892 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE}, 4893 #endif 4894 #ifdef FEAT_EVAL 4895 {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE}, 4896 {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE}, 4897 {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE}, 4898 {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE}, 4899 #endif 4900 #ifdef FEAT_MENU 4901 {EXPAND_MENUS, get_menu_name, FALSE, TRUE}, 4902 {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE}, 4903 #endif 4904 #ifdef FEAT_SYN_HL 4905 {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE}, 4906 #endif 4907 #ifdef FEAT_PROFILE 4908 {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE}, 4909 #endif 4910 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE}, 4911 #ifdef FEAT_AUTOCMD 4912 {EXPAND_EVENTS, get_event_name, TRUE, TRUE}, 4913 {EXPAND_AUGROUP, get_augroup_name, TRUE, TRUE}, 4914 #endif 4915 #ifdef FEAT_CSCOPE 4916 {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE}, 4917 #endif 4918 #ifdef FEAT_SIGNS 4919 {EXPAND_SIGN, get_sign_name, TRUE, TRUE}, 4920 #endif 4921 #ifdef FEAT_PROFILE 4922 {EXPAND_PROFILE, get_profile_name, TRUE, TRUE}, 4923 #endif 4924 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 4925 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 4926 {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE}, 4927 {EXPAND_LOCALES, get_locales, TRUE, FALSE}, 4928 #endif 4929 {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE}, 4930 {EXPAND_USER, get_users, TRUE, FALSE}, 4931 }; 4932 int i; 4933 4934 /* 4935 * Find a context in the table and call the ExpandGeneric() with the 4936 * right function to do the expansion. 4937 */ 4938 ret = FAIL; 4939 for (i = 0; i < (int)(sizeof(tab) / sizeof(struct expgen)); ++i) 4940 if (xp->xp_context == tab[i].context) 4941 { 4942 if (tab[i].ic) 4943 regmatch.rm_ic = TRUE; 4944 ret = ExpandGeneric(xp, ®match, num_file, file, 4945 tab[i].func, tab[i].escaped); 4946 break; 4947 } 4948 } 4949 4950 vim_regfree(regmatch.regprog); 4951 4952 return ret; 4953 #endif /* FEAT_CMDL_COMPL */ 4954 } 4955 4956 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 4957 /* 4958 * Expand a list of names. 4959 * 4960 * Generic function for command line completion. It calls a function to 4961 * obtain strings, one by one. The strings are matched against a regexp 4962 * program. Matching strings are copied into an array, which is returned. 4963 * 4964 * Returns OK when no problems encountered, FAIL for error (out of memory). 4965 */ 4966 int 4967 ExpandGeneric( 4968 expand_T *xp, 4969 regmatch_T *regmatch, 4970 int *num_file, 4971 char_u ***file, 4972 char_u *((*func)(expand_T *, int)), 4973 /* returns a string from the list */ 4974 int escaped) 4975 { 4976 int i; 4977 int count = 0; 4978 int round; 4979 char_u *str; 4980 4981 /* do this loop twice: 4982 * round == 0: count the number of matching names 4983 * round == 1: copy the matching names into allocated memory 4984 */ 4985 for (round = 0; round <= 1; ++round) 4986 { 4987 for (i = 0; ; ++i) 4988 { 4989 str = (*func)(xp, i); 4990 if (str == NULL) /* end of list */ 4991 break; 4992 if (*str == NUL) /* skip empty strings */ 4993 continue; 4994 4995 if (vim_regexec(regmatch, str, (colnr_T)0)) 4996 { 4997 if (round) 4998 { 4999 if (escaped) 5000 str = vim_strsave_escaped(str, (char_u *)" \t\\."); 5001 else 5002 str = vim_strsave(str); 5003 (*file)[count] = str; 5004 #ifdef FEAT_MENU 5005 if (func == get_menu_names && str != NULL) 5006 { 5007 /* test for separator added by get_menu_names() */ 5008 str += STRLEN(str) - 1; 5009 if (*str == '\001') 5010 *str = '.'; 5011 } 5012 #endif 5013 } 5014 ++count; 5015 } 5016 } 5017 if (round == 0) 5018 { 5019 if (count == 0) 5020 return OK; 5021 *num_file = count; 5022 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *))); 5023 if (*file == NULL) 5024 { 5025 *file = (char_u **)""; 5026 return FAIL; 5027 } 5028 count = 0; 5029 } 5030 } 5031 5032 /* Sort the results. Keep menu's in the specified order. */ 5033 if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) 5034 { 5035 if (xp->xp_context == EXPAND_EXPRESSION 5036 || xp->xp_context == EXPAND_FUNCTIONS 5037 || xp->xp_context == EXPAND_USER_FUNC) 5038 /* <SNR> functions should be sorted to the end. */ 5039 qsort((void *)*file, (size_t)*num_file, sizeof(char_u *), 5040 sort_func_compare); 5041 else 5042 sort_strings(*file, *num_file); 5043 } 5044 5045 #ifdef FEAT_CMDL_COMPL 5046 /* Reset the variables used for special highlight names expansion, so that 5047 * they don't show up when getting normal highlight names by ID. */ 5048 reset_expand_highlight(); 5049 #endif 5050 5051 return OK; 5052 } 5053 5054 /* 5055 * Complete a shell command. 5056 * Returns FAIL or OK; 5057 */ 5058 static int 5059 expand_shellcmd( 5060 char_u *filepat, /* pattern to match with command names */ 5061 int *num_file, /* return: number of matches */ 5062 char_u ***file, /* return: array with matches */ 5063 int flagsarg) /* EW_ flags */ 5064 { 5065 char_u *pat; 5066 int i; 5067 char_u *path; 5068 int mustfree = FALSE; 5069 garray_T ga; 5070 char_u *buf = alloc(MAXPATHL); 5071 size_t l; 5072 char_u *s, *e; 5073 int flags = flagsarg; 5074 int ret; 5075 int did_curdir = FALSE; 5076 5077 if (buf == NULL) 5078 return FAIL; 5079 5080 /* for ":set path=" and ":set tags=" halve backslashes for escaped 5081 * space */ 5082 pat = vim_strsave(filepat); 5083 for (i = 0; pat[i]; ++i) 5084 if (pat[i] == '\\' && pat[i + 1] == ' ') 5085 STRMOVE(pat + i, pat + i + 1); 5086 5087 flags |= EW_FILE | EW_EXEC | EW_SHELLCMD; 5088 5089 /* For an absolute name we don't use $PATH. */ 5090 if (mch_isFullName(pat)) 5091 path = (char_u *)" "; 5092 else if ((pat[0] == '.' && (vim_ispathsep(pat[1]) 5093 || (pat[1] == '.' && vim_ispathsep(pat[2]))))) 5094 path = (char_u *)"."; 5095 else 5096 { 5097 path = vim_getenv((char_u *)"PATH", &mustfree); 5098 if (path == NULL) 5099 path = (char_u *)""; 5100 } 5101 5102 /* 5103 * Go over all directories in $PATH. Expand matches in that directory and 5104 * collect them in "ga". When "." is not in $PATH also expand for the 5105 * current directory, to find "subdir/cmd". 5106 */ 5107 ga_init2(&ga, (int)sizeof(char *), 10); 5108 for (s = path; ; s = e) 5109 { 5110 if (*s == NUL) 5111 { 5112 if (did_curdir) 5113 break; 5114 /* Find directories in the current directory, path is empty. */ 5115 did_curdir = TRUE; 5116 } 5117 else if (*s == '.') 5118 did_curdir = TRUE; 5119 5120 if (*s == ' ') 5121 ++s; /* Skip space used for absolute path name. */ 5122 5123 #if defined(MSWIN) 5124 e = vim_strchr(s, ';'); 5125 #else 5126 e = vim_strchr(s, ':'); 5127 #endif 5128 if (e == NULL) 5129 e = s + STRLEN(s); 5130 5131 l = e - s; 5132 if (l > MAXPATHL - 5) 5133 break; 5134 vim_strncpy(buf, s, l); 5135 add_pathsep(buf); 5136 l = STRLEN(buf); 5137 vim_strncpy(buf + l, pat, MAXPATHL - 1 - l); 5138 5139 /* Expand matches in one directory of $PATH. */ 5140 ret = expand_wildcards(1, &buf, num_file, file, flags); 5141 if (ret == OK) 5142 { 5143 if (ga_grow(&ga, *num_file) == FAIL) 5144 FreeWild(*num_file, *file); 5145 else 5146 { 5147 for (i = 0; i < *num_file; ++i) 5148 { 5149 s = (*file)[i]; 5150 if (STRLEN(s) > l) 5151 { 5152 /* Remove the path again. */ 5153 STRMOVE(s, s + l); 5154 ((char_u **)ga.ga_data)[ga.ga_len++] = s; 5155 } 5156 else 5157 vim_free(s); 5158 } 5159 vim_free(*file); 5160 } 5161 } 5162 if (*e != NUL) 5163 ++e; 5164 } 5165 *file = ga.ga_data; 5166 *num_file = ga.ga_len; 5167 5168 vim_free(buf); 5169 vim_free(pat); 5170 if (mustfree) 5171 vim_free(path); 5172 return OK; 5173 } 5174 5175 5176 # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) 5177 static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file); 5178 5179 /* 5180 * Call "user_expand_func()" to invoke a user defined Vim script function and 5181 * return the result (either a string or a List). 5182 */ 5183 static void * 5184 call_user_expand_func( 5185 void *(*user_expand_func)(char_u *, int, char_u **, int), 5186 expand_T *xp, 5187 int *num_file, 5188 char_u ***file) 5189 { 5190 int keep = 0; 5191 char_u num[50]; 5192 char_u *args[3]; 5193 int save_current_SID = current_SID; 5194 void *ret; 5195 struct cmdline_info save_ccline; 5196 5197 if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) 5198 return NULL; 5199 *num_file = 0; 5200 *file = NULL; 5201 5202 if (ccline.cmdbuff != NULL) 5203 { 5204 keep = ccline.cmdbuff[ccline.cmdlen]; 5205 ccline.cmdbuff[ccline.cmdlen] = 0; 5206 } 5207 5208 args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); 5209 args[1] = xp->xp_line; 5210 sprintf((char *)num, "%d", xp->xp_col); 5211 args[2] = num; 5212 5213 /* Save the cmdline, we don't know what the function may do. */ 5214 save_ccline = ccline; 5215 ccline.cmdbuff = NULL; 5216 ccline.cmdprompt = NULL; 5217 current_SID = xp->xp_scriptID; 5218 5219 ret = user_expand_func(xp->xp_arg, 3, args, FALSE); 5220 5221 ccline = save_ccline; 5222 current_SID = save_current_SID; 5223 if (ccline.cmdbuff != NULL) 5224 ccline.cmdbuff[ccline.cmdlen] = keep; 5225 5226 vim_free(args[0]); 5227 return ret; 5228 } 5229 5230 /* 5231 * Expand names with a function defined by the user. 5232 */ 5233 static int 5234 ExpandUserDefined( 5235 expand_T *xp, 5236 regmatch_T *regmatch, 5237 int *num_file, 5238 char_u ***file) 5239 { 5240 char_u *retstr; 5241 char_u *s; 5242 char_u *e; 5243 char_u keep; 5244 garray_T ga; 5245 5246 retstr = call_user_expand_func(call_func_retstr, xp, num_file, file); 5247 if (retstr == NULL) 5248 return FAIL; 5249 5250 ga_init2(&ga, (int)sizeof(char *), 3); 5251 for (s = retstr; *s != NUL; s = e) 5252 { 5253 e = vim_strchr(s, '\n'); 5254 if (e == NULL) 5255 e = s + STRLEN(s); 5256 keep = *e; 5257 *e = 0; 5258 5259 if (xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0) 5260 { 5261 *e = keep; 5262 if (*e != NUL) 5263 ++e; 5264 continue; 5265 } 5266 5267 if (ga_grow(&ga, 1) == FAIL) 5268 break; 5269 5270 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s)); 5271 ++ga.ga_len; 5272 5273 *e = keep; 5274 if (*e != NUL) 5275 ++e; 5276 } 5277 vim_free(retstr); 5278 *file = ga.ga_data; 5279 *num_file = ga.ga_len; 5280 return OK; 5281 } 5282 5283 /* 5284 * Expand names with a list returned by a function defined by the user. 5285 */ 5286 static int 5287 ExpandUserList( 5288 expand_T *xp, 5289 int *num_file, 5290 char_u ***file) 5291 { 5292 list_T *retlist; 5293 listitem_T *li; 5294 garray_T ga; 5295 5296 retlist = call_user_expand_func(call_func_retlist, xp, num_file, file); 5297 if (retlist == NULL) 5298 return FAIL; 5299 5300 ga_init2(&ga, (int)sizeof(char *), 3); 5301 /* Loop over the items in the list. */ 5302 for (li = retlist->lv_first; li != NULL; li = li->li_next) 5303 { 5304 if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL) 5305 continue; /* Skip non-string items and empty strings */ 5306 5307 if (ga_grow(&ga, 1) == FAIL) 5308 break; 5309 5310 ((char_u **)ga.ga_data)[ga.ga_len] = 5311 vim_strsave(li->li_tv.vval.v_string); 5312 ++ga.ga_len; 5313 } 5314 list_unref(retlist); 5315 5316 *file = ga.ga_data; 5317 *num_file = ga.ga_len; 5318 return OK; 5319 } 5320 #endif 5321 5322 /* 5323 * Expand color scheme, compiler or filetype names. 5324 * Search from 'runtimepath': 5325 * 'runtimepath'/{dirnames}/{pat}.vim 5326 * When "flags" has DIP_START: search also from 'start' of 'packpath': 5327 * 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim 5328 * When "flags" has DIP_OPT: search also from 'opt' of 'packpath': 5329 * 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim 5330 * "dirnames" is an array with one or more directory names. 5331 */ 5332 static int 5333 ExpandRTDir( 5334 char_u *pat, 5335 int flags, 5336 int *num_file, 5337 char_u ***file, 5338 char *dirnames[]) 5339 { 5340 char_u *s; 5341 char_u *e; 5342 char_u *match; 5343 garray_T ga; 5344 int i; 5345 int pat_len; 5346 5347 *num_file = 0; 5348 *file = NULL; 5349 pat_len = (int)STRLEN(pat); 5350 ga_init2(&ga, (int)sizeof(char *), 10); 5351 5352 for (i = 0; dirnames[i] != NULL; ++i) 5353 { 5354 s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 7)); 5355 if (s == NULL) 5356 { 5357 ga_clear_strings(&ga); 5358 return FAIL; 5359 } 5360 sprintf((char *)s, "%s/%s*.vim", dirnames[i], pat); 5361 globpath(p_rtp, s, &ga, 0); 5362 vim_free(s); 5363 } 5364 5365 if (flags & DIP_START) { 5366 for (i = 0; dirnames[i] != NULL; ++i) 5367 { 5368 s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 22)); 5369 if (s == NULL) 5370 { 5371 ga_clear_strings(&ga); 5372 return FAIL; 5373 } 5374 sprintf((char *)s, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); 5375 globpath(p_pp, s, &ga, 0); 5376 vim_free(s); 5377 } 5378 } 5379 5380 if (flags & DIP_OPT) { 5381 for (i = 0; dirnames[i] != NULL; ++i) 5382 { 5383 s = alloc((unsigned)(STRLEN(dirnames[i]) + pat_len + 20)); 5384 if (s == NULL) 5385 { 5386 ga_clear_strings(&ga); 5387 return FAIL; 5388 } 5389 sprintf((char *)s, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); 5390 globpath(p_pp, s, &ga, 0); 5391 vim_free(s); 5392 } 5393 } 5394 5395 for (i = 0; i < ga.ga_len; ++i) 5396 { 5397 match = ((char_u **)ga.ga_data)[i]; 5398 s = match; 5399 e = s + STRLEN(s); 5400 if (e - 4 > s && STRNICMP(e - 4, ".vim", 4) == 0) 5401 { 5402 e -= 4; 5403 for (s = e; s > match; MB_PTR_BACK(match, s)) 5404 if (s < match || vim_ispathsep(*s)) 5405 break; 5406 ++s; 5407 *e = NUL; 5408 mch_memmove(match, s, e - s + 1); 5409 } 5410 } 5411 5412 if (ga.ga_len == 0) 5413 return FAIL; 5414 5415 /* Sort and remove duplicates which can happen when specifying multiple 5416 * directories in dirnames. */ 5417 remove_duplicates(&ga); 5418 5419 *file = ga.ga_data; 5420 *num_file = ga.ga_len; 5421 return OK; 5422 } 5423 5424 /* 5425 * Expand loadplugin names: 5426 * 'packpath'/pack/ * /opt/{pat} 5427 */ 5428 static int 5429 ExpandPackAddDir( 5430 char_u *pat, 5431 int *num_file, 5432 char_u ***file) 5433 { 5434 char_u *s; 5435 char_u *e; 5436 char_u *match; 5437 garray_T ga; 5438 int i; 5439 int pat_len; 5440 5441 *num_file = 0; 5442 *file = NULL; 5443 pat_len = (int)STRLEN(pat); 5444 ga_init2(&ga, (int)sizeof(char *), 10); 5445 5446 s = alloc((unsigned)(pat_len + 26)); 5447 if (s == NULL) 5448 { 5449 ga_clear_strings(&ga); 5450 return FAIL; 5451 } 5452 sprintf((char *)s, "pack/*/opt/%s*", pat); 5453 globpath(p_pp, s, &ga, 0); 5454 vim_free(s); 5455 5456 for (i = 0; i < ga.ga_len; ++i) 5457 { 5458 match = ((char_u **)ga.ga_data)[i]; 5459 s = gettail(match); 5460 e = s + STRLEN(s); 5461 mch_memmove(match, s, e - s + 1); 5462 } 5463 5464 if (ga.ga_len == 0) 5465 return FAIL; 5466 5467 /* Sort and remove duplicates which can happen when specifying multiple 5468 * directories in dirnames. */ 5469 remove_duplicates(&ga); 5470 5471 *file = ga.ga_data; 5472 *num_file = ga.ga_len; 5473 return OK; 5474 } 5475 5476 #endif 5477 5478 #if defined(FEAT_CMDL_COMPL) || defined(FEAT_EVAL) || defined(PROTO) 5479 /* 5480 * Expand "file" for all comma-separated directories in "path". 5481 * Adds the matches to "ga". Caller must init "ga". 5482 */ 5483 void 5484 globpath( 5485 char_u *path, 5486 char_u *file, 5487 garray_T *ga, 5488 int expand_options) 5489 { 5490 expand_T xpc; 5491 char_u *buf; 5492 int i; 5493 int num_p; 5494 char_u **p; 5495 5496 buf = alloc(MAXPATHL); 5497 if (buf == NULL) 5498 return; 5499 5500 ExpandInit(&xpc); 5501 xpc.xp_context = EXPAND_FILES; 5502 5503 /* Loop over all entries in {path}. */ 5504 while (*path != NUL) 5505 { 5506 /* Copy one item of the path to buf[] and concatenate the file name. */ 5507 copy_option_part(&path, buf, MAXPATHL, ","); 5508 if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL) 5509 { 5510 # if defined(MSWIN) 5511 /* Using the platform's path separator (\) makes vim incorrectly 5512 * treat it as an escape character, use '/' instead. */ 5513 if (*buf != NUL && !after_pathsep(buf, buf + STRLEN(buf))) 5514 STRCAT(buf, "/"); 5515 # else 5516 add_pathsep(buf); 5517 # endif 5518 STRCAT(buf, file); 5519 if (ExpandFromContext(&xpc, buf, &num_p, &p, 5520 WILD_SILENT|expand_options) != FAIL && num_p > 0) 5521 { 5522 ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options); 5523 5524 if (ga_grow(ga, num_p) == OK) 5525 { 5526 for (i = 0; i < num_p; ++i) 5527 { 5528 ((char_u **)ga->ga_data)[ga->ga_len] = 5529 vim_strnsave(p[i], (int)STRLEN(p[i])); 5530 ++ga->ga_len; 5531 } 5532 } 5533 5534 FreeWild(num_p, p); 5535 } 5536 } 5537 } 5538 5539 vim_free(buf); 5540 } 5541 5542 #endif 5543 5544 #if defined(FEAT_CMDHIST) || defined(PROTO) 5545 5546 /********************************* 5547 * Command line history stuff * 5548 *********************************/ 5549 5550 /* 5551 * Translate a history character to the associated type number. 5552 */ 5553 static int 5554 hist_char2type(int c) 5555 { 5556 if (c == ':') 5557 return HIST_CMD; 5558 if (c == '=') 5559 return HIST_EXPR; 5560 if (c == '@') 5561 return HIST_INPUT; 5562 if (c == '>') 5563 return HIST_DEBUG; 5564 return HIST_SEARCH; /* must be '?' or '/' */ 5565 } 5566 5567 /* 5568 * Table of history names. 5569 * These names are used in :history and various hist...() functions. 5570 * It is sufficient to give the significant prefix of a history name. 5571 */ 5572 5573 static char *(history_names[]) = 5574 { 5575 "cmd", 5576 "search", 5577 "expr", 5578 "input", 5579 "debug", 5580 NULL 5581 }; 5582 5583 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 5584 /* 5585 * Function given to ExpandGeneric() to obtain the possible first 5586 * arguments of the ":history command. 5587 */ 5588 static char_u * 5589 get_history_arg(expand_T *xp UNUSED, int idx) 5590 { 5591 static char_u compl[2] = { NUL, NUL }; 5592 char *short_names = ":=@>?/"; 5593 int short_names_count = (int)STRLEN(short_names); 5594 int history_name_count = sizeof(history_names) / sizeof(char *) - 1; 5595 5596 if (idx < short_names_count) 5597 { 5598 compl[0] = (char_u)short_names[idx]; 5599 return compl; 5600 } 5601 if (idx < short_names_count + history_name_count) 5602 return (char_u *)history_names[idx - short_names_count]; 5603 if (idx == short_names_count + history_name_count) 5604 return (char_u *)"all"; 5605 return NULL; 5606 } 5607 #endif 5608 5609 /* 5610 * init_history() - Initialize the command line history. 5611 * Also used to re-allocate the history when the size changes. 5612 */ 5613 void 5614 init_history(void) 5615 { 5616 int newlen; /* new length of history table */ 5617 histentry_T *temp; 5618 int i; 5619 int j; 5620 int type; 5621 5622 /* 5623 * If size of history table changed, reallocate it 5624 */ 5625 newlen = (int)p_hi; 5626 if (newlen != hislen) /* history length changed */ 5627 { 5628 for (type = 0; type < HIST_COUNT; ++type) /* adjust the tables */ 5629 { 5630 if (newlen) 5631 { 5632 temp = (histentry_T *)lalloc( 5633 (long_u)(newlen * sizeof(histentry_T)), TRUE); 5634 if (temp == NULL) /* out of memory! */ 5635 { 5636 if (type == 0) /* first one: just keep the old length */ 5637 { 5638 newlen = hislen; 5639 break; 5640 } 5641 /* Already changed one table, now we can only have zero 5642 * length for all tables. */ 5643 newlen = 0; 5644 type = -1; 5645 continue; 5646 } 5647 } 5648 else 5649 temp = NULL; 5650 if (newlen == 0 || temp != NULL) 5651 { 5652 if (hisidx[type] < 0) /* there are no entries yet */ 5653 { 5654 for (i = 0; i < newlen; ++i) 5655 clear_hist_entry(&temp[i]); 5656 } 5657 else if (newlen > hislen) /* array becomes bigger */ 5658 { 5659 for (i = 0; i <= hisidx[type]; ++i) 5660 temp[i] = history[type][i]; 5661 j = i; 5662 for ( ; i <= newlen - (hislen - hisidx[type]); ++i) 5663 clear_hist_entry(&temp[i]); 5664 for ( ; j < hislen; ++i, ++j) 5665 temp[i] = history[type][j]; 5666 } 5667 else /* array becomes smaller or 0 */ 5668 { 5669 j = hisidx[type]; 5670 for (i = newlen - 1; ; --i) 5671 { 5672 if (i >= 0) /* copy newest entries */ 5673 temp[i] = history[type][j]; 5674 else /* remove older entries */ 5675 vim_free(history[type][j].hisstr); 5676 if (--j < 0) 5677 j = hislen - 1; 5678 if (j == hisidx[type]) 5679 break; 5680 } 5681 hisidx[type] = newlen - 1; 5682 } 5683 vim_free(history[type]); 5684 history[type] = temp; 5685 } 5686 } 5687 hislen = newlen; 5688 } 5689 } 5690 5691 static void 5692 clear_hist_entry(histentry_T *hisptr) 5693 { 5694 hisptr->hisnum = 0; 5695 hisptr->viminfo = FALSE; 5696 hisptr->hisstr = NULL; 5697 hisptr->time_set = 0; 5698 } 5699 5700 /* 5701 * Check if command line 'str' is already in history. 5702 * If 'move_to_front' is TRUE, matching entry is moved to end of history. 5703 */ 5704 static int 5705 in_history( 5706 int type, 5707 char_u *str, 5708 int move_to_front, /* Move the entry to the front if it exists */ 5709 int sep, 5710 int writing) /* ignore entries read from viminfo */ 5711 { 5712 int i; 5713 int last_i = -1; 5714 char_u *p; 5715 5716 if (hisidx[type] < 0) 5717 return FALSE; 5718 i = hisidx[type]; 5719 do 5720 { 5721 if (history[type][i].hisstr == NULL) 5722 return FALSE; 5723 5724 /* For search history, check that the separator character matches as 5725 * well. */ 5726 p = history[type][i].hisstr; 5727 if (STRCMP(str, p) == 0 5728 && !(writing && history[type][i].viminfo) 5729 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) 5730 { 5731 if (!move_to_front) 5732 return TRUE; 5733 last_i = i; 5734 break; 5735 } 5736 if (--i < 0) 5737 i = hislen - 1; 5738 } while (i != hisidx[type]); 5739 5740 if (last_i >= 0) 5741 { 5742 str = history[type][i].hisstr; 5743 while (i != hisidx[type]) 5744 { 5745 if (++i >= hislen) 5746 i = 0; 5747 history[type][last_i] = history[type][i]; 5748 last_i = i; 5749 } 5750 history[type][i].hisnum = ++hisnum[type]; 5751 history[type][i].viminfo = FALSE; 5752 history[type][i].hisstr = str; 5753 history[type][i].time_set = vim_time(); 5754 return TRUE; 5755 } 5756 return FALSE; 5757 } 5758 5759 /* 5760 * Convert history name (from table above) to its HIST_ equivalent. 5761 * When "name" is empty, return "cmd" history. 5762 * Returns -1 for unknown history name. 5763 */ 5764 int 5765 get_histtype(char_u *name) 5766 { 5767 int i; 5768 int len = (int)STRLEN(name); 5769 5770 /* No argument: use current history. */ 5771 if (len == 0) 5772 return hist_char2type(ccline.cmdfirstc); 5773 5774 for (i = 0; history_names[i] != NULL; ++i) 5775 if (STRNICMP(name, history_names[i], len) == 0) 5776 return i; 5777 5778 if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL) 5779 return hist_char2type(name[0]); 5780 5781 return -1; 5782 } 5783 5784 static int last_maptick = -1; /* last seen maptick */ 5785 5786 /* 5787 * Add the given string to the given history. If the string is already in the 5788 * history then it is moved to the front. "histype" may be one of he HIST_ 5789 * values. 5790 */ 5791 void 5792 add_to_history( 5793 int histype, 5794 char_u *new_entry, 5795 int in_map, /* consider maptick when inside a mapping */ 5796 int sep) /* separator character used (search hist) */ 5797 { 5798 histentry_T *hisptr; 5799 int len; 5800 5801 if (hislen == 0) /* no history */ 5802 return; 5803 5804 if (cmdmod.keeppatterns && histype == HIST_SEARCH) 5805 return; 5806 5807 /* 5808 * Searches inside the same mapping overwrite each other, so that only 5809 * the last line is kept. Be careful not to remove a line that was moved 5810 * down, only lines that were added. 5811 */ 5812 if (histype == HIST_SEARCH && in_map) 5813 { 5814 if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0) 5815 { 5816 /* Current line is from the same mapping, remove it */ 5817 hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]]; 5818 vim_free(hisptr->hisstr); 5819 clear_hist_entry(hisptr); 5820 --hisnum[histype]; 5821 if (--hisidx[HIST_SEARCH] < 0) 5822 hisidx[HIST_SEARCH] = hislen - 1; 5823 } 5824 last_maptick = -1; 5825 } 5826 if (!in_history(histype, new_entry, TRUE, sep, FALSE)) 5827 { 5828 if (++hisidx[histype] == hislen) 5829 hisidx[histype] = 0; 5830 hisptr = &history[histype][hisidx[histype]]; 5831 vim_free(hisptr->hisstr); 5832 5833 /* Store the separator after the NUL of the string. */ 5834 len = (int)STRLEN(new_entry); 5835 hisptr->hisstr = vim_strnsave(new_entry, len + 2); 5836 if (hisptr->hisstr != NULL) 5837 hisptr->hisstr[len + 1] = sep; 5838 5839 hisptr->hisnum = ++hisnum[histype]; 5840 hisptr->viminfo = FALSE; 5841 hisptr->time_set = vim_time(); 5842 if (histype == HIST_SEARCH && in_map) 5843 last_maptick = maptick; 5844 } 5845 } 5846 5847 #if defined(FEAT_EVAL) || defined(PROTO) 5848 5849 /* 5850 * Get identifier of newest history entry. 5851 * "histype" may be one of the HIST_ values. 5852 */ 5853 int 5854 get_history_idx(int histype) 5855 { 5856 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT 5857 || hisidx[histype] < 0) 5858 return -1; 5859 5860 return history[histype][hisidx[histype]].hisnum; 5861 } 5862 5863 /* 5864 * Calculate history index from a number: 5865 * num > 0: seen as identifying number of a history entry 5866 * num < 0: relative position in history wrt newest entry 5867 * "histype" may be one of the HIST_ values. 5868 */ 5869 static int 5870 calc_hist_idx(int histype, int num) 5871 { 5872 int i; 5873 histentry_T *hist; 5874 int wrapped = FALSE; 5875 5876 if (hislen == 0 || histype < 0 || histype >= HIST_COUNT 5877 || (i = hisidx[histype]) < 0 || num == 0) 5878 return -1; 5879 5880 hist = history[histype]; 5881 if (num > 0) 5882 { 5883 while (hist[i].hisnum > num) 5884 if (--i < 0) 5885 { 5886 if (wrapped) 5887 break; 5888 i += hislen; 5889 wrapped = TRUE; 5890 } 5891 if (hist[i].hisnum == num && hist[i].hisstr != NULL) 5892 return i; 5893 } 5894 else if (-num <= hislen) 5895 { 5896 i += num + 1; 5897 if (i < 0) 5898 i += hislen; 5899 if (hist[i].hisstr != NULL) 5900 return i; 5901 } 5902 return -1; 5903 } 5904 5905 /* 5906 * Get a history entry by its index. 5907 * "histype" may be one of the HIST_ values. 5908 */ 5909 char_u * 5910 get_history_entry(int histype, int idx) 5911 { 5912 idx = calc_hist_idx(histype, idx); 5913 if (idx >= 0) 5914 return history[histype][idx].hisstr; 5915 else 5916 return (char_u *)""; 5917 } 5918 5919 /* 5920 * Clear all entries of a history. 5921 * "histype" may be one of the HIST_ values. 5922 */ 5923 int 5924 clr_history(int histype) 5925 { 5926 int i; 5927 histentry_T *hisptr; 5928 5929 if (hislen != 0 && histype >= 0 && histype < HIST_COUNT) 5930 { 5931 hisptr = history[histype]; 5932 for (i = hislen; i--;) 5933 { 5934 vim_free(hisptr->hisstr); 5935 clear_hist_entry(hisptr); 5936 hisptr++; 5937 } 5938 hisidx[histype] = -1; /* mark history as cleared */ 5939 hisnum[histype] = 0; /* reset identifier counter */ 5940 return OK; 5941 } 5942 return FAIL; 5943 } 5944 5945 /* 5946 * Remove all entries matching {str} from a history. 5947 * "histype" may be one of the HIST_ values. 5948 */ 5949 int 5950 del_history_entry(int histype, char_u *str) 5951 { 5952 regmatch_T regmatch; 5953 histentry_T *hisptr; 5954 int idx; 5955 int i; 5956 int last; 5957 int found = FALSE; 5958 5959 regmatch.regprog = NULL; 5960 regmatch.rm_ic = FALSE; /* always match case */ 5961 if (hislen != 0 5962 && histype >= 0 5963 && histype < HIST_COUNT 5964 && *str != NUL 5965 && (idx = hisidx[histype]) >= 0 5966 && (regmatch.regprog = vim_regcomp(str, RE_MAGIC + RE_STRING)) 5967 != NULL) 5968 { 5969 i = last = idx; 5970 do 5971 { 5972 hisptr = &history[histype][i]; 5973 if (hisptr->hisstr == NULL) 5974 break; 5975 if (vim_regexec(®match, hisptr->hisstr, (colnr_T)0)) 5976 { 5977 found = TRUE; 5978 vim_free(hisptr->hisstr); 5979 clear_hist_entry(hisptr); 5980 } 5981 else 5982 { 5983 if (i != last) 5984 { 5985 history[histype][last] = *hisptr; 5986 clear_hist_entry(hisptr); 5987 } 5988 if (--last < 0) 5989 last += hislen; 5990 } 5991 if (--i < 0) 5992 i += hislen; 5993 } while (i != idx); 5994 if (history[histype][idx].hisstr == NULL) 5995 hisidx[histype] = -1; 5996 } 5997 vim_regfree(regmatch.regprog); 5998 return found; 5999 } 6000 6001 /* 6002 * Remove an indexed entry from a history. 6003 * "histype" may be one of the HIST_ values. 6004 */ 6005 int 6006 del_history_idx(int histype, int idx) 6007 { 6008 int i, j; 6009 6010 i = calc_hist_idx(histype, idx); 6011 if (i < 0) 6012 return FALSE; 6013 idx = hisidx[histype]; 6014 vim_free(history[histype][i].hisstr); 6015 6016 /* When deleting the last added search string in a mapping, reset 6017 * last_maptick, so that the last added search string isn't deleted again. 6018 */ 6019 if (histype == HIST_SEARCH && maptick == last_maptick && i == idx) 6020 last_maptick = -1; 6021 6022 while (i != idx) 6023 { 6024 j = (i + 1) % hislen; 6025 history[histype][i] = history[histype][j]; 6026 i = j; 6027 } 6028 clear_hist_entry(&history[histype][i]); 6029 if (--i < 0) 6030 i += hislen; 6031 hisidx[histype] = i; 6032 return TRUE; 6033 } 6034 6035 #endif /* FEAT_EVAL */ 6036 6037 #if defined(FEAT_CRYPT) || defined(PROTO) 6038 /* 6039 * Very specific function to remove the value in ":set key=val" from the 6040 * history. 6041 */ 6042 void 6043 remove_key_from_history(void) 6044 { 6045 char_u *p; 6046 int i; 6047 6048 i = hisidx[HIST_CMD]; 6049 if (i < 0) 6050 return; 6051 p = history[HIST_CMD][i].hisstr; 6052 if (p != NULL) 6053 for ( ; *p; ++p) 6054 if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3])) 6055 { 6056 p = vim_strchr(p + 3, '='); 6057 if (p == NULL) 6058 break; 6059 ++p; 6060 for (i = 0; p[i] && !VIM_ISWHITE(p[i]); ++i) 6061 if (p[i] == '\\' && p[i + 1]) 6062 ++i; 6063 STRMOVE(p, p + i); 6064 --p; 6065 } 6066 } 6067 #endif 6068 6069 #endif /* FEAT_CMDHIST */ 6070 6071 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO) 6072 /* 6073 * Get pointer to the command line info to use. cmdline_paste() may clear 6074 * ccline and put the previous value in prev_ccline. 6075 */ 6076 static struct cmdline_info * 6077 get_ccline_ptr(void) 6078 { 6079 if ((State & CMDLINE) == 0) 6080 return NULL; 6081 if (ccline.cmdbuff != NULL) 6082 return &ccline; 6083 if (prev_ccline_used && prev_ccline.cmdbuff != NULL) 6084 return &prev_ccline; 6085 return NULL; 6086 } 6087 #endif 6088 6089 #if defined(FEAT_EVAL) || defined(PROTO) 6090 /* 6091 * Get the current command line in allocated memory. 6092 * Only works when the command line is being edited. 6093 * Returns NULL when something is wrong. 6094 */ 6095 char_u * 6096 get_cmdline_str(void) 6097 { 6098 struct cmdline_info *p = get_ccline_ptr(); 6099 6100 if (p == NULL) 6101 return NULL; 6102 return vim_strnsave(p->cmdbuff, p->cmdlen); 6103 } 6104 6105 /* 6106 * Get the current command line position, counted in bytes. 6107 * Zero is the first position. 6108 * Only works when the command line is being edited. 6109 * Returns -1 when something is wrong. 6110 */ 6111 int 6112 get_cmdline_pos(void) 6113 { 6114 struct cmdline_info *p = get_ccline_ptr(); 6115 6116 if (p == NULL) 6117 return -1; 6118 return p->cmdpos; 6119 } 6120 6121 /* 6122 * Set the command line byte position to "pos". Zero is the first position. 6123 * Only works when the command line is being edited. 6124 * Returns 1 when failed, 0 when OK. 6125 */ 6126 int 6127 set_cmdline_pos( 6128 int pos) 6129 { 6130 struct cmdline_info *p = get_ccline_ptr(); 6131 6132 if (p == NULL) 6133 return 1; 6134 6135 /* The position is not set directly but after CTRL-\ e or CTRL-R = has 6136 * changed the command line. */ 6137 if (pos < 0) 6138 new_cmdpos = 0; 6139 else 6140 new_cmdpos = pos; 6141 return 0; 6142 } 6143 #endif 6144 6145 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO) 6146 /* 6147 * Get the current command-line type. 6148 * Returns ':' or '/' or '?' or '@' or '>' or '-' 6149 * Only works when the command line is being edited. 6150 * Returns NUL when something is wrong. 6151 */ 6152 int 6153 get_cmdline_type(void) 6154 { 6155 struct cmdline_info *p = get_ccline_ptr(); 6156 6157 if (p == NULL) 6158 return NUL; 6159 if (p->cmdfirstc == NUL) 6160 return 6161 # ifdef FEAT_EVAL 6162 (p->input_fn) ? '@' : 6163 # endif 6164 '-'; 6165 return p->cmdfirstc; 6166 } 6167 #endif 6168 6169 #if defined(FEAT_QUICKFIX) || defined(FEAT_CMDHIST) || defined(PROTO) 6170 /* 6171 * Get indices "num1,num2" that specify a range within a list (not a range of 6172 * text lines in a buffer!) from a string. Used for ":history" and ":clist". 6173 * Returns OK if parsed successfully, otherwise FAIL. 6174 */ 6175 int 6176 get_list_range(char_u **str, int *num1, int *num2) 6177 { 6178 int len; 6179 int first = FALSE; 6180 varnumber_T num; 6181 6182 *str = skipwhite(*str); 6183 if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */ 6184 { 6185 vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); 6186 *str += len; 6187 *num1 = (int)num; 6188 first = TRUE; 6189 } 6190 *str = skipwhite(*str); 6191 if (**str == ',') /* parse "to" part of range */ 6192 { 6193 *str = skipwhite(*str + 1); 6194 vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0); 6195 if (len > 0) 6196 { 6197 *num2 = (int)num; 6198 *str = skipwhite(*str + len); 6199 } 6200 else if (!first) /* no number given at all */ 6201 return FAIL; 6202 } 6203 else if (first) /* only one number given */ 6204 *num2 = *num1; 6205 return OK; 6206 } 6207 #endif 6208 6209 #if defined(FEAT_CMDHIST) || defined(PROTO) 6210 /* 6211 * :history command - print a history 6212 */ 6213 void 6214 ex_history(exarg_T *eap) 6215 { 6216 histentry_T *hist; 6217 int histype1 = HIST_CMD; 6218 int histype2 = HIST_CMD; 6219 int hisidx1 = 1; 6220 int hisidx2 = -1; 6221 int idx; 6222 int i, j, k; 6223 char_u *end; 6224 char_u *arg = eap->arg; 6225 6226 if (hislen == 0) 6227 { 6228 MSG(_("'history' option is zero")); 6229 return; 6230 } 6231 6232 if (!(VIM_ISDIGIT(*arg) || *arg == '-' || *arg == ',')) 6233 { 6234 end = arg; 6235 while (ASCII_ISALPHA(*end) 6236 || vim_strchr((char_u *)":=@>/?", *end) != NULL) 6237 end++; 6238 i = *end; 6239 *end = NUL; 6240 histype1 = get_histtype(arg); 6241 if (histype1 == -1) 6242 { 6243 if (STRNICMP(arg, "all", STRLEN(arg)) == 0) 6244 { 6245 histype1 = 0; 6246 histype2 = HIST_COUNT-1; 6247 } 6248 else 6249 { 6250 *end = i; 6251 EMSG(_(e_trailing)); 6252 return; 6253 } 6254 } 6255 else 6256 histype2 = histype1; 6257 *end = i; 6258 } 6259 else 6260 end = arg; 6261 if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) 6262 { 6263 EMSG(_(e_trailing)); 6264 return; 6265 } 6266 6267 for (; !got_int && histype1 <= histype2; ++histype1) 6268 { 6269 STRCPY(IObuff, "\n # "); 6270 STRCAT(STRCAT(IObuff, history_names[histype1]), " history"); 6271 MSG_PUTS_TITLE(IObuff); 6272 idx = hisidx[histype1]; 6273 hist = history[histype1]; 6274 j = hisidx1; 6275 k = hisidx2; 6276 if (j < 0) 6277 j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum; 6278 if (k < 0) 6279 k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum; 6280 if (idx >= 0 && j <= k) 6281 for (i = idx + 1; !got_int; ++i) 6282 { 6283 if (i == hislen) 6284 i = 0; 6285 if (hist[i].hisstr != NULL 6286 && hist[i].hisnum >= j && hist[i].hisnum <= k) 6287 { 6288 msg_putchar('\n'); 6289 sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ', 6290 hist[i].hisnum); 6291 if (vim_strsize(hist[i].hisstr) > (int)Columns - 10) 6292 trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff), 6293 (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff)); 6294 else 6295 STRCAT(IObuff, hist[i].hisstr); 6296 msg_outtrans(IObuff); 6297 out_flush(); 6298 } 6299 if (i == idx) 6300 break; 6301 } 6302 } 6303 } 6304 #endif 6305 6306 #if (defined(FEAT_VIMINFO) && defined(FEAT_CMDHIST)) || defined(PROTO) 6307 /* 6308 * Buffers for history read from a viminfo file. Only valid while reading. 6309 */ 6310 static histentry_T *viminfo_history[HIST_COUNT] = 6311 {NULL, NULL, NULL, NULL, NULL}; 6312 static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0}; 6313 static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0}; 6314 static int viminfo_add_at_front = FALSE; 6315 6316 static int hist_type2char(int type, int use_question); 6317 6318 /* 6319 * Translate a history type number to the associated character. 6320 */ 6321 static int 6322 hist_type2char( 6323 int type, 6324 int use_question) /* use '?' instead of '/' */ 6325 { 6326 if (type == HIST_CMD) 6327 return ':'; 6328 if (type == HIST_SEARCH) 6329 { 6330 if (use_question) 6331 return '?'; 6332 else 6333 return '/'; 6334 } 6335 if (type == HIST_EXPR) 6336 return '='; 6337 return '@'; 6338 } 6339 6340 /* 6341 * Prepare for reading the history from the viminfo file. 6342 * This allocates history arrays to store the read history lines. 6343 */ 6344 void 6345 prepare_viminfo_history(int asklen, int writing) 6346 { 6347 int i; 6348 int num; 6349 int type; 6350 int len; 6351 6352 init_history(); 6353 viminfo_add_at_front = (asklen != 0 && !writing); 6354 if (asklen > hislen) 6355 asklen = hislen; 6356 6357 for (type = 0; type < HIST_COUNT; ++type) 6358 { 6359 /* Count the number of empty spaces in the history list. Entries read 6360 * from viminfo previously are also considered empty. If there are 6361 * more spaces available than we request, then fill them up. */ 6362 for (i = 0, num = 0; i < hislen; i++) 6363 if (history[type][i].hisstr == NULL || history[type][i].viminfo) 6364 num++; 6365 len = asklen; 6366 if (num > len) 6367 len = num; 6368 if (len <= 0) 6369 viminfo_history[type] = NULL; 6370 else 6371 viminfo_history[type] = (histentry_T *)lalloc( 6372 (long_u)(len * sizeof(histentry_T)), FALSE); 6373 if (viminfo_history[type] == NULL) 6374 len = 0; 6375 viminfo_hislen[type] = len; 6376 viminfo_hisidx[type] = 0; 6377 } 6378 } 6379 6380 /* 6381 * Accept a line from the viminfo, store it in the history array when it's 6382 * new. 6383 */ 6384 int 6385 read_viminfo_history(vir_T *virp, int writing) 6386 { 6387 int type; 6388 long_u len; 6389 char_u *val; 6390 char_u *p; 6391 6392 type = hist_char2type(virp->vir_line[0]); 6393 if (viminfo_hisidx[type] < viminfo_hislen[type]) 6394 { 6395 val = viminfo_readstring(virp, 1, TRUE); 6396 if (val != NULL && *val != NUL) 6397 { 6398 int sep = (*val == ' ' ? NUL : *val); 6399 6400 if (!in_history(type, val + (type == HIST_SEARCH), 6401 viminfo_add_at_front, sep, writing)) 6402 { 6403 /* Need to re-allocate to append the separator byte. */ 6404 len = STRLEN(val); 6405 p = lalloc(len + 2, TRUE); 6406 if (p != NULL) 6407 { 6408 if (type == HIST_SEARCH) 6409 { 6410 /* Search entry: Move the separator from the first 6411 * column to after the NUL. */ 6412 mch_memmove(p, val + 1, (size_t)len); 6413 p[len] = sep; 6414 } 6415 else 6416 { 6417 /* Not a search entry: No separator in the viminfo 6418 * file, add a NUL separator. */ 6419 mch_memmove(p, val, (size_t)len + 1); 6420 p[len + 1] = NUL; 6421 } 6422 viminfo_history[type][viminfo_hisidx[type]].hisstr = p; 6423 viminfo_history[type][viminfo_hisidx[type]].time_set = 0; 6424 viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE; 6425 viminfo_history[type][viminfo_hisidx[type]].hisnum = 0; 6426 viminfo_hisidx[type]++; 6427 } 6428 } 6429 } 6430 vim_free(val); 6431 } 6432 return viminfo_readline(virp); 6433 } 6434 6435 /* 6436 * Accept a new style history line from the viminfo, store it in the history 6437 * array when it's new. 6438 */ 6439 void 6440 handle_viminfo_history( 6441 garray_T *values, 6442 int writing) 6443 { 6444 int type; 6445 long_u len; 6446 char_u *val; 6447 char_u *p; 6448 bval_T *vp = (bval_T *)values->ga_data; 6449 6450 /* Check the format: 6451 * |{bartype},{histtype},{timestamp},{separator},"text" */ 6452 if (values->ga_len < 4 6453 || vp[0].bv_type != BVAL_NR 6454 || vp[1].bv_type != BVAL_NR 6455 || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY) 6456 || vp[3].bv_type != BVAL_STRING) 6457 return; 6458 6459 type = vp[0].bv_nr; 6460 if (type >= HIST_COUNT) 6461 return; 6462 if (viminfo_hisidx[type] < viminfo_hislen[type]) 6463 { 6464 val = vp[3].bv_string; 6465 if (val != NULL && *val != NUL) 6466 { 6467 int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR 6468 ? vp[2].bv_nr : NUL; 6469 int idx; 6470 int overwrite = FALSE; 6471 6472 if (!in_history(type, val, viminfo_add_at_front, sep, writing)) 6473 { 6474 /* If lines were written by an older Vim we need to avoid 6475 * getting duplicates. See if the entry already exists. */ 6476 for (idx = 0; idx < viminfo_hisidx[type]; ++idx) 6477 { 6478 p = viminfo_history[type][idx].hisstr; 6479 if (STRCMP(val, p) == 0 6480 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) 6481 { 6482 overwrite = TRUE; 6483 break; 6484 } 6485 } 6486 6487 if (!overwrite) 6488 { 6489 /* Need to re-allocate to append the separator byte. */ 6490 len = vp[3].bv_len; 6491 p = lalloc(len + 2, TRUE); 6492 } 6493 else 6494 len = 0; /* for picky compilers */ 6495 if (p != NULL) 6496 { 6497 viminfo_history[type][idx].time_set = vp[1].bv_nr; 6498 if (!overwrite) 6499 { 6500 mch_memmove(p, val, (size_t)len + 1); 6501 /* Put the separator after the NUL. */ 6502 p[len + 1] = sep; 6503 viminfo_history[type][idx].hisstr = p; 6504 viminfo_history[type][idx].hisnum = 0; 6505 viminfo_history[type][idx].viminfo = TRUE; 6506 viminfo_hisidx[type]++; 6507 } 6508 } 6509 } 6510 } 6511 } 6512 } 6513 6514 /* 6515 * Concatenate history lines from viminfo after the lines typed in this Vim. 6516 */ 6517 static void 6518 concat_history(int type) 6519 { 6520 int idx; 6521 int i; 6522 6523 idx = hisidx[type] + viminfo_hisidx[type]; 6524 if (idx >= hislen) 6525 idx -= hislen; 6526 else if (idx < 0) 6527 idx = hislen - 1; 6528 if (viminfo_add_at_front) 6529 hisidx[type] = idx; 6530 else 6531 { 6532 if (hisidx[type] == -1) 6533 hisidx[type] = hislen - 1; 6534 do 6535 { 6536 if (history[type][idx].hisstr != NULL 6537 || history[type][idx].viminfo) 6538 break; 6539 if (++idx == hislen) 6540 idx = 0; 6541 } while (idx != hisidx[type]); 6542 if (idx != hisidx[type] && --idx < 0) 6543 idx = hislen - 1; 6544 } 6545 for (i = 0; i < viminfo_hisidx[type]; i++) 6546 { 6547 vim_free(history[type][idx].hisstr); 6548 history[type][idx].hisstr = viminfo_history[type][i].hisstr; 6549 history[type][idx].viminfo = TRUE; 6550 history[type][idx].time_set = viminfo_history[type][i].time_set; 6551 if (--idx < 0) 6552 idx = hislen - 1; 6553 } 6554 idx += 1; 6555 idx %= hislen; 6556 for (i = 0; i < viminfo_hisidx[type]; i++) 6557 { 6558 history[type][idx++].hisnum = ++hisnum[type]; 6559 idx %= hislen; 6560 } 6561 } 6562 6563 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 6564 static int 6565 #ifdef __BORLANDC__ 6566 _RTLENTRYF 6567 #endif 6568 sort_hist(const void *s1, const void *s2) 6569 { 6570 histentry_T *p1 = *(histentry_T **)s1; 6571 histentry_T *p2 = *(histentry_T **)s2; 6572 6573 if (p1->time_set < p2->time_set) return -1; 6574 if (p1->time_set > p2->time_set) return 1; 6575 return 0; 6576 } 6577 #endif 6578 6579 /* 6580 * Merge history lines from viminfo and lines typed in this Vim based on the 6581 * timestamp; 6582 */ 6583 static void 6584 merge_history(int type) 6585 { 6586 int max_len; 6587 histentry_T **tot_hist; 6588 histentry_T *new_hist; 6589 int i; 6590 int len; 6591 6592 /* Make one long list with all entries. */ 6593 max_len = hislen + viminfo_hisidx[type]; 6594 tot_hist = (histentry_T **)alloc(max_len * (int)sizeof(histentry_T *)); 6595 new_hist = (histentry_T *)alloc(hislen * (int)sizeof(histentry_T)); 6596 if (tot_hist == NULL || new_hist == NULL) 6597 { 6598 vim_free(tot_hist); 6599 vim_free(new_hist); 6600 return; 6601 } 6602 for (i = 0; i < viminfo_hisidx[type]; i++) 6603 tot_hist[i] = &viminfo_history[type][i]; 6604 len = i; 6605 for (i = 0; i < hislen; i++) 6606 if (history[type][i].hisstr != NULL) 6607 tot_hist[len++] = &history[type][i]; 6608 6609 /* Sort the list on timestamp. */ 6610 qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist); 6611 6612 /* Keep the newest ones. */ 6613 for (i = 0; i < hislen; i++) 6614 { 6615 if (i < len) 6616 { 6617 new_hist[i] = *tot_hist[i]; 6618 tot_hist[i]->hisstr = NULL; 6619 if (new_hist[i].hisnum == 0) 6620 new_hist[i].hisnum = ++hisnum[type]; 6621 } 6622 else 6623 clear_hist_entry(&new_hist[i]); 6624 } 6625 hisidx[type] = (i < len ? i : len) - 1; 6626 6627 /* Free what is not kept. */ 6628 for (i = 0; i < viminfo_hisidx[type]; i++) 6629 vim_free(viminfo_history[type][i].hisstr); 6630 for (i = 0; i < hislen; i++) 6631 vim_free(history[type][i].hisstr); 6632 vim_free(history[type]); 6633 history[type] = new_hist; 6634 vim_free(tot_hist); 6635 } 6636 6637 /* 6638 * Finish reading history lines from viminfo. Not used when writing viminfo. 6639 */ 6640 void 6641 finish_viminfo_history(vir_T *virp) 6642 { 6643 int type; 6644 int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY; 6645 6646 for (type = 0; type < HIST_COUNT; ++type) 6647 { 6648 if (history[type] == NULL) 6649 continue; 6650 6651 if (merge) 6652 merge_history(type); 6653 else 6654 concat_history(type); 6655 6656 vim_free(viminfo_history[type]); 6657 viminfo_history[type] = NULL; 6658 viminfo_hisidx[type] = 0; 6659 } 6660 } 6661 6662 /* 6663 * Write history to viminfo file in "fp". 6664 * When "merge" is TRUE merge history lines with a previously read viminfo 6665 * file, data is in viminfo_history[]. 6666 * When "merge" is FALSE just write all history lines. Used for ":wviminfo!". 6667 */ 6668 void 6669 write_viminfo_history(FILE *fp, int merge) 6670 { 6671 int i; 6672 int type; 6673 int num_saved; 6674 int round; 6675 6676 init_history(); 6677 if (hislen == 0) 6678 return; 6679 for (type = 0; type < HIST_COUNT; ++type) 6680 { 6681 num_saved = get_viminfo_parameter(hist_type2char(type, FALSE)); 6682 if (num_saved == 0) 6683 continue; 6684 if (num_saved < 0) /* Use default */ 6685 num_saved = hislen; 6686 fprintf(fp, _("\n# %s History (newest to oldest):\n"), 6687 type == HIST_CMD ? _("Command Line") : 6688 type == HIST_SEARCH ? _("Search String") : 6689 type == HIST_EXPR ? _("Expression") : 6690 type == HIST_INPUT ? _("Input Line") : 6691 _("Debug Line")); 6692 if (num_saved > hislen) 6693 num_saved = hislen; 6694 6695 /* 6696 * Merge typed and viminfo history: 6697 * round 1: history of typed commands. 6698 * round 2: history from recently read viminfo. 6699 */ 6700 for (round = 1; round <= 2; ++round) 6701 { 6702 if (round == 1) 6703 /* start at newest entry, somewhere in the list */ 6704 i = hisidx[type]; 6705 else if (viminfo_hisidx[type] > 0) 6706 /* start at newest entry, first in the list */ 6707 i = 0; 6708 else 6709 /* empty list */ 6710 i = -1; 6711 if (i >= 0) 6712 while (num_saved > 0 6713 && !(round == 2 && i >= viminfo_hisidx[type])) 6714 { 6715 char_u *p; 6716 time_t timestamp; 6717 int c = NUL; 6718 6719 if (round == 1) 6720 { 6721 p = history[type][i].hisstr; 6722 timestamp = history[type][i].time_set; 6723 } 6724 else 6725 { 6726 p = viminfo_history[type] == NULL ? NULL 6727 : viminfo_history[type][i].hisstr; 6728 timestamp = viminfo_history[type] == NULL ? 0 6729 : viminfo_history[type][i].time_set; 6730 } 6731 6732 if (p != NULL && (round == 2 6733 || !merge 6734 || !history[type][i].viminfo)) 6735 { 6736 --num_saved; 6737 fputc(hist_type2char(type, TRUE), fp); 6738 /* For the search history: put the separator in the 6739 * second column; use a space if there isn't one. */ 6740 if (type == HIST_SEARCH) 6741 { 6742 c = p[STRLEN(p) + 1]; 6743 putc(c == NUL ? ' ' : c, fp); 6744 } 6745 viminfo_writestring(fp, p); 6746 6747 { 6748 char cbuf[NUMBUFLEN]; 6749 6750 /* New style history with a bar line. Format: 6751 * |{bartype},{histtype},{timestamp},{separator},"text" */ 6752 if (c == NUL) 6753 cbuf[0] = NUL; 6754 else 6755 sprintf(cbuf, "%d", c); 6756 fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY, 6757 type, (long)timestamp, cbuf); 6758 barline_writestring(fp, p, LSIZE - 20); 6759 putc('\n', fp); 6760 } 6761 } 6762 if (round == 1) 6763 { 6764 /* Decrement index, loop around and stop when back at 6765 * the start. */ 6766 if (--i < 0) 6767 i = hislen - 1; 6768 if (i == hisidx[type]) 6769 break; 6770 } 6771 else 6772 { 6773 /* Increment index. Stop at the end in the while. */ 6774 ++i; 6775 } 6776 } 6777 } 6778 for (i = 0; i < viminfo_hisidx[type]; ++i) 6779 if (viminfo_history[type] != NULL) 6780 vim_free(viminfo_history[type][i].hisstr); 6781 vim_free(viminfo_history[type]); 6782 viminfo_history[type] = NULL; 6783 viminfo_hisidx[type] = 0; 6784 } 6785 } 6786 #endif /* FEAT_VIMINFO */ 6787 6788 #if defined(FEAT_FKMAP) || defined(PROTO) 6789 /* 6790 * Write a character at the current cursor+offset position. 6791 * It is directly written into the command buffer block. 6792 */ 6793 void 6794 cmd_pchar(int c, int offset) 6795 { 6796 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0) 6797 { 6798 EMSG(_("E198: cmd_pchar beyond the command length")); 6799 return; 6800 } 6801 ccline.cmdbuff[ccline.cmdpos + offset] = (char_u)c; 6802 ccline.cmdbuff[ccline.cmdlen] = NUL; 6803 } 6804 6805 int 6806 cmd_gchar(int offset) 6807 { 6808 if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0) 6809 { 6810 /* EMSG(_("cmd_gchar beyond the command length")); */ 6811 return NUL; 6812 } 6813 return (int)ccline.cmdbuff[ccline.cmdpos + offset]; 6814 } 6815 #endif 6816 6817 #if defined(FEAT_CMDWIN) || defined(PROTO) 6818 /* 6819 * Open a window on the current command line and history. Allow editing in 6820 * the window. Returns when the window is closed. 6821 * Returns: 6822 * CR if the command is to be executed 6823 * Ctrl_C if it is to be abandoned 6824 * K_IGNORE if editing continues 6825 */ 6826 static int 6827 open_cmdwin(void) 6828 { 6829 struct cmdline_info save_ccline; 6830 bufref_T old_curbuf; 6831 win_T *old_curwin = curwin; 6832 bufref_T bufref; 6833 win_T *wp; 6834 int i; 6835 linenr_T lnum; 6836 int histtype; 6837 garray_T winsizes; 6838 #ifdef FEAT_AUTOCMD 6839 char_u typestr[2]; 6840 #endif 6841 int save_restart_edit = restart_edit; 6842 int save_State = State; 6843 int save_exmode = exmode_active; 6844 #ifdef FEAT_RIGHTLEFT 6845 int save_cmdmsg_rl = cmdmsg_rl; 6846 #endif 6847 #ifdef FEAT_FOLDING 6848 int save_KeyTyped; 6849 #endif 6850 6851 /* Can't do this recursively. Can't do it when typing a password. */ 6852 if (cmdwin_type != 0 6853 # if defined(FEAT_CRYPT) || defined(FEAT_EVAL) 6854 || cmdline_star > 0 6855 # endif 6856 ) 6857 { 6858 beep_flush(); 6859 return K_IGNORE; 6860 } 6861 set_bufref(&old_curbuf, curbuf); 6862 6863 /* Save current window sizes. */ 6864 win_size_save(&winsizes); 6865 6866 # ifdef FEAT_AUTOCMD 6867 /* Don't execute autocommands while creating the window. */ 6868 block_autocmds(); 6869 # endif 6870 /* don't use a new tab page */ 6871 cmdmod.tab = 0; 6872 cmdmod.noswapfile = 1; 6873 6874 /* Create a window for the command-line buffer. */ 6875 if (win_split((int)p_cwh, WSP_BOT) == FAIL) 6876 { 6877 beep_flush(); 6878 # ifdef FEAT_AUTOCMD 6879 unblock_autocmds(); 6880 # endif 6881 return K_IGNORE; 6882 } 6883 cmdwin_type = get_cmdline_type(); 6884 6885 /* Create the command-line buffer empty. */ 6886 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL); 6887 (void)setfname(curbuf, (char_u *)"[Command Line]", NULL, TRUE); 6888 set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL); 6889 curbuf->b_p_ma = TRUE; 6890 #ifdef FEAT_FOLDING 6891 curwin->w_p_fen = FALSE; 6892 #endif 6893 # ifdef FEAT_RIGHTLEFT 6894 curwin->w_p_rl = cmdmsg_rl; 6895 cmdmsg_rl = FALSE; 6896 # endif 6897 RESET_BINDING(curwin); 6898 6899 # ifdef FEAT_AUTOCMD 6900 /* Do execute autocommands for setting the filetype (load syntax). */ 6901 unblock_autocmds(); 6902 /* But don't allow switching to another buffer. */ 6903 ++curbuf_lock; 6904 # endif 6905 6906 /* Showing the prompt may have set need_wait_return, reset it. */ 6907 need_wait_return = FALSE; 6908 6909 histtype = hist_char2type(cmdwin_type); 6910 if (histtype == HIST_CMD || histtype == HIST_DEBUG) 6911 { 6912 if (p_wc == TAB) 6913 { 6914 add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT); 6915 add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL); 6916 } 6917 set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL); 6918 } 6919 # ifdef FEAT_AUTOCMD 6920 --curbuf_lock; 6921 # endif 6922 6923 /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin 6924 * sets 'textwidth' to 78). */ 6925 curbuf->b_p_tw = 0; 6926 6927 /* Fill the buffer with the history. */ 6928 init_history(); 6929 if (hislen > 0) 6930 { 6931 i = hisidx[histtype]; 6932 if (i >= 0) 6933 { 6934 lnum = 0; 6935 do 6936 { 6937 if (++i == hislen) 6938 i = 0; 6939 if (history[histtype][i].hisstr != NULL) 6940 ml_append(lnum++, history[histtype][i].hisstr, 6941 (colnr_T)0, FALSE); 6942 } 6943 while (i != hisidx[histtype]); 6944 } 6945 } 6946 6947 /* Replace the empty last line with the current command-line and put the 6948 * cursor there. */ 6949 ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE); 6950 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 6951 curwin->w_cursor.col = ccline.cmdpos; 6952 changed_line_abv_curs(); 6953 invalidate_botline(); 6954 redraw_later(SOME_VALID); 6955 6956 /* Save the command line info, can be used recursively. */ 6957 save_cmdline(&save_ccline); 6958 6959 /* No Ex mode here! */ 6960 exmode_active = 0; 6961 6962 State = NORMAL; 6963 # ifdef FEAT_MOUSE 6964 setmouse(); 6965 # endif 6966 6967 # ifdef FEAT_AUTOCMD 6968 /* Trigger CmdwinEnter autocommands. */ 6969 typestr[0] = cmdwin_type; 6970 typestr[1] = NUL; 6971 apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, FALSE, curbuf); 6972 if (restart_edit != 0) /* autocmd with ":startinsert" */ 6973 stuffcharReadbuff(K_NOP); 6974 # endif 6975 6976 i = RedrawingDisabled; 6977 RedrawingDisabled = 0; 6978 6979 /* 6980 * Call the main loop until <CR> or CTRL-C is typed. 6981 */ 6982 cmdwin_result = 0; 6983 main_loop(TRUE, FALSE); 6984 6985 RedrawingDisabled = i; 6986 6987 # ifdef FEAT_AUTOCMD 6988 6989 # ifdef FEAT_FOLDING 6990 save_KeyTyped = KeyTyped; 6991 # endif 6992 6993 /* Trigger CmdwinLeave autocommands. */ 6994 apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, FALSE, curbuf); 6995 6996 # ifdef FEAT_FOLDING 6997 /* Restore KeyTyped in case it is modified by autocommands */ 6998 KeyTyped = save_KeyTyped; 6999 # endif 7000 7001 # endif 7002 7003 /* Restore the command line info. */ 7004 restore_cmdline(&save_ccline); 7005 cmdwin_type = 0; 7006 7007 exmode_active = save_exmode; 7008 7009 /* Safety check: The old window or buffer was deleted: It's a bug when 7010 * this happens! */ 7011 if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf)) 7012 { 7013 cmdwin_result = Ctrl_C; 7014 EMSG(_("E199: Active window or buffer deleted")); 7015 } 7016 else 7017 { 7018 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 7019 /* autocmds may abort script processing */ 7020 if (aborting() && cmdwin_result != K_IGNORE) 7021 cmdwin_result = Ctrl_C; 7022 # endif 7023 /* Set the new command line from the cmdline buffer. */ 7024 vim_free(ccline.cmdbuff); 7025 if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) /* :qa[!] typed */ 7026 { 7027 char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!"; 7028 7029 if (histtype == HIST_CMD) 7030 { 7031 /* Execute the command directly. */ 7032 ccline.cmdbuff = vim_strsave((char_u *)p); 7033 cmdwin_result = CAR; 7034 } 7035 else 7036 { 7037 /* First need to cancel what we were doing. */ 7038 ccline.cmdbuff = NULL; 7039 stuffcharReadbuff(':'); 7040 stuffReadbuff((char_u *)p); 7041 stuffcharReadbuff(CAR); 7042 } 7043 } 7044 else if (cmdwin_result == K_XF2) /* :qa typed */ 7045 { 7046 ccline.cmdbuff = vim_strsave((char_u *)"qa"); 7047 cmdwin_result = CAR; 7048 } 7049 else if (cmdwin_result == Ctrl_C) 7050 { 7051 /* :q or :close, don't execute any command 7052 * and don't modify the cmd window. */ 7053 ccline.cmdbuff = NULL; 7054 } 7055 else 7056 ccline.cmdbuff = vim_strsave(ml_get_curline()); 7057 if (ccline.cmdbuff == NULL) 7058 { 7059 ccline.cmdbuff = vim_strsave((char_u *)""); 7060 ccline.cmdlen = 0; 7061 ccline.cmdbufflen = 1; 7062 ccline.cmdpos = 0; 7063 cmdwin_result = Ctrl_C; 7064 } 7065 else 7066 { 7067 ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); 7068 ccline.cmdbufflen = ccline.cmdlen + 1; 7069 ccline.cmdpos = curwin->w_cursor.col; 7070 if (ccline.cmdpos > ccline.cmdlen) 7071 ccline.cmdpos = ccline.cmdlen; 7072 if (cmdwin_result == K_IGNORE) 7073 { 7074 set_cmdspos_cursor(); 7075 redrawcmd(); 7076 } 7077 } 7078 7079 # ifdef FEAT_AUTOCMD 7080 /* Don't execute autocommands while deleting the window. */ 7081 block_autocmds(); 7082 # endif 7083 # ifdef FEAT_CONCEAL 7084 /* Avoid command-line window first character being concealed. */ 7085 curwin->w_p_cole = 0; 7086 # endif 7087 wp = curwin; 7088 set_bufref(&bufref, curbuf); 7089 win_goto(old_curwin); 7090 win_close(wp, TRUE); 7091 7092 /* win_close() may have already wiped the buffer when 'bh' is 7093 * set to 'wipe' */ 7094 if (bufref_valid(&bufref)) 7095 close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, FALSE); 7096 7097 /* Restore window sizes. */ 7098 win_size_restore(&winsizes); 7099 7100 # ifdef FEAT_AUTOCMD 7101 unblock_autocmds(); 7102 # endif 7103 } 7104 7105 ga_clear(&winsizes); 7106 restart_edit = save_restart_edit; 7107 # ifdef FEAT_RIGHTLEFT 7108 cmdmsg_rl = save_cmdmsg_rl; 7109 # endif 7110 7111 State = save_State; 7112 # ifdef FEAT_MOUSE 7113 setmouse(); 7114 # endif 7115 7116 return cmdwin_result; 7117 } 7118 #endif /* FEAT_CMDWIN */ 7119 7120 /* 7121 * Used for commands that either take a simple command string argument, or: 7122 * cmd << endmarker 7123 * {script} 7124 * endmarker 7125 * Returns a pointer to allocated memory with {script} or NULL. 7126 */ 7127 char_u * 7128 script_get(exarg_T *eap, char_u *cmd) 7129 { 7130 char_u *theline; 7131 char *end_pattern = NULL; 7132 char dot[] = "."; 7133 garray_T ga; 7134 7135 if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) 7136 return NULL; 7137 7138 ga_init2(&ga, 1, 0x400); 7139 7140 if (cmd[2] != NUL) 7141 end_pattern = (char *)skipwhite(cmd + 2); 7142 else 7143 end_pattern = dot; 7144 7145 for (;;) 7146 { 7147 theline = eap->getline( 7148 #ifdef FEAT_EVAL 7149 eap->cstack->cs_looplevel > 0 ? -1 : 7150 #endif 7151 NUL, eap->cookie, 0); 7152 7153 if (theline == NULL || STRCMP(end_pattern, theline) == 0) 7154 { 7155 vim_free(theline); 7156 break; 7157 } 7158 7159 ga_concat(&ga, theline); 7160 ga_append(&ga, '\n'); 7161 vim_free(theline); 7162 } 7163 ga_append(&ga, NUL); 7164 7165 return (char_u *)ga.ga_data; 7166 } 7167 7168 #ifdef FEAT_SEARCH_EXTRA 7169 static void 7170 set_search_match(pos_T *t) 7171 { 7172 /* 7173 * First move cursor to end of match, then to the start. This 7174 * moves the whole match onto the screen when 'nowrap' is set. 7175 */ 7176 t->lnum += search_match_lines; 7177 t->col = search_match_endcol; 7178 if (t->lnum > curbuf->b_ml.ml_line_count) 7179 { 7180 t->lnum = curbuf->b_ml.ml_line_count; 7181 coladvance((colnr_T)MAXCOL); 7182 } 7183 } 7184 #endif 7185