comparison src/cmdexpand.c @ 27661:2062de7c0edd v8.2.4356

patch 8.2.4356: command line completion functions are very long Commit: https://github.com/vim/vim/commit/620d8edba01bb2779485718dd1a99ca670ca894b Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sat Feb 12 12:03:07 2022 +0000 patch 8.2.4356: command line completion functions are very long Problem: Command line completion functions are very long. Solution: Refactor into multiple functions. (Yegappan Lakshmanan, closes #9753)
author Bram Moolenaar <Bram@vim.org>
date Sat, 12 Feb 2022 13:15:03 +0100
parents 9caeb7f8b094
children 38eab98ef5a9
comparison
equal deleted inserted replaced
27660:6322a4258c29 27661:2062de7c0edd
347 int cmdline_compl_startcol(void) 347 int cmdline_compl_startcol(void)
348 { 348 {
349 return compl_startcol; 349 return compl_startcol;
350 } 350 }
351 #endif 351 #endif
352
353 /*
354 * Get the next or prev cmdline completion match. The index of the match is set
355 * in 'p_findex'
356 */
357 static char_u *
358 get_next_or_prev_match(
359 int mode,
360 expand_T *xp,
361 int *p_findex,
362 char_u *orig_save)
363 {
364 int findex = *p_findex;
365
366 if (xp->xp_numfiles <= 0)
367 return NULL;
368
369 if (mode == WILD_PREV)
370 {
371 if (findex == -1)
372 findex = xp->xp_numfiles;
373 --findex;
374 }
375 else // mode == WILD_NEXT
376 ++findex;
377
378 // When wrapping around, return the original string, set findex to
379 // -1.
380 if (findex < 0)
381 {
382 if (orig_save == NULL)
383 findex = xp->xp_numfiles - 1;
384 else
385 findex = -1;
386 }
387 if (findex >= xp->xp_numfiles)
388 {
389 if (orig_save == NULL)
390 findex = 0;
391 else
392 findex = -1;
393 }
394 #ifdef FEAT_WILDMENU
395 if (compl_match_array)
396 {
397 compl_selected = findex;
398 cmdline_pum_display();
399 }
400 else if (p_wmnu)
401 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
402 findex, cmd_showtail);
403 #endif
404 *p_findex = findex;
405
406 if (findex == -1)
407 return vim_strsave(orig_save);
408
409 return vim_strsave(xp->xp_files[findex]);
410 }
411
412 /*
413 * Start the command-line expansion and get the matches.
414 */
415 static char_u *
416 ExpandOne_start(int mode, expand_T *xp, char_u *str, int options)
417 {
418 int non_suf_match; // number without matching suffix
419 int i;
420 char_u *ss = NULL;
421
422 // Do the expansion.
423 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
424 options) == FAIL)
425 {
426 #ifdef FNAME_ILLEGAL
427 // Illegal file name has been silently skipped. But when there
428 // are wildcards, the real problem is that there was no match,
429 // causing the pattern to be added, which has illegal characters.
430 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
431 semsg(_(e_no_match_str_2), str);
432 #endif
433 }
434 else if (xp->xp_numfiles == 0)
435 {
436 if (!(options & WILD_SILENT))
437 semsg(_(e_no_match_str_2), str);
438 }
439 else
440 {
441 // Escape the matches for use on the command line.
442 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
443
444 // Check for matching suffixes in file names.
445 if (mode != WILD_ALL && mode != WILD_ALL_KEEP
446 && mode != WILD_LONGEST)
447 {
448 if (xp->xp_numfiles)
449 non_suf_match = xp->xp_numfiles;
450 else
451 non_suf_match = 1;
452 if ((xp->xp_context == EXPAND_FILES
453 || xp->xp_context == EXPAND_DIRECTORIES)
454 && xp->xp_numfiles > 1)
455 {
456 // More than one match; check suffix.
457 // The files will have been sorted on matching suffix in
458 // expand_wildcards, only need to check the first two.
459 non_suf_match = 0;
460 for (i = 0; i < 2; ++i)
461 if (match_suffix(xp->xp_files[i]))
462 ++non_suf_match;
463 }
464 if (non_suf_match != 1)
465 {
466 // Can we ever get here unless it's while expanding
467 // interactively? If not, we can get rid of this all
468 // together. Don't really want to wait for this message
469 // (and possibly have to hit return to continue!).
470 if (!(options & WILD_SILENT))
471 emsg(_(e_too_many_file_names));
472 else if (!(options & WILD_NO_BEEP))
473 beep_flush();
474 }
475 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
476 ss = vim_strsave(xp->xp_files[0]);
477 }
478 }
479
480 return ss;
481 }
482
483 /*
484 * Return the longest common part in the list of cmdline completion matches.
485 */
486 static char_u *
487 find_longest_match(expand_T *xp, int options)
488 {
489 long_u len;
490 int mb_len = 1;
491 int c0, ci;
492 int i;
493 char_u *ss;
494
495 for (len = 0; xp->xp_files[0][len]; len += mb_len)
496 {
497 if (has_mbyte)
498 {
499 mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]);
500 c0 =(* mb_ptr2char)(&xp->xp_files[0][len]);
501 }
502 else
503 c0 = xp->xp_files[0][len];
504 for (i = 1; i < xp->xp_numfiles; ++i)
505 {
506 if (has_mbyte)
507 ci =(* mb_ptr2char)(&xp->xp_files[i][len]);
508 else
509 ci = xp->xp_files[i][len];
510 if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES
511 || xp->xp_context == EXPAND_FILES
512 || xp->xp_context == EXPAND_SHELLCMD
513 || xp->xp_context == EXPAND_BUFFERS))
514 {
515 if (MB_TOLOWER(c0) != MB_TOLOWER(ci))
516 break;
517 }
518 else if (c0 != ci)
519 break;
520 }
521 if (i < xp->xp_numfiles)
522 {
523 if (!(options & WILD_NO_BEEP))
524 vim_beep(BO_WILD);
525 break;
526 }
527 }
528
529 ss = alloc(len + 1);
530 if (ss)
531 vim_strncpy(ss, xp->xp_files[0], (size_t)len);
532
533 return ss;
534 }
352 535
353 /* 536 /*
354 * Do wildcard expansion on the string 'str'. 537 * Do wildcard expansion on the string 'str'.
355 * Chars that should not be expanded must be preceded with a backslash. 538 * Chars that should not be expanded must be preceded with a backslash.
356 * Return a pointer to allocated memory containing the new string. 539 * Return a pointer to allocated memory containing the new string.
369 * mode = WILD_NEXT: use next match in multiple match, wrap to first 552 * mode = WILD_NEXT: use next match in multiple match, wrap to first
370 * mode = WILD_PREV: use previous match in multiple match, wrap to first 553 * mode = WILD_PREV: use previous match in multiple match, wrap to first
371 * mode = WILD_ALL: return all matches concatenated 554 * mode = WILD_ALL: return all matches concatenated
372 * mode = WILD_LONGEST: return longest matched part 555 * mode = WILD_LONGEST: return longest matched part
373 * mode = WILD_ALL_KEEP: get all matches, keep matches 556 * mode = WILD_ALL_KEEP: get all matches, keep matches
557 * mode = WILD_APPLY: apply the item selected in the cmdline completion
558 * popup menu and close the menu.
559 * mode = WILD_CANCEL: cancel and close the cmdline completion popup and
560 * use the original text.
374 * 561 *
375 * options = WILD_LIST_NOTFOUND: list entries without a match 562 * options = WILD_LIST_NOTFOUND: list entries without a match
376 * options = WILD_HOME_REPLACE: do home_replace() for buffer names 563 * options = WILD_HOME_REPLACE: do home_replace() for buffer names
377 * options = WILD_USE_NL: Use '\n' for WILD_ALL 564 * options = WILD_USE_NL: Use '\n' for WILD_ALL
378 * options = WILD_NO_BEEP: Don't beep for multiple matches 565 * options = WILD_NO_BEEP: Don't beep for multiple matches
397 static int findex; 584 static int findex;
398 static char_u *orig_save = NULL; // kept value of orig 585 static char_u *orig_save = NULL; // kept value of orig
399 int orig_saved = FALSE; 586 int orig_saved = FALSE;
400 int i; 587 int i;
401 long_u len; 588 long_u len;
402 int non_suf_match; // number without matching suffix
403 589
404 // first handle the case of using an old match 590 // first handle the case of using an old match
405 if (mode == WILD_NEXT || mode == WILD_PREV) 591 if (mode == WILD_NEXT || mode == WILD_PREV)
406 { 592 return get_next_or_prev_match(mode, xp, &findex, orig_save);
407 if (xp->xp_numfiles > 0)
408 {
409 if (mode == WILD_PREV)
410 {
411 if (findex == -1)
412 findex = xp->xp_numfiles;
413 --findex;
414 }
415 else // mode == WILD_NEXT
416 ++findex;
417
418 // When wrapping around, return the original string, set findex to
419 // -1.
420 if (findex < 0)
421 {
422 if (orig_save == NULL)
423 findex = xp->xp_numfiles - 1;
424 else
425 findex = -1;
426 }
427 if (findex >= xp->xp_numfiles)
428 {
429 if (orig_save == NULL)
430 findex = 0;
431 else
432 findex = -1;
433 }
434 #ifdef FEAT_WILDMENU
435 if (compl_match_array)
436 {
437 compl_selected = findex;
438 cmdline_pum_display();
439 }
440 else if (p_wmnu)
441 win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files,
442 findex, cmd_showtail);
443 #endif
444 if (findex == -1)
445 return vim_strsave(orig_save);
446 return vim_strsave(xp->xp_files[findex]);
447 }
448 else
449 return NULL;
450 }
451 593
452 if (mode == WILD_CANCEL) 594 if (mode == WILD_CANCEL)
453 ss = vim_strsave(orig_save ? orig_save : (char_u *)""); 595 ss = vim_strsave(orig_save ? orig_save : (char_u *)"");
454 else if (mode == WILD_APPLY) 596 else if (mode == WILD_APPLY)
455 ss = vim_strsave(findex == -1 ? (orig_save ? 597 ss = vim_strsave(findex == -1 ? (orig_save ?
471 { 613 {
472 vim_free(orig_save); 614 vim_free(orig_save);
473 orig_save = orig; 615 orig_save = orig;
474 orig_saved = TRUE; 616 orig_saved = TRUE;
475 617
476 // Do the expansion. 618 ss = ExpandOne_start(mode, xp, str, options);
477 if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
478 options) == FAIL)
479 {
480 #ifdef FNAME_ILLEGAL
481 // Illegal file name has been silently skipped. But when there
482 // are wildcards, the real problem is that there was no match,
483 // causing the pattern to be added, which has illegal characters.
484 if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
485 semsg(_(e_no_match_str_2), str);
486 #endif
487 }
488 else if (xp->xp_numfiles == 0)
489 {
490 if (!(options & WILD_SILENT))
491 semsg(_(e_no_match_str_2), str);
492 }
493 else
494 {
495 // Escape the matches for use on the command line.
496 ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
497
498 // Check for matching suffixes in file names.
499 if (mode != WILD_ALL && mode != WILD_ALL_KEEP
500 && mode != WILD_LONGEST)
501 {
502 if (xp->xp_numfiles)
503 non_suf_match = xp->xp_numfiles;
504 else
505 non_suf_match = 1;
506 if ((xp->xp_context == EXPAND_FILES
507 || xp->xp_context == EXPAND_DIRECTORIES)
508 && xp->xp_numfiles > 1)
509 {
510 // More than one match; check suffix.
511 // The files will have been sorted on matching suffix in
512 // expand_wildcards, only need to check the first two.
513 non_suf_match = 0;
514 for (i = 0; i < 2; ++i)
515 if (match_suffix(xp->xp_files[i]))
516 ++non_suf_match;
517 }
518 if (non_suf_match != 1)
519 {
520 // Can we ever get here unless it's while expanding
521 // interactively? If not, we can get rid of this all
522 // together. Don't really want to wait for this message
523 // (and possibly have to hit return to continue!).
524 if (!(options & WILD_SILENT))
525 emsg(_(e_too_many_file_names));
526 else if (!(options & WILD_NO_BEEP))
527 beep_flush();
528 }
529 if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
530 ss = vim_strsave(xp->xp_files[0]);
531 }
532 }
533 } 619 }
534 620
535 // Find longest common part 621 // Find longest common part
536 if (mode == WILD_LONGEST && xp->xp_numfiles > 0) 622 if (mode == WILD_LONGEST && xp->xp_numfiles > 0)
537 { 623 {
538 int mb_len = 1; 624 ss = find_longest_match(xp, options);
539 int c0, ci;
540
541 for (len = 0; xp->xp_files[0][len]; len += mb_len)
542 {
543 if (has_mbyte)
544 {
545 mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]);
546 c0 =(* mb_ptr2char)(&xp->xp_files[0][len]);
547 }
548 else
549 c0 = xp->xp_files[0][len];
550 for (i = 1; i < xp->xp_numfiles; ++i)
551 {
552 if (has_mbyte)
553 ci =(* mb_ptr2char)(&xp->xp_files[i][len]);
554 else
555 ci = xp->xp_files[i][len];
556 if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES
557 || xp->xp_context == EXPAND_FILES
558 || xp->xp_context == EXPAND_SHELLCMD
559 || xp->xp_context == EXPAND_BUFFERS))
560 {
561 if (MB_TOLOWER(c0) != MB_TOLOWER(ci))
562 break;
563 }
564 else if (c0 != ci)
565 break;
566 }
567 if (i < xp->xp_numfiles)
568 {
569 if (!(options & WILD_NO_BEEP))
570 vim_beep(BO_WILD);
571 break;
572 }
573 }
574
575 ss = alloc(len + 1);
576 if (ss)
577 vim_strncpy(ss, xp->xp_files[0], (size_t)len);
578 findex = -1; // next p_wc gets first one 625 findex = -1; // next p_wc gets first one
579 } 626 }
580 627
581 // Concatenate all matching names 628 // Concatenate all matching names
582 if (mode == WILD_ALL && xp->xp_numfiles > 0) 629 if (mode == WILD_ALL && xp->xp_numfiles > 0)
1075 } 1122 }
1076 set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, TRUE); 1123 set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, TRUE);
1077 } 1124 }
1078 1125
1079 /* 1126 /*
1080 * This is all pretty much copied from do_one_cmd(), with all the extra stuff 1127 * Sets the index of a built-in or user defined command 'cmd' in eap->cmdidx.
1081 * we don't need/want deleted. Maybe this could be done better if we didn't 1128 * For user defined commands, the completion context is set in 'xp' and the
1082 * repeat all this stuff. The only problem is that they may not stay 1129 * completion flags in 'complp'.
1083 * perfectly compatible with each other, but then the command line syntax 1130 *
1084 * probably won't change that much -- webb. 1131 * Returns a pointer to the text after the command or NULL for failure.
1085 */ 1132 */
1086 static char_u * 1133 static char_u *
1087 set_one_cmd_context( 1134 set_cmd_index(char_u *cmd, exarg_T *eap, expand_T *xp, int *complp)
1088 expand_T *xp, 1135 {
1089 char_u *buff) // buffer for command string 1136 char_u *p = NULL;
1090 { 1137 int len = 0;
1091 char_u *p;
1092 char_u *cmd, *arg;
1093 int len = 0;
1094 exarg_T ea;
1095 int compl = EXPAND_NOTHING;
1096 int delim;
1097 int forceit = FALSE;
1098 int usefilter = FALSE; // filter instead of file name
1099
1100 ExpandInit(xp);
1101 xp->xp_pattern = buff;
1102 xp->xp_line = buff;
1103 xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
1104 ea.argt = 0;
1105
1106 // 1. skip comment lines and leading space, colons or bars
1107 for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
1108 ;
1109 xp->xp_pattern = cmd;
1110
1111 if (*cmd == NUL)
1112 return NULL;
1113 if (*cmd == '"') // ignore comment lines
1114 {
1115 xp->xp_context = EXPAND_NOTHING;
1116 return NULL;
1117 }
1118
1119 // 3. Skip over the range to find the command.
1120 cmd = skip_range(cmd, TRUE, &xp->xp_context);
1121 xp->xp_pattern = cmd;
1122 if (*cmd == NUL)
1123 return NULL;
1124 if (*cmd == '"')
1125 {
1126 xp->xp_context = EXPAND_NOTHING;
1127 return NULL;
1128 }
1129
1130 if (*cmd == '|' || *cmd == '\n')
1131 return cmd + 1; // There's another command
1132 1138
1133 // Isolate the command and search for it in the command table. 1139 // Isolate the command and search for it in the command table.
1134 // Exceptions: 1140 // Exceptions:
1135 // - the 'k' command can directly be followed by any character, but 1141 // - the 'k' command can directly be followed by any character, but
1136 // do accept "keepmarks", "keepalt" and "keepjumps". 1142 // do accept "keepmarks", "keepalt" and "keepjumps".
1137 // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' 1143 // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
1138 if (*cmd == 'k' && cmd[1] != 'e') 1144 if (*cmd == 'k' && cmd[1] != 'e')
1139 { 1145 {
1140 ea.cmdidx = CMD_k; 1146 eap->cmdidx = CMD_k;
1141 p = cmd + 1; 1147 p = cmd + 1;
1142 } 1148 }
1143 else 1149 else
1144 { 1150 {
1145 p = cmd; 1151 p = cmd;
1166 { 1172 {
1167 xp->xp_context = EXPAND_UNSUCCESSFUL; 1173 xp->xp_context = EXPAND_UNSUCCESSFUL;
1168 return NULL; 1174 return NULL;
1169 } 1175 }
1170 1176
1171 ea.cmdidx = excmd_get_cmdidx(cmd, len); 1177 eap->cmdidx = excmd_get_cmdidx(cmd, len);
1172 1178
1173 if (cmd[0] >= 'A' && cmd[0] <= 'Z') 1179 if (cmd[0] >= 'A' && cmd[0] <= 'Z')
1174 while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card 1180 while (ASCII_ISALNUM(*p) || *p == '*') // Allow * wild card
1175 ++p; 1181 ++p;
1176 } 1182 }
1178 // If the cursor is touching the command, and it ends in an alphanumeric 1184 // If the cursor is touching the command, and it ends in an alphanumeric
1179 // character, complete the command name. 1185 // character, complete the command name.
1180 if (*p == NUL && ASCII_ISALNUM(p[-1])) 1186 if (*p == NUL && ASCII_ISALNUM(p[-1]))
1181 return NULL; 1187 return NULL;
1182 1188
1183 if (ea.cmdidx == CMD_SIZE) 1189 if (eap->cmdidx == CMD_SIZE)
1184 { 1190 {
1185 if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) 1191 if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
1186 { 1192 {
1187 ea.cmdidx = CMD_substitute; 1193 eap->cmdidx = CMD_substitute;
1188 p = cmd + 1; 1194 p = cmd + 1;
1189 } 1195 }
1190 else if (cmd[0] >= 'A' && cmd[0] <= 'Z') 1196 else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
1191 { 1197 {
1192 ea.cmd = cmd; 1198 eap->cmd = cmd;
1193 p = find_ucmd(&ea, p, NULL, xp, &compl); 1199 p = find_ucmd(eap, p, NULL, xp, complp);
1194 if (p == NULL) 1200 if (p == NULL)
1195 ea.cmdidx = CMD_SIZE; // ambiguous user command 1201 eap->cmdidx = CMD_SIZE; // ambiguous user command
1196 } 1202 }
1197 } 1203 }
1198 if (ea.cmdidx == CMD_SIZE) 1204 if (eap->cmdidx == CMD_SIZE)
1199 { 1205 {
1200 // Not still touching the command and it was an illegal one 1206 // Not still touching the command and it was an illegal one
1201 xp->xp_context = EXPAND_UNSUCCESSFUL; 1207 xp->xp_context = EXPAND_UNSUCCESSFUL;
1202 return NULL; 1208 return NULL;
1203 } 1209 }
1204 1210
1205 xp->xp_context = EXPAND_NOTHING; // Default now that we're past command 1211 return p;
1206 1212 }
1207 if (*p == '!') // forced commands 1213
1208 { 1214 /*
1209 forceit = TRUE; 1215 * Set the completion context for a command argument with wild card characters.
1210 ++p; 1216 */
1211 } 1217 static void
1212 1218 set_context_for_wildcard_arg(
1213 // 6. parse arguments 1219 exarg_T *eap,
1214 if (!IS_USER_CMDIDX(ea.cmdidx)) 1220 char_u *arg,
1215 ea.argt = excmd_get_argt(ea.cmdidx); 1221 int usefilter,
1216 1222 expand_T *xp,
1217 arg = skipwhite(p); 1223 int *complp)
1218 1224 {
1219 // Skip over ++argopt argument 1225 char_u *p;
1220 if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0) 1226 int c;
1221 { 1227 int in_quote = FALSE;
1222 p = arg; 1228 char_u *bow = NULL; // Beginning of word
1223 while (*p && !vim_isspace(*p)) 1229 int len = 0;
1224 MB_PTR_ADV(p); 1230
1225 arg = skipwhite(p); 1231 // Allow spaces within back-quotes to count as part of the argument
1226 } 1232 // being expanded.
1227 1233 xp->xp_pattern = skipwhite(arg);
1228 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) 1234 p = xp->xp_pattern;
1229 { 1235 while (*p != NUL)
1230 if (*arg == '>') // append 1236 {
1231 { 1237 if (has_mbyte)
1232 if (*++arg == '>') 1238 c = mb_ptr2char(p);
1233 ++arg;
1234 arg = skipwhite(arg);
1235 }
1236 else if (*arg == '!' && ea.cmdidx == CMD_write) // :w !filter
1237 {
1238 ++arg;
1239 usefilter = TRUE;
1240 }
1241 }
1242
1243 if (ea.cmdidx == CMD_read)
1244 {
1245 usefilter = forceit; // :r! filter if forced
1246 if (*arg == '!') // :r !filter
1247 {
1248 ++arg;
1249 usefilter = TRUE;
1250 }
1251 }
1252
1253 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
1254 {
1255 while (*arg == *cmd) // allow any number of '>' or '<'
1256 ++arg;
1257 arg = skipwhite(arg);
1258 }
1259
1260 // Does command allow "+command"?
1261 if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+')
1262 {
1263 // Check if we're in the +command
1264 p = arg + 1;
1265 arg = skip_cmd_arg(arg, FALSE);
1266
1267 // Still touching the command after '+'?
1268 if (*arg == NUL)
1269 return p;
1270
1271 // Skip space(s) after +command to get to the real argument
1272 arg = skipwhite(arg);
1273 }
1274
1275
1276 // Check for '|' to separate commands and '"' to start comments.
1277 // Don't do this for ":read !cmd" and ":write !cmd".
1278 if ((ea.argt & EX_TRLBAR) && !usefilter)
1279 {
1280 p = arg;
1281 // ":redir @" is not the start of a comment
1282 if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
1283 p += 2;
1284 while (*p)
1285 {
1286 if (*p == Ctrl_V)
1287 {
1288 if (p[1] != NUL)
1289 ++p;
1290 }
1291 else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM))
1292 || *p == '|' || *p == '\n')
1293 {
1294 if (*(p - 1) != '\\')
1295 {
1296 if (*p == '|' || *p == '\n')
1297 return p + 1;
1298 return NULL; // It's a comment
1299 }
1300 }
1301 MB_PTR_ADV(p);
1302 }
1303 }
1304
1305 if (!(ea.argt & EX_EXTRA) && *arg != NUL
1306 && vim_strchr((char_u *)"|\"", *arg) == NULL)
1307 // no arguments allowed but there is something
1308 return NULL;
1309
1310 // Find start of last argument (argument just before cursor):
1311 p = buff;
1312 xp->xp_pattern = p;
1313 len = (int)STRLEN(buff);
1314 while (*p && p < buff + len)
1315 {
1316 if (*p == ' ' || *p == TAB)
1317 {
1318 // argument starts after a space
1319 xp->xp_pattern = ++p;
1320 }
1321 else 1239 else
1322 { 1240 c = *p;
1323 if (*p == '\\' && *(p + 1) != NUL) 1241 if (c == '\\' && p[1] != NUL)
1324 ++p; // skip over escaped character 1242 ++p;
1325 MB_PTR_ADV(p); 1243 else if (c == '`')
1326 } 1244 {
1327 } 1245 if (!in_quote)
1328 1246 {
1329 if (ea.argt & EX_XFILE) 1247 xp->xp_pattern = p;
1330 { 1248 bow = p + 1;
1331 int c; 1249 }
1332 int in_quote = FALSE; 1250 in_quote = !in_quote;
1333 char_u *bow = NULL; // Beginning of word 1251 }
1334 1252 // An argument can contain just about everything, except
1335 // Allow spaces within back-quotes to count as part of the argument 1253 // characters that end the command and white space.
1336 // being expanded. 1254 else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c)
1337 xp->xp_pattern = skipwhite(arg); 1255 #ifdef SPACE_IN_FILENAME
1338 p = xp->xp_pattern; 1256 && (!(eap->argt & EX_NOSPC) || usefilter)
1339 while (*p != NUL) 1257 #endif
1340 { 1258 ))
1341 if (has_mbyte) 1259 {
1342 c = mb_ptr2char(p); 1260 len = 0; // avoid getting stuck when space is in 'isfname'
1261 while (*p != NUL)
1262 {
1263 if (has_mbyte)
1264 c = mb_ptr2char(p);
1265 else
1266 c = *p;
1267 if (c == '`' || vim_isfilec_or_wc(c))
1268 break;
1269 if (has_mbyte)
1270 len = (*mb_ptr2len)(p);
1271 else
1272 len = 1;
1273 MB_PTR_ADV(p);
1274 }
1275 if (in_quote)
1276 bow = p;
1343 else 1277 else
1344 c = *p; 1278 xp->xp_pattern = p;
1345 if (c == '\\' && p[1] != NUL) 1279 p -= len;
1346 ++p; 1280 }
1347 else if (c == '`') 1281 MB_PTR_ADV(p);
1348 { 1282 }
1349 if (!in_quote) 1283
1350 { 1284 // If we are still inside the quotes, and we passed a space, just
1351 xp->xp_pattern = p; 1285 // expand from there.
1352 bow = p + 1; 1286 if (bow != NULL && in_quote)
1353 } 1287 xp->xp_pattern = bow;
1354 in_quote = !in_quote; 1288 xp->xp_context = EXPAND_FILES;
1355 } 1289
1356 // An argument can contain just about everything, except 1290 // For a shell command more chars need to be escaped.
1357 // characters that end the command and white space. 1291 if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal)
1358 else if (c == '|' || c == '\n' || c == '"' || (VIM_ISWHITE(c) 1292 {
1359 #ifdef SPACE_IN_FILENAME
1360 && (!(ea.argt & EX_NOSPC) || usefilter)
1361 #endif
1362 ))
1363 {
1364 len = 0; // avoid getting stuck when space is in 'isfname'
1365 while (*p != NUL)
1366 {
1367 if (has_mbyte)
1368 c = mb_ptr2char(p);
1369 else
1370 c = *p;
1371 if (c == '`' || vim_isfilec_or_wc(c))
1372 break;
1373 if (has_mbyte)
1374 len = (*mb_ptr2len)(p);
1375 else
1376 len = 1;
1377 MB_PTR_ADV(p);
1378 }
1379 if (in_quote)
1380 bow = p;
1381 else
1382 xp->xp_pattern = p;
1383 p -= len;
1384 }
1385 MB_PTR_ADV(p);
1386 }
1387
1388 // If we are still inside the quotes, and we passed a space, just
1389 // expand from there.
1390 if (bow != NULL && in_quote)
1391 xp->xp_pattern = bow;
1392 xp->xp_context = EXPAND_FILES;
1393
1394 // For a shell command more chars need to be escaped.
1395 if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal)
1396 {
1397 #ifndef BACKSLASH_IN_FILENAME 1293 #ifndef BACKSLASH_IN_FILENAME
1398 xp->xp_shell = TRUE; 1294 xp->xp_shell = TRUE;
1399 #endif 1295 #endif
1400 // When still after the command name expand executables. 1296 // When still after the command name expand executables.
1401 if (xp->xp_pattern == skipwhite(arg)) 1297 if (xp->xp_pattern == skipwhite(arg))
1402 xp->xp_context = EXPAND_SHELLCMD; 1298 xp->xp_context = EXPAND_SHELLCMD;
1403 } 1299 }
1404 1300
1405 // Check for environment variable. 1301 // Check for environment variable.
1406 if (*xp->xp_pattern == '$') 1302 if (*xp->xp_pattern == '$')
1407 { 1303 {
1408 for (p = xp->xp_pattern + 1; *p != NUL; ++p) 1304 for (p = xp->xp_pattern + 1; *p != NUL; ++p)
1409 if (!vim_isIDc(*p)) 1305 if (!vim_isIDc(*p))
1410 break; 1306 break;
1411 if (*p == NUL) 1307 if (*p == NUL)
1412 { 1308 {
1413 xp->xp_context = EXPAND_ENV_VARS; 1309 xp->xp_context = EXPAND_ENV_VARS;
1414 ++xp->xp_pattern; 1310 ++xp->xp_pattern;
1415 // Avoid that the assignment uses EXPAND_FILES again. 1311 // Avoid that the assignment uses EXPAND_FILES again.
1416 if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) 1312 if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST)
1417 compl = EXPAND_ENV_VARS; 1313 *complp = EXPAND_ENV_VARS;
1418 } 1314 }
1419 } 1315 }
1420 // Check for user names. 1316 // Check for user names.
1421 if (*xp->xp_pattern == '~') 1317 if (*xp->xp_pattern == '~')
1422 { 1318 {
1423 for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) 1319 for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
1424 ; 1320 ;
1425 // Complete ~user only if it partially matches a user name. 1321 // Complete ~user only if it partially matches a user name.
1426 // A full match ~user<Tab> will be replaced by user's home 1322 // A full match ~user<Tab> will be replaced by user's home
1427 // directory i.e. something like ~user<Tab> -> /home/user/ 1323 // directory i.e. something like ~user<Tab> -> /home/user/
1428 if (*p == NUL && p > xp->xp_pattern + 1 1324 if (*p == NUL && p > xp->xp_pattern + 1
1429 && match_user(xp->xp_pattern + 1) >= 1) 1325 && match_user(xp->xp_pattern + 1) >= 1)
1430 { 1326 {
1431 xp->xp_context = EXPAND_USER; 1327 xp->xp_context = EXPAND_USER;
1432 ++xp->xp_pattern; 1328 ++xp->xp_pattern;
1433 } 1329 }
1434 } 1330 }
1435 } 1331 }
1436 1332
1437 // 6. Switch on command name. 1333 /*
1438 switch (ea.cmdidx) 1334 * Set the completion context in 'xp' for command 'cmd' with index 'cmdidx'.
1335 * The argument to the command is 'arg' and the argument flags is 'argt'.
1336 * For user-defined commands and for environment variables, 'compl' has the
1337 * completion type.
1338 * Returns a pointer to the next command. Returns NULL if there is no next
1339 * command.
1340 */
1341 static char_u *
1342 set_context_by_cmdname(
1343 char_u *cmd,
1344 cmdidx_T cmdidx,
1345 char_u *arg,
1346 long argt,
1347 int compl,
1348 expand_T *xp,
1349 int forceit)
1350 {
1351 char_u *p;
1352 int delim;
1353
1354 switch (cmdidx)
1439 { 1355 {
1440 case CMD_find: 1356 case CMD_find:
1441 case CMD_sfind: 1357 case CMD_sfind:
1442 case CMD_tabfind: 1358 case CMD_tabfind:
1443 if (xp->xp_context == EXPAND_FILES) 1359 if (xp->xp_context == EXPAND_FILES)
1656 case CMD_caddexpr: 1572 case CMD_caddexpr:
1657 case CMD_cgetexpr: 1573 case CMD_cgetexpr:
1658 case CMD_lexpr: 1574 case CMD_lexpr:
1659 case CMD_laddexpr: 1575 case CMD_laddexpr:
1660 case CMD_lgetexpr: 1576 case CMD_lgetexpr:
1661 set_context_for_expression(xp, arg, ea.cmdidx); 1577 set_context_for_expression(xp, arg, cmdidx);
1662 break; 1578 break;
1663 1579
1664 case CMD_unlet: 1580 case CMD_unlet:
1665 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) 1581 while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
1666 arg = xp->xp_pattern + 1; 1582 arg = xp->xp_pattern + 1;
1694 break; 1610 break;
1695 #ifdef FEAT_CSCOPE 1611 #ifdef FEAT_CSCOPE
1696 case CMD_cscope: 1612 case CMD_cscope:
1697 case CMD_lcscope: 1613 case CMD_lcscope:
1698 case CMD_scscope: 1614 case CMD_scscope:
1699 set_context_in_cscope_cmd(xp, arg, ea.cmdidx); 1615 set_context_in_cscope_cmd(xp, arg, cmdidx);
1700 break; 1616 break;
1701 #endif 1617 #endif
1702 #ifdef FEAT_SIGNS 1618 #ifdef FEAT_SIGNS
1703 case CMD_sign: 1619 case CMD_sign:
1704 set_context_in_sign_cmd(xp, arg); 1620 set_context_in_sign_cmd(xp, arg);
1728 case CMD_USER: 1644 case CMD_USER:
1729 case CMD_USER_BUF: 1645 case CMD_USER_BUF:
1730 if (compl != EXPAND_NOTHING) 1646 if (compl != EXPAND_NOTHING)
1731 { 1647 {
1732 // EX_XFILE: file names are handled above 1648 // EX_XFILE: file names are handled above
1733 if (!(ea.argt & EX_XFILE)) 1649 if (!(argt & EX_XFILE))
1734 { 1650 {
1735 #ifdef FEAT_MENU 1651 #ifdef FEAT_MENU
1736 if (compl == EXPAND_MENUS) 1652 if (compl == EXPAND_MENUS)
1737 return set_context_in_menu_cmd(xp, cmd, arg, forceit); 1653 return set_context_in_menu_cmd(xp, cmd, arg, forceit);
1738 #endif 1654 #endif
1767 case CMD_lmap: case CMD_lnoremap: 1683 case CMD_lmap: case CMD_lnoremap:
1768 case CMD_smap: case CMD_snoremap: 1684 case CMD_smap: case CMD_snoremap:
1769 case CMD_tmap: case CMD_tnoremap: 1685 case CMD_tmap: case CMD_tnoremap:
1770 case CMD_xmap: case CMD_xnoremap: 1686 case CMD_xmap: case CMD_xnoremap:
1771 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1687 return set_context_in_map_cmd(xp, cmd, arg, forceit,
1772 FALSE, FALSE, ea.cmdidx); 1688 FALSE, FALSE, cmdidx);
1773 case CMD_unmap: 1689 case CMD_unmap:
1774 case CMD_nunmap: 1690 case CMD_nunmap:
1775 case CMD_vunmap: 1691 case CMD_vunmap:
1776 case CMD_ounmap: 1692 case CMD_ounmap:
1777 case CMD_iunmap: 1693 case CMD_iunmap:
1779 case CMD_lunmap: 1695 case CMD_lunmap:
1780 case CMD_sunmap: 1696 case CMD_sunmap:
1781 case CMD_tunmap: 1697 case CMD_tunmap:
1782 case CMD_xunmap: 1698 case CMD_xunmap:
1783 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1699 return set_context_in_map_cmd(xp, cmd, arg, forceit,
1784 FALSE, TRUE, ea.cmdidx); 1700 FALSE, TRUE, cmdidx);
1785 case CMD_mapclear: 1701 case CMD_mapclear:
1786 case CMD_nmapclear: 1702 case CMD_nmapclear:
1787 case CMD_vmapclear: 1703 case CMD_vmapclear:
1788 case CMD_omapclear: 1704 case CMD_omapclear:
1789 case CMD_imapclear: 1705 case CMD_imapclear:
1798 1714
1799 case CMD_abbreviate: case CMD_noreabbrev: 1715 case CMD_abbreviate: case CMD_noreabbrev:
1800 case CMD_cabbrev: case CMD_cnoreabbrev: 1716 case CMD_cabbrev: case CMD_cnoreabbrev:
1801 case CMD_iabbrev: case CMD_inoreabbrev: 1717 case CMD_iabbrev: case CMD_inoreabbrev:
1802 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1718 return set_context_in_map_cmd(xp, cmd, arg, forceit,
1803 TRUE, FALSE, ea.cmdidx); 1719 TRUE, FALSE, cmdidx);
1804 case CMD_unabbreviate: 1720 case CMD_unabbreviate:
1805 case CMD_cunabbrev: 1721 case CMD_cunabbrev:
1806 case CMD_iunabbrev: 1722 case CMD_iunabbrev:
1807 return set_context_in_map_cmd(xp, cmd, arg, forceit, 1723 return set_context_in_map_cmd(xp, cmd, arg, forceit,
1808 TRUE, TRUE, ea.cmdidx); 1724 TRUE, TRUE, cmdidx);
1809 #ifdef FEAT_MENU 1725 #ifdef FEAT_MENU
1810 case CMD_menu: case CMD_noremenu: case CMD_unmenu: 1726 case CMD_menu: case CMD_noremenu: case CMD_unmenu:
1811 case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: 1727 case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
1812 case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: 1728 case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
1813 case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu: 1729 case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
1905 break; 1821 break;
1906 } 1822 }
1907 return NULL; 1823 return NULL;
1908 } 1824 }
1909 1825
1826 /*
1827 * This is all pretty much copied from do_one_cmd(), with all the extra stuff
1828 * we don't need/want deleted. Maybe this could be done better if we didn't
1829 * repeat all this stuff. The only problem is that they may not stay
1830 * perfectly compatible with each other, but then the command line syntax
1831 * probably won't change that much -- webb.
1832 */
1833 static char_u *
1834 set_one_cmd_context(
1835 expand_T *xp,
1836 char_u *buff) // buffer for command string
1837 {
1838 char_u *p;
1839 char_u *cmd, *arg;
1840 int len = 0;
1841 exarg_T ea;
1842 int compl = EXPAND_NOTHING;
1843 int forceit = FALSE;
1844 int usefilter = FALSE; // filter instead of file name
1845
1846 ExpandInit(xp);
1847 xp->xp_pattern = buff;
1848 xp->xp_line = buff;
1849 xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
1850 ea.argt = 0;
1851
1852 // 1. skip comment lines and leading space, colons or bars
1853 for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
1854 ;
1855 xp->xp_pattern = cmd;
1856
1857 if (*cmd == NUL)
1858 return NULL;
1859 if (*cmd == '"') // ignore comment lines
1860 {
1861 xp->xp_context = EXPAND_NOTHING;
1862 return NULL;
1863 }
1864
1865 // 3. Skip over the range to find the command.
1866 cmd = skip_range(cmd, TRUE, &xp->xp_context);
1867 xp->xp_pattern = cmd;
1868 if (*cmd == NUL)
1869 return NULL;
1870 if (*cmd == '"')
1871 {
1872 xp->xp_context = EXPAND_NOTHING;
1873 return NULL;
1874 }
1875
1876 if (*cmd == '|' || *cmd == '\n')
1877 return cmd + 1; // There's another command
1878
1879 // Get the command index.
1880 p = set_cmd_index(cmd, &ea, xp, &compl);
1881 if (p == NULL)
1882 return NULL;
1883
1884 xp->xp_context = EXPAND_NOTHING; // Default now that we're past command
1885
1886 if (*p == '!') // forced commands
1887 {
1888 forceit = TRUE;
1889 ++p;
1890 }
1891
1892 // 6. parse arguments
1893 if (!IS_USER_CMDIDX(ea.cmdidx))
1894 ea.argt = excmd_get_argt(ea.cmdidx);
1895
1896 arg = skipwhite(p);
1897
1898 // Skip over ++argopt argument
1899 if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0)
1900 {
1901 p = arg;
1902 while (*p && !vim_isspace(*p))
1903 MB_PTR_ADV(p);
1904 arg = skipwhite(p);
1905 }
1906
1907 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
1908 {
1909 if (*arg == '>') // append
1910 {
1911 if (*++arg == '>')
1912 ++arg;
1913 arg = skipwhite(arg);
1914 }
1915 else if (*arg == '!' && ea.cmdidx == CMD_write) // :w !filter
1916 {
1917 ++arg;
1918 usefilter = TRUE;
1919 }
1920 }
1921
1922 if (ea.cmdidx == CMD_read)
1923 {
1924 usefilter = forceit; // :r! filter if forced
1925 if (*arg == '!') // :r !filter
1926 {
1927 ++arg;
1928 usefilter = TRUE;
1929 }
1930 }
1931
1932 if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
1933 {
1934 while (*arg == *cmd) // allow any number of '>' or '<'
1935 ++arg;
1936 arg = skipwhite(arg);
1937 }
1938
1939 // Does command allow "+command"?
1940 if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+')
1941 {
1942 // Check if we're in the +command
1943 p = arg + 1;
1944 arg = skip_cmd_arg(arg, FALSE);
1945
1946 // Still touching the command after '+'?
1947 if (*arg == NUL)
1948 return p;
1949
1950 // Skip space(s) after +command to get to the real argument
1951 arg = skipwhite(arg);
1952 }
1953
1954
1955 // Check for '|' to separate commands and '"' to start comments.
1956 // Don't do this for ":read !cmd" and ":write !cmd".
1957 if ((ea.argt & EX_TRLBAR) && !usefilter)
1958 {
1959 p = arg;
1960 // ":redir @" is not the start of a comment
1961 if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
1962 p += 2;
1963 while (*p)
1964 {
1965 if (*p == Ctrl_V)
1966 {
1967 if (p[1] != NUL)
1968 ++p;
1969 }
1970 else if ( (*p == '"' && !(ea.argt & EX_NOTRLCOM))
1971 || *p == '|' || *p == '\n')
1972 {
1973 if (*(p - 1) != '\\')
1974 {
1975 if (*p == '|' || *p == '\n')
1976 return p + 1;
1977 return NULL; // It's a comment
1978 }
1979 }
1980 MB_PTR_ADV(p);
1981 }
1982 }
1983
1984 if (!(ea.argt & EX_EXTRA) && *arg != NUL
1985 && vim_strchr((char_u *)"|\"", *arg) == NULL)
1986 // no arguments allowed but there is something
1987 return NULL;
1988
1989 // Find start of last argument (argument just before cursor):
1990 p = buff;
1991 xp->xp_pattern = p;
1992 len = (int)STRLEN(buff);
1993 while (*p && p < buff + len)
1994 {
1995 if (*p == ' ' || *p == TAB)
1996 {
1997 // argument starts after a space
1998 xp->xp_pattern = ++p;
1999 }
2000 else
2001 {
2002 if (*p == '\\' && *(p + 1) != NUL)
2003 ++p; // skip over escaped character
2004 MB_PTR_ADV(p);
2005 }
2006 }
2007
2008 if (ea.argt & EX_XFILE)
2009 set_context_for_wildcard_arg(&ea, arg, usefilter, xp, &compl);
2010
2011 // 6. Switch on command name.
2012 return set_context_by_cmdname(cmd, ea.cmdidx, arg, ea.argt, compl, xp,
2013 forceit);
2014 }
2015
1910 void 2016 void
1911 set_cmd_context( 2017 set_cmd_context(
1912 expand_T *xp, 2018 expand_T *xp,
1913 char_u *str, // start of command line 2019 char_u *str, // start of command line
1914 int len, // length of command line (excl. NUL) 2020 int len, // length of command line (excl. NUL)
2005 2111
2006 return EXPAND_OK; 2112 return EXPAND_OK;
2007 } 2113 }
2008 2114
2009 /* 2115 /*
2116 * Expand file or directory names.
2117 */
2118 static int
2119 expand_files_and_dirs(
2120 expand_T *xp,
2121 char_u *pat,
2122 char_u ***file,
2123 int *num_file,
2124 int flags,
2125 int options)
2126 {
2127 int free_pat = FALSE;
2128 int i;
2129 int ret;
2130
2131 // for ":set path=" and ":set tags=" halve backslashes for escaped
2132 // space
2133 if (xp->xp_backslash != XP_BS_NONE)
2134 {
2135 free_pat = TRUE;
2136 pat = vim_strsave(pat);
2137 for (i = 0; pat[i]; ++i)
2138 if (pat[i] == '\\')
2139 {
2140 if (xp->xp_backslash == XP_BS_THREE
2141 && pat[i + 1] == '\\'
2142 && pat[i + 2] == '\\'
2143 && pat[i + 3] == ' ')
2144 STRMOVE(pat + i, pat + i + 3);
2145 if (xp->xp_backslash == XP_BS_ONE
2146 && pat[i + 1] == ' ')
2147 STRMOVE(pat + i, pat + i + 1);
2148 }
2149 }
2150
2151 if (xp->xp_context == EXPAND_FILES)
2152 flags |= EW_FILE;
2153 else if (xp->xp_context == EXPAND_FILES_IN_PATH)
2154 flags |= (EW_FILE | EW_PATH);
2155 else
2156 flags = (flags | EW_DIR) & ~EW_FILE;
2157 if (options & WILD_ICASE)
2158 flags |= EW_ICASE;
2159
2160 // Expand wildcards, supporting %:h and the like.
2161 ret = expand_wildcards_eval(&pat, num_file, file, flags);
2162 if (free_pat)
2163 vim_free(pat);
2164 #ifdef BACKSLASH_IN_FILENAME
2165 if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0)
2166 {
2167 int j;
2168
2169 for (j = 0; j < *num_file; ++j)
2170 {
2171 char_u *ptr = (*file)[j];
2172
2173 while (*ptr != NUL)
2174 {
2175 if (p_csl[0] == 's' && *ptr == '\\')
2176 *ptr = '/';
2177 else if (p_csl[0] == 'b' && *ptr == '/')
2178 *ptr = '\\';
2179 ptr += (*mb_ptr2len)(ptr);
2180 }
2181 }
2182 }
2183 #endif
2184 return ret;
2185 }
2186
2187 /*
2010 * Function given to ExpandGeneric() to obtain the possible arguments of the 2188 * Function given to ExpandGeneric() to obtain the possible arguments of the
2011 * ":behave {mswin,xterm}" command. 2189 * ":behave {mswin,xterm}" command.
2012 */ 2190 */
2013 static char_u * 2191 static char_u *
2014 get_behave_arg(expand_T *xp UNUSED, int idx) 2192 get_behave_arg(expand_T *xp UNUSED, int idx)
2036 get_mapclear_arg(expand_T *xp UNUSED, int idx) 2214 get_mapclear_arg(expand_T *xp UNUSED, int idx)
2037 { 2215 {
2038 if (idx == 0) 2216 if (idx == 0)
2039 return (char_u *)"<buffer>"; 2217 return (char_u *)"<buffer>";
2040 return NULL; 2218 return NULL;
2219 }
2220
2221 /*
2222 * Do the expansion based on xp->xp_context and 'rmp'.
2223 */
2224 static int
2225 ExpandOther(
2226 expand_T *xp,
2227 regmatch_T *rmp,
2228 int *num_file,
2229 char_u ***file)
2230 {
2231 static struct expgen
2232 {
2233 int context;
2234 char_u *((*func)(expand_T *, int));
2235 int ic;
2236 int escaped;
2237 } tab[] =
2238 {
2239 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE},
2240 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE},
2241 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE},
2242 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE},
2243 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE},
2244 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE},
2245 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE},
2246 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
2247 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
2248 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
2249 # ifdef FEAT_EVAL
2250 {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE},
2251 {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE},
2252 {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE},
2253 {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE},
2254 {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE},
2255 # endif
2256 # ifdef FEAT_MENU
2257 {EXPAND_MENUS, get_menu_name, FALSE, TRUE},
2258 {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE},
2259 # endif
2260 # ifdef FEAT_SYN_HL
2261 {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE},
2262 # endif
2263 # ifdef FEAT_PROFILE
2264 {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE},
2265 # endif
2266 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE},
2267 {EXPAND_EVENTS, get_event_name, TRUE, FALSE},
2268 {EXPAND_AUGROUP, get_augroup_name, TRUE, FALSE},
2269 # ifdef FEAT_CSCOPE
2270 {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE},
2271 # endif
2272 # ifdef FEAT_SIGNS
2273 {EXPAND_SIGN, get_sign_name, TRUE, TRUE},
2274 # endif
2275 # ifdef FEAT_PROFILE
2276 {EXPAND_PROFILE, get_profile_name, TRUE, TRUE},
2277 # endif
2278 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
2279 {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE},
2280 {EXPAND_LOCALES, get_locales, TRUE, FALSE},
2281 # endif
2282 {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
2283 {EXPAND_USER, get_users, TRUE, FALSE},
2284 {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE},
2285 };
2286 int i;
2287 int ret = FAIL;
2288
2289 // Find a context in the table and call the ExpandGeneric() with the
2290 // right function to do the expansion.
2291 for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i)
2292 {
2293 if (xp->xp_context == tab[i].context)
2294 {
2295 if (tab[i].ic)
2296 rmp->rm_ic = TRUE;
2297 ret = ExpandGeneric(xp, rmp, num_file, file,
2298 tab[i].func, tab[i].escaped);
2299 break;
2300 }
2301 }
2302
2303 return ret;
2041 } 2304 }
2042 2305
2043 /* 2306 /*
2044 * Do the expansion based on xp->xp_context and "pat". 2307 * Do the expansion based on xp->xp_context and "pat".
2045 */ 2308 */
2071 flags |= EW_ALLLINKS; 2334 flags |= EW_ALLLINKS;
2072 2335
2073 if (xp->xp_context == EXPAND_FILES 2336 if (xp->xp_context == EXPAND_FILES
2074 || xp->xp_context == EXPAND_DIRECTORIES 2337 || xp->xp_context == EXPAND_DIRECTORIES
2075 || xp->xp_context == EXPAND_FILES_IN_PATH) 2338 || xp->xp_context == EXPAND_FILES_IN_PATH)
2076 { 2339 return expand_files_and_dirs(xp, pat, file, num_file, flags, options);
2077 // Expand file or directory names.
2078 int free_pat = FALSE;
2079 int i;
2080
2081 // for ":set path=" and ":set tags=" halve backslashes for escaped
2082 // space
2083 if (xp->xp_backslash != XP_BS_NONE)
2084 {
2085 free_pat = TRUE;
2086 pat = vim_strsave(pat);
2087 for (i = 0; pat[i]; ++i)
2088 if (pat[i] == '\\')
2089 {
2090 if (xp->xp_backslash == XP_BS_THREE
2091 && pat[i + 1] == '\\'
2092 && pat[i + 2] == '\\'
2093 && pat[i + 3] == ' ')
2094 STRMOVE(pat + i, pat + i + 3);
2095 if (xp->xp_backslash == XP_BS_ONE
2096 && pat[i + 1] == ' ')
2097 STRMOVE(pat + i, pat + i + 1);
2098 }
2099 }
2100
2101 if (xp->xp_context == EXPAND_FILES)
2102 flags |= EW_FILE;
2103 else if (xp->xp_context == EXPAND_FILES_IN_PATH)
2104 flags |= (EW_FILE | EW_PATH);
2105 else
2106 flags = (flags | EW_DIR) & ~EW_FILE;
2107 if (options & WILD_ICASE)
2108 flags |= EW_ICASE;
2109
2110 // Expand wildcards, supporting %:h and the like.
2111 ret = expand_wildcards_eval(&pat, num_file, file, flags);
2112 if (free_pat)
2113 vim_free(pat);
2114 #ifdef BACKSLASH_IN_FILENAME
2115 if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0)
2116 {
2117 int j;
2118
2119 for (j = 0; j < *num_file; ++j)
2120 {
2121 char_u *ptr = (*file)[j];
2122
2123 while (*ptr != NUL)
2124 {
2125 if (p_csl[0] == 's' && *ptr == '\\')
2126 *ptr = '/';
2127 else if (p_csl[0] == 'b' && *ptr == '/')
2128 *ptr = '\\';
2129 ptr += (*mb_ptr2len)(ptr);
2130 }
2131 }
2132 }
2133 #endif
2134 return ret;
2135 }
2136 2340
2137 *file = (char_u **)""; 2341 *file = (char_u **)"";
2138 *num_file = 0; 2342 *num_file = 0;
2139 if (xp->xp_context == EXPAND_HELP) 2343 if (xp->xp_context == EXPAND_HELP)
2140 { 2344 {
2220 # if defined(FEAT_EVAL) 2424 # if defined(FEAT_EVAL)
2221 else if (xp->xp_context == EXPAND_USER_DEFINED) 2425 else if (xp->xp_context == EXPAND_USER_DEFINED)
2222 ret = ExpandUserDefined(xp, &regmatch, num_file, file); 2426 ret = ExpandUserDefined(xp, &regmatch, num_file, file);
2223 # endif 2427 # endif
2224 else 2428 else
2225 { 2429 ret = ExpandOther(xp, &regmatch, num_file, file);
2226 static struct expgen
2227 {
2228 int context;
2229 char_u *((*func)(expand_T *, int));
2230 int ic;
2231 int escaped;
2232 } tab[] =
2233 {
2234 {EXPAND_COMMANDS, get_command_name, FALSE, TRUE},
2235 {EXPAND_BEHAVE, get_behave_arg, TRUE, TRUE},
2236 {EXPAND_MAPCLEAR, get_mapclear_arg, TRUE, TRUE},
2237 {EXPAND_MESSAGES, get_messages_arg, TRUE, TRUE},
2238 {EXPAND_HISTORY, get_history_arg, TRUE, TRUE},
2239 {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE},
2240 {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE},
2241 {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
2242 {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
2243 {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
2244 # ifdef FEAT_EVAL
2245 {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE},
2246 {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE},
2247 {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE},
2248 {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE},
2249 {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE},
2250 # endif
2251 # ifdef FEAT_MENU
2252 {EXPAND_MENUS, get_menu_name, FALSE, TRUE},
2253 {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE},
2254 # endif
2255 # ifdef FEAT_SYN_HL
2256 {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE},
2257 # endif
2258 # ifdef FEAT_PROFILE
2259 {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE},
2260 # endif
2261 {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE},
2262 {EXPAND_EVENTS, get_event_name, TRUE, FALSE},
2263 {EXPAND_AUGROUP, get_augroup_name, TRUE, FALSE},
2264 # ifdef FEAT_CSCOPE
2265 {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE},
2266 # endif
2267 # ifdef FEAT_SIGNS
2268 {EXPAND_SIGN, get_sign_name, TRUE, TRUE},
2269 # endif
2270 # ifdef FEAT_PROFILE
2271 {EXPAND_PROFILE, get_profile_name, TRUE, TRUE},
2272 # endif
2273 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
2274 {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE},
2275 {EXPAND_LOCALES, get_locales, TRUE, FALSE},
2276 # endif
2277 {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
2278 {EXPAND_USER, get_users, TRUE, FALSE},
2279 {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE},
2280 };
2281 int i;
2282
2283 // Find a context in the table and call the ExpandGeneric() with the
2284 // right function to do the expansion.
2285 ret = FAIL;
2286 for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i)
2287 if (xp->xp_context == tab[i].context)
2288 {
2289 if (tab[i].ic)
2290 regmatch.rm_ic = TRUE;
2291 ret = ExpandGeneric(xp, &regmatch, num_file, file,
2292 tab[i].func, tab[i].escaped);
2293 break;
2294 }
2295 }
2296 2430
2297 vim_regfree(regmatch.regprog); 2431 vim_regfree(regmatch.regprog);
2298 vim_free(tofree); 2432 vim_free(tofree);
2299 2433
2300 return ret; 2434 return ret;