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 * cmdexpand.c: functions for command-line completion 12 */ 13 14 #include "vim.h" 15 16 static int cmd_showtail; // Only show path tail in lists ? 17 18 static void set_expand_context(expand_T *xp); 19 static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, 20 int *num_file, char_u ***file, 21 char_u *((*func)(expand_T *, int)), int escaped); 22 static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int); 23 static int expand_showtail(expand_T *xp); 24 static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg); 25 #if defined(FEAT_EVAL) 26 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); 27 static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); 28 #endif 29 30 static int 31 sort_func_compare(const void *s1, const void *s2) 32 { 33 char_u *p1 = *(char_u **)s1; 34 char_u *p2 = *(char_u **)s2; 35 36 if (*p1 != '<' && *p2 == '<') return -1; 37 if (*p1 == '<' && *p2 != '<') return 1; 38 return STRCMP(p1, p2); 39 } 40 41 static void 42 ExpandEscape( 43 expand_T *xp, 44 char_u *str, 45 int numfiles, 46 char_u **files, 47 int options) 48 { 49 int i; 50 char_u *p; 51 52 // May change home directory back to "~" 53 if (options & WILD_HOME_REPLACE) 54 tilde_replace(str, numfiles, files); 55 56 if (options & WILD_ESCAPE) 57 { 58 if (xp->xp_context == EXPAND_FILES 59 || xp->xp_context == EXPAND_FILES_IN_PATH 60 || xp->xp_context == EXPAND_SHELLCMD 61 || xp->xp_context == EXPAND_BUFFERS 62 || xp->xp_context == EXPAND_DIRECTORIES) 63 { 64 // Insert a backslash into a file name before a space, \, %, # 65 // and wildmatch characters, except '~'. 66 for (i = 0; i < numfiles; ++i) 67 { 68 // for ":set path=" we need to escape spaces twice 69 if (xp->xp_backslash == XP_BS_THREE) 70 { 71 p = vim_strsave_escaped(files[i], (char_u *)" "); 72 if (p != NULL) 73 { 74 vim_free(files[i]); 75 files[i] = p; 76 #if defined(BACKSLASH_IN_FILENAME) 77 p = vim_strsave_escaped(files[i], (char_u *)" "); 78 if (p != NULL) 79 { 80 vim_free(files[i]); 81 files[i] = p; 82 } 83 #endif 84 } 85 } 86 #ifdef BACKSLASH_IN_FILENAME 87 p = vim_strsave_fnameescape(files[i], FALSE); 88 #else 89 p = vim_strsave_fnameescape(files[i], xp->xp_shell); 90 #endif 91 if (p != NULL) 92 { 93 vim_free(files[i]); 94 files[i] = p; 95 } 96 97 // If 'str' starts with "\~", replace "~" at start of 98 // files[i] with "\~". 99 if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') 100 escape_fname(&files[i]); 101 } 102 xp->xp_backslash = XP_BS_NONE; 103 104 // If the first file starts with a '+' escape it. Otherwise it 105 // could be seen as "+cmd". 106 if (*files[0] == '+') 107 escape_fname(&files[0]); 108 } 109 else if (xp->xp_context == EXPAND_TAGS) 110 { 111 // Insert a backslash before characters in a tag name that 112 // would terminate the ":tag" command. 113 for (i = 0; i < numfiles; ++i) 114 { 115 p = vim_strsave_escaped(files[i], (char_u *)"\\|\""); 116 if (p != NULL) 117 { 118 vim_free(files[i]); 119 files[i] = p; 120 } 121 } 122 } 123 } 124 } 125 126 /* 127 * Return FAIL if this is not an appropriate context in which to do 128 * completion of anything, return OK if it is (even if there are no matches). 129 * For the caller, this means that the character is just passed through like a 130 * normal character (instead of being expanded). This allows :s/^I^D etc. 131 */ 132 int 133 nextwild( 134 expand_T *xp, 135 int type, 136 int options, // extra options for ExpandOne() 137 int escape) // if TRUE, escape the returned matches 138 { 139 cmdline_info_T *ccline = get_cmdline_info(); 140 int i, j; 141 char_u *p1; 142 char_u *p2; 143 int difflen; 144 int v; 145 146 if (xp->xp_numfiles == -1) 147 { 148 set_expand_context(xp); 149 cmd_showtail = expand_showtail(xp); 150 } 151 152 if (xp->xp_context == EXPAND_UNSUCCESSFUL) 153 { 154 beep_flush(); 155 return OK; // Something illegal on command line 156 } 157 if (xp->xp_context == EXPAND_NOTHING) 158 { 159 // Caller can use the character as a normal char instead 160 return FAIL; 161 } 162 163 msg_puts("..."); // show that we are busy 164 out_flush(); 165 166 i = (int)(xp->xp_pattern - ccline->cmdbuff); 167 xp->xp_pattern_len = ccline->cmdpos - i; 168 169 if (type == WILD_NEXT || type == WILD_PREV) 170 { 171 // Get next/previous match for a previous expanded pattern. 172 p2 = ExpandOne(xp, NULL, NULL, 0, type); 173 } 174 else 175 { 176 // Translate string into pattern and expand it. 177 if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, 178 xp->xp_context)) == NULL) 179 p2 = NULL; 180 else 181 { 182 int use_options = options | 183 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; 184 if (escape) 185 use_options |= WILD_ESCAPE; 186 187 if (p_wic) 188 use_options += WILD_ICASE; 189 p2 = ExpandOne(xp, p1, 190 vim_strnsave(&ccline->cmdbuff[i], xp->xp_pattern_len), 191 use_options, type); 192 vim_free(p1); 193 // longest match: make sure it is not shorter, happens with :help 194 if (p2 != NULL && type == WILD_LONGEST) 195 { 196 for (j = 0; j < xp->xp_pattern_len; ++j) 197 if (ccline->cmdbuff[i + j] == '*' 198 || ccline->cmdbuff[i + j] == '?') 199 break; 200 if ((int)STRLEN(p2) < j) 201 VIM_CLEAR(p2); 202 } 203 } 204 } 205 206 if (p2 != NULL && !got_int) 207 { 208 difflen = (int)STRLEN(p2) - xp->xp_pattern_len; 209 if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen) 210 { 211 v = realloc_cmdbuff(ccline->cmdlen + difflen + 4); 212 xp->xp_pattern = ccline->cmdbuff + i; 213 } 214 else 215 v = OK; 216 if (v == OK) 217 { 218 mch_memmove(&ccline->cmdbuff[ccline->cmdpos + difflen], 219 &ccline->cmdbuff[ccline->cmdpos], 220 (size_t)(ccline->cmdlen - ccline->cmdpos + 1)); 221 mch_memmove(&ccline->cmdbuff[i], p2, STRLEN(p2)); 222 ccline->cmdlen += difflen; 223 ccline->cmdpos += difflen; 224 } 225 } 226 vim_free(p2); 227 228 redrawcmd(); 229 cursorcmd(); 230 231 // When expanding a ":map" command and no matches are found, assume that 232 // the key is supposed to be inserted literally 233 if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL) 234 return FAIL; 235 236 if (xp->xp_numfiles <= 0 && p2 == NULL) 237 beep_flush(); 238 else if (xp->xp_numfiles == 1) 239 // free expanded pattern 240 (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE); 241 242 return OK; 243 } 244 245 /* 246 * Do wildcard expansion on the string 'str'. 247 * Chars that should not be expanded must be preceded with a backslash. 248 * Return a pointer to allocated memory containing the new string. 249 * Return NULL for failure. 250 * 251 * "orig" is the originally expanded string, copied to allocated memory. It 252 * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or 253 * WILD_PREV "orig" should be NULL. 254 * 255 * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode" 256 * is WILD_EXPAND_FREE or WILD_ALL. 257 * 258 * mode = WILD_FREE: just free previously expanded matches 259 * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches 260 * mode = WILD_EXPAND_KEEP: normal expansion, keep matches 261 * mode = WILD_NEXT: use next match in multiple match, wrap to first 262 * mode = WILD_PREV: use previous match in multiple match, wrap to first 263 * mode = WILD_ALL: return all matches concatenated 264 * mode = WILD_LONGEST: return longest matched part 265 * mode = WILD_ALL_KEEP: get all matches, keep matches 266 * 267 * options = WILD_LIST_NOTFOUND: list entries without a match 268 * options = WILD_HOME_REPLACE: do home_replace() for buffer names 269 * options = WILD_USE_NL: Use '\n' for WILD_ALL 270 * options = WILD_NO_BEEP: Don't beep for multiple matches 271 * options = WILD_ADD_SLASH: add a slash after directory names 272 * options = WILD_KEEP_ALL: don't remove 'wildignore' entries 273 * options = WILD_SILENT: don't print warning messages 274 * options = WILD_ESCAPE: put backslash before special chars 275 * options = WILD_ICASE: ignore case for files 276 * options = WILD_ALLLINKS; keep broken links 277 * 278 * The variables xp->xp_context and xp->xp_backslash must have been set! 279 */ 280 char_u * 281 ExpandOne( 282 expand_T *xp, 283 char_u *str, 284 char_u *orig, // allocated copy of original of expanded string 285 int options, 286 int mode) 287 { 288 char_u *ss = NULL; 289 static int findex; 290 static char_u *orig_save = NULL; // kept value of orig 291 int orig_saved = FALSE; 292 int i; 293 long_u len; 294 int non_suf_match; // number without matching suffix 295 296 // first handle the case of using an old match 297 if (mode == WILD_NEXT || mode == WILD_PREV) 298 { 299 if (xp->xp_numfiles > 0) 300 { 301 if (mode == WILD_PREV) 302 { 303 if (findex == -1) 304 findex = xp->xp_numfiles; 305 --findex; 306 } 307 else // mode == WILD_NEXT 308 ++findex; 309 310 // When wrapping around, return the original string, set findex to 311 // -1. 312 if (findex < 0) 313 { 314 if (orig_save == NULL) 315 findex = xp->xp_numfiles - 1; 316 else 317 findex = -1; 318 } 319 if (findex >= xp->xp_numfiles) 320 { 321 if (orig_save == NULL) 322 findex = 0; 323 else 324 findex = -1; 325 } 326 #ifdef FEAT_WILDMENU 327 if (p_wmnu) 328 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, 329 findex, cmd_showtail); 330 #endif 331 if (findex == -1) 332 return vim_strsave(orig_save); 333 return vim_strsave(xp->xp_files[findex]); 334 } 335 else 336 return NULL; 337 } 338 339 // free old names 340 if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) 341 { 342 FreeWild(xp->xp_numfiles, xp->xp_files); 343 xp->xp_numfiles = -1; 344 VIM_CLEAR(orig_save); 345 } 346 findex = 0; 347 348 if (mode == WILD_FREE) // only release file name 349 return NULL; 350 351 if (xp->xp_numfiles == -1) 352 { 353 vim_free(orig_save); 354 orig_save = orig; 355 orig_saved = TRUE; 356 357 // Do the expansion. 358 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files, 359 options) == FAIL) 360 { 361 #ifdef FNAME_ILLEGAL 362 // Illegal file name has been silently skipped. But when there 363 // are wildcards, the real problem is that there was no match, 364 // causing the pattern to be added, which has illegal characters. 365 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) 366 semsg(_(e_nomatch2), str); 367 #endif 368 } 369 else if (xp->xp_numfiles == 0) 370 { 371 if (!(options & WILD_SILENT)) 372 semsg(_(e_nomatch2), str); 373 } 374 else 375 { 376 // Escape the matches for use on the command line. 377 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options); 378 379 // Check for matching suffixes in file names. 380 if (mode != WILD_ALL && mode != WILD_ALL_KEEP 381 && mode != WILD_LONGEST) 382 { 383 if (xp->xp_numfiles) 384 non_suf_match = xp->xp_numfiles; 385 else 386 non_suf_match = 1; 387 if ((xp->xp_context == EXPAND_FILES 388 || xp->xp_context == EXPAND_DIRECTORIES) 389 && xp->xp_numfiles > 1) 390 { 391 // More than one match; check suffix. 392 // The files will have been sorted on matching suffix in 393 // expand_wildcards, only need to check the first two. 394 non_suf_match = 0; 395 for (i = 0; i < 2; ++i) 396 if (match_suffix(xp->xp_files[i])) 397 ++non_suf_match; 398 } 399 if (non_suf_match != 1) 400 { 401 // Can we ever get here unless it's while expanding 402 // interactively? If not, we can get rid of this all 403 // together. Don't really want to wait for this message 404 // (and possibly have to hit return to continue!). 405 if (!(options & WILD_SILENT)) 406 emsg(_(e_toomany)); 407 else if (!(options & WILD_NO_BEEP)) 408 beep_flush(); 409 } 410 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) 411 ss = vim_strsave(xp->xp_files[0]); 412 } 413 } 414 } 415 416 // Find longest common part 417 if (mode == WILD_LONGEST && xp->xp_numfiles > 0) 418 { 419 int mb_len = 1; 420 int c0, ci; 421 422 for (len = 0; xp->xp_files[0][len]; len += mb_len) 423 { 424 if (has_mbyte) 425 { 426 mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]); 427 c0 =(* mb_ptr2char)(&xp->xp_files[0][len]); 428 } 429 else 430 c0 = xp->xp_files[0][len]; 431 for (i = 1; i < xp->xp_numfiles; ++i) 432 { 433 if (has_mbyte) 434 ci =(* mb_ptr2char)(&xp->xp_files[i][len]); 435 else 436 ci = xp->xp_files[i][len]; 437 if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES 438 || xp->xp_context == EXPAND_FILES 439 || xp->xp_context == EXPAND_SHELLCMD 440 || xp->xp_context == EXPAND_BUFFERS)) 441 { 442 if (MB_TOLOWER(c0) != MB_TOLOWER(ci)) 443 break; 444 } 445 else if (c0 != ci) 446 break; 447 } 448 if (i < xp->xp_numfiles) 449 { 450 if (!(options & WILD_NO_BEEP)) 451 vim_beep(BO_WILD); 452 break; 453 } 454 } 455 456 ss = alloc(len + 1); 457 if (ss) 458 vim_strncpy(ss, xp->xp_files[0], (size_t)len); 459 findex = -1; // next p_wc gets first one 460 } 461 462 // Concatenate all matching names 463 if (mode == WILD_ALL && xp->xp_numfiles > 0) 464 { 465 len = 0; 466 for (i = 0; i < xp->xp_numfiles; ++i) 467 len += (long_u)STRLEN(xp->xp_files[i]) + 1; 468 ss = alloc(len); 469 if (ss != NULL) 470 { 471 *ss = NUL; 472 for (i = 0; i < xp->xp_numfiles; ++i) 473 { 474 STRCAT(ss, xp->xp_files[i]); 475 if (i != xp->xp_numfiles - 1) 476 STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " "); 477 } 478 } 479 } 480 481 if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) 482 ExpandCleanup(xp); 483 484 // Free "orig" if it wasn't stored in "orig_save". 485 if (!orig_saved) 486 vim_free(orig); 487 488 return ss; 489 } 490 491 /* 492 * Prepare an expand structure for use. 493 */ 494 void 495 ExpandInit(expand_T *xp) 496 { 497 CLEAR_POINTER(xp); 498 xp->xp_backslash = XP_BS_NONE; 499 xp->xp_numfiles = -1; 500 } 501 502 /* 503 * Cleanup an expand structure after use. 504 */ 505 void 506 ExpandCleanup(expand_T *xp) 507 { 508 if (xp->xp_numfiles >= 0) 509 { 510 FreeWild(xp->xp_numfiles, xp->xp_files); 511 xp->xp_numfiles = -1; 512 } 513 } 514 515 /* 516 * Show all matches for completion on the command line. 517 * Returns EXPAND_NOTHING when the character that triggered expansion should 518 * be inserted like a normal character. 519 */ 520 int 521 showmatches(expand_T *xp, int wildmenu UNUSED) 522 { 523 cmdline_info_T *ccline = get_cmdline_info(); 524 #define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m]) 525 int num_files; 526 char_u **files_found; 527 int i, j, k; 528 int maxlen; 529 int lines; 530 int columns; 531 char_u *p; 532 int lastlen; 533 int attr; 534 int showtail; 535 536 if (xp->xp_numfiles == -1) 537 { 538 set_expand_context(xp); 539 i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos, 540 &num_files, &files_found); 541 showtail = expand_showtail(xp); 542 if (i != EXPAND_OK) 543 return i; 544 545 } 546 else 547 { 548 num_files = xp->xp_numfiles; 549 files_found = xp->xp_files; 550 showtail = cmd_showtail; 551 } 552 553 #ifdef FEAT_WILDMENU 554 if (!wildmenu) 555 { 556 #endif 557 msg_didany = FALSE; // lines_left will be set 558 msg_start(); // prepare for paging 559 msg_putchar('\n'); 560 out_flush(); 561 cmdline_row = msg_row; 562 msg_didany = FALSE; // lines_left will be set again 563 msg_start(); // prepare for paging 564 #ifdef FEAT_WILDMENU 565 } 566 #endif 567 568 if (got_int) 569 got_int = FALSE; // only int. the completion, not the cmd line 570 #ifdef FEAT_WILDMENU 571 else if (wildmenu) 572 win_redr_status_matches(xp, num_files, files_found, -1, showtail); 573 #endif 574 else 575 { 576 // find the length of the longest file name 577 maxlen = 0; 578 for (i = 0; i < num_files; ++i) 579 { 580 if (!showtail && (xp->xp_context == EXPAND_FILES 581 || xp->xp_context == EXPAND_SHELLCMD 582 || xp->xp_context == EXPAND_BUFFERS)) 583 { 584 home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE); 585 j = vim_strsize(NameBuff); 586 } 587 else 588 j = vim_strsize(L_SHOWFILE(i)); 589 if (j > maxlen) 590 maxlen = j; 591 } 592 593 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 594 lines = num_files; 595 else 596 { 597 // compute the number of columns and lines for the listing 598 maxlen += 2; // two spaces between file names 599 columns = ((int)Columns + 2) / maxlen; 600 if (columns < 1) 601 columns = 1; 602 lines = (num_files + columns - 1) / columns; 603 } 604 605 attr = HL_ATTR(HLF_D); // find out highlighting for directories 606 607 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 608 { 609 msg_puts_attr(_("tagname"), HL_ATTR(HLF_T)); 610 msg_clr_eos(); 611 msg_advance(maxlen - 3); 612 msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T)); 613 } 614 615 // list the files line by line 616 for (i = 0; i < lines; ++i) 617 { 618 lastlen = 999; 619 for (k = i; k < num_files; k += lines) 620 { 621 if (xp->xp_context == EXPAND_TAGS_LISTFILES) 622 { 623 msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D)); 624 p = files_found[k] + STRLEN(files_found[k]) + 1; 625 msg_advance(maxlen + 1); 626 msg_puts((char *)p); 627 msg_advance(maxlen + 3); 628 msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D)); 629 break; 630 } 631 for (j = maxlen - lastlen; --j >= 0; ) 632 msg_putchar(' '); 633 if (xp->xp_context == EXPAND_FILES 634 || xp->xp_context == EXPAND_SHELLCMD 635 || xp->xp_context == EXPAND_BUFFERS) 636 { 637 // highlight directories 638 if (xp->xp_numfiles != -1) 639 { 640 char_u *halved_slash; 641 char_u *exp_path; 642 char_u *path; 643 644 // Expansion was done before and special characters 645 // were escaped, need to halve backslashes. Also 646 // $HOME has been replaced with ~/. 647 exp_path = expand_env_save_opt(files_found[k], TRUE); 648 path = exp_path != NULL ? exp_path : files_found[k]; 649 halved_slash = backslash_halve_save(path); 650 j = mch_isdir(halved_slash != NULL ? halved_slash 651 : files_found[k]); 652 vim_free(exp_path); 653 if (halved_slash != path) 654 vim_free(halved_slash); 655 } 656 else 657 // Expansion was done here, file names are literal. 658 j = mch_isdir(files_found[k]); 659 if (showtail) 660 p = L_SHOWFILE(k); 661 else 662 { 663 home_replace(NULL, files_found[k], NameBuff, MAXPATHL, 664 TRUE); 665 p = NameBuff; 666 } 667 } 668 else 669 { 670 j = FALSE; 671 p = L_SHOWFILE(k); 672 } 673 lastlen = msg_outtrans_attr(p, j ? attr : 0); 674 } 675 if (msg_col > 0) // when not wrapped around 676 { 677 msg_clr_eos(); 678 msg_putchar('\n'); 679 } 680 out_flush(); // show one line at a time 681 if (got_int) 682 { 683 got_int = FALSE; 684 break; 685 } 686 } 687 688 // we redraw the command below the lines that we have just listed 689 // This is a bit tricky, but it saves a lot of screen updating. 690 cmdline_row = msg_row; // will put it back later 691 } 692 693 if (xp->xp_numfiles == -1) 694 FreeWild(num_files, files_found); 695 696 return EXPAND_OK; 697 } 698 699 /* 700 * Private gettail for showmatches() (and win_redr_status_matches()): 701 * Find tail of file name path, but ignore trailing "/". 702 */ 703 char_u * 704 sm_gettail(char_u *s) 705 { 706 char_u *p; 707 char_u *t = s; 708 int had_sep = FALSE; 709 710 for (p = s; *p != NUL; ) 711 { 712 if (vim_ispathsep(*p) 713 #ifdef BACKSLASH_IN_FILENAME 714 && !rem_backslash(p) 715 #endif 716 ) 717 had_sep = TRUE; 718 else if (had_sep) 719 { 720 t = p; 721 had_sep = FALSE; 722 } 723 MB_PTR_ADV(p); 724 } 725 return t; 726 } 727 728 /* 729 * Return TRUE if we only need to show the tail of completion matches. 730 * When not completing file names or there is a wildcard in the path FALSE is 731 * returned. 732 */ 733 static int 734 expand_showtail(expand_T *xp) 735 { 736 char_u *s; 737 char_u *end; 738 739 // When not completing file names a "/" may mean something different. 740 if (xp->xp_context != EXPAND_FILES 741 && xp->xp_context != EXPAND_SHELLCMD 742 && xp->xp_context != EXPAND_DIRECTORIES) 743 return FALSE; 744 745 end = gettail(xp->xp_pattern); 746 if (end == xp->xp_pattern) // there is no path separator 747 return FALSE; 748 749 for (s = xp->xp_pattern; s < end; s++) 750 { 751 // Skip escaped wildcards. Only when the backslash is not a path 752 // separator, on DOS the '*' "path\*\file" must not be skipped. 753 if (rem_backslash(s)) 754 ++s; 755 else if (vim_strchr((char_u *)"*?[", *s) != NULL) 756 return FALSE; 757 } 758 return TRUE; 759 } 760 761 /* 762 * Prepare a string for expansion. 763 * When expanding file names: The string will be used with expand_wildcards(). 764 * Copy "fname[len]" into allocated memory and add a '*' at the end. 765 * When expanding other names: The string will be used with regcomp(). Copy 766 * the name into allocated memory and prepend "^". 767 */ 768 char_u * 769 addstar( 770 char_u *fname, 771 int len, 772 int context) // EXPAND_FILES etc. 773 { 774 char_u *retval; 775 int i, j; 776 int new_len; 777 char_u *tail; 778 int ends_in_star; 779 780 if (context != EXPAND_FILES 781 && context != EXPAND_FILES_IN_PATH 782 && context != EXPAND_SHELLCMD 783 && context != EXPAND_DIRECTORIES) 784 { 785 // Matching will be done internally (on something other than files). 786 // So we convert the file-matching-type wildcards into our kind for 787 // use with vim_regcomp(). First work out how long it will be: 788 789 // For help tags the translation is done in find_help_tags(). 790 // For a tag pattern starting with "/" no translation is needed. 791 if (context == EXPAND_HELP 792 || context == EXPAND_COLORS 793 || context == EXPAND_COMPILER 794 || context == EXPAND_OWNSYNTAX 795 || context == EXPAND_FILETYPE 796 || context == EXPAND_PACKADD 797 || ((context == EXPAND_TAGS_LISTFILES 798 || context == EXPAND_TAGS) 799 && fname[0] == '/')) 800 retval = vim_strnsave(fname, len); 801 else 802 { 803 new_len = len + 2; // +2 for '^' at start, NUL at end 804 for (i = 0; i < len; i++) 805 { 806 if (fname[i] == '*' || fname[i] == '~') 807 new_len++; // '*' needs to be replaced by ".*" 808 // '~' needs to be replaced by "\~" 809 810 // Buffer names are like file names. "." should be literal 811 if (context == EXPAND_BUFFERS && fname[i] == '.') 812 new_len++; // "." becomes "\." 813 814 // Custom expansion takes care of special things, match 815 // backslashes literally (perhaps also for other types?) 816 if ((context == EXPAND_USER_DEFINED 817 || context == EXPAND_USER_LIST) && fname[i] == '\\') 818 new_len++; // '\' becomes "\\" 819 } 820 retval = alloc(new_len); 821 if (retval != NULL) 822 { 823 retval[0] = '^'; 824 j = 1; 825 for (i = 0; i < len; i++, j++) 826 { 827 // Skip backslash. But why? At least keep it for custom 828 // expansion. 829 if (context != EXPAND_USER_DEFINED 830 && context != EXPAND_USER_LIST 831 && fname[i] == '\\' 832 && ++i == len) 833 break; 834 835 switch (fname[i]) 836 { 837 case '*': retval[j++] = '.'; 838 break; 839 case '~': retval[j++] = '\\'; 840 break; 841 case '?': retval[j] = '.'; 842 continue; 843 case '.': if (context == EXPAND_BUFFERS) 844 retval[j++] = '\\'; 845 break; 846 case '\\': if (context == EXPAND_USER_DEFINED 847 || context == EXPAND_USER_LIST) 848 retval[j++] = '\\'; 849 break; 850 } 851 retval[j] = fname[i]; 852 } 853 retval[j] = NUL; 854 } 855 } 856 } 857 else 858 { 859 retval = alloc(len + 4); 860 if (retval != NULL) 861 { 862 vim_strncpy(retval, fname, len); 863 864 // Don't add a star to *, ~, ~user, $var or `cmd`. 865 // * would become **, which walks the whole tree. 866 // ~ would be at the start of the file name, but not the tail. 867 // $ could be anywhere in the tail. 868 // ` could be anywhere in the file name. 869 // When the name ends in '$' don't add a star, remove the '$'. 870 tail = gettail(retval); 871 ends_in_star = (len > 0 && retval[len - 1] == '*'); 872 #ifndef BACKSLASH_IN_FILENAME 873 for (i = len - 2; i >= 0; --i) 874 { 875 if (retval[i] != '\\') 876 break; 877 ends_in_star = !ends_in_star; 878 } 879 #endif 880 if ((*retval != '~' || tail != retval) 881 && !ends_in_star 882 && vim_strchr(tail, '$') == NULL 883 && vim_strchr(retval, '`') == NULL) 884 retval[len++] = '*'; 885 else if (len > 0 && retval[len - 1] == '$') 886 --len; 887 retval[len] = NUL; 888 } 889 } 890 return retval; 891 } 892 893 /* 894 * Must parse the command line so far to work out what context we are in. 895 * Completion can then be done based on that context. 896 * This routine sets the variables: 897 * xp->xp_pattern The start of the pattern to be expanded within 898 * the command line (ends at the cursor). 899 * xp->xp_context The type of thing to expand. Will be one of: 900 * 901 * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on 902 * the command line, like an unknown command. Caller 903 * should beep. 904 * EXPAND_NOTHING Unrecognised context for completion, use char like 905 * a normal char, rather than for completion. eg 906 * :s/^I/ 907 * EXPAND_COMMANDS Cursor is still touching the command, so complete 908 * it. 909 * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. 910 * EXPAND_FILES After command with EX_XFILE set, or after setting 911 * with P_EXPAND set. eg :e ^I, :w>>^I 912 * EXPAND_DIRECTORIES In some cases this is used instead of the latter 913 * when we know only directories are of interest. eg 914 * :set dir=^I 915 * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd". 916 * EXPAND_SETTINGS Complete variable names. eg :set d^I 917 * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I 918 * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I 919 * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect 920 * EXPAND_HELP Complete tags from the file 'helpfile'/tags 921 * EXPAND_EVENTS Complete event names 922 * EXPAND_SYNTAX Complete :syntax command arguments 923 * EXPAND_HIGHLIGHT Complete highlight (syntax) group names 924 * EXPAND_AUGROUP Complete autocommand group names 925 * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I 926 * EXPAND_MAPPINGS Complete mapping and abbreviation names, 927 * eg :unmap a^I , :cunab x^I 928 * EXPAND_FUNCTIONS Complete internal or user defined function names, 929 * eg :call sub^I 930 * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I 931 * EXPAND_EXPRESSION Complete internal or user defined function/variable 932 * names in expressions, eg :while s^I 933 * EXPAND_ENV_VARS Complete environment variable names 934 * EXPAND_USER Complete user names 935 */ 936 static void 937 set_expand_context(expand_T *xp) 938 { 939 cmdline_info_T *ccline = get_cmdline_info(); 940 941 // only expansion for ':', '>' and '=' command-lines 942 if (ccline->cmdfirstc != ':' 943 #ifdef FEAT_EVAL 944 && ccline->cmdfirstc != '>' && ccline->cmdfirstc != '=' 945 && !ccline->input_fn 946 #endif 947 ) 948 { 949 xp->xp_context = EXPAND_NOTHING; 950 return; 951 } 952 set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, TRUE); 953 } 954 955 /* 956 * This is all pretty much copied from do_one_cmd(), with all the extra stuff 957 * we don't need/want deleted. Maybe this could be done better if we didn't 958 * repeat all this stuff. The only problem is that they may not stay 959 * perfectly compatible with each other, but then the command line syntax 960 * probably won't change that much -- webb. 961 */ 962 static char_u * 963 set_one_cmd_context( 964 expand_T *xp, 965 char_u *buff) // buffer for command string 966 { 967 char_u *p; 968 char_u *cmd, *arg; 969 int len = 0; 970 exarg_T ea; 971 int compl = EXPAND_NOTHING; 972 int delim; 973 int forceit = FALSE; 974 int usefilter = FALSE; // filter instead of file name 975 976 ExpandInit(xp); 977 xp->xp_pattern = buff; 978 xp->xp_context = EXPAND_COMMANDS; // Default until we get past command 979 ea.argt = 0; 980 981 // 1. skip comment lines and leading space, colons or bars 982 for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++) 983 ; 984 xp->xp_pattern = cmd; 985 986 if (*cmd == NUL) 987 return NULL; 988 if (*cmd == '"') // ignore comment lines 989 { 990 xp->xp_context = EXPAND_NOTHING; 991 return NULL; 992 } 993 994 // 3. Skip over the range to find the command. 995 cmd = skip_range(cmd, TRUE, &xp->xp_context); 996 xp->xp_pattern = cmd; 997 if (*cmd == NUL) 998 return NULL; 999 if (*cmd == '"') 1000 { 1001 xp->xp_context = EXPAND_NOTHING; 1002 return NULL; 1003 } 1004 1005 if (*cmd == '|' || *cmd == '\n') 1006 return cmd + 1; // There's another command 1007 1008 // Isolate the command and search for it in the command table. 1009 // Exceptions: 1010 // - the 'k' command can directly be followed by any character, but 1011 // do accept "keepmarks", "keepalt" and "keepjumps". 1012 // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' 1013 if (*cmd == 'k' && cmd[1] != 'e') 1014 { 1015 ea.cmdidx = CMD_k; 1016 p = cmd + 1; 1017 } 1018 else 1019 { 1020 p = cmd; 1021 while (ASCII_ISALPHA(*p) || *p == '*') // Allow * wild card 1022 ++p; 1023 // A user command may contain digits. 1024 // Include "9" for "vim9*" commands; "vim9cmd" and "vim9script". 1025 if (ASCII_ISUPPER(cmd[0]) || STRNCMP("vim9", cmd, 4) == 0) 1026 while (ASCII_ISALNUM(*p) || *p == '*') 1027 ++p; 1028 // for python 3.x: ":py3*" commands completion 1029 if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3') 1030 { 1031 ++p; 1032 while (ASCII_ISALPHA(*p) || *p == '*') 1033 ++p; 1034 } 1035 // check for non-alpha command 1036 if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) 1037 ++p; 1038 len = (int)(p - cmd); 1039 1040 if (len == 0) 1041 { 1042 xp->xp_context = EXPAND_UNSUCCESSFUL; 1043 return NULL; 1044 } 1045 1046 ea.cmdidx = excmd_get_cmdidx(cmd, len); 1047 1048 if (cmd[0] >= 'A' && cmd[0] <= 'Z') 1049 while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card 1050 ++p; 1051 } 1052 1053 // If the cursor is touching the command, and it ends in an alphanumeric 1054 // character, complete the command name. 1055 if (*p == NUL && ASCII_ISALNUM(p[-1])) 1056 return NULL; 1057 1058 if (ea.cmdidx == CMD_SIZE) 1059 { 1060 if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) 1061 { 1062 ea.cmdidx = CMD_substitute; 1063 p = cmd + 1; 1064 } 1065 else if (cmd[0] >= 'A' && cmd[0] <= 'Z') 1066 { 1067 ea.cmd = cmd; 1068 p = find_ucmd(&ea, p, NULL, xp, &compl); 1069 if (p == NULL) 1070 ea.cmdidx = CMD_SIZE; // ambiguous user command 1071 } 1072 } 1073 if (ea.cmdidx == CMD_SIZE) 1074 { 1075 // Not still touching the command and it was an illegal one 1076 xp->xp_context = EXPAND_UNSUCCESSFUL; 1077 return NULL; 1078 } 1079 1080 xp->xp_context = EXPAND_NOTHING; // Default now that we're past command 1081 1082 if (*p == '!') // forced commands 1083 { 1084 forceit = TRUE; 1085 ++p; 1086 } 1087 1088 // 6. parse arguments 1089 if (!IS_USER_CMDIDX(ea.cmdidx)) 1090 ea.argt = excmd_get_argt(ea.cmdidx); 1091 1092 arg = skipwhite(p); 1093 1094 // Skip over ++argopt argument 1095 if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0) 1096 { 1097 p = arg; 1098 while (*p && !vim_isspace(*p)) 1099 MB_PTR_ADV(p); 1100 arg = skipwhite(p); 1101 } 1102 1103 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) 1104 { 1105 if (*arg == '>') // append 1106 { 1107 if (*++arg == '>') 1108 ++arg; 1109 arg = skipwhite(arg); 1110 } 1111 else if (*arg == '!' && ea.cmdidx == CMD_write) // :w !filter 1112 { 1113 ++arg; 1114 usefilter = TRUE; 1115 } 1116 } 1117 1118 if (ea.cmdidx == CMD_read) 1119 { 1120 usefilter = forceit; // :r! filter if forced 1121 if (*arg == '!') // :r !filter 1122 { 1123 ++arg; 1124 usefilter = TRUE; 1125 } 1126 } 1127 1128 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) 1129 { 1130 while (*arg == *cmd) // allow any number of '>' or '<' 1131 ++arg; 1132 arg = skipwhite(arg); 1133 } 1134 1135 // Does command allow "+command"? 1136 if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') 1137 { 1138 // Check if we're in the +command 1139 p = arg + 1; 1140 arg = skip_cmd_arg(arg, FALSE); 1141 1142 // Still touching the command after '+'? 1143 if (*arg == NUL) 1144 return p; 1145 1146 // Skip space(s) after +command to get to the real argument 1147 arg = skipwhite(arg); 1148 } 1149 1150 1151 // Check for '|' to separate commands and '"' to start comments. 1152 // Don't do this for ":read !cmd" and ":write !cmd". 1153 if ((ea.argt & EX_TRLBAR) && !usefilter) 1154 { 1155 p = arg; 1156 // ":redir @" is not the start of a comment 1157 if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') 1158 p += 2; 1159 while (*p) 1160 { 1161 if (*p == Ctrl_V) 1162 { 1163 if (p[1] != NUL) 1164 ++p; 1165 } 1166 else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM)) 1167 || *p == '|' || *p == '\n') 1168 { 1169 if (*(p - 1) != '\\') 1170 { 1171 if (*p == '|' || *p == '\n') 1172 return p + 1; 1173 return NULL; // It's a comment 1174 } 1175 } 1176 MB_PTR_ADV(p); 1177 } 1178 } 1179 1180 if (!(ea.argt & EX_EXTRA) && *arg != NUL 1181 && vim_strchr((char_u *)"|\"", *arg) == NULL) 1182 // no arguments allowed but there is something 1183 return NULL; 1184 1185 // Find start of last argument (argument just before cursor): 1186 p = buff; 1187 xp->xp_pattern = p; 1188 len = (int)STRLEN(buff); 1189 while (*p && p < buff + len) 1190 { 1191 if (*p == ' ' || *p == TAB) 1192 { 1193 // argument starts after a space 1194 xp->xp_pattern = ++p; 1195 } 1196 else 1197 { 1198 if (*p == '\\' && *(p + 1) != NUL) 1199 ++p; // skip over escaped character 1200 MB_PTR_ADV(p); 1201 } 1202 } 1203 1204 if (ea.argt & EX_XFILE) 1205 { 1206 int c; 1207 int in_quote = FALSE; 1208 char_u *bow = NULL; // Beginning of word 1209 1210 // Allow spaces within back-quotes to count as part of the argument 1211 // being expanded. 1212 xp->xp_pattern = skipwhite(arg); 1213 p = xp->xp_pattern; 1214 while (*p != NUL) 1215 { 1216 if (has_mbyte) 1217 c = mb_ptr2char(p); 1218 else 1219 c = *p; 1220 if (c == '\\' && p[1] != NUL) 1221 ++p; 1222 else if (c == '`') 1223 { 1224 if (!in_quote) 1225 { 1226 xp->xp_pattern = p; 1227 bow = p + 1; 1228 } 1229 in_quote = !in_quote; 1230 } 1231 // An argument can contain just about everything, except 1232 // characters that end the command and white space. 1233 else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c) 1234 #ifdef SPACE_IN_FILENAME 1235 && (!(ea.argt & EX_NOSPC) || usefilter) 1236 #endif 1237 )) 1238 { 1239 len = 0; // avoid getting stuck when space is in 'isfname' 1240 while (*p != NUL) 1241 { 1242 if (has_mbyte) 1243 c = mb_ptr2char(p); 1244 else 1245 c = *p; 1246 if (c == '`' || vim_isfilec_or_wc(c)) 1247 break; 1248 if (has_mbyte) 1249 len = (*mb_ptr2len)(p); 1250 else 1251 len = 1; 1252 MB_PTR_ADV(p); 1253 } 1254 if (in_quote) 1255 bow = p; 1256 else 1257 xp->xp_pattern = p; 1258 p -= len; 1259 } 1260 MB_PTR_ADV(p); 1261 } 1262 1263 // If we are still inside the quotes, and we passed a space, just 1264 // expand from there. 1265 if (bow != NULL && in_quote) 1266 xp->xp_pattern = bow; 1267 xp->xp_context = EXPAND_FILES; 1268 1269 // For a shell command more chars need to be escaped. 1270 if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal) 1271 { 1272 #ifndef BACKSLASH_IN_FILENAME 1273 xp->xp_shell = TRUE; 1274 #endif 1275 // When still after the command name expand executables. 1276 if (xp->xp_pattern == skipwhite(arg)) 1277 xp->xp_context = EXPAND_SHELLCMD; 1278 } 1279 1280 // Check for environment variable. 1281 if (*xp->xp_pattern == '$') 1282 { 1283 for (p = xp->xp_pattern + 1; *p != NUL; ++p) 1284 if (!vim_isIDc(*p)) 1285 break; 1286 if (*p == NUL) 1287 { 1288 xp->xp_context = EXPAND_ENV_VARS; 1289 ++xp->xp_pattern; 1290 // Avoid that the assignment uses EXPAND_FILES again. 1291 if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) 1292 compl = EXPAND_ENV_VARS; 1293 } 1294 } 1295 // Check for user names. 1296 if (*xp->xp_pattern == '~') 1297 { 1298 for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) 1299 ; 1300 // Complete ~user only if it partially matches a user name. 1301 // A full match ~user<Tab> will be replaced by user's home 1302 // directory i.e. something like ~user<Tab> -> /home/user/ 1303 if (*p == NUL && p > xp->xp_pattern + 1 1304 && match_user(xp->xp_pattern + 1) >= 1) 1305 { 1306 xp->xp_context = EXPAND_USER; 1307 ++xp->xp_pattern; 1308 } 1309 } 1310 } 1311 1312 // 6. Switch on command name. 1313 switch (ea.cmdidx) 1314 { 1315 case CMD_find: 1316 case CMD_sfind: 1317 case CMD_tabfind: 1318 if (xp->xp_context == EXPAND_FILES) 1319 xp->xp_context = EXPAND_FILES_IN_PATH; 1320 break; 1321 case CMD_cd: 1322 case CMD_chdir: 1323 case CMD_tcd: 1324 case CMD_tchdir: 1325 case CMD_lcd: 1326 case CMD_lchdir: 1327 if (xp->xp_context == EXPAND_FILES) 1328 xp->xp_context = EXPAND_DIRECTORIES; 1329 break; 1330 case CMD_help: 1331 xp->xp_context = EXPAND_HELP; 1332 xp->xp_pattern = arg; 1333 break; 1334 1335 // Command modifiers: return the argument. 1336 // Also for commands with an argument that is a command. 1337 case CMD_aboveleft: 1338 case CMD_argdo: 1339 case CMD_belowright: 1340 case CMD_botright: 1341 case CMD_browse: 1342 case CMD_bufdo: 1343 case CMD_cdo: 1344 case CMD_cfdo: 1345 case CMD_confirm: 1346 case CMD_debug: 1347 case CMD_folddoclosed: 1348 case CMD_folddoopen: 1349 case CMD_hide: 1350 case CMD_keepalt: 1351 case CMD_keepjumps: 1352 case CMD_keepmarks: 1353 case CMD_keeppatterns: 1354 case CMD_ldo: 1355 case CMD_leftabove: 1356 case CMD_lfdo: 1357 case CMD_lockmarks: 1358 case CMD_noautocmd: 1359 case CMD_noswapfile: 1360 case CMD_rightbelow: 1361 case CMD_sandbox: 1362 case CMD_silent: 1363 case CMD_tab: 1364 case CMD_tabdo: 1365 case CMD_topleft: 1366 case CMD_verbose: 1367 case CMD_vertical: 1368 case CMD_windo: 1369 case CMD_vim9cmd: 1370 case CMD_legacy: 1371 return arg; 1372 1373 case CMD_filter: 1374 if (*arg != NUL) 1375 arg = skip_vimgrep_pat(arg, NULL, NULL); 1376 if (arg == NULL || *arg == NUL) 1377 { 1378 xp->xp_context = EXPAND_NOTHING; 1379 return NULL; 1380 } 1381 return skipwhite(arg); 1382 1383 #ifdef FEAT_SEARCH_EXTRA 1384 case CMD_match: 1385 if (*arg == NUL || !ends_excmd(*arg)) 1386 { 1387 // also complete "None" 1388 set_context_in_echohl_cmd(xp, arg); 1389 arg = skipwhite(skiptowhite(arg)); 1390 if (*arg != NUL) 1391 { 1392 xp->xp_context = EXPAND_NOTHING; 1393 arg = skip_regexp(arg + 1, *arg, magic_isset()); 1394 } 1395 } 1396 return find_nextcmd(arg); 1397 #endif 1398 1399 // All completion for the +cmdline_compl feature goes here. 1400 1401 case CMD_command: 1402 return set_context_in_user_cmd(xp, arg); 1403 1404 case CMD_delcommand: 1405 xp->xp_context = EXPAND_USER_COMMANDS; 1406 xp->xp_pattern = arg; 1407 break; 1408 1409 case CMD_global: 1410 case CMD_vglobal: 1411 delim = *arg; // get the delimiter 1412 if (delim) 1413 ++arg; // skip delimiter if there is one 1414 1415 while (arg[0] != NUL && arg[0] != delim) 1416 { 1417 if (arg[0] == '\\' && arg[1] != NUL) 1418 ++arg; 1419 ++arg; 1420 } 1421 if (arg[0] != NUL) 1422 return arg + 1; 1423 break; 1424 case CMD_and: 1425 case CMD_substitute: 1426 delim = *arg; 1427 if (delim) 1428 { 1429 // skip "from" part 1430 ++arg; 1431 arg = skip_regexp(arg, delim, magic_isset()); 1432 } 1433 // skip "to" part 1434 while (arg[0] != NUL && arg[0] != delim) 1435 { 1436 if (arg[0] == '\\' && arg[1] != NUL) 1437 ++arg; 1438 ++arg; 1439 } 1440 if (arg[0] != NUL) // skip delimiter 1441 ++arg; 1442 while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL) 1443 ++arg; 1444 if (arg[0] != NUL) 1445 return arg; 1446 break; 1447 case CMD_isearch: 1448 case CMD_dsearch: 1449 case CMD_ilist: 1450 case CMD_dlist: 1451 case CMD_ijump: 1452 case CMD_psearch: 1453 case CMD_djump: 1454 case CMD_isplit: 1455 case CMD_dsplit: 1456 arg = skipwhite(skipdigits(arg)); // skip count 1457 if (*arg == '/') // Match regexp, not just whole words 1458 { 1459 for (++arg; *arg && *arg != '/'; arg++) 1460 if (*arg == '\\' && arg[1] != NUL) 1461 arg++; 1462 if (*arg) 1463 { 1464 arg = skipwhite(arg + 1); 1465 1466 // Check for trailing illegal characters 1467 if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL) 1468 xp->xp_context = EXPAND_NOTHING; 1469 else 1470 return arg; 1471 } 1472 } 1473 break; 1474 1475 case CMD_autocmd: 1476 return set_context_in_autocmd(xp, arg, FALSE); 1477 case CMD_doautocmd: 1478 case CMD_doautoall: 1479 return set_context_in_autocmd(xp, arg, TRUE); 1480 case CMD_set: 1481 set_context_in_set_cmd(xp, arg, 0); 1482 break; 1483 case CMD_setglobal: 1484 set_context_in_set_cmd(xp, arg, OPT_GLOBAL); 1485 break; 1486 case CMD_setlocal: 1487 set_context_in_set_cmd(xp, arg, OPT_LOCAL); 1488 break; 1489 case CMD_tag: 1490 case CMD_stag: 1491 case CMD_ptag: 1492 case CMD_ltag: 1493 case CMD_tselect: 1494 case CMD_stselect: 1495 case CMD_ptselect: 1496 case CMD_tjump: 1497 case CMD_stjump: 1498 case CMD_ptjump: 1499 if (*p_wop != NUL) 1500 xp->xp_context = EXPAND_TAGS_LISTFILES; 1501 else 1502 xp->xp_context = EXPAND_TAGS; 1503 xp->xp_pattern = arg; 1504 break; 1505 case CMD_augroup: 1506 xp->xp_context = EXPAND_AUGROUP; 1507 xp->xp_pattern = arg; 1508 break; 1509 #ifdef FEAT_SYN_HL 1510 case CMD_syntax: 1511 set_context_in_syntax_cmd(xp, arg); 1512 break; 1513 #endif 1514 #ifdef FEAT_EVAL 1515 case CMD_final: 1516 case CMD_const: 1517 case CMD_let: 1518 case CMD_var: 1519 case CMD_if: 1520 case CMD_elseif: 1521 case CMD_while: 1522 case CMD_for: 1523 case CMD_echo: 1524 case CMD_echon: 1525 case CMD_execute: 1526 case CMD_echomsg: 1527 case CMD_echoerr: 1528 case CMD_call: 1529 case CMD_return: 1530 case CMD_cexpr: 1531 case CMD_caddexpr: 1532 case CMD_cgetexpr: 1533 case CMD_lexpr: 1534 case CMD_laddexpr: 1535 case CMD_lgetexpr: 1536 set_context_for_expression(xp, arg, ea.cmdidx); 1537 break; 1538 1539 case CMD_unlet: 1540 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 1541 arg = xp->xp_pattern + 1; 1542 1543 xp->xp_context = EXPAND_USER_VARS; 1544 xp->xp_pattern = arg; 1545 1546 if (*xp->xp_pattern == '$') 1547 { 1548 xp->xp_context = EXPAND_ENV_VARS; 1549 ++xp->xp_pattern; 1550 } 1551 1552 break; 1553 1554 case CMD_function: 1555 case CMD_delfunction: 1556 xp->xp_context = EXPAND_USER_FUNC; 1557 xp->xp_pattern = arg; 1558 break; 1559 case CMD_disassemble: 1560 set_context_in_disassemble_cmd(xp, arg); 1561 break; 1562 1563 case CMD_echohl: 1564 set_context_in_echohl_cmd(xp, arg); 1565 break; 1566 #endif 1567 case CMD_highlight: 1568 set_context_in_highlight_cmd(xp, arg); 1569 break; 1570 #ifdef FEAT_CSCOPE 1571 case CMD_cscope: 1572 case CMD_lcscope: 1573 case CMD_scscope: 1574 set_context_in_cscope_cmd(xp, arg, ea.cmdidx); 1575 break; 1576 #endif 1577 #ifdef FEAT_SIGNS 1578 case CMD_sign: 1579 set_context_in_sign_cmd(xp, arg); 1580 break; 1581 #endif 1582 case CMD_bdelete: 1583 case CMD_bwipeout: 1584 case CMD_bunload: 1585 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 1586 arg = xp->xp_pattern + 1; 1587 // FALLTHROUGH 1588 case CMD_buffer: 1589 case CMD_sbuffer: 1590 case CMD_checktime: 1591 xp->xp_context = EXPAND_BUFFERS; 1592 xp->xp_pattern = arg; 1593 break; 1594 #ifdef FEAT_DIFF 1595 case CMD_diffget: 1596 case CMD_diffput: 1597 // If current buffer is in diff mode, complete buffer names 1598 // which are in diff mode, and different than current buffer. 1599 xp->xp_context = EXPAND_DIFF_BUFFERS; 1600 xp->xp_pattern = arg; 1601 break; 1602 #endif 1603 case CMD_USER: 1604 case CMD_USER_BUF: 1605 if (compl != EXPAND_NOTHING) 1606 { 1607 // EX_XFILE: file names are handled above 1608 if (!(ea.argt & EX_XFILE)) 1609 { 1610 #ifdef FEAT_MENU 1611 if (compl == EXPAND_MENUS) 1612 return set_context_in_menu_cmd(xp, cmd, arg, forceit); 1613 #endif 1614 if (compl == EXPAND_COMMANDS) 1615 return arg; 1616 if (compl == EXPAND_MAPPINGS) 1617 return set_context_in_map_cmd(xp, (char_u *)"map", 1618 arg, forceit, FALSE, FALSE, CMD_map); 1619 // Find start of last argument. 1620 p = arg; 1621 while (*p) 1622 { 1623 if (*p == ' ') 1624 // argument starts after a space 1625 arg = p + 1; 1626 else if (*p == '\\' && *(p + 1) != NUL) 1627 ++p; // skip over escaped character 1628 MB_PTR_ADV(p); 1629 } 1630 xp->xp_pattern = arg; 1631 } 1632 xp->xp_context = compl; 1633 } 1634 break; 1635 1636 case CMD_map: case CMD_noremap: 1637 case CMD_nmap: case CMD_nnoremap: 1638 case CMD_vmap: case CMD_vnoremap: 1639 case CMD_omap: case CMD_onoremap: 1640 case CMD_imap: case CMD_inoremap: 1641 case CMD_cmap: case CMD_cnoremap: 1642 case CMD_lmap: case CMD_lnoremap: 1643 case CMD_smap: case CMD_snoremap: 1644 case CMD_tmap: case CMD_tnoremap: 1645 case CMD_xmap: case CMD_xnoremap: 1646 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1647 FALSE, FALSE, ea.cmdidx); 1648 case CMD_unmap: 1649 case CMD_nunmap: 1650 case CMD_vunmap: 1651 case CMD_ounmap: 1652 case CMD_iunmap: 1653 case CMD_cunmap: 1654 case CMD_lunmap: 1655 case CMD_sunmap: 1656 case CMD_tunmap: 1657 case CMD_xunmap: 1658 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1659 FALSE, TRUE, ea.cmdidx); 1660 case CMD_mapclear: 1661 case CMD_nmapclear: 1662 case CMD_vmapclear: 1663 case CMD_omapclear: 1664 case CMD_imapclear: 1665 case CMD_cmapclear: 1666 case CMD_lmapclear: 1667 case CMD_smapclear: 1668 case CMD_tmapclear: 1669 case CMD_xmapclear: 1670 xp->xp_context = EXPAND_MAPCLEAR; 1671 xp->xp_pattern = arg; 1672 break; 1673 1674 case CMD_abbreviate: case CMD_noreabbrev: 1675 case CMD_cabbrev: case CMD_cnoreabbrev: 1676 case CMD_iabbrev: case CMD_inoreabbrev: 1677 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1678 TRUE, FALSE, ea.cmdidx); 1679 case CMD_unabbreviate: 1680 case CMD_cunabbrev: 1681 case CMD_iunabbrev: 1682 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1683 TRUE, TRUE, ea.cmdidx); 1684 #ifdef FEAT_MENU 1685 case CMD_menu: case CMD_noremenu: case CMD_unmenu: 1686 case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: 1687 case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: 1688 case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu: 1689 case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu: 1690 case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu: 1691 case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu: 1692 case CMD_tlmenu: case CMD_tlnoremenu: case CMD_tlunmenu: 1693 case CMD_tmenu: case CMD_tunmenu: 1694 case CMD_popup: case CMD_tearoff: case CMD_emenu: 1695 return set_context_in_menu_cmd(xp, cmd, arg, forceit); 1696 #endif 1697 1698 case CMD_colorscheme: 1699 xp->xp_context = EXPAND_COLORS; 1700 xp->xp_pattern = arg; 1701 break; 1702 1703 case CMD_compiler: 1704 xp->xp_context = EXPAND_COMPILER; 1705 xp->xp_pattern = arg; 1706 break; 1707 1708 case CMD_ownsyntax: 1709 xp->xp_context = EXPAND_OWNSYNTAX; 1710 xp->xp_pattern = arg; 1711 break; 1712 1713 case CMD_setfiletype: 1714 xp->xp_context = EXPAND_FILETYPE; 1715 xp->xp_pattern = arg; 1716 break; 1717 1718 case CMD_packadd: 1719 xp->xp_context = EXPAND_PACKADD; 1720 xp->xp_pattern = arg; 1721 break; 1722 1723 #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 1724 case CMD_language: 1725 p = skiptowhite(arg); 1726 if (*p == NUL) 1727 { 1728 xp->xp_context = EXPAND_LANGUAGE; 1729 xp->xp_pattern = arg; 1730 } 1731 else 1732 { 1733 if ( STRNCMP(arg, "messages", p - arg) == 0 1734 || STRNCMP(arg, "ctype", p - arg) == 0 1735 || STRNCMP(arg, "time", p - arg) == 0 1736 || STRNCMP(arg, "collate", p - arg) == 0) 1737 { 1738 xp->xp_context = EXPAND_LOCALES; 1739 xp->xp_pattern = skipwhite(p); 1740 } 1741 else 1742 xp->xp_context = EXPAND_NOTHING; 1743 } 1744 break; 1745 #endif 1746 #if defined(FEAT_PROFILE) 1747 case CMD_profile: 1748 set_context_in_profile_cmd(xp, arg); 1749 break; 1750 #endif 1751 case CMD_behave: 1752 xp->xp_context = EXPAND_BEHAVE; 1753 xp->xp_pattern = arg; 1754 break; 1755 1756 case CMD_messages: 1757 xp->xp_context = EXPAND_MESSAGES; 1758 xp->xp_pattern = arg; 1759 break; 1760 1761 case CMD_history: 1762 xp->xp_context = EXPAND_HISTORY; 1763 xp->xp_pattern = arg; 1764 break; 1765 #if defined(FEAT_PROFILE) 1766 case CMD_syntime: 1767 xp->xp_context = EXPAND_SYNTIME; 1768 xp->xp_pattern = arg; 1769 break; 1770 #endif 1771 1772 case CMD_argdelete: 1773 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 1774 arg = xp->xp_pattern + 1; 1775 xp->xp_context = EXPAND_ARGLIST; 1776 xp->xp_pattern = arg; 1777 break; 1778 1779 default: 1780 break; 1781 } 1782 return NULL; 1783 } 1784 1785 void 1786 set_cmd_context( 1787 expand_T *xp, 1788 char_u *str, // start of command line 1789 int len, // length of command line (excl. NUL) 1790 int col, // position of cursor 1791 int use_ccline UNUSED) // use ccline for info 1792 { 1793 #ifdef FEAT_EVAL 1794 cmdline_info_T *ccline = get_cmdline_info(); 1795 #endif 1796 int old_char = NUL; 1797 char_u *nextcomm; 1798 1799 // Avoid a UMR warning from Purify, only save the character if it has been 1800 // written before. 1801 if (col < len) 1802 old_char = str[col]; 1803 str[col] = NUL; 1804 nextcomm = str; 1805 1806 #ifdef FEAT_EVAL 1807 if (use_ccline && ccline->cmdfirstc == '=') 1808 { 1809 // pass CMD_SIZE because there is no real command 1810 set_context_for_expression(xp, str, CMD_SIZE); 1811 } 1812 else if (use_ccline && ccline->input_fn) 1813 { 1814 xp->xp_context = ccline->xp_context; 1815 xp->xp_pattern = ccline->cmdbuff; 1816 xp->xp_arg = ccline->xp_arg; 1817 } 1818 else 1819 #endif 1820 while (nextcomm != NULL) 1821 nextcomm = set_one_cmd_context(xp, nextcomm); 1822 1823 // Store the string here so that call_user_expand_func() can get to them 1824 // easily. 1825 xp->xp_line = str; 1826 xp->xp_col = col; 1827 1828 str[col] = old_char; 1829 } 1830 1831 /* 1832 * Expand the command line "str" from context "xp". 1833 * "xp" must have been set by set_cmd_context(). 1834 * xp->xp_pattern points into "str", to where the text that is to be expanded 1835 * starts. 1836 * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the 1837 * cursor. 1838 * Returns EXPAND_NOTHING when there is nothing to expand, might insert the 1839 * key that triggered expansion literally. 1840 * Returns EXPAND_OK otherwise. 1841 */ 1842 int 1843 expand_cmdline( 1844 expand_T *xp, 1845 char_u *str, // start of command line 1846 int col, // position of cursor 1847 int *matchcount, // return: nr of matches 1848 char_u ***matches) // return: array of pointers to matches 1849 { 1850 char_u *file_str = NULL; 1851 int options = WILD_ADD_SLASH|WILD_SILENT; 1852 1853 if (xp->xp_context == EXPAND_UNSUCCESSFUL) 1854 { 1855 beep_flush(); 1856 return EXPAND_UNSUCCESSFUL; // Something illegal on command line 1857 } 1858 if (xp->xp_context == EXPAND_NOTHING) 1859 { 1860 // Caller can use the character as a normal char instead 1861 return EXPAND_NOTHING; 1862 } 1863 1864 // add star to file name, or convert to regexp if not exp. files. 1865 xp->xp_pattern_len = (int)(str + col - xp->xp_pattern); 1866 file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); 1867 if (file_str == NULL) 1868 return EXPAND_UNSUCCESSFUL; 1869 1870 if (p_wic) 1871 options += WILD_ICASE; 1872 1873 // find all files that match the description 1874 if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL) 1875 { 1876 *matchcount = 0; 1877 *matches = NULL; 1878 } 1879 vim_free(file_str); 1880 1881 return EXPAND_OK; 1882 } 1883 1884 /* 1885 * Function given to ExpandGeneric() to obtain the possible arguments of the 1886 * ":behave {mswin,xterm}" command. 1887 */ 1888 static char_u * 1889 get_behave_arg(expand_T *xp UNUSED, int idx) 1890 { 1891 if (idx == 0) 1892 return (char_u *)"mswin"; 1893 if (idx == 1) 1894 return (char_u *)"xterm"; 1895 return NULL; 1896 } 1897 1898 /* 1899 * Function given to ExpandGeneric() to obtain the possible arguments of the 1900 * ":messages {clear}" command. 1901 */ 1902 static char_u * 1903 get_messages_arg(expand_T *xp UNUSED, int idx) 1904 { 1905 if (idx == 0) 1906 return (char_u *)"clear"; 1907 return NULL; 1908 } 1909 1910 static char_u * 1911 get_mapclear_arg(expand_T *xp UNUSED, int idx) 1912 { 1913 if (idx == 0) 1914 return (char_u *)"<buffer>"; 1915 return NULL; 1916 } 1917 1918 /* 1919 * Do the expansion based on xp->xp_context and "pat". 1920 */ 1921 static int 1922 ExpandFromContext( 1923 expand_T *xp, 1924 char_u *pat, 1925 int *num_file, 1926 char_u ***file, 1927 int options) // WILD_ flags 1928 { 1929 regmatch_T regmatch; 1930 int ret; 1931 int flags; 1932 char_u *tofree = NULL; 1933 1934 flags = EW_DIR; // include directories 1935 if (options & WILD_LIST_NOTFOUND) 1936 flags |= EW_NOTFOUND; 1937 if (options & WILD_ADD_SLASH) 1938 flags |= EW_ADDSLASH; 1939 if (options & WILD_KEEP_ALL) 1940 flags |= EW_KEEPALL; 1941 if (options & WILD_SILENT) 1942 flags |= EW_SILENT; 1943 if (options & WILD_NOERROR) 1944 flags |= EW_NOERROR; 1945 if (options & WILD_ALLLINKS) 1946 flags |= EW_ALLLINKS; 1947 1948 if (xp->xp_context == EXPAND_FILES 1949 || xp->xp_context == EXPAND_DIRECTORIES 1950 || xp->xp_context == EXPAND_FILES_IN_PATH) 1951 { 1952 // Expand file or directory names. 1953 int free_pat = FALSE; 1954 int i; 1955 1956 // for ":set path=" and ":set tags=" halve backslashes for escaped 1957 // space 1958 if (xp->xp_backslash != XP_BS_NONE) 1959 { 1960 free_pat = TRUE; 1961 pat = vim_strsave(pat); 1962 for (i = 0; pat[i]; ++i) 1963 if (pat[i] == '\\') 1964 { 1965 if (xp->xp_backslash == XP_BS_THREE 1966 && pat[i + 1] == '\\' 1967 && pat[i + 2] == '\\' 1968 && pat[i + 3] == ' ') 1969 STRMOVE(pat + i, pat + i + 3); 1970 if (xp->xp_backslash == XP_BS_ONE 1971 && pat[i + 1] == ' ') 1972 STRMOVE(pat + i, pat + i + 1); 1973 } 1974 } 1975 1976 if (xp->xp_context == EXPAND_FILES) 1977 flags |= EW_FILE; 1978 else if (xp->xp_context == EXPAND_FILES_IN_PATH) 1979 flags |= (EW_FILE | EW_PATH); 1980 else 1981 flags = (flags | EW_DIR) & ~EW_FILE; 1982 if (options & WILD_ICASE) 1983 flags |= EW_ICASE; 1984 1985 // Expand wildcards, supporting %:h and the like. 1986 ret = expand_wildcards_eval(&pat, num_file, file, flags); 1987 if (free_pat) 1988 vim_free(pat); 1989 #ifdef BACKSLASH_IN_FILENAME 1990 if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) 1991 { 1992 int i; 1993 1994 for (i = 0; i < *num_file; ++i) 1995 { 1996 char_u *ptr = (*file)[i]; 1997 1998 while (*ptr != NUL) 1999 { 2000 if (p_csl[0] == 's' && *ptr == '\\') 2001 *ptr = '/'; 2002 else if (p_csl[0] == 'b' && *ptr == '/') 2003 *ptr = '\\'; 2004 ptr += (*mb_ptr2len)(ptr); 2005 } 2006 } 2007 } 2008 #endif 2009 return ret; 2010 } 2011 2012 *file = (char_u **)""; 2013 *num_file = 0; 2014 if (xp->xp_context == EXPAND_HELP) 2015 { 2016 // With an empty argument we would get all the help tags, which is 2017 // very slow. Get matches for "help" instead. 2018 if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat, 2019 num_file, file, FALSE) == OK) 2020 { 2021 #ifdef FEAT_MULTI_LANG 2022 cleanup_help_tags(*num_file, *file); 2023 #endif 2024 return OK; 2025 } 2026 return FAIL; 2027 } 2028 2029 if (xp->xp_context == EXPAND_SHELLCMD) 2030 return expand_shellcmd(pat, num_file, file, flags); 2031 if (xp->xp_context == EXPAND_OLD_SETTING) 2032 return ExpandOldSetting(num_file, file); 2033 if (xp->xp_context == EXPAND_BUFFERS) 2034 return ExpandBufnames(pat, num_file, file, options); 2035 #ifdef FEAT_DIFF 2036 if (xp->xp_context == EXPAND_DIFF_BUFFERS) 2037 return ExpandBufnames(pat, num_file, file, options | BUF_DIFF_FILTER); 2038 #endif 2039 if (xp->xp_context == EXPAND_TAGS 2040 || xp->xp_context == EXPAND_TAGS_LISTFILES) 2041 return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file); 2042 if (xp->xp_context == EXPAND_COLORS) 2043 { 2044 char *directories[] = {"colors", NULL}; 2045 return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, 2046 directories); 2047 } 2048 if (xp->xp_context == EXPAND_COMPILER) 2049 { 2050 char *directories[] = {"compiler", NULL}; 2051 return ExpandRTDir(pat, 0, num_file, file, directories); 2052 } 2053 if (xp->xp_context == EXPAND_OWNSYNTAX) 2054 { 2055 char *directories[] = {"syntax", NULL}; 2056 return ExpandRTDir(pat, 0, num_file, file, directories); 2057 } 2058 if (xp->xp_context == EXPAND_FILETYPE) 2059 { 2060 char *directories[] = {"syntax", "indent", "ftplugin", NULL}; 2061 return ExpandRTDir(pat, 0, num_file, file, directories); 2062 } 2063 # if defined(FEAT_EVAL) 2064 if (xp->xp_context == EXPAND_USER_LIST) 2065 return ExpandUserList(xp, num_file, file); 2066 # endif 2067 if (xp->xp_context == EXPAND_PACKADD) 2068 return ExpandPackAddDir(pat, num_file, file); 2069 2070 // When expanding a function name starting with s:, match the <SNR>nr_ 2071 // prefix. 2072 if ((xp->xp_context == EXPAND_USER_FUNC 2073 || xp->xp_context == EXPAND_DISASSEMBLE) 2074 && STRNCMP(pat, "^s:", 3) == 0) 2075 { 2076 int len = (int)STRLEN(pat) + 20; 2077 2078 tofree = alloc(len); 2079 vim_snprintf((char *)tofree, len, "^<SNR>\\d\\+_%s", pat + 3); 2080 pat = tofree; 2081 } 2082 2083 regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); 2084 if (regmatch.regprog == NULL) 2085 return FAIL; 2086 2087 // set ignore-case according to p_ic, p_scs and pat 2088 regmatch.rm_ic = ignorecase(pat); 2089 2090 if (xp->xp_context == EXPAND_SETTINGS 2091 || xp->xp_context == EXPAND_BOOL_SETTINGS) 2092 ret = ExpandSettings(xp, ®match, num_file, file); 2093 else if (xp->xp_context == EXPAND_MAPPINGS) 2094 ret = ExpandMappings(®match, num_file, file); 2095 # if defined(FEAT_EVAL) 2096 else if (xp->xp_context == EXPAND_USER_DEFINED) 2097 ret = ExpandUserDefined(xp, ®match, num_file, file); 2098 # endif 2099 else 2100 { 2101 static struct expgen 2102 { 2103 int context; 2104 char_u *((*func)(expand_T *, int)); 2105 int ic; 2106 int escaped; 2107 } tab[] = 2108 { 2109 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE}, 2110 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE}, 2111 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE}, 2112 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE}, 2113 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE}, 2114 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE}, 2115 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE}, 2116 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE}, 2117 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE}, 2118 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE}, 2119 # ifdef FEAT_EVAL 2120 {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE}, 2121 {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE}, 2122 {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE}, 2123 {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE}, 2124 {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE}, 2125 # endif 2126 # ifdef FEAT_MENU 2127 {EXPAND_MENUS, get_menu_name, FALSE, TRUE}, 2128 {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE}, 2129 # endif 2130 # ifdef FEAT_SYN_HL 2131 {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE}, 2132 # endif 2133 # ifdef FEAT_PROFILE 2134 {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE}, 2135 # endif 2136 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE}, 2137 {EXPAND_EVENTS, get_event_name, TRUE, FALSE}, 2138 {EXPAND_AUGROUP, get_augroup_name, TRUE, FALSE}, 2139 # ifdef FEAT_CSCOPE 2140 {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE}, 2141 # endif 2142 # ifdef FEAT_SIGNS 2143 {EXPAND_SIGN, get_sign_name, TRUE, TRUE}, 2144 # endif 2145 # ifdef FEAT_PROFILE 2146 {EXPAND_PROFILE, get_profile_name, TRUE, TRUE}, 2147 # endif 2148 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 2149 {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE}, 2150 {EXPAND_LOCALES, get_locales, TRUE, FALSE}, 2151 # endif 2152 {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE}, 2153 {EXPAND_USER, get_users, TRUE, FALSE}, 2154 {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE}, 2155 }; 2156 int i; 2157 2158 // Find a context in the table and call the ExpandGeneric() with the 2159 // right function to do the expansion. 2160 ret = FAIL; 2161 for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i) 2162 if (xp->xp_context == tab[i].context) 2163 { 2164 if (tab[i].ic) 2165 regmatch.rm_ic = TRUE; 2166 ret = ExpandGeneric(xp, ®match, num_file, file, 2167 tab[i].func, tab[i].escaped); 2168 break; 2169 } 2170 } 2171 2172 vim_regfree(regmatch.regprog); 2173 vim_free(tofree); 2174 2175 return ret; 2176 } 2177 2178 /* 2179 * Expand a list of names. 2180 * 2181 * Generic function for command line completion. It calls a function to 2182 * obtain strings, one by one. The strings are matched against a regexp 2183 * program. Matching strings are copied into an array, which is returned. 2184 * 2185 * Returns OK when no problems encountered, FAIL for error (out of memory). 2186 */ 2187 static int 2188 ExpandGeneric( 2189 expand_T *xp, 2190 regmatch_T *regmatch, 2191 int *num_file, 2192 char_u ***file, 2193 char_u *((*func)(expand_T *, int)), 2194 // returns a string from the list 2195 int escaped) 2196 { 2197 int i; 2198 int count = 0; 2199 int round; 2200 char_u *str; 2201 2202 // do this loop twice: 2203 // round == 0: count the number of matching names 2204 // round == 1: copy the matching names into allocated memory 2205 for (round = 0; round <= 1; ++round) 2206 { 2207 for (i = 0; ; ++i) 2208 { 2209 str = (*func)(xp, i); 2210 if (str == NULL) // end of list 2211 break; 2212 if (*str == NUL) // skip empty strings 2213 continue; 2214 2215 if (vim_regexec(regmatch, str, (colnr_T)0)) 2216 { 2217 if (round) 2218 { 2219 if (escaped) 2220 str = vim_strsave_escaped(str, (char_u *)" \t\\."); 2221 else 2222 str = vim_strsave(str); 2223 if (str == NULL) 2224 { 2225 FreeWild(count, *file); 2226 *num_file = 0; 2227 *file = NULL; 2228 return FAIL; 2229 } 2230 (*file)[count] = str; 2231 # ifdef FEAT_MENU 2232 if (func == get_menu_names && str != NULL) 2233 { 2234 // test for separator added by get_menu_names() 2235 str += STRLEN(str) - 1; 2236 if (*str == '\001') 2237 *str = '.'; 2238 } 2239 # endif 2240 } 2241 ++count; 2242 } 2243 } 2244 if (round == 0) 2245 { 2246 if (count == 0) 2247 return OK; 2248 *file = ALLOC_MULT(char_u *, count); 2249 if (*file == NULL) 2250 { 2251 *num_file = 0; 2252 *file = NULL; 2253 return FAIL; 2254 } 2255 *num_file = count; 2256 count = 0; 2257 } 2258 } 2259 2260 // Sort the results. Keep menu's in the specified order. 2261 if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) 2262 { 2263 if (xp->xp_context == EXPAND_EXPRESSION 2264 || xp->xp_context == EXPAND_FUNCTIONS 2265 || xp->xp_context == EXPAND_USER_FUNC 2266 || xp->xp_context == EXPAND_DISASSEMBLE) 2267 // <SNR> functions should be sorted to the end. 2268 qsort((void *)*file, (size_t)*num_file, sizeof(char_u *), 2269 sort_func_compare); 2270 else 2271 sort_strings(*file, *num_file); 2272 } 2273 2274 #if defined(FEAT_SYN_HL) 2275 // Reset the variables used for special highlight names expansion, so that 2276 // they don't show up when getting normal highlight names by ID. 2277 reset_expand_highlight(); 2278 #endif 2279 return OK; 2280 } 2281 2282 /* 2283 * Complete a shell command. 2284 * Returns FAIL or OK; 2285 */ 2286 static int 2287 expand_shellcmd( 2288 char_u *filepat, // pattern to match with command names 2289 int *num_file, // return: number of matches 2290 char_u ***file, // return: array with matches 2291 int flagsarg) // EW_ flags 2292 { 2293 char_u *pat; 2294 int i; 2295 char_u *path = NULL; 2296 int mustfree = FALSE; 2297 garray_T ga; 2298 char_u *buf; 2299 size_t l; 2300 char_u *s, *e; 2301 int flags = flagsarg; 2302 int ret; 2303 int did_curdir = FALSE; 2304 hashtab_T found_ht; 2305 hashitem_T *hi; 2306 hash_T hash; 2307 2308 buf = alloc(MAXPATHL); 2309 if (buf == NULL) 2310 return FAIL; 2311 2312 // for ":set path=" and ":set tags=" halve backslashes for escaped space 2313 pat = vim_strsave(filepat); 2314 if (pat == NULL) 2315 { 2316 vim_free(buf); 2317 return FAIL; 2318 } 2319 2320 for (i = 0; pat[i]; ++i) 2321 if (pat[i] == '\\' && pat[i + 1] == ' ') 2322 STRMOVE(pat + i, pat + i + 1); 2323 2324 flags |= EW_FILE | EW_EXEC | EW_SHELLCMD; 2325 2326 if (pat[0] == '.' && (vim_ispathsep(pat[1]) 2327 || (pat[1] == '.' && vim_ispathsep(pat[2])))) 2328 path = (char_u *)"."; 2329 else 2330 { 2331 // For an absolute name we don't use $PATH. 2332 if (!mch_isFullName(pat)) 2333 path = vim_getenv((char_u *)"PATH", &mustfree); 2334 if (path == NULL) 2335 path = (char_u *)""; 2336 } 2337 2338 // Go over all directories in $PATH. Expand matches in that directory and 2339 // collect them in "ga". When "." is not in $PATH also expand for the 2340 // current directory, to find "subdir/cmd". 2341 ga_init2(&ga, (int)sizeof(char *), 10); 2342 hash_init(&found_ht); 2343 for (s = path; ; s = e) 2344 { 2345 # if defined(MSWIN) 2346 e = vim_strchr(s, ';'); 2347 # else 2348 e = vim_strchr(s, ':'); 2349 # endif 2350 if (e == NULL) 2351 e = s + STRLEN(s); 2352 2353 if (*s == NUL) 2354 { 2355 if (did_curdir) 2356 break; 2357 // Find directories in the current directory, path is empty. 2358 did_curdir = TRUE; 2359 flags |= EW_DIR; 2360 } 2361 else if (STRNCMP(s, ".", (int)(e - s)) == 0) 2362 { 2363 did_curdir = TRUE; 2364 flags |= EW_DIR; 2365 } 2366 else 2367 // Do not match directories inside a $PATH item. 2368 flags &= ~EW_DIR; 2369 2370 l = e - s; 2371 if (l > MAXPATHL - 5) 2372 break; 2373 vim_strncpy(buf, s, l); 2374 add_pathsep(buf); 2375 l = STRLEN(buf); 2376 vim_strncpy(buf + l, pat, MAXPATHL - 1 - l); 2377 2378 // Expand matches in one directory of $PATH. 2379 ret = expand_wildcards(1, &buf, num_file, file, flags); 2380 if (ret == OK) 2381 { 2382 if (ga_grow(&ga, *num_file) == FAIL) 2383 FreeWild(*num_file, *file); 2384 else 2385 { 2386 for (i = 0; i < *num_file; ++i) 2387 { 2388 char_u *name = (*file)[i]; 2389 2390 if (STRLEN(name) > l) 2391 { 2392 // Check if this name was already found. 2393 hash = hash_hash(name + l); 2394 hi = hash_lookup(&found_ht, name + l, hash); 2395 if (HASHITEM_EMPTY(hi)) 2396 { 2397 // Remove the path that was prepended. 2398 STRMOVE(name, name + l); 2399 ((char_u **)ga.ga_data)[ga.ga_len++] = name; 2400 hash_add_item(&found_ht, hi, name, hash); 2401 name = NULL; 2402 } 2403 } 2404 vim_free(name); 2405 } 2406 vim_free(*file); 2407 } 2408 } 2409 if (*e != NUL) 2410 ++e; 2411 } 2412 *file = ga.ga_data; 2413 *num_file = ga.ga_len; 2414 2415 vim_free(buf); 2416 vim_free(pat); 2417 if (mustfree) 2418 vim_free(path); 2419 hash_clear(&found_ht); 2420 return OK; 2421 } 2422 2423 # if defined(FEAT_EVAL) 2424 /* 2425 * Call "user_expand_func()" to invoke a user defined Vim script function and 2426 * return the result (either a string, a List or NULL). 2427 */ 2428 static void * 2429 call_user_expand_func( 2430 void *(*user_expand_func)(char_u *, int, typval_T *), 2431 expand_T *xp, 2432 int *num_file, 2433 char_u ***file) 2434 { 2435 cmdline_info_T *ccline = get_cmdline_info(); 2436 int keep = 0; 2437 typval_T args[4]; 2438 sctx_T save_current_sctx = current_sctx; 2439 char_u *pat = NULL; 2440 void *ret; 2441 2442 if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) 2443 return NULL; 2444 *num_file = 0; 2445 *file = NULL; 2446 2447 if (ccline->cmdbuff != NULL) 2448 { 2449 keep = ccline->cmdbuff[ccline->cmdlen]; 2450 ccline->cmdbuff[ccline->cmdlen] = 0; 2451 } 2452 2453 pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); 2454 2455 args[0].v_type = VAR_STRING; 2456 args[0].vval.v_string = pat; 2457 args[1].v_type = VAR_STRING; 2458 args[1].vval.v_string = xp->xp_line; 2459 args[2].v_type = VAR_NUMBER; 2460 args[2].vval.v_number = xp->xp_col; 2461 args[3].v_type = VAR_UNKNOWN; 2462 2463 current_sctx = xp->xp_script_ctx; 2464 2465 ret = user_expand_func(xp->xp_arg, 3, args); 2466 2467 current_sctx = save_current_sctx; 2468 if (ccline->cmdbuff != NULL) 2469 ccline->cmdbuff[ccline->cmdlen] = keep; 2470 2471 vim_free(pat); 2472 return ret; 2473 } 2474 2475 /* 2476 * Expand names with a function defined by the user. 2477 */ 2478 static int 2479 ExpandUserDefined( 2480 expand_T *xp, 2481 regmatch_T *regmatch, 2482 int *num_file, 2483 char_u ***file) 2484 { 2485 char_u *retstr; 2486 char_u *s; 2487 char_u *e; 2488 int keep; 2489 garray_T ga; 2490 int skip; 2491 2492 retstr = call_user_expand_func(call_func_retstr, xp, num_file, file); 2493 if (retstr == NULL) 2494 return FAIL; 2495 2496 ga_init2(&ga, (int)sizeof(char *), 3); 2497 for (s = retstr; *s != NUL; s = e) 2498 { 2499 e = vim_strchr(s, '\n'); 2500 if (e == NULL) 2501 e = s + STRLEN(s); 2502 keep = *e; 2503 *e = NUL; 2504 2505 skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0; 2506 *e = keep; 2507 2508 if (!skip) 2509 { 2510 if (ga_grow(&ga, 1) == FAIL) 2511 break; 2512 ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, e - s); 2513 ++ga.ga_len; 2514 } 2515 2516 if (*e != NUL) 2517 ++e; 2518 } 2519 vim_free(retstr); 2520 *file = ga.ga_data; 2521 *num_file = ga.ga_len; 2522 return OK; 2523 } 2524 2525 /* 2526 * Expand names with a list returned by a function defined by the user. 2527 */ 2528 static int 2529 ExpandUserList( 2530 expand_T *xp, 2531 int *num_file, 2532 char_u ***file) 2533 { 2534 list_T *retlist; 2535 listitem_T *li; 2536 garray_T ga; 2537 2538 retlist = call_user_expand_func(call_func_retlist, xp, num_file, file); 2539 if (retlist == NULL) 2540 return FAIL; 2541 2542 ga_init2(&ga, (int)sizeof(char *), 3); 2543 // Loop over the items in the list. 2544 FOR_ALL_LIST_ITEMS(retlist, li) 2545 { 2546 if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL) 2547 continue; // Skip non-string items and empty strings 2548 2549 if (ga_grow(&ga, 1) == FAIL) 2550 break; 2551 2552 ((char_u **)ga.ga_data)[ga.ga_len] = 2553 vim_strsave(li->li_tv.vval.v_string); 2554 ++ga.ga_len; 2555 } 2556 list_unref(retlist); 2557 2558 *file = ga.ga_data; 2559 *num_file = ga.ga_len; 2560 return OK; 2561 } 2562 # endif 2563 2564 /* 2565 * Expand "file" for all comma-separated directories in "path". 2566 * Adds the matches to "ga". Caller must init "ga". 2567 */ 2568 void 2569 globpath( 2570 char_u *path, 2571 char_u *file, 2572 garray_T *ga, 2573 int expand_options) 2574 { 2575 expand_T xpc; 2576 char_u *buf; 2577 int i; 2578 int num_p; 2579 char_u **p; 2580 2581 buf = alloc(MAXPATHL); 2582 if (buf == NULL) 2583 return; 2584 2585 ExpandInit(&xpc); 2586 xpc.xp_context = EXPAND_FILES; 2587 2588 // Loop over all entries in {path}. 2589 while (*path != NUL) 2590 { 2591 // Copy one item of the path to buf[] and concatenate the file name. 2592 copy_option_part(&path, buf, MAXPATHL, ","); 2593 if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL) 2594 { 2595 # if defined(MSWIN) 2596 // Using the platform's path separator (\) makes vim incorrectly 2597 // treat it as an escape character, use '/' instead. 2598 if (*buf != NUL && !after_pathsep(buf, buf + STRLEN(buf))) 2599 STRCAT(buf, "/"); 2600 # else 2601 add_pathsep(buf); 2602 # endif 2603 STRCAT(buf, file); 2604 if (ExpandFromContext(&xpc, buf, &num_p, &p, 2605 WILD_SILENT|expand_options) != FAIL && num_p > 0) 2606 { 2607 ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options); 2608 2609 if (ga_grow(ga, num_p) == OK) 2610 // take over the pointers and put them in "ga" 2611 for (i = 0; i < num_p; ++i) 2612 { 2613 ((char_u **)ga->ga_data)[ga->ga_len] = p[i]; 2614 ++ga->ga_len; 2615 } 2616 vim_free(p); 2617 } 2618 } 2619 } 2620 2621 vim_free(buf); 2622 } 2623 2624 #ifdef FEAT_WILDMENU 2625 2626 /* 2627 * Translate some keys pressed when 'wildmenu' is used. 2628 */ 2629 int 2630 wildmenu_translate_key( 2631 cmdline_info_T *cclp, 2632 int key, 2633 expand_T *xp, 2634 int did_wild_list) 2635 { 2636 int c = key; 2637 2638 if (did_wild_list && p_wmnu) 2639 { 2640 if (c == K_LEFT) 2641 c = Ctrl_P; 2642 else if (c == K_RIGHT) 2643 c = Ctrl_N; 2644 } 2645 // Hitting CR after "emenu Name.": complete submenu 2646 if (xp->xp_context == EXPAND_MENUNAMES && p_wmnu 2647 && cclp->cmdpos > 1 2648 && cclp->cmdbuff[cclp->cmdpos - 1] == '.' 2649 && cclp->cmdbuff[cclp->cmdpos - 2] != '\\' 2650 && (c == '\n' || c == '\r' || c == K_KENTER)) 2651 c = K_DOWN; 2652 2653 return c; 2654 } 2655 2656 /* 2657 * Delete characters on the command line, from "from" to the current 2658 * position. 2659 */ 2660 static void 2661 cmdline_del(cmdline_info_T *cclp, int from) 2662 { 2663 mch_memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos, 2664 (size_t)(cclp->cmdlen - cclp->cmdpos + 1)); 2665 cclp->cmdlen -= cclp->cmdpos - from; 2666 cclp->cmdpos = from; 2667 } 2668 2669 /* 2670 * Handle a key pressed when wild menu is displayed 2671 */ 2672 int 2673 wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp) 2674 { 2675 int c = key; 2676 int i; 2677 int j; 2678 2679 if (!p_wmnu) 2680 return c; 2681 2682 // Special translations for 'wildmenu' 2683 if (xp->xp_context == EXPAND_MENUNAMES) 2684 { 2685 // Hitting <Down> after "emenu Name.": complete submenu 2686 if (c == K_DOWN && cclp->cmdpos > 0 2687 && cclp->cmdbuff[cclp->cmdpos - 1] == '.') 2688 { 2689 c = p_wc; 2690 KeyTyped = TRUE; // in case the key was mapped 2691 } 2692 else if (c == K_UP) 2693 { 2694 // Hitting <Up>: Remove one submenu name in front of the 2695 // cursor 2696 int found = FALSE; 2697 2698 j = (int)(xp->xp_pattern - cclp->cmdbuff); 2699 i = 0; 2700 while (--j > 0) 2701 { 2702 // check for start of menu name 2703 if (cclp->cmdbuff[j] == ' ' 2704 && cclp->cmdbuff[j - 1] != '\\') 2705 { 2706 i = j + 1; 2707 break; 2708 } 2709 // check for start of submenu name 2710 if (cclp->cmdbuff[j] == '.' 2711 && cclp->cmdbuff[j - 1] != '\\') 2712 { 2713 if (found) 2714 { 2715 i = j + 1; 2716 break; 2717 } 2718 else 2719 found = TRUE; 2720 } 2721 } 2722 if (i > 0) 2723 cmdline_del(cclp, i); 2724 c = p_wc; 2725 KeyTyped = TRUE; // in case the key was mapped 2726 xp->xp_context = EXPAND_NOTHING; 2727 } 2728 } 2729 if ((xp->xp_context == EXPAND_FILES 2730 || xp->xp_context == EXPAND_DIRECTORIES 2731 || xp->xp_context == EXPAND_SHELLCMD)) 2732 { 2733 char_u upseg[5]; 2734 2735 upseg[0] = PATHSEP; 2736 upseg[1] = '.'; 2737 upseg[2] = '.'; 2738 upseg[3] = PATHSEP; 2739 upseg[4] = NUL; 2740 2741 if (c == K_DOWN 2742 && cclp->cmdpos > 0 2743 && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP 2744 && (cclp->cmdpos < 3 2745 || cclp->cmdbuff[cclp->cmdpos - 2] != '.' 2746 || cclp->cmdbuff[cclp->cmdpos - 3] != '.')) 2747 { 2748 // go down a directory 2749 c = p_wc; 2750 KeyTyped = TRUE; // in case the key was mapped 2751 } 2752 else if (STRNCMP(xp->xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) 2753 { 2754 // If in a direct ancestor, strip off one ../ to go down 2755 int found = FALSE; 2756 2757 j = cclp->cmdpos; 2758 i = (int)(xp->xp_pattern - cclp->cmdbuff); 2759 while (--j > i) 2760 { 2761 if (has_mbyte) 2762 j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); 2763 if (vim_ispathsep(cclp->cmdbuff[j])) 2764 { 2765 found = TRUE; 2766 break; 2767 } 2768 } 2769 if (found 2770 && cclp->cmdbuff[j - 1] == '.' 2771 && cclp->cmdbuff[j - 2] == '.' 2772 && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2)) 2773 { 2774 cmdline_del(cclp, j - 2); 2775 c = p_wc; 2776 KeyTyped = TRUE; // in case the key was mapped 2777 } 2778 } 2779 else if (c == K_UP) 2780 { 2781 // go up a directory 2782 int found = FALSE; 2783 2784 j = cclp->cmdpos - 1; 2785 i = (int)(xp->xp_pattern - cclp->cmdbuff); 2786 while (--j > i) 2787 { 2788 if (has_mbyte) 2789 j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); 2790 if (vim_ispathsep(cclp->cmdbuff[j]) 2791 # ifdef BACKSLASH_IN_FILENAME 2792 && vim_strchr((char_u *)" *?[{`$%#", 2793 cclp->cmdbuff[j + 1]) == NULL 2794 # endif 2795 ) 2796 { 2797 if (found) 2798 { 2799 i = j + 1; 2800 break; 2801 } 2802 else 2803 found = TRUE; 2804 } 2805 } 2806 2807 if (!found) 2808 j = i; 2809 else if (STRNCMP(cclp->cmdbuff + j, upseg, 4) == 0) 2810 j += 4; 2811 else if (STRNCMP(cclp->cmdbuff + j, upseg + 1, 3) == 0 2812 && j == i) 2813 j += 3; 2814 else 2815 j = 0; 2816 if (j > 0) 2817 { 2818 // TODO this is only for DOS/UNIX systems - need to put in 2819 // machine-specific stuff here and in upseg init 2820 cmdline_del(cclp, j); 2821 put_on_cmdline(upseg + 1, 3, FALSE); 2822 } 2823 else if (cclp->cmdpos > i) 2824 cmdline_del(cclp, i); 2825 2826 // Now complete in the new directory. Set KeyTyped in case the 2827 // Up key came from a mapping. 2828 c = p_wc; 2829 KeyTyped = TRUE; 2830 } 2831 } 2832 2833 return c; 2834 } 2835 2836 /* 2837 * Free expanded names when finished walking through the matches 2838 */ 2839 void 2840 wildmenu_cleanup(cmdline_info_T *cclp) 2841 { 2842 int skt = KeyTyped; 2843 int old_RedrawingDisabled = RedrawingDisabled; 2844 2845 if (!p_wmnu || wild_menu_showing == 0) 2846 return; 2847 2848 if (cclp->input_fn) 2849 RedrawingDisabled = 0; 2850 2851 if (wild_menu_showing == WM_SCROLLED) 2852 { 2853 // Entered command line, move it up 2854 cmdline_row--; 2855 redrawcmd(); 2856 } 2857 else if (save_p_ls != -1) 2858 { 2859 // restore 'laststatus' and 'winminheight' 2860 p_ls = save_p_ls; 2861 p_wmh = save_p_wmh; 2862 last_status(FALSE); 2863 update_screen(VALID); // redraw the screen NOW 2864 redrawcmd(); 2865 save_p_ls = -1; 2866 } 2867 else 2868 { 2869 win_redraw_last_status(topframe); 2870 redraw_statuslines(); 2871 } 2872 KeyTyped = skt; 2873 wild_menu_showing = 0; 2874 if (cclp->input_fn) 2875 RedrawingDisabled = old_RedrawingDisabled; 2876 } 2877 #endif 2878 2879 #if defined(FEAT_EVAL) || defined(PROTO) 2880 /* 2881 * "getcompletion()" function 2882 */ 2883 void 2884 f_getcompletion(typval_T *argvars, typval_T *rettv) 2885 { 2886 char_u *pat; 2887 char_u *type; 2888 expand_T xpc; 2889 int filtered = FALSE; 2890 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH 2891 | WILD_NO_BEEP; 2892 2893 if (in_vim9script() 2894 && (check_for_string_arg(argvars, 0) == FAIL 2895 || check_for_string_arg(argvars, 1) == FAIL 2896 || check_for_opt_bool_arg(argvars, 2) == FAIL)) 2897 return; 2898 2899 if (argvars[1].v_type != VAR_STRING) 2900 { 2901 semsg(_(e_invarg2), "type must be a string"); 2902 return; 2903 } 2904 type = tv_get_string(&argvars[1]); 2905 2906 if (argvars[2].v_type != VAR_UNKNOWN) 2907 filtered = tv_get_bool_chk(&argvars[2], NULL); 2908 2909 if (p_wic) 2910 options |= WILD_ICASE; 2911 2912 // For filtered results, 'wildignore' is used 2913 if (!filtered) 2914 options |= WILD_KEEP_ALL; 2915 2916 ExpandInit(&xpc); 2917 if (STRCMP(type, "cmdline") == 0) 2918 { 2919 set_one_cmd_context(&xpc, tv_get_string(&argvars[0])); 2920 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 2921 } 2922 else 2923 { 2924 xpc.xp_pattern = tv_get_string(&argvars[0]); 2925 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 2926 2927 xpc.xp_context = cmdcomplete_str_to_type(type); 2928 if (xpc.xp_context == EXPAND_NOTHING) 2929 { 2930 semsg(_(e_invarg2), type); 2931 return; 2932 } 2933 2934 # if defined(FEAT_MENU) 2935 if (xpc.xp_context == EXPAND_MENUS) 2936 { 2937 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); 2938 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 2939 } 2940 # endif 2941 # ifdef FEAT_CSCOPE 2942 if (xpc.xp_context == EXPAND_CSCOPE) 2943 { 2944 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope); 2945 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 2946 } 2947 # endif 2948 # ifdef FEAT_SIGNS 2949 if (xpc.xp_context == EXPAND_SIGN) 2950 { 2951 set_context_in_sign_cmd(&xpc, xpc.xp_pattern); 2952 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); 2953 } 2954 # endif 2955 } 2956 2957 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); 2958 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) 2959 { 2960 int i; 2961 2962 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); 2963 2964 for (i = 0; i < xpc.xp_numfiles; i++) 2965 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); 2966 } 2967 vim_free(pat); 2968 ExpandCleanup(&xpc); 2969 } 2970 #endif // FEAT_EVAL 2971