Patch 8.2.4406
Problem: Expand functions use confusing argument names.
Solution: Rename "file" to "match". Refactor some completion code. Add a
few more tests. (Yegappan Lakshmanan, closes #9790)
Files: src/cmdexpand.c, src/testdir/test_usercommands.vim
*** ../vim-8.2.4405/src/cmdexpand.c 2022-02-16 12:44:26.129908861 +0000
--- src/cmdexpand.c 2022-02-17 11:22:52.229287488 +0000
***************
*** 17,30 ****
static void set_expand_context(expand_T *xp);
static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch,
! int *num_file, char_u ***file,
char_u *((*func)(expand_T *, int)), int escaped);
! static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int);
static int expand_showtail(expand_T *xp);
! static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg);
#if defined(FEAT_EVAL)
! static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file);
! static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file);
#endif
#ifdef FEAT_WILDMENU
--- 17,30 ----
static void set_expand_context(expand_T *xp);
static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch,
! char_u ***matches, int *numMatches,
char_u *((*func)(expand_T *, int)), int escaped);
! static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int);
static int expand_showtail(expand_T *xp);
! static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg);
#if defined(FEAT_EVAL)
! static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches);
! static int ExpandUserList(expand_T *xp, char_u ***matches, int *numMatches);
#endif
#ifdef FEAT_WILDMENU
***************
*** 37,44 ****
static int compl_selected;
#endif
! #define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(files_found[m]) : files_found[m])
static int
sort_func_compare(const void *s1, const void *s2)
{
--- 37,48 ----
static int compl_selected;
#endif
! #define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(matches[m]) : matches[m])
+ /*
+ * sort function for the completion matches.
+ * <SNR> functions should be sorted to the end.
+ */
static int
sort_func_compare(const void *s1, const void *s2)
{
***************
*** 264,286 ****
/*
* Create and display a cmdline completion popup menu with items from
! * 'files_found'.
*/
static int
cmdline_pum_create(
cmdline_info_T *ccline,
expand_T *xp,
! char_u **files_found,
! int num_files,
int showtail)
{
int i;
int columns;
// Add all the completion matches
! compl_match_arraysize = num_files;
compl_match_array = ALLOC_MULT(pumitem_T, compl_match_arraysize);
! for (i = 0; i < num_files; i++)
{
compl_match_array[i].pum_text = SHOW_FILE_TEXT(i);
compl_match_array[i].pum_info = NULL;
--- 268,290 ----
/*
* Create and display a cmdline completion popup menu with items from
! * 'matches'.
*/
static int
cmdline_pum_create(
cmdline_info_T *ccline,
expand_T *xp,
! char_u **matches,
! int numMatches,
int showtail)
{
int i;
int columns;
// Add all the completion matches
! compl_match_arraysize = numMatches;
compl_match_array = ALLOC_MULT(pumitem_T, compl_match_arraysize);
! for (i = 0; i < numMatches; i++)
{
compl_match_array[i].pum_text = SHOW_FILE_TEXT(i);
compl_match_array[i].pum_info = NULL;
***************
*** 293,300 ****
columns = vim_strsize(xp->xp_pattern);
if (showtail)
{
! columns += vim_strsize(sm_gettail(files_found[0]));
! columns -= vim_strsize(files_found[0]);
}
if (columns >= compl_startcol)
compl_startcol = 0;
--- 297,304 ----
columns = vim_strsize(xp->xp_pattern);
if (showtail)
{
! columns += vim_strsize(sm_gettail(matches[0]));
! columns -= vim_strsize(matches[0]);
}
if (columns >= compl_startcol)
compl_startcol = 0;
***************
*** 423,429 ****
char_u *ss = NULL;
// Do the expansion.
! if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
options) == FAIL)
{
#ifdef FNAME_ILLEGAL
--- 427,433 ----
char_u *ss = NULL;
// Do the expansion.
! if (ExpandFromContext(xp, str, &xp->xp_files, &xp->xp_numfiles,
options) == FAIL)
{
#ifdef FNAME_ILLEGAL
***************
*** 445,452 ****
ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
// Check for matching suffixes in file names.
! if (mode != WILD_ALL && mode != WILD_ALL_KEEP
! && mode != WILD_LONGEST)
{
if (xp->xp_numfiles)
non_suf_match = xp->xp_numfiles;
--- 449,455 ----
ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
// Check for matching suffixes in file names.
! if (mode != WILD_ALL && mode != WILD_ALL_KEEP && mode != WILD_LONGEST)
{
if (xp->xp_numfiles)
non_suf_match = xp->xp_numfiles;
***************
*** 684,691 ****
/*
* Display one line of completion matches. Multiple matches are displayed in
* each line (used by wildmode=list and CTRL-D)
! * files_found - list of completion match names
! * num_files - number of completion matches in "files_found"
* lines - number of output lines
* linenr - line number of matches to display
* maxlen - maximum number of characters in each line
--- 687,694 ----
/*
* Display one line of completion matches. Multiple matches are displayed in
* each line (used by wildmode=list and CTRL-D)
! * matches - list of completion match names
! * numMatches - number of completion matches in "matches"
* lines - number of output lines
* linenr - line number of matches to display
* maxlen - maximum number of characters in each line
***************
*** 695,702 ****
static void
showmatches_oneline(
expand_T *xp,
! char_u **files_found,
! int num_files,
int lines,
int linenr,
int maxlen,
--- 698,705 ----
static void
showmatches_oneline(
expand_T *xp,
! char_u **matches,
! int numMatches,
int lines,
int linenr,
int maxlen,
***************
*** 709,720 ****
char_u *p;
lastlen = 999;
! for (j = linenr; j < num_files; j += lines)
{
if (xp->xp_context == EXPAND_TAGS_LISTFILES)
{
! msg_outtrans_attr(files_found[j], HL_ATTR(HLF_D));
! p = files_found[j] + STRLEN(files_found[j]) + 1;
msg_advance(maxlen + 1);
msg_puts((char *)p);
msg_advance(maxlen + 3);
--- 712,723 ----
char_u *p;
lastlen = 999;
! for (j = linenr; j < numMatches; j += lines)
{
if (xp->xp_context == EXPAND_TAGS_LISTFILES)
{
! msg_outtrans_attr(matches[j], HL_ATTR(HLF_D));
! p = matches[j] + STRLEN(matches[j]) + 1;
msg_advance(maxlen + 1);
msg_puts((char *)p);
msg_advance(maxlen + 3);
***************
*** 737,759 ****
// Expansion was done before and special characters
// were escaped, need to halve backslashes. Also
// $HOME has been replaced with ~/.
! exp_path = expand_env_save_opt(files_found[j], TRUE);
! path = exp_path != NULL ? exp_path : files_found[j];
halved_slash = backslash_halve_save(path);
isdir = mch_isdir(halved_slash != NULL ? halved_slash
! : files_found[j]);
vim_free(exp_path);
if (halved_slash != path)
vim_free(halved_slash);
}
else
// Expansion was done here, file names are literal.
! isdir = mch_isdir(files_found[j]);
if (showtail)
p = SHOW_FILE_TEXT(j);
else
{
! home_replace(NULL, files_found[j], NameBuff, MAXPATHL,
TRUE);
p = NameBuff;
}
--- 740,762 ----
// Expansion was done before and special characters
// were escaped, need to halve backslashes. Also
// $HOME has been replaced with ~/.
! exp_path = expand_env_save_opt(matches[j], TRUE);
! path = exp_path != NULL ? exp_path : matches[j];
halved_slash = backslash_halve_save(path);
isdir = mch_isdir(halved_slash != NULL ? halved_slash
! : matches[j]);
vim_free(exp_path);
if (halved_slash != path)
vim_free(halved_slash);
}
else
// Expansion was done here, file names are literal.
! isdir = mch_isdir(matches[j]);
if (showtail)
p = SHOW_FILE_TEXT(j);
else
{
! home_replace(NULL, matches[j], NameBuff, MAXPATHL,
TRUE);
p = NameBuff;
}
***************
*** 782,789 ****
showmatches(expand_T *xp, int wildmenu UNUSED)
{
cmdline_info_T *ccline = get_cmdline_info();
! int num_files;
! char_u **files_found;
int i, j;
int maxlen;
int lines;
--- 785,792 ----
showmatches(expand_T *xp, int wildmenu UNUSED)
{
cmdline_info_T *ccline = get_cmdline_info();
! int numMatches;
! char_u **matches;
int i, j;
int maxlen;
int lines;
***************
*** 795,816 ****
{
set_expand_context(xp);
i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
! &num_files, &files_found);
showtail = expand_showtail(xp);
if (i != EXPAND_OK)
return i;
}
else
{
! num_files = xp->xp_numfiles;
! files_found = xp->xp_files;
showtail = cmd_showtail;
}
#ifdef FEAT_WILDMENU
if (wildmenu && vim_strchr(p_wop, WOP_PUM) != NULL)
// cmdline completion popup menu (with wildoptions=pum)
! return cmdline_pum_create(ccline, xp, files_found, num_files, showtail);
#endif
#ifdef FEAT_WILDMENU
--- 798,819 ----
{
set_expand_context(xp);
i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
! &numMatches, &matches);
showtail = expand_showtail(xp);
if (i != EXPAND_OK)
return i;
}
else
{
! numMatches = xp->xp_numfiles;
! matches = xp->xp_files;
showtail = cmd_showtail;
}
#ifdef FEAT_WILDMENU
if (wildmenu && vim_strchr(p_wop, WOP_PUM) != NULL)
// cmdline completion popup menu (with wildoptions=pum)
! return cmdline_pum_create(ccline, xp, matches, numMatches, showtail);
#endif
#ifdef FEAT_WILDMENU
***************
*** 832,850 ****
got_int = FALSE; // only int. the completion, not the cmd line
#ifdef FEAT_WILDMENU
else if (wildmenu)
! win_redr_status_matches(xp, num_files, files_found, -1, showtail);
#endif
else
{
// find the length of the longest file name
maxlen = 0;
! for (i = 0; i < num_files; ++i)
{
if (!showtail && (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS))
{
! home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
j = vim_strsize(NameBuff);
}
else
--- 835,853 ----
got_int = FALSE; // only int. the completion, not the cmd line
#ifdef FEAT_WILDMENU
else if (wildmenu)
! win_redr_status_matches(xp, numMatches, matches, -1, showtail);
#endif
else
{
// find the length of the longest file name
maxlen = 0;
! for (i = 0; i < numMatches; ++i)
{
if (!showtail && (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS))
{
! home_replace(NULL, matches[i], NameBuff, MAXPATHL, TRUE);
j = vim_strsize(NameBuff);
}
else
***************
*** 854,860 ****
}
if (xp->xp_context == EXPAND_TAGS_LISTFILES)
! lines = num_files;
else
{
// compute the number of columns and lines for the listing
--- 857,863 ----
}
if (xp->xp_context == EXPAND_TAGS_LISTFILES)
! lines = numMatches;
else
{
// compute the number of columns and lines for the listing
***************
*** 862,868 ****
columns = ((int)Columns + 2) / maxlen;
if (columns < 1)
columns = 1;
! lines = (num_files + columns - 1) / columns;
}
attr = HL_ATTR(HLF_D); // find out highlighting for directories
--- 865,871 ----
columns = ((int)Columns + 2) / maxlen;
if (columns < 1)
columns = 1;
! lines = (numMatches + columns - 1) / columns;
}
attr = HL_ATTR(HLF_D); // find out highlighting for directories
***************
*** 878,884 ****
// list the files line by line
for (i = 0; i < lines; ++i)
{
! showmatches_oneline(xp, files_found, num_files, lines, i,
maxlen, showtail, attr);
if (got_int)
{
--- 881,887 ----
// list the files line by line
for (i = 0; i < lines; ++i)
{
! showmatches_oneline(xp, matches, numMatches, lines, i,
maxlen, showtail, attr);
if (got_int)
{
***************
*** 893,899 ****
}
if (xp->xp_numfiles == -1)
! FreeWild(num_files, files_found);
return EXPAND_OK;
}
--- 896,902 ----
}
if (xp->xp_numfiles == -1)
! FreeWild(numMatches, matches);
return EXPAND_OK;
}
***************
*** 1362,1367 ****
--- 1365,1435 ----
}
/*
+ * Set the completion context for the :filter command. Returns a pointer to the
+ * next command after the :filter command.
+ */
+ static char_u *
+ set_context_in_filter_cmd(expand_T *xp, char_u *arg)
+ {
+ if (*arg != NUL)
+ arg = skip_vimgrep_pat(arg, NULL, NULL);
+ if (arg == NULL || *arg == NUL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+ return skipwhite(arg);
+ }
+
+ #ifdef FEAT_SEARCH_EXTRA
+ /*
+ * Set the completion context for the :match command. Returns a pointer to the
+ * next command after the :match command.
+ */
+ static char_u *
+ set_context_in_match_cmd(expand_T *xp, char_u *arg)
+ {
+ if (*arg == NUL || !ends_excmd(*arg))
+ {
+ // also complete "None"
+ set_context_in_echohl_cmd(xp, arg);
+ arg = skipwhite(skiptowhite(arg));
+ if (*arg != NUL)
+ {
+ xp->xp_context = EXPAND_NOTHING;
+ arg = skip_regexp(arg + 1, *arg, magic_isset());
+ }
+ }
+ return find_nextcmd(arg);
+ }
+ #endif
+
+ /*
+ * Returns a pointer to the next command after a :global or a :v command.
+ * Returns NULL if there is no next command.
+ */
+ static char_u *
+ find_cmd_after_global_cmd(char_u *arg)
+ {
+ int delim;
+
+ delim = *arg; // get the delimiter
+ if (delim)
+ ++arg; // skip delimiter if there is one
+
+ while (arg[0] != NUL && arg[0] != delim)
+ {
+ if (arg[0] == '\\' && arg[1] != NUL)
+ ++arg;
+ ++arg;
+ }
+ if (arg[0] != NUL)
+ return arg + 1;
+
+ return NULL;
+ }
+
+ /*
* Returns a pointer to the next command after a :substitute or a :& command.
* Returns NULL if there is no next command.
*/
***************
*** 1405,1411 ****
* Returns NULL if there is no next command.
*/
static char_u *
! find_cmd_after_isearch_cmd(char_u *arg, expand_T *xp)
{
arg = skipwhite(skipdigits(arg)); // skip count
if (*arg == '/') // Match regexp, not just whole words
--- 1473,1479 ----
* Returns NULL if there is no next command.
*/
static char_u *
! find_cmd_after_isearch_cmd(expand_T *xp, char_u *arg)
{
arg = skipwhite(skipdigits(arg)); // skip count
if (*arg == '/') // Match regexp, not just whole words
***************
*** 1428,1433 ****
--- 1496,1557 ----
return NULL;
}
+ #ifdef FEAT_EVAL
+ /*
+ * Set the completion context for the :unlet command. Always returns NULL.
+ */
+ static char_u *
+ set_context_in_unlet_cmd(expand_T *xp, char_u *arg)
+ {
+ while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
+ arg = xp->xp_pattern + 1;
+
+ xp->xp_context = EXPAND_USER_VARS;
+ xp->xp_pattern = arg;
+
+ if (*xp->xp_pattern == '$')
+ {
+ xp->xp_context = EXPAND_ENV_VARS;
+ ++xp->xp_pattern;
+ }
+
+ return NULL;
+ }
+ #endif
+
+ #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+ /*
+ * Set the completion context for the :language command. Always returns NULL.
+ */
+ static char_u *
+ set_context_in_lang_cmd(expand_T *xp, char_u *arg)
+ {
+ char_u *p;
+
+ p = skiptowhite(arg);
+ if (*p == NUL)
+ {
+ xp->xp_context = EXPAND_LANGUAGE;
+ xp->xp_pattern = arg;
+ }
+ else
+ {
+ if ( STRNCMP(arg, "messages", p - arg) == 0
+ || STRNCMP(arg, "ctype", p - arg) == 0
+ || STRNCMP(arg, "time", p - arg) == 0
+ || STRNCMP(arg, "collate", p - arg) == 0)
+ {
+ xp->xp_context = EXPAND_LOCALES;
+ xp->xp_pattern = skipwhite(p);
+ }
+ else
+ xp->xp_context = EXPAND_NOTHING;
+ }
+
+ return NULL;
+ }
+ #endif
+
/*
* Set the completion context in 'xp' for command 'cmd' with index 'cmdidx'.
* The argument to the command is 'arg' and the argument flags is 'argt'.
***************
*** 1440,1454 ****
set_context_by_cmdname(
char_u *cmd,
cmdidx_T cmdidx,
char_u *arg,
long argt,
int compl,
- expand_T *xp,
int forceit)
{
- char_u *p;
- int delim;
-
switch (cmdidx)
{
case CMD_find:
--- 1564,1575 ----
set_context_by_cmdname(
char_u *cmd,
cmdidx_T cmdidx,
+ expand_T *xp,
char_u *arg,
long argt,
int compl,
int forceit)
{
switch (cmdidx)
{
case CMD_find:
***************
*** 1510,1538 ****
return arg;
case CMD_filter:
! if (*arg != NUL)
! arg = skip_vimgrep_pat(arg, NULL, NULL);
! if (arg == NULL || *arg == NUL)
! {
! xp->xp_context = EXPAND_NOTHING;
! return NULL;
! }
! return skipwhite(arg);
#ifdef FEAT_SEARCH_EXTRA
case CMD_match:
! if (*arg == NUL || !ends_excmd(*arg))
! {
! // also complete "None"
! set_context_in_echohl_cmd(xp, arg);
! arg = skipwhite(skiptowhite(arg));
! if (*arg != NUL)
! {
! xp->xp_context = EXPAND_NOTHING;
! arg = skip_regexp(arg + 1, *arg, magic_isset());
! }
! }
! return find_nextcmd(arg);
#endif
// All completion for the +cmdline_compl feature goes here.
--- 1631,1641 ----
return arg;
case CMD_filter:
! return set_context_in_filter_cmd(xp, arg);
#ifdef FEAT_SEARCH_EXTRA
case CMD_match:
! return set_context_in_match_cmd(xp, arg);
#endif
// All completion for the +cmdline_compl feature goes here.
***************
*** 1547,1565 ****
case CMD_global:
case CMD_vglobal:
! delim = *arg; // get the delimiter
! if (delim)
! ++arg; // skip delimiter if there is one
!
! while (arg[0] != NUL && arg[0] != delim)
! {
! if (arg[0] == '\\' && arg[1] != NUL)
! ++arg;
! ++arg;
! }
! if (arg[0] != NUL)
! return arg + 1;
! break;
case CMD_and:
case CMD_substitute:
return find_cmd_after_substitute_cmd(arg);
--- 1650,1656 ----
case CMD_global:
case CMD_vglobal:
! return find_cmd_after_global_cmd(arg);
case CMD_and:
case CMD_substitute:
return find_cmd_after_substitute_cmd(arg);
***************
*** 1572,1578 ****
case CMD_djump:
case CMD_isplit:
case CMD_dsplit:
! return find_cmd_after_isearch_cmd(arg, xp);
case CMD_autocmd:
return set_context_in_autocmd(xp, arg, FALSE);
case CMD_doautocmd:
--- 1663,1669 ----
case CMD_djump:
case CMD_isplit:
case CMD_dsplit:
! return find_cmd_after_isearch_cmd(xp, arg);
case CMD_autocmd:
return set_context_in_autocmd(xp, arg, FALSE);
case CMD_doautocmd:
***************
*** 1638,1657 ****
break;
case CMD_unlet:
! while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
! arg = xp->xp_pattern + 1;
!
! xp->xp_context = EXPAND_USER_VARS;
! xp->xp_pattern = arg;
!
! if (*xp->xp_pattern == '$')
! {
! xp->xp_context = EXPAND_ENV_VARS;
! ++xp->xp_pattern;
! }
!
! break;
!
case CMD_function:
case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC;
--- 1729,1735 ----
break;
case CMD_unlet:
! return set_context_in_unlet_cmd(xp, arg);
case CMD_function:
case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC;
***************
*** 1795,1820 ****
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
case CMD_language:
! p = skiptowhite(arg);
! if (*p == NUL)
! {
! xp->xp_context = EXPAND_LANGUAGE;
! xp->xp_pattern = arg;
! }
! else
! {
! if ( STRNCMP(arg, "messages", p - arg) == 0
! || STRNCMP(arg, "ctype", p - arg) == 0
! || STRNCMP(arg, "time", p - arg) == 0
! || STRNCMP(arg, "collate", p - arg) == 0)
! {
! xp->xp_context = EXPAND_LOCALES;
! xp->xp_pattern = skipwhite(p);
! }
! else
! xp->xp_context = EXPAND_NOTHING;
! }
! break;
#endif
#if defined(FEAT_PROFILE)
case CMD_profile:
--- 1873,1879 ----
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
case CMD_language:
! return set_context_in_lang_cmd(xp, arg);
#endif
#if defined(FEAT_PROFILE)
case CMD_profile:
***************
*** 2041,2050 ****
set_context_for_wildcard_arg(&ea, arg, usefilter, xp, &compl);
// 6. Switch on command name.
! return set_context_by_cmdname(cmd, ea.cmdidx, arg, ea.argt, compl, xp,
forceit);
}
void
set_cmd_context(
expand_T *xp,
--- 2100,2112 ----
set_context_for_wildcard_arg(&ea, arg, usefilter, xp, &compl);
// 6. Switch on command name.
! return set_context_by_cmdname(cmd, ea.cmdidx, xp, arg, ea.argt, compl,
forceit);
}
+ /*
+ * Set the completion context in 'xp' for command 'str'
+ */
void
set_cmd_context(
expand_T *xp,
***************
*** 2134,2140 ****
options += WILD_ICASE;
// find all files that match the description
! if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL)
{
*matchcount = 0;
*matches = NULL;
--- 2196,2202 ----
options += WILD_ICASE;
// find all files that match the description
! if (ExpandFromContext(xp, file_str, matches, matchcount, options) == FAIL)
{
*matchcount = 0;
*matches = NULL;
***************
*** 2151,2158 ****
expand_files_and_dirs(
expand_T *xp,
char_u *pat,
! char_u ***file,
! int *num_file,
int flags,
int options)
{
--- 2213,2220 ----
expand_files_and_dirs(
expand_T *xp,
char_u *pat,
! char_u ***matches,
! int *numMatches,
int flags,
int options)
{
***************
*** 2190,2196 ****
flags |= EW_ICASE;
// Expand wildcards, supporting %:h and the like.
! ret = expand_wildcards_eval(&pat, num_file, file, flags);
if (free_pat)
vim_free(pat);
#ifdef BACKSLASH_IN_FILENAME
--- 2252,2258 ----
flags |= EW_ICASE;
// Expand wildcards, supporting %:h and the like.
! ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
if (free_pat)
vim_free(pat);
#ifdef BACKSLASH_IN_FILENAME
***************
*** 2198,2206 ****
{
int j;
! for (j = 0; j < *num_file; ++j)
{
! char_u *ptr = (*file)[j];
while (*ptr != NUL)
{
--- 2260,2268 ----
{
int j;
! for (j = 0; j < *numMatches; ++j)
{
! char_u *ptr = (*matches)[j];
while (*ptr != NUL)
{
***************
*** 2257,2264 ****
ExpandOther(
expand_T *xp,
regmatch_T *rmp,
! int *num_file,
! char_u ***file)
{
static struct expgen
{
--- 2319,2326 ----
ExpandOther(
expand_T *xp,
regmatch_T *rmp,
! char_u ***matches,
! int *numMatches)
{
static struct expgen
{
***************
*** 2326,2332 ****
{
if (tab[i].ic)
rmp->rm_ic = TRUE;
! ret = ExpandGeneric(xp, rmp, num_file, file,
tab[i].func, tab[i].escaped);
break;
}
--- 2388,2394 ----
{
if (tab[i].ic)
rmp->rm_ic = TRUE;
! ret = ExpandGeneric(xp, rmp, matches, numMatches,
tab[i].func, tab[i].escaped);
break;
}
***************
*** 2367,2374 ****
ExpandFromContext(
expand_T *xp,
char_u *pat,
! int *num_file,
! char_u ***file,
int options) // WILD_ flags
{
regmatch_T regmatch;
--- 2429,2436 ----
ExpandFromContext(
expand_T *xp,
char_u *pat,
! char_u ***matches,
! int *numMatches,
int options) // WILD_ flags
{
regmatch_T regmatch;
***************
*** 2381,2399 ****
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH)
! return expand_files_and_dirs(xp, pat, file, num_file, flags, options);
! *file = (char_u **)"";
! *num_file = 0;
if (xp->xp_context == EXPAND_HELP)
{
// With an empty argument we would get all the help tags, which is
// very slow. Get matches for "help" instead.
if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat,
! num_file, file, FALSE) == OK)
{
#ifdef FEAT_MULTI_LANG
! cleanup_help_tags(*num_file, *file);
#endif
return OK;
}
--- 2443,2462 ----
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH)
! return expand_files_and_dirs(xp, pat, matches, numMatches, flags,
! options);
! *matches = (char_u **)"";
! *numMatches = 0;
if (xp->xp_context == EXPAND_HELP)
{
// With an empty argument we would get all the help tags, which is
// very slow. Get matches for "help" instead.
if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat,
! numMatches, matches, FALSE) == OK)
{
#ifdef FEAT_MULTI_LANG
! cleanup_help_tags(*numMatches, *matches);
#endif
return OK;
}
***************
*** 2401,2445 ****
}
if (xp->xp_context == EXPAND_SHELLCMD)
! return expand_shellcmd(pat, num_file, file, flags);
if (xp->xp_context == EXPAND_OLD_SETTING)
! return ExpandOldSetting(num_file, file);
if (xp->xp_context == EXPAND_BUFFERS)
! return ExpandBufnames(pat, num_file, file, options);
#ifdef FEAT_DIFF
if (xp->xp_context == EXPAND_DIFF_BUFFERS)
! return ExpandBufnames(pat, num_file, file, options | BUF_DIFF_FILTER);
#endif
if (xp->xp_context == EXPAND_TAGS
|| xp->xp_context == EXPAND_TAGS_LISTFILES)
! return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
if (xp->xp_context == EXPAND_COLORS)
{
char *directories[] = {"colors", NULL};
! return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file,
directories);
}
if (xp->xp_context == EXPAND_COMPILER)
{
char *directories[] = {"compiler", NULL};
! return ExpandRTDir(pat, 0, num_file, file, directories);
}
if (xp->xp_context == EXPAND_OWNSYNTAX)
{
char *directories[] = {"syntax", NULL};
! return ExpandRTDir(pat, 0, num_file, file, directories);
}
if (xp->xp_context == EXPAND_FILETYPE)
{
char *directories[] = {"syntax", "indent", "ftplugin", NULL};
! return ExpandRTDir(pat, 0, num_file, file, directories);
}
# if defined(FEAT_EVAL)
if (xp->xp_context == EXPAND_USER_LIST)
! return ExpandUserList(xp, num_file, file);
# endif
if (xp->xp_context == EXPAND_PACKADD)
! return ExpandPackAddDir(pat, num_file, file);
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
--- 2464,2510 ----
}
if (xp->xp_context == EXPAND_SHELLCMD)
! return expand_shellcmd(pat, matches, numMatches, flags);
if (xp->xp_context == EXPAND_OLD_SETTING)
! return ExpandOldSetting(numMatches, matches);
if (xp->xp_context == EXPAND_BUFFERS)
! return ExpandBufnames(pat, numMatches, matches, options);
#ifdef FEAT_DIFF
if (xp->xp_context == EXPAND_DIFF_BUFFERS)
! return ExpandBufnames(pat, numMatches, matches,
! options | BUF_DIFF_FILTER);
#endif
if (xp->xp_context == EXPAND_TAGS
|| xp->xp_context == EXPAND_TAGS_LISTFILES)
! return expand_tags(xp->xp_context == EXPAND_TAGS, pat, numMatches,
! matches);
if (xp->xp_context == EXPAND_COLORS)
{
char *directories[] = {"colors", NULL};
! return ExpandRTDir(pat, DIP_START + DIP_OPT, numMatches, matches,
directories);
}
if (xp->xp_context == EXPAND_COMPILER)
{
char *directories[] = {"compiler", NULL};
! return ExpandRTDir(pat, 0, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_OWNSYNTAX)
{
char *directories[] = {"syntax", NULL};
! return ExpandRTDir(pat, 0, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_FILETYPE)
{
char *directories[] = {"syntax", "indent", "ftplugin", NULL};
! return ExpandRTDir(pat, 0, numMatches, matches, directories);
}
# if defined(FEAT_EVAL)
if (xp->xp_context == EXPAND_USER_LIST)
! return ExpandUserList(xp, matches, numMatches);
# endif
if (xp->xp_context == EXPAND_PACKADD)
! return ExpandPackAddDir(pat, numMatches, matches);
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
***************
*** 2465,2479 ****
if (xp->xp_context == EXPAND_SETTINGS
|| xp->xp_context == EXPAND_BOOL_SETTINGS)
! ret = ExpandSettings(xp, ®match, num_file, file);
else if (xp->xp_context == EXPAND_MAPPINGS)
! ret = ExpandMappings(®match, num_file, file);
# if defined(FEAT_EVAL)
else if (xp->xp_context == EXPAND_USER_DEFINED)
! ret = ExpandUserDefined(xp, ®match, num_file, file);
# endif
else
! ret = ExpandOther(xp, ®match, num_file, file);
vim_regfree(regmatch.regprog);
vim_free(tofree);
--- 2530,2544 ----
if (xp->xp_context == EXPAND_SETTINGS
|| xp->xp_context == EXPAND_BOOL_SETTINGS)
! ret = ExpandSettings(xp, ®match, numMatches, matches);
else if (xp->xp_context == EXPAND_MAPPINGS)
! ret = ExpandMappings(®match, numMatches, matches);
# if defined(FEAT_EVAL)
else if (xp->xp_context == EXPAND_USER_DEFINED)
! ret = ExpandUserDefined(xp, ®match, matches, numMatches);
# endif
else
! ret = ExpandOther(xp, ®match, matches, numMatches);
vim_regfree(regmatch.regprog);
vim_free(tofree);
***************
*** 2494,2501 ****
ExpandGeneric(
expand_T *xp,
regmatch_T *regmatch,
! int *num_file,
! char_u ***file,
char_u *((*func)(expand_T *, int)),
// returns a string from the list
int escaped)
--- 2559,2566 ----
ExpandGeneric(
expand_T *xp,
regmatch_T *regmatch,
! char_u ***matches,
! int *numMatches,
char_u *((*func)(expand_T *, int)),
// returns a string from the list
int escaped)
***************
*** 2528,2539 ****
str = vim_strsave(str);
if (str == NULL)
{
! FreeWild(count, *file);
! *num_file = 0;
! *file = NULL;
return FAIL;
}
! (*file)[count] = str;
# ifdef FEAT_MENU
if (func == get_menu_names && str != NULL)
{
--- 2593,2604 ----
str = vim_strsave(str);
if (str == NULL)
{
! FreeWild(count, *matches);
! *numMatches = 0;
! *matches = NULL;
return FAIL;
}
! (*matches)[count] = str;
# ifdef FEAT_MENU
if (func == get_menu_names && str != NULL)
{
***************
*** 2551,2564 ****
{
if (count == 0)
return OK;
! *file = ALLOC_MULT(char_u *, count);
! if (*file == NULL)
{
! *num_file = 0;
! *file = NULL;
return FAIL;
}
! *num_file = count;
count = 0;
}
}
--- 2616,2629 ----
{
if (count == 0)
return OK;
! *matches = ALLOC_MULT(char_u *, count);
! if (*matches == NULL)
{
! *numMatches = 0;
! *matches = NULL;
return FAIL;
}
! *numMatches = count;
count = 0;
}
}
***************
*** 2571,2580 ****
|| xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE)
// <SNR> functions should be sorted to the end.
! qsort((void *)*file, (size_t)*num_file, sizeof(char_u *),
sort_func_compare);
else
! sort_strings(*file, *num_file);
}
#if defined(FEAT_SYN_HL)
--- 2636,2645 ----
|| xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE)
// <SNR> functions should be sorted to the end.
! qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *),
sort_func_compare);
else
! sort_strings(*matches, *numMatches);
}
#if defined(FEAT_SYN_HL)
***************
*** 2594,2601 ****
char_u *s,
size_t l,
char_u *pat,
! char_u ***files,
! int *num_files,
int flags,
hashtab_T *ht,
garray_T *gap)
--- 2659,2666 ----
char_u *s,
size_t l,
char_u *pat,
! char_u ***matches,
! int *numMatches,
int flags,
hashtab_T *ht,
garray_T *gap)
***************
*** 2611,2626 ****
vim_strncpy(buf + l, pat, MAXPATHL - 1 - l);
// Expand matches in one directory of $PATH.
! ret = expand_wildcards(1, &buf, num_files, files, flags);
if (ret == OK)
{
! if (ga_grow(gap, *num_files) == FAIL)
! FreeWild(*num_files, *files);
else
{
! for (i = 0; i < *num_files; ++i)
{
! char_u *name = (*files)[i];
if (STRLEN(name) > l)
{
--- 2676,2691 ----
vim_strncpy(buf + l, pat, MAXPATHL - 1 - l);
// Expand matches in one directory of $PATH.
! ret = expand_wildcards(1, &buf, numMatches, matches, flags);
if (ret == OK)
{
! if (ga_grow(gap, *numMatches) == FAIL)
! FreeWild(*numMatches, *matches);
else
{
! for (i = 0; i < *numMatches; ++i)
{
! char_u *name = (*matches)[i];
if (STRLEN(name) > l)
{
***************
*** 2638,2644 ****
}
vim_free(name);
}
! vim_free(*files);
}
}
}
--- 2703,2709 ----
}
vim_free(name);
}
! vim_free(*matches);
}
}
}
***************
*** 2650,2657 ****
static int
expand_shellcmd(
char_u *filepat, // pattern to match with command names
! int *num_file, // return: number of matches
! char_u ***file, // return: array with matches
int flagsarg) // EW_ flags
{
char_u *pat;
--- 2715,2722 ----
static int
expand_shellcmd(
char_u *filepat, // pattern to match with command names
! char_u ***matches, // return: array with matches
! int *numMatches, // return: number of matches
int flagsarg) // EW_ flags
{
char_u *pat;
***************
*** 2732,2745 ****
if (l > MAXPATHL - 5)
break;
! expand_shellcmd_onedir(buf, s, l, pat, file, num_file, flags,
&found_ht, &ga);
if (*e != NUL)
++e;
}
! *file = ga.ga_data;
! *num_file = ga.ga_len;
vim_free(buf);
vim_free(pat);
--- 2797,2810 ----
if (l > MAXPATHL - 5)
break;
! expand_shellcmd_onedir(buf, s, l, pat, matches, numMatches, flags,
&found_ht, &ga);
if (*e != NUL)
++e;
}
! *matches = ga.ga_data;
! *numMatches = ga.ga_len;
vim_free(buf);
vim_free(pat);
***************
*** 2757,2765 ****
static void *
call_user_expand_func(
void *(*user_expand_func)(char_u *, int, typval_T *),
! expand_T *xp,
! int *num_file,
! char_u ***file)
{
cmdline_info_T *ccline = get_cmdline_info();
int keep = 0;
--- 2822,2828 ----
static void *
call_user_expand_func(
void *(*user_expand_func)(char_u *, int, typval_T *),
! expand_T *xp)
{
cmdline_info_T *ccline = get_cmdline_info();
int keep = 0;
***************
*** 2770,2777 ****
if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
return NULL;
- *num_file = 0;
- *file = NULL;
if (ccline->cmdbuff != NULL)
{
--- 2833,2838 ----
***************
*** 2808,2815 ****
ExpandUserDefined(
expand_T *xp,
regmatch_T *regmatch,
! int *num_file,
! char_u ***file)
{
char_u *retstr;
char_u *s;
--- 2869,2876 ----
ExpandUserDefined(
expand_T *xp,
regmatch_T *regmatch,
! char_u ***matches,
! int *numMatches)
{
char_u *retstr;
char_u *s;
***************
*** 2818,2824 ****
garray_T ga;
int skip;
! retstr = call_user_expand_func(call_func_retstr, xp, num_file, file);
if (retstr == NULL)
return FAIL;
--- 2879,2887 ----
garray_T ga;
int skip;
! *matches = NULL;
! *numMatches = 0;
! retstr = call_user_expand_func(call_func_retstr, xp);
if (retstr == NULL)
return FAIL;
***************
*** 2846,2853 ****
++e;
}
vim_free(retstr);
! *file = ga.ga_data;
! *num_file = ga.ga_len;
return OK;
}
--- 2909,2916 ----
++e;
}
vim_free(retstr);
! *matches = ga.ga_data;
! *numMatches = ga.ga_len;
return OK;
}
***************
*** 2857,2870 ****
static int
ExpandUserList(
expand_T *xp,
! int *num_file,
! char_u ***file)
{
list_T *retlist;
listitem_T *li;
garray_T ga;
! retlist = call_user_expand_func(call_func_retlist, xp, num_file, file);
if (retlist == NULL)
return FAIL;
--- 2920,2935 ----
static int
ExpandUserList(
expand_T *xp,
! char_u ***matches,
! int *numMatches)
{
list_T *retlist;
listitem_T *li;
garray_T ga;
! *matches = NULL;
! *numMatches = 0;
! retlist = call_user_expand_func(call_func_retlist, xp);
if (retlist == NULL)
return FAIL;
***************
*** 2884,2891 ****
}
list_unref(retlist);
! *file = ga.ga_data;
! *num_file = ga.ga_len;
return OK;
}
# endif
--- 2949,2956 ----
}
list_unref(retlist);
! *matches = ga.ga_data;
! *numMatches = ga.ga_len;
return OK;
}
# endif
***************
*** 2930,2936 ****
add_pathsep(buf);
# endif
STRCAT(buf, file);
! if (ExpandFromContext(&xpc, buf, &num_p, &p,
WILD_SILENT|expand_options) != FAIL && num_p > 0)
{
ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options);
--- 2995,3001 ----
add_pathsep(buf);
# endif
STRCAT(buf, file);
! if (ExpandFromContext(&xpc, buf, &p, &num_p,
WILD_SILENT|expand_options) != FAIL && num_p > 0)
{
ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT|expand_options);
*** ../vim-8.2.4405/src/testdir/test_usercommands.vim 2022-02-14 11:10:54.365486323 +0000
--- src/testdir/test_usercommands.vim 2022-02-17 11:22:52.229287488 +0000
***************
*** 333,338 ****
--- 333,346 ----
call feedkeys(":com -complete=co\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -complete=color command compiler', @:)
+ " try completion for unsupported argument values
+ call feedkeys(":com -newarg=\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"com -newarg=\t", @:)
+
+ " command completion after the name in a user defined command
+ call feedkeys(":com MyCmd chist\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"com MyCmd chistory", @:)
+
command! DoCmd1 :
command! DoCmd2 :
call feedkeys(":com \<C-A>\<C-B>\"\<CR>", 'tx')
***************
*** 344,349 ****
--- 352,361 ----
call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"delcom DoCmd1 DoCmd2', @:)
+ " try argument completion for a command without completion
+ call feedkeys(":DoCmd1 \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"DoCmd1 \t", @:)
+
delcom DoCmd1
call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"delcom DoCmd2', @:)
***************
*** 362,367 ****
--- 374,394 ----
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd mswin xterm', @:)
+ " Test for file name completion
+ com! -nargs=1 -complete=file DoCmd :
+ call feedkeys(":DoCmd READM\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd README.txt', @:)
+
+ " Test for buffer name completion
+ com! -nargs=1 -complete=buffer DoCmd :
+ let bnum = bufadd('BufForUserCmd')
+ call setbufvar(bnum, '&buflisted', 1)
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufForUserCmd', @:)
+ bwipe BufForUserCmd
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufFor', @:)
+
com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
***************
*** 745,749 ****
--- 772,801 ----
endwhile
endfunc
+ " Test for using buffer-local ambiguous user-defined commands
+ func Test_buflocal_ambiguous_usercmd()
+ new
+ command -buffer -nargs=1 -complete=sign TestCmd1 echo "Hello"
+ command -buffer -nargs=1 -complete=sign TestCmd2 echo "World"
+
+ call assert_fails("call feedkeys(':TestCmd\<CR>', 'xt')", 'E464:')
+ call feedkeys(":TestCmd \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"TestCmd ', @:)
+
+ delcommand TestCmd1
+ delcommand TestCmd2
+ bw!
+ endfunc
+
+ " Test for using a multibyte character in a user command
+ func Test_multibyte_in_usercmd()
+ command SubJapanesePeriodToDot exe "%s/\u3002/./g"
+ new
+ call setline(1, "Hello\u3002")
+ SubJapanesePeriodToDot
+ call assert_equal('Hello.', getline(1))
+ bw!
+ delcommand SubJapanesePeriodToDot
+ endfunc
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.4405/src/version.c 2022-02-16 21:50:53.966082550 +0000
--- src/version.c 2022-02-17 11:25:39.885127520 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4406,
/**/
--
Be thankful to be in a traffic jam, because it means you own a car.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///