aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/cmdexpand.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/cmdexpand.c')
-rw-r--r--src/nvim/cmdexpand.c1295
1 files changed, 753 insertions, 542 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index d603e964e5..ca19d6de95 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -73,7 +73,7 @@
typedef char *(*CompleteListItemGetter)(expand_T *, int);
/// Type used by call_user_expand_func
-typedef void *(*user_expand_func_T)(const char_u *, int, typval_T *);
+typedef void *(*user_expand_func_T)(const char *, int, typval_T *);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cmdexpand.c.generated.h"
@@ -89,6 +89,10 @@ static int compl_match_arraysize;
static int compl_startcol;
static int compl_selected;
+#define SHOW_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : 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)
{
char *p1 = *(char **)s1;
@@ -104,71 +108,75 @@ static int sort_func_compare(const void *s1, const void *s2)
}
/// Escape special characters in the cmdline completion matches.
-static void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char **files, int options)
+static void wildescape(expand_T *xp, const char *str, int numfiles, char **files)
{
- int i;
char *p;
const int vse_what = xp->xp_context == EXPAND_BUFFERS ? VSE_BUFFER : VSE_NONE;
- // May change home directory back to "~"
- if (options & WILD_HOME_REPLACE) {
- tilde_replace(str, numfiles, files);
- }
-
- if (options & WILD_ESCAPE) {
- if (xp->xp_context == EXPAND_FILES
- || xp->xp_context == EXPAND_FILES_IN_PATH
- || xp->xp_context == EXPAND_SHELLCMD
- || xp->xp_context == EXPAND_BUFFERS
- || xp->xp_context == EXPAND_DIRECTORIES) {
- // Insert a backslash into a file name before a space, \, %, #
- // and wildmatch characters, except '~'.
- for (i = 0; i < numfiles; i++) {
- // for ":set path=" we need to escape spaces twice
- if (xp->xp_backslash == XP_BS_THREE) {
- p = (char *)vim_strsave_escaped((char_u *)files[i], (char_u *)" ");
- xfree(files[i]);
- files[i] = p;
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS
+ || xp->xp_context == EXPAND_DIRECTORIES) {
+ // Insert a backslash into a file name before a space, \, %, #
+ // and wildmatch characters, except '~'.
+ for (int i = 0; i < numfiles; i++) {
+ // for ":set path=" we need to escape spaces twice
+ if (xp->xp_backslash == XP_BS_THREE) {
+ p = vim_strsave_escaped(files[i], " ");
+ xfree(files[i]);
+ files[i] = p;
#if defined(BACKSLASH_IN_FILENAME)
- p = vim_strsave_escaped(files[i], (char_u *)" ");
- xfree(files[i]);
- files[i] = p;
+ p = vim_strsave_escaped(files[i], " ");
+ xfree(files[i]);
+ files[i] = p;
#endif
- }
+ }
#ifdef BACKSLASH_IN_FILENAME
- p = vim_strsave_fnameescape((const char *)files[i], vse_what);
+ p = vim_strsave_fnameescape(files[i], vse_what);
#else
- p = vim_strsave_fnameescape((const char *)files[i],
- xp->xp_shell ? VSE_SHELL : vse_what);
+ p = vim_strsave_fnameescape(files[i], xp->xp_shell ? VSE_SHELL : vse_what);
#endif
- xfree(files[i]);
- files[i] = p;
+ xfree(files[i]);
+ files[i] = p;
- // If 'str' starts with "\~", replace "~" at start of
- // files[i] with "\~".
- if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') {
- escape_fname(&files[i]);
- }
+ // If 'str' starts with "\~", replace "~" at start of
+ // files[i] with "\~".
+ if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') {
+ escape_fname(&files[i]);
}
- xp->xp_backslash = XP_BS_NONE;
+ }
+ xp->xp_backslash = XP_BS_NONE;
- // If the first file starts with a '+' escape it. Otherwise it
- // could be seen as "+cmd".
- if (*files[0] == '+') {
- escape_fname(&files[0]);
- }
- } else if (xp->xp_context == EXPAND_TAGS) {
- // Insert a backslash before characters in a tag name that
- // would terminate the ":tag" command.
- for (i = 0; i < numfiles; i++) {
- p = (char *)vim_strsave_escaped((char_u *)files[i], (char_u *)"\\|\"");
- xfree(files[i]);
- files[i] = p;
- }
+ // If the first file starts with a '+' escape it. Otherwise it
+ // could be seen as "+cmd".
+ if (*files[0] == '+') {
+ escape_fname(&files[0]);
+ }
+ } else if (xp->xp_context == EXPAND_TAGS) {
+ // Insert a backslash before characters in a tag name that
+ // would terminate the ":tag" command.
+ for (int i = 0; i < numfiles; i++) {
+ p = vim_strsave_escaped(files[i], "\\|\"");
+ xfree(files[i]);
+ files[i] = p;
}
}
}
+/// Escape special characters in the cmdline completion matches.
+static void ExpandEscape(expand_T *xp, char *str, int numfiles, char **files, int options)
+{
+ // May change home directory back to "~"
+ if (options & WILD_HOME_REPLACE) {
+ tilde_replace(str, numfiles, files);
+ }
+
+ if (options & WILD_ESCAPE) {
+ wildescape(xp, str, numfiles, files);
+ }
+}
+
/// Return FAIL if this is not an appropriate context in which to do
/// completion of anything, return OK if it is (even if there are no matches).
/// For the caller, this means that the character is just passed through like a
@@ -209,7 +217,9 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
assert(ccline->cmdpos >= i);
xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i;
- if (type == WILD_NEXT || type == WILD_PREV || type == WILD_PUM_WANT) {
+ if (type == WILD_NEXT || type == WILD_PREV
+ || type == WILD_PAGEUP || type == WILD_PAGEDOWN
+ || type == WILD_PUM_WANT) {
// Get next/previous match for a previous expanded pattern.
p2 = ExpandOne(xp, NULL, NULL, 0, type);
} else {
@@ -279,19 +289,54 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
return OK;
}
+/// Create and display a cmdline completion popup menu with items from
+/// "matches".
+static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches, int numMatches,
+ int showtail)
+{
+ assert(numMatches >= 0);
+ // Add all the completion matches
+ compl_match_arraysize = numMatches;
+ compl_match_array = xmalloc(sizeof(pumitem_T) * (size_t)compl_match_arraysize);
+ for (int i = 0; i < numMatches; i++) {
+ compl_match_array[i] = (pumitem_T){
+ .pum_text = SHOW_MATCH(i),
+ .pum_info = NULL,
+ .pum_extra = NULL,
+ .pum_kind = NULL,
+ };
+ }
+
+ // Compute the popup menu starting column
+ char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, true) : xp->xp_pattern;
+ if (ui_has(kUICmdline)) {
+ compl_startcol = (int)(endpos - ccline->cmdbuff);
+ } else {
+ compl_startcol = cmd_screencol((int)(endpos - ccline->cmdbuff));
+ }
+
+ // no default selection
+ compl_selected = -1;
+
+ cmdline_pum_display(true);
+
+ return EXPAND_OK;
+}
+
void cmdline_pum_display(bool changed_array)
{
pum_display(compl_match_array, compl_match_arraysize, compl_selected,
changed_array, compl_startcol);
}
+/// Returns true if the cmdline completion popup menu is being displayed.
bool cmdline_pum_active(void)
{
// compl_match_array != NULL should already imply pum_visible() in Nvim.
return compl_match_array != NULL;
}
-/// Remove the cmdline completion popup menu
+/// Remove the cmdline completion popup menu (if present), free the list of items.
void cmdline_pum_remove(void)
{
pum_undisplay(true);
@@ -306,9 +351,9 @@ void cmdline_pum_cleanup(CmdlineInfo *cclp)
/// Return the number of characters that should be skipped in the wildmenu
/// These are backslashes used for escaping. Do show backslashes in help tags.
-static int skip_wildmenu_char(expand_T *xp, char_u *s)
+static int skip_wildmenu_char(expand_T *xp, char *s)
{
- if ((rem_backslash((char *)s) && xp->xp_context != EXPAND_HELP)
+ if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
|| ((xp->xp_context == EXPAND_MENUS || xp->xp_context == EXPAND_MENUNAMES)
&& (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))) {
#ifndef BACKSLASH_IN_FILENAME
@@ -326,7 +371,7 @@ static int skip_wildmenu_char(expand_T *xp, char_u *s)
}
/// Get the length of an item as it will be shown in the status line.
-static int wildmenu_match_len(expand_T *xp, char_u *s)
+static int wildmenu_match_len(expand_T *xp, char *s)
{
int len = 0;
@@ -334,13 +379,13 @@ static int wildmenu_match_len(expand_T *xp, char_u *s)
|| xp->xp_context == EXPAND_MENUNAMES);
// Check for menu separators - replace with '|'.
- if (emenu && menu_is_separator((char *)s)) {
+ if (emenu && menu_is_separator(s)) {
return 1;
}
while (*s != NUL) {
s += skip_wildmenu_char(xp, s);
- len += ptr2cells((char *)s);
+ len += ptr2cells(s);
MB_PTR_ADV(s);
}
@@ -356,7 +401,6 @@ static int wildmenu_match_len(expand_T *xp, char_u *s)
/// @param matches list of matches
static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int match, int showtail)
{
-#define L_MATCH(m) (showtail ? showmatches_gettail(matches[m], false) : matches[m])
int row;
char *buf;
int len;
@@ -385,7 +429,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
highlight = false;
}
// count 1 for the ending ">"
- clen = wildmenu_match_len(xp, (char_u *)L_MATCH(match)) + 3;
+ clen = wildmenu_match_len(xp, SHOW_MATCH(match)) + 3;
if (match == 0) {
first_match = 0;
} else if (match < first_match) {
@@ -395,7 +439,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
} else {
// check if match fits on the screen
for (i = first_match; i < match; i++) {
- clen += wildmenu_match_len(xp, (char_u *)L_MATCH(i)) + 2;
+ clen += wildmenu_match_len(xp, SHOW_MATCH(i)) + 2;
}
if (first_match > 0) {
clen += 2;
@@ -406,7 +450,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
// if showing the last match, we can add some on the left
clen = 2;
for (i = match; i < num_matches; i++) {
- clen += wildmenu_match_len(xp, (char_u *)L_MATCH(i)) + 2;
+ clen += wildmenu_match_len(xp, SHOW_MATCH(i)) + 2;
if ((long)clen >= Columns) {
break;
}
@@ -418,7 +462,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
}
if (add_left) {
while (first_match > 0) {
- clen += wildmenu_match_len(xp, (char_u *)L_MATCH(first_match - 1)) + 2;
+ clen += wildmenu_match_len(xp, SHOW_MATCH(first_match - 1)) + 2;
if ((long)clen >= Columns) {
break;
}
@@ -438,13 +482,13 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
clen = len;
i = first_match;
- while (clen + wildmenu_match_len(xp, (char_u *)L_MATCH(i)) + 2 < Columns) {
+ while (clen + wildmenu_match_len(xp, SHOW_MATCH(i)) + 2 < Columns) {
if (i == match) {
selstart = buf + len;
selstart_col = clen;
}
- s = L_MATCH(i);
+ s = SHOW_MATCH(i);
// Check for menu separators - replace with '|'
emenu = (xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES);
@@ -455,7 +499,7 @@ static void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int m
clen += l;
} else {
for (; *s != NUL; s++) {
- s += skip_wildmenu_char(xp, (char_u *)s);
+ s += skip_wildmenu_char(xp, s);
clen += ptr2cells(s);
if ((l = utfc_ptr2len(s)) > 1) {
strncpy(buf + len, s, (size_t)l); // NOLINT(runtime/printf)
@@ -551,6 +595,44 @@ static char *get_next_or_prev_match(int mode, expand_T *xp, int *p_findex, char
findex--;
} else if (mode == WILD_NEXT) {
findex++;
+ } else if (mode == WILD_PAGEUP) {
+ if (findex == 0) {
+ // at the first entry, don't select any entries
+ findex = -1;
+ } else if (findex == -1) {
+ // no entry is selected. select the last entry
+ findex = xp->xp_numfiles - 1;
+ } else {
+ // go up by the pum height
+ int ht = pum_get_height();
+ if (ht > 3) {
+ ht -= 2;
+ }
+ findex -= ht;
+ if (findex < 0) {
+ // few entries left, select the first entry
+ findex = 0;
+ }
+ }
+ } else if (mode == WILD_PAGEDOWN) {
+ if (findex == xp->xp_numfiles - 1) {
+ // at the last entry, don't select any entries
+ findex = -1;
+ } else if (findex == -1) {
+ // no entry is selected. select the first entry
+ findex = 0;
+ } else {
+ // go down by the pum height
+ int ht = pum_get_height();
+ if (ht > 3) {
+ ht -= 2;
+ }
+ findex += ht;
+ if (findex >= xp->xp_numfiles) {
+ // few entries left, select the last entry
+ findex = xp->xp_numfiles - 1;
+ }
+ }
} else { // mode == WILD_PUM_WANT
assert(pum_want.active);
findex = pum_want.item;
@@ -589,7 +671,7 @@ static char *ExpandOne_start(int mode, expand_T *xp, char *str, int options)
char *ss = NULL;
// Do the expansion.
- if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files, options) == FAIL) {
+ if (ExpandFromContext(xp, str, &xp->xp_files, &xp->xp_numfiles, options) == FAIL) {
#ifdef FNAME_ILLEGAL
// Illegal file name has been silently skipped. But when there
// are wildcards, the real problem is that there was no match,
@@ -604,11 +686,10 @@ static char *ExpandOne_start(int mode, expand_T *xp, char *str, int options)
}
} else {
// Escape the matches for use on the command line.
- ExpandEscape(xp, (char_u *)str, xp->xp_numfiles, xp->xp_files, options);
+ 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 (mode != WILD_ALL && mode != WILD_ALL_KEEP && mode != WILD_LONGEST) {
if (xp->xp_numfiles) {
non_suf_match = xp->xp_numfiles;
} else {
@@ -729,7 +810,9 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode)
int i;
// first handle the case of using an old match
- if (mode == WILD_NEXT || mode == WILD_PREV || mode == WILD_PUM_WANT) {
+ if (mode == WILD_NEXT || mode == WILD_PREV
+ || mode == WILD_PAGEUP || mode == WILD_PAGEDOWN
+ || mode == WILD_PUM_WANT) {
return get_next_or_prev_match(mode, xp, &findex, orig_save);
}
@@ -820,37 +903,99 @@ void ExpandCleanup(expand_T *xp)
}
}
+/// Display one line of completion matches. Multiple matches are displayed in
+/// each line (used by wildmode=list and CTRL-D)
+///
+/// @param matches list of completion match names
+/// @param numMatches number of completion matches in "matches"
+/// @param lines number of output lines
+/// @param linenr line number of matches to display
+/// @param maxlen maximum number of characters in each line
+/// @param showtail display only the tail of the full path of a file name
+/// @param dir_attr highlight attribute to use for directory names
+static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, int lines, int linenr,
+ int maxlen, int showtail, int dir_attr)
+{
+ char *p;
+ int lastlen = 999;
+ for (int 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((const char *)p);
+ msg_advance(maxlen + 3);
+ msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D));
+ break;
+ }
+ for (int i = maxlen - lastlen; --i >= 0;) {
+ msg_putchar(' ');
+ }
+ bool isdir;
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_SHELLCMD
+ || xp->xp_context == EXPAND_BUFFERS) {
+ // highlight directories
+ if (xp->xp_numfiles != -1) {
+ // Expansion was done before and special characters
+ // were escaped, need to halve backslashes. Also
+ // $HOME has been replaced with ~/.
+ char *exp_path = (char *)expand_env_save_opt(matches[j], true);
+ char *path = exp_path != NULL ? exp_path : matches[j];
+ char *halved_slash = backslash_halve_save(path);
+ isdir = os_isdir(halved_slash);
+ xfree(exp_path);
+ if (halved_slash != path) {
+ xfree(halved_slash);
+ }
+ } else {
+ // Expansion was done here, file names are literal.
+ isdir = os_isdir(matches[j]);
+ }
+ if (showtail) {
+ p = SHOW_MATCH(j);
+ } else {
+ home_replace(NULL, matches[j], NameBuff, MAXPATHL, true);
+ p = NameBuff;
+ }
+ } else {
+ isdir = false;
+ p = SHOW_MATCH(j);
+ }
+ lastlen = msg_outtrans_attr(p, isdir ? dir_attr : 0);
+ }
+ if (msg_col > 0) { // when not wrapped around
+ msg_clr_eos();
+ msg_putchar('\n');
+ }
+}
+
/// Show all matches for completion on the command line.
/// Returns EXPAND_NOTHING when the character that triggered expansion should
/// be inserted like a normal character.
int showmatches(expand_T *xp, int wildmenu)
{
CmdlineInfo *const ccline = get_cmdline_info();
-#define L_SHOWFILE(m) (showtail \
- ? showmatches_gettail(files_found[m], false) \
- : files_found[m])
- int num_files;
- char **files_found;
- int i, j, k;
+ int numMatches;
+ char **matches;
+ int i, j;
int maxlen;
int lines;
int columns;
- char *p;
- int lastlen;
int attr;
int showtail;
if (xp->xp_numfiles == -1) {
set_expand_context(xp);
i = expand_cmdline(xp, ccline->cmdbuff, ccline->cmdpos,
- &num_files, &files_found);
+ &numMatches, &matches);
showtail = expand_showtail(xp);
if (i != EXPAND_OK) {
return i;
}
} else {
- num_files = xp->xp_numfiles;
- files_found = xp->xp_files;
+ numMatches = xp->xp_numfiles;
+ matches = xp->xp_files;
showtail = cmd_showtail;
}
@@ -860,26 +1005,8 @@ int showmatches(expand_T *xp, int wildmenu)
|| ui_has(kUIWildmenu);
if (compl_use_pum) {
- assert(num_files >= 0);
- compl_match_arraysize = num_files;
- compl_match_array = xmalloc(sizeof(pumitem_T) * (size_t)compl_match_arraysize);
- for (i = 0; i < num_files; i++) {
- compl_match_array[i] = (pumitem_T){
- .pum_text = (char_u *)L_SHOWFILE(i),
- .pum_info = NULL,
- .pum_extra = NULL,
- .pum_kind = NULL,
- };
- }
- char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, true) : xp->xp_pattern;
- if (ui_has(kUICmdline)) {
- compl_startcol = (int)(endpos - ccline->cmdbuff);
- } else {
- compl_startcol = cmd_screencol((int)(endpos - ccline->cmdbuff));
- }
- compl_selected = -1;
- cmdline_pum_display(true);
- return EXPAND_OK;
+ // cmdline completion popup menu (with wildoptions=pum)
+ return cmdline_pum_create(ccline, xp, matches, numMatches, showtail);
}
if (!wildmenu) {
@@ -895,18 +1022,18 @@ int showmatches(expand_T *xp, int wildmenu)
if (got_int) {
got_int = false; // only int. the completion, not the cmd line
} else if (wildmenu) {
- redraw_wildmenu(xp, num_files, files_found, -1, showtail);
+ redraw_wildmenu(xp, numMatches, matches, -1, showtail);
} else {
// find the length of the longest file name
maxlen = 0;
- for (i = 0; i < num_files; i++) {
+ 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, files_found[i], NameBuff, MAXPATHL, true);
+ home_replace(NULL, matches[i], NameBuff, MAXPATHL, true);
j = vim_strsize(NameBuff);
} else {
- j = vim_strsize(L_SHOWFILE(i));
+ j = vim_strsize(SHOW_MATCH(i));
}
if (j > maxlen) {
maxlen = j;
@@ -914,7 +1041,7 @@ int showmatches(expand_T *xp, int wildmenu)
}
if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
- lines = num_files;
+ lines = numMatches;
} else {
// compute the number of columns and lines for the listing
maxlen += 2; // two spaces between file names
@@ -922,7 +1049,7 @@ int showmatches(expand_T *xp, int wildmenu)
if (columns < 1) {
columns = 1;
}
- lines = (num_files + columns - 1) / columns;
+ lines = (numMatches + columns - 1) / columns;
}
attr = HL_ATTR(HLF_D); // find out highlighting for directories
@@ -936,56 +1063,7 @@ int showmatches(expand_T *xp, int wildmenu)
// list the files line by line
for (i = 0; i < lines; i++) {
- lastlen = 999;
- for (k = i; k < num_files; k += lines) {
- if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
- msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D));
- p = files_found[k] + strlen(files_found[k]) + 1;
- msg_advance(maxlen + 1);
- msg_puts((const char *)p);
- msg_advance(maxlen + 3);
- msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D));
- break;
- }
- for (j = maxlen - lastlen; --j >= 0;) {
- msg_putchar(' ');
- }
- if (xp->xp_context == EXPAND_FILES
- || xp->xp_context == EXPAND_SHELLCMD
- || xp->xp_context == EXPAND_BUFFERS) {
- // highlight directories
- if (xp->xp_numfiles != -1) {
- // Expansion was done before and special characters
- // were escaped, need to halve backslashes. Also
- // $HOME has been replaced with ~/.
- char *exp_path = (char *)expand_env_save_opt((char_u *)files_found[k], true);
- char *path = exp_path != NULL ? exp_path : files_found[k];
- char *halved_slash = backslash_halve_save(path);
- j = os_isdir(halved_slash);
- xfree(exp_path);
- if (halved_slash != path) {
- xfree(halved_slash);
- }
- } else {
- // Expansion was done here, file names are literal.
- j = os_isdir(files_found[k]);
- }
- if (showtail) {
- p = L_SHOWFILE(k);
- } else {
- home_replace(NULL, files_found[k], NameBuff, MAXPATHL, true);
- p = NameBuff;
- }
- } else {
- j = false;
- p = L_SHOWFILE(k);
- }
- lastlen = msg_outtrans_attr(p, j ? attr : 0);
- }
- if (msg_col > 0) { // when not wrapped around
- msg_clr_eos();
- msg_putchar('\n');
- }
+ showmatches_oneline(xp, matches, numMatches, lines, i, maxlen, showtail, attr);
if (got_int) {
got_int = false;
break;
@@ -998,7 +1076,7 @@ int showmatches(expand_T *xp, int wildmenu)
}
if (xp->xp_numfiles == -1) {
- FreeWild(num_files, files_found);
+ FreeWild(numMatches, matches);
}
return EXPAND_OK;
@@ -1245,7 +1323,7 @@ void set_expand_context(expand_T *xp)
xp->xp_context = EXPAND_NOTHING;
return;
}
- set_cmd_context(xp, (char_u *)ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, true);
+ set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, true);
}
/// Sets the index of a built-in or user defined command "cmd" in eap->cmdidx.
@@ -1423,17 +1501,228 @@ static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool use
}
}
+/// Set the completion context for the :filter command. Returns a pointer to the
+/// next command after the :filter command.
+static const char *set_context_in_filter_cmd(expand_T *xp, const char *arg)
+{
+ if (*arg != NUL) {
+ arg = (const char *)skip_vimgrep_pat((char *)arg, NULL, NULL);
+ }
+ if (arg == NULL || *arg == NUL) {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+ return (const char *)skipwhite(arg);
+}
+
+/// Set the completion context for the :match command. Returns a pointer to the
+/// next command after the :match command.
+static const char *set_context_in_match_cmd(expand_T *xp, const char *arg)
+{
+ if (*arg == NUL || !ends_excmd(*arg)) {
+ // also complete "None"
+ set_context_in_echohl_cmd(xp, arg);
+ arg = (const char *)skipwhite(skiptowhite(arg));
+ if (*arg != NUL) {
+ xp->xp_context = EXPAND_NOTHING;
+ arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), magic_isset());
+ }
+ }
+ return (const char *)find_nextcmd(arg);
+}
+
+/// Returns a pointer to the next command after a :global or a :v command.
+/// Returns NULL if there is no next command.
+static const char *find_cmd_after_global_cmd(const char *arg)
+{
+ const int delim = (uint8_t)(*arg); // Get the delimiter.
+ if (delim) {
+ arg++; // Skip delimiter if there is one.
+ }
+
+ while (arg[0] != NUL && (uint8_t)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.
+static const char *find_cmd_after_substitute_cmd(const char *arg)
+{
+ const int delim = (uint8_t)(*arg);
+ if (delim) {
+ // Skip "from" part.
+ arg++;
+ arg = (const char *)skip_regexp((char *)arg, delim, magic_isset());
+
+ if (arg[0] != NUL && arg[0] == delim) {
+ // Skip "to" part.
+ arg++;
+ while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
+ if (arg[0] == '\\' && arg[1] != NUL) {
+ arg++;
+ }
+ arg++;
+ }
+ if (arg[0] != NUL) { // Skip delimiter.
+ arg++;
+ }
+ }
+ }
+ while (arg[0] && strchr("|\"#", arg[0]) == NULL) {
+ arg++;
+ }
+ if (arg[0] != NUL) {
+ return arg;
+ }
+
+ return NULL;
+}
+
+/// Returns a pointer to the next command after a :isearch/:dsearch/:ilist
+/// :dlist/:ijump/:psearch/:djump/:isplit/:dsplit command.
+/// Returns NULL if there is no next command.
+static const char *find_cmd_after_isearch_cmd(expand_T *xp, const char *arg)
+{
+ // Skip count.
+ arg = (const char *)skipwhite(skipdigits(arg));
+ if (*arg != '/') {
+ return NULL;
+ }
+
+ // Match regexp, not just whole words.
+ for (++arg; *arg && *arg != '/'; arg++) {
+ if (*arg == '\\' && arg[1] != NUL) {
+ arg++;
+ }
+ }
+ if (*arg) {
+ arg = (const char *)skipwhite(arg + 1);
+
+ // Check for trailing illegal characters.
+ if (*arg == NUL || strchr("|\"\n", *arg) == NULL) {
+ xp->xp_context = EXPAND_NOTHING;
+ } else {
+ return arg;
+ }
+ }
+
+ return NULL;
+}
+
+/// Set the completion context for the :unlet command. Always returns NULL.
+static const char *set_context_in_unlet_cmd(expand_T *xp, const char *arg)
+{
+ while ((xp->xp_pattern = strchr(arg, ' ')) != NULL) {
+ arg = (const char *)xp->xp_pattern + 1;
+ }
+
+ xp->xp_context = EXPAND_USER_VARS;
+ xp->xp_pattern = (char *)arg;
+
+ if (*xp->xp_pattern == '$') {
+ xp->xp_context = EXPAND_ENV_VARS;
+ xp->xp_pattern++;
+ }
+
+ return NULL;
+}
+
+/// Set the completion context for the :language command. Always returns NULL.
+static const char *set_context_in_lang_cmd(expand_T *xp, const char *arg)
+{
+ const char *p = (const char *)skiptowhite(arg);
+ if (*p == NUL) {
+ xp->xp_context = EXPAND_LANGUAGE;
+ xp->xp_pattern = (char *)arg;
+ } else {
+ if (strncmp(arg, "messages", (size_t)(p - arg)) == 0
+ || strncmp(arg, "ctype", (size_t)(p - arg)) == 0
+ || strncmp(arg, "time", (size_t)(p - arg)) == 0
+ || strncmp(arg, "collate", (size_t)(p - arg)) == 0) {
+ xp->xp_context = EXPAND_LOCALES;
+ xp->xp_pattern = skipwhite(p);
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+
+ return NULL;
+}
+
+static enum {
+ EXP_BREAKPT_ADD, ///< expand ":breakadd" sub-commands
+ EXP_BREAKPT_DEL, ///< expand ":breakdel" sub-commands
+ EXP_PROFDEL, ///< expand ":profdel" sub-commands
+} breakpt_expand_what;
+
+/// Set the completion context for the :breakadd command. Always returns NULL.
+static const char *set_context_in_breakadd_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx)
+{
+ xp->xp_context = EXPAND_BREAKPOINT;
+ xp->xp_pattern = (char *)arg;
+
+ if (cmdidx == CMD_breakadd) {
+ breakpt_expand_what = EXP_BREAKPT_ADD;
+ } else if (cmdidx == CMD_breakdel) {
+ breakpt_expand_what = EXP_BREAKPT_DEL;
+ } else {
+ breakpt_expand_what = EXP_PROFDEL;
+ }
+
+ const char *p = skipwhite(arg);
+ if (*p == NUL) {
+ return NULL;
+ }
+ const char *subcmd_start = p;
+
+ if (strncmp("file ", p, 5) == 0 || strncmp("func ", p, 5) == 0) {
+ // :breakadd file [lnum] <filename>
+ // :breakadd func [lnum] <funcname>
+ p += 4;
+ p = skipwhite(p);
+
+ // skip line number (if specified)
+ if (ascii_isdigit(*p)) {
+ p = skipdigits(p);
+ if (*p != ' ') {
+ xp->xp_context = EXPAND_NOTHING;
+ return NULL;
+ }
+ p = skipwhite(p);
+ }
+ if (strncmp("file", subcmd_start, 4) == 0) {
+ xp->xp_context = EXPAND_FILES;
+ } else {
+ xp->xp_context = EXPAND_USER_FUNC;
+ }
+ xp->xp_pattern = (char *)p;
+ } else if (strncmp("expr ", p, 5) == 0) {
+ // :breakadd expr <expression>
+ xp->xp_context = EXPAND_EXPRESSION;
+ xp->xp_pattern = skipwhite(p + 5);
+ }
+
+ return NULL;
+}
+
/// 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".
/// For user-defined commands and for environment variables, "context" has the
/// completion type.
///
/// @return a pointer to the next command, or NULL if there is no next command.
-static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, const char *arg,
- uint32_t argt, int context, expand_T *xp, bool forceit)
+static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expand_T *xp,
+ const char *arg, uint32_t argt, int context, bool forceit)
{
- const char *p;
-
switch (cmdidx) {
case CMD_find:
case CMD_sfind:
@@ -1495,26 +1784,10 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
return arg;
case CMD_filter:
- if (*arg != NUL) {
- arg = (const char *)skip_vimgrep_pat((char *)arg, NULL, NULL);
- }
- if (arg == NULL || *arg == NUL) {
- xp->xp_context = EXPAND_NOTHING;
- return NULL;
- }
- return (const char *)skipwhite(arg);
+ return set_context_in_filter_cmd(xp, arg);
case CMD_match:
- if (*arg == NUL || !ends_excmd(*arg)) {
- // also complete "None"
- set_context_in_echohl_cmd(xp, arg);
- arg = (const char *)skipwhite(skiptowhite(arg));
- if (*arg != NUL) {
- xp->xp_context = EXPAND_NOTHING;
- arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), magic_isset());
- }
- }
- return (const char *)find_nextcmd(arg);
+ return set_context_in_match_cmd(xp, arg);
// All completion for the +cmdline_compl feature goes here.
@@ -1527,53 +1800,11 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
break;
case CMD_global:
- case CMD_vglobal: {
- const int delim = (uint8_t)(*arg); // Get the delimiter.
- if (delim) {
- arg++; // Skip delimiter if there is one.
- }
-
- while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
- if (arg[0] == '\\' && arg[1] != NUL) {
- arg++;
- }
- arg++;
- }
- if (arg[0] != NUL) {
- return arg + 1;
- }
- break;
- }
+ case CMD_vglobal:
+ return find_cmd_after_global_cmd(arg);
case CMD_and:
- case CMD_substitute: {
- const int delim = (uint8_t)(*arg);
- if (delim) {
- // Skip "from" part.
- arg++;
- arg = (const char *)skip_regexp((char *)arg, delim, magic_isset());
-
- if (arg[0] != NUL && arg[0] == delim) {
- // Skip "to" part.
- arg++;
- while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
- if (arg[0] == '\\' && arg[1] != NUL) {
- arg++;
- }
- arg++;
- }
- if (arg[0] != NUL) { // Skip delimiter.
- arg++;
- }
- }
- }
- while (arg[0] && strchr("|\"#", arg[0]) == NULL) {
- arg++;
- }
- if (arg[0] != NUL) {
- return arg;
- }
- break;
- }
+ case CMD_substitute:
+ return find_cmd_after_substitute_cmd(arg);
case CMD_isearch:
case CMD_dsearch:
case CMD_ilist:
@@ -1583,29 +1814,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
case CMD_djump:
case CMD_isplit:
case CMD_dsplit:
- // Skip count.
- arg = (const char *)skipwhite(skipdigits(arg));
- if (*arg != '/') {
- return NULL;
- }
-
- // Match regexp, not just whole words.
- for (++arg; *arg && *arg != '/'; arg++) {
- if (*arg == '\\' && arg[1] != NUL) {
- arg++;
- }
- }
- if (*arg) {
- arg = (const char *)skipwhite(arg + 1);
-
- // Check for trailing illegal characters.
- if (*arg == NUL || strchr("|\"\n", *arg) == NULL) {
- xp->xp_context = EXPAND_NOTHING;
- } else {
- return arg;
- }
- }
- break;
+ return find_cmd_after_isearch_cmd(xp, arg);
case CMD_autocmd:
return (const char *)set_context_in_autocmd(xp, (char *)arg, false);
@@ -1668,20 +1877,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
break;
case CMD_unlet:
- while ((xp->xp_pattern = strchr(arg, ' ')) != NULL) {
- arg = (const char *)xp->xp_pattern + 1;
- }
-
- xp->xp_context = EXPAND_USER_VARS;
- xp->xp_pattern = (char *)arg;
-
- if (*xp->xp_pattern == '$') {
- xp->xp_context = EXPAND_ENV_VARS;
- xp->xp_pattern++;
- }
-
- break;
-
+ return set_context_in_unlet_cmd(xp, arg);
case CMD_function:
case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC;
@@ -1720,34 +1916,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
case CMD_USER:
case CMD_USER_BUF:
- if (context != EXPAND_NOTHING) {
- // EX_XFILE: file names are handled above.
- if (!(argt & EX_XFILE)) {
- if (context == EXPAND_MENUS) {
- return (const char *)set_context_in_menu_cmd(xp, cmd, (char *)arg, forceit);
- } else if (context == EXPAND_COMMANDS) {
- return arg;
- } else if (context == EXPAND_MAPPINGS) {
- return (const char *)set_context_in_map_cmd(xp, "map", (char *)arg, forceit,
- false, false,
- CMD_map);
- }
- // Find start of last argument.
- p = arg;
- while (*p) {
- if (*p == ' ') {
- // argument starts after a space
- arg = p + 1;
- } else if (*p == '\\' && *(p + 1) != NUL) {
- p++; // skip over escaped character
- }
- MB_PTR_ADV(p);
- }
- xp->xp_pattern = (char *)arg;
- }
- xp->xp_context = context;
- }
- break;
+ return set_context_in_user_cmdarg(cmd, arg, argt, context, xp, forceit);
case CMD_map:
case CMD_noremap:
@@ -1863,22 +2032,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
- p = (const char *)skiptowhite(arg);
- if (*p == NUL) {
- xp->xp_context = EXPAND_LANGUAGE;
- xp->xp_pattern = (char *)arg;
- } else {
- if (strncmp(arg, "messages", (size_t)(p - arg)) == 0
- || strncmp(arg, "ctype", (size_t)(p - arg)) == 0
- || strncmp(arg, "time", (size_t)(p - arg)) == 0
- || strncmp(arg, "collate", (size_t)(p - arg)) == 0) {
- xp->xp_context = EXPAND_LOCALES;
- xp->xp_pattern = skipwhite(p);
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- }
- break;
+ return set_context_in_lang_cmd(xp, arg);
#endif
case CMD_profile:
set_context_in_profile_cmd(xp, arg);
@@ -1914,6 +2068,11 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
xp->xp_pattern = (char *)arg;
break;
+ case CMD_breakadd:
+ case CMD_profdel:
+ case CMD_breakdel:
+ return set_context_in_breakadd_cmd(xp, arg, cmdidx);
+
case CMD_lua:
xp->xp_context = EXPAND_LUA;
break;
@@ -2097,17 +2256,19 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
// Switch on command name.
- return set_context_by_cmdname(cmd, ea.cmdidx, arg, ea.argt, context, xp, forceit);
+ return set_context_by_cmdname(cmd, ea.cmdidx, xp, arg, ea.argt, context, forceit);
}
+/// Set the completion context in "xp" for command "str"
+///
/// @param str start of command line
/// @param len length of command line (excl. NUL)
/// @param col position of cursor
/// @param use_ccline use ccline for info
-void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline)
+void set_cmd_context(expand_T *xp, char *str, int len, int col, int use_ccline)
{
CmdlineInfo *const ccline = get_cmdline_info();
- char_u old_char = NUL;
+ char old_char = NUL;
// Avoid a UMR warning from Purify, only save the character if it has been
// written before.
@@ -2119,7 +2280,7 @@ void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline
if (use_ccline && ccline->cmdfirstc == '=') {
// pass CMD_SIZE because there is no real command
- set_context_for_expression(xp, (char *)str, CMD_SIZE);
+ set_context_for_expression(xp, str, CMD_SIZE);
} else if (use_ccline && ccline->input_fn) {
xp->xp_context = ccline->xp_context;
xp->xp_pattern = ccline->cmdbuff;
@@ -2132,7 +2293,7 @@ void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline
// Store the string here so that call_user_expand_func() can get to them
// easily.
- xp->xp_line = (char *)str;
+ xp->xp_line = str;
xp->xp_col = col;
str[col] = old_char;
@@ -2176,7 +2337,7 @@ int expand_cmdline(expand_T *xp, const char *str, int col, int *matchcount, char
}
// find all files that match the description
- if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL) {
+ if (ExpandFromContext(xp, file_str, matches, matchcount, options) == FAIL) {
*matchcount = 0;
*matches = NULL;
}
@@ -2186,8 +2347,8 @@ int expand_cmdline(expand_T *xp, const char *str, int col, int *matchcount, char
}
/// Expand file or directory names.
-static int expand_files_and_dirs(expand_T *xp, char *pat, char ***file, int *num_file, int flags,
- int options)
+static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int *numMatches,
+ int flags, int options)
{
bool free_pat = false;
@@ -2223,14 +2384,14 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***file, int *num
}
// Expand wildcards, supporting %:h and the like.
- int ret = expand_wildcards_eval(&pat, num_file, file, flags);
+ int ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
if (free_pat) {
xfree(pat);
}
#ifdef BACKSLASH_IN_FILENAME
if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) {
- for (int j = 0; j < *num_file; j++) {
- char *ptr = (*file)[j];
+ for (int j = 0; j < *numMatches; j++) {
+ char *ptr = (*matches)[j];
while (*ptr != NUL) {
if (p_csl[0] == 's' && *ptr == '\\') {
*ptr = '/';
@@ -2259,6 +2420,32 @@ static char *get_behave_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
}
/// Function given to ExpandGeneric() to obtain the possible arguments of the
+/// ":breakadd {expr, file, func, here}" command.
+/// ":breakdel {func, file, here}" command.
+static char *get_breakadd_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
+{
+ char *opts[] = { "expr", "file", "func", "here" };
+
+ if (idx >= 0 && idx <= 3) {
+ // breakadd {expr, file, func, here}
+ if (breakpt_expand_what == EXP_BREAKPT_ADD) {
+ return opts[idx];
+ } else if (breakpt_expand_what == EXP_BREAKPT_DEL) {
+ // breakdel {func, file, here}
+ if (idx <= 2) {
+ return opts[idx + 1];
+ }
+ } else {
+ // profdel {func, file}
+ if (idx <= 1) {
+ return opts[idx + 1];
+ }
+ }
+ }
+ return NULL;
+}
+
+/// Function given to ExpandGeneric() to obtain the possible arguments of the
/// ":messages {clear}" command.
static char *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
{
@@ -2303,7 +2490,7 @@ static char *get_healthcheck_names(expand_T *xp FUNC_ATTR_UNUSED, int idx)
}
/// Do the expansion based on xp->xp_context and "rmp".
-static int ExpandOther(expand_T *xp, regmatch_T *rmp, int *num_file, char ***file)
+static int ExpandOther(expand_T *xp, regmatch_T *rmp, char ***matches, int *numMatches)
{
typedef CompleteListItemGetter ExpandFunc;
static struct expgen {
@@ -2342,6 +2529,7 @@ static int ExpandOther(expand_T *xp, regmatch_T *rmp, int *num_file, char ***fil
{ EXPAND_ENV_VARS, get_env_name, true, true },
{ EXPAND_USER, get_users, true, false },
{ EXPAND_ARGLIST, get_arglist_name, true, false },
+ { EXPAND_BREAKPOINT, get_breakadd_arg, true, true },
{ EXPAND_CHECKHEALTH, get_healthcheck_names, true, false },
};
int ret = FAIL;
@@ -2353,7 +2541,7 @@ static int ExpandOther(expand_T *xp, regmatch_T *rmp, int *num_file, char ***fil
if (tab[i].ic) {
rmp->rm_ic = true;
}
- ExpandGeneric(xp, rmp, num_file, file, tab[i].func, tab[i].escaped);
+ ExpandGeneric(xp, rmp, matches, numMatches, tab[i].func, tab[i].escaped);
ret = OK;
break;
}
@@ -2362,16 +2550,10 @@ static int ExpandOther(expand_T *xp, regmatch_T *rmp, int *num_file, char ***fil
return ret;
}
-/// Do the expansion based on xp->xp_context and "pat".
-///
-/// @param options WILD_ flags
-static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***file, int options)
+/// Map wild expand options to flags for expand_wildcards()
+static int map_wildopts_to_ewflags(int options)
{
- regmatch_T regmatch;
- int ret;
- int flags;
-
- flags = EW_DIR; // include directories
+ int flags = EW_DIR; // include directories
if (options & WILD_LIST_NOTFOUND) {
flags |= EW_NOTFOUND;
}
@@ -2391,68 +2573,79 @@ static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***fil
flags |= EW_ALLLINKS;
}
+ return flags;
+}
+
+/// Do the expansion based on xp->xp_context and "pat".
+///
+/// @param options WILD_ flags
+static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numMatches, int options)
+{
+ regmatch_T regmatch;
+ int ret;
+ int flags = map_wildopts_to_ewflags(options);
+
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);
+ return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options);
}
- *file = NULL;
- *num_file = 0;
+ *matches = NULL;
+ *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 ? "help" : pat,
- num_file, file, false) == OK) {
- cleanup_help_tags(*num_file, *file);
+ numMatches, matches, false) == OK) {
+ cleanup_help_tags(*numMatches, *matches);
return OK;
}
return FAIL;
}
if (xp->xp_context == EXPAND_SHELLCMD) {
- *file = NULL;
- expand_shellcmd(pat, num_file, file, flags);
+ expand_shellcmd(pat, matches, numMatches, flags);
return OK;
}
if (xp->xp_context == EXPAND_OLD_SETTING) {
- ExpandOldSetting(num_file, file);
+ ExpandOldSetting(numMatches, matches);
return OK;
}
if (xp->xp_context == EXPAND_BUFFERS) {
- return ExpandBufnames(pat, num_file, file, options);
+ return ExpandBufnames(pat, numMatches, matches, options);
}
if (xp->xp_context == EXPAND_DIFF_BUFFERS) {
- return ExpandBufnames(pat, num_file, file, options | BUF_DIFF_FILTER);
+ return ExpandBufnames(pat, numMatches, matches, options | BUF_DIFF_FILTER);
}
if (xp->xp_context == EXPAND_TAGS
|| xp->xp_context == EXPAND_TAGS_LISTFILES) {
- return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file);
+ 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 + DIP_LUA, num_file, file, directories);
+ return ExpandRTDir(pat, DIP_START + DIP_OPT + DIP_LUA, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_COMPILER) {
char *directories[] = { "compiler", NULL };
- return ExpandRTDir(pat, DIP_LUA, num_file, file, directories);
+ return ExpandRTDir(pat, DIP_LUA, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_OWNSYNTAX) {
char *directories[] = { "syntax", NULL };
- return ExpandRTDir(pat, 0, num_file, file, directories);
+ return ExpandRTDir(pat, 0, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_FILETYPE) {
char *directories[] = { "syntax", "indent", "ftplugin", NULL };
- return ExpandRTDir(pat, DIP_LUA, num_file, file, directories);
+ return ExpandRTDir(pat, DIP_LUA, numMatches, matches, directories);
}
if (xp->xp_context == EXPAND_USER_LIST) {
- return ExpandUserList(xp, num_file, file);
+ return ExpandUserList(xp, matches, numMatches);
}
if (xp->xp_context == EXPAND_USER_LUA) {
- return ExpandUserLua(xp, num_file, file);
+ return ExpandUserLua(xp, numMatches, matches);
}
if (xp->xp_context == EXPAND_PACKADD) {
- return ExpandPackAddDir(pat, num_file, file);
+ return ExpandPackAddDir(pat, numMatches, matches);
}
// When expanding a function name starting with s:, match the <SNR>nr_
@@ -2468,7 +2661,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***fil
if (xp->xp_context == EXPAND_LUA) {
ILOG("PAT %s", pat);
- return nlua_expand_pat(xp, pat, num_file, file);
+ return nlua_expand_pat(xp, pat, numMatches, matches);
}
regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0);
@@ -2477,17 +2670,17 @@ static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***fil
}
// set ignore-case according to p_ic, p_scs and pat
- regmatch.rm_ic = ignorecase((char_u *)pat);
+ regmatch.rm_ic = ignorecase(pat);
if (xp->xp_context == EXPAND_SETTINGS
|| xp->xp_context == EXPAND_BOOL_SETTINGS) {
- ret = ExpandSettings(xp, &regmatch, num_file, file);
+ ret = ExpandSettings(xp, &regmatch, numMatches, matches);
} else if (xp->xp_context == EXPAND_MAPPINGS) {
- ret = ExpandMappings(&regmatch, num_file, file);
+ ret = ExpandMappings(&regmatch, numMatches, matches);
} else if (xp->xp_context == EXPAND_USER_DEFINED) {
- ret = ExpandUserDefined(xp, &regmatch, num_file, file);
+ ret = ExpandUserDefined(xp, &regmatch, matches, numMatches);
} else {
- ret = ExpandOther(xp, &regmatch, num_file, file);
+ ret = ExpandOther(xp, &regmatch, matches, numMatches);
}
vim_regfree(regmatch.regprog);
@@ -2503,7 +2696,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***fil
/// program. Matching strings are copied into an array, which is returned.
///
/// @param func returns a string from the list
-static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file,
+static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches,
CompleteListItemGetter func, int escaped)
{
int i;
@@ -2527,8 +2720,8 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
return;
}
assert(count < INT_MAX);
- *num_file = (int)count;
- *file = xmalloc(count * sizeof(char_u *));
+ *numMatches = (int)count;
+ *matches = xmalloc(count * sizeof(char *));
// copy the matching names into allocated memory
count = 0;
@@ -2542,11 +2735,11 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
}
if (vim_regexec(regmatch, str, (colnr_T)0)) {
if (escaped) {
- str = (char *)vim_strsave_escaped((char_u *)str, (char_u *)" \t\\.");
+ str = vim_strsave_escaped(str, " \t\\.");
} else {
str = xstrdup(str);
}
- (*file)[count++] = str;
+ (*matches)[count++] = str;
if (func == get_menu_names) {
// Test for separator added by get_menu_names().
str += strlen(str) - 1;
@@ -2563,9 +2756,9 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
|| xp->xp_context == EXPAND_FUNCTIONS
|| xp->xp_context == EXPAND_USER_FUNC) {
// <SNR> functions should be sorted to the end.
- qsort((void *)(*file), (size_t)(*num_file), sizeof(char *), sort_func_compare);
+ qsort((void *)(*matches), (size_t)(*numMatches), sizeof(char *), sort_func_compare);
} else {
- sort_strings(*file, *num_file);
+ sort_strings(*matches, *numMatches);
}
}
@@ -2574,15 +2767,53 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, cha
reset_expand_highlight();
}
+/// Expand shell command matches in one directory of $PATH.
+static void expand_shellcmd_onedir(char *buf, char *s, size_t l, char *pat, char ***matches,
+ int *numMatches, int flags, hashtab_T *ht, garray_T *gap)
+{
+ xstrlcpy(buf, s, l + 1);
+ add_pathsep(buf);
+ l = strlen(buf);
+ xstrlcpy(buf + l, pat, MAXPATHL - l);
+
+ // Expand matches in one directory of $PATH.
+ int ret = expand_wildcards(1, &buf, numMatches, matches, flags);
+ if (ret != OK) {
+ return;
+ }
+
+ ga_grow(gap, *numMatches);
+
+ for (int i = 0; i < *numMatches; i++) {
+ char *name = (*matches)[i];
+
+ if (strlen(name) > l) {
+ // Check if this name was already found.
+ hash_T hash = hash_hash((char_u *)name + l);
+ hashitem_T *hi =
+ hash_lookup(ht, (const char *)(name + l), strlen(name + l), hash);
+ if (HASHITEM_EMPTY(hi)) {
+ // Remove the path that was prepended.
+ STRMOVE(name, name + l);
+ ((char **)gap->ga_data)[gap->ga_len++] = name;
+ hash_add_item(ht, hi, (char_u *)name, hash);
+ name = NULL;
+ }
+ }
+ xfree(name);
+ }
+ xfree(*matches);
+}
+
/// Complete a shell command.
///
-/// @param filepat is a pattern to match with command names.
-/// @param[out] num_file is pointer to number of matches.
-/// @param[out] file is pointer to array of pointers to matches.
-/// *file will either be set to NULL or point to
-/// allocated memory.
-/// @param flagsarg is a combination of EW_* flags.
-static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flagsarg)
+/// @param filepat is a pattern to match with command names.
+/// @param[out] matches is pointer to array of pointers to matches.
+/// *matches will either be set to NULL or point to
+/// allocated memory.
+/// @param[out] numMatches is pointer to number of matches.
+/// @param flagsarg is a combination of EW_* flags.
+static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int flagsarg)
FUNC_ATTR_NONNULL_ALL
{
char *pat;
@@ -2593,7 +2824,6 @@ static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flag
size_t l;
char *s, *e;
int flags = flagsarg;
- int ret;
bool did_curdir = false;
// for ":set path=" and ":set tags=" halve backslashes for escaped space
@@ -2653,44 +2883,13 @@ static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flag
if (l > MAXPATHL - 5) {
break;
}
- xstrlcpy(buf, s, l + 1);
- add_pathsep(buf);
- l = strlen(buf);
- xstrlcpy(buf + l, pat, MAXPATHL - l);
-
- // Expand matches in one directory of $PATH.
- ret = expand_wildcards(1, &buf, num_file, file, flags);
- if (ret == OK) {
- ga_grow(&ga, *num_file);
- {
- for (i = 0; i < *num_file; i++) {
- char *name = (*file)[i];
-
- if (strlen(name) > l) {
- // Check if this name was already found.
- hash_T hash = hash_hash((char_u *)name + l);
- hashitem_T *hi =
- hash_lookup(&found_ht, (const char *)(name + l),
- strlen(name + l), hash);
- if (HASHITEM_EMPTY(hi)) {
- // Remove the path that was prepended.
- STRMOVE(name, name + l);
- ((char **)ga.ga_data)[ga.ga_len++] = name;
- hash_add_item(&found_ht, hi, (char_u *)name, hash);
- name = NULL;
- }
- }
- xfree(name);
- }
- xfree(*file);
- }
- }
+ expand_shellcmd_onedir(buf, s, l, pat, matches, numMatches, flags, &found_ht, &ga);
if (*e != NUL) {
e++;
}
}
- *file = ga.ga_data;
- *num_file = ga.ga_len;
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
xfree(buf);
xfree(pat);
@@ -2702,8 +2901,7 @@ static void expand_shellcmd(char *filepat, int *num_file, char ***file, int flag
/// Call "user_expand_func()" to invoke a user defined Vim script function and
/// return the result (either a string, a List or NULL).
-static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T *xp, int *num_file,
- char ***file)
+static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T *xp)
FUNC_ATTR_NONNULL_ALL
{
CmdlineInfo *const ccline = get_cmdline_info();
@@ -2715,8 +2913,6 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
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) {
keep = ccline->cmdbuff[ccline->cmdlen];
@@ -2734,7 +2930,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
current_sctx = xp->xp_script_ctx;
- void *const ret = user_expand_func((char_u *)xp->xp_arg, 3, args);
+ void *const ret = user_expand_func(xp->xp_arg, 3, args);
current_sctx = save_current_sctx;
if (ccline->cmdbuff != NULL) {
@@ -2746,13 +2942,14 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
}
/// Expand names with a function defined by the user.
-static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char ***file)
+static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches)
{
char *e;
garray_T ga;
- char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp, num_file,
- file);
+ *matches = NULL;
+ *numMatches = 0;
+ char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp);
if (retstr == NULL) {
return FAIL;
@@ -2778,16 +2975,17 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
}
}
xfree(retstr);
- *file = ga.ga_data;
- *num_file = ga.ga_len;
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
return OK;
}
/// Expand names with a list returned by a function defined by the user.
-static int ExpandUserList(expand_T *xp, int *num_file, char ***file)
+static int ExpandUserList(expand_T *xp, char ***matches, int *numMatches)
{
- list_T *const retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp, num_file,
- file);
+ *matches = NULL;
+ *numMatches = 0;
+ list_T *const retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp);
if (retlist == NULL) {
return FAIL;
}
@@ -2805,8 +3003,8 @@ static int ExpandUserList(expand_T *xp, int *num_file, char ***file)
});
tv_list_unref(retlist);
- *file = ga.ga_data;
- *num_file = ga.ga_len;
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
return OK;
}
@@ -2859,10 +3057,10 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options)
char **p;
int num_p = 0;
- (void)ExpandFromContext(&xpc, buf, &num_p, &p,
+ (void)ExpandFromContext(&xpc, buf, &p, &num_p,
WILD_SILENT | expand_options);
if (num_p > 0) {
- ExpandEscape(&xpc, (char_u *)buf, num_p, p, WILD_SILENT | expand_options);
+ ExpandEscape(&xpc, buf, num_p, p, WILD_SILENT | expand_options);
// Concatenate new results to previous ones.
ga_grow(ga, num_p);
@@ -2914,145 +3112,158 @@ static void cmdline_del(CmdlineInfo *cclp, int from)
cclp->cmdpos = from;
}
-/// Handle a key pressed when wild menu is displayed
-int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp)
+/// Handle a key pressed when the wild menu for the menu names
+/// (EXPAND_MENUNAMES) is displayed.
+static int wildmenu_process_key_menunames(CmdlineInfo *cclp, int key, expand_T *xp)
{
- int c = key;
-
- // Special translations for 'wildmenu'
- if (xp->xp_context == EXPAND_MENUNAMES) {
- // Hitting <Down> after "emenu Name.": complete submenu
- if (c == K_DOWN && cclp->cmdpos > 0
- && cclp->cmdbuff[cclp->cmdpos - 1] == '.') {
- c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- } else if (c == K_UP) {
- // Hitting <Up>: Remove one submenu name in front of the
- // cursor
- int found = false;
-
- int j = (int)(xp->xp_pattern - cclp->cmdbuff);
- int i = 0;
- while (--j > 0) {
- // check for start of menu name
- if (cclp->cmdbuff[j] == ' '
- && cclp->cmdbuff[j - 1] != '\\') {
+ // Hitting <Down> after "emenu Name.": complete submenu
+ if (key == K_DOWN && cclp->cmdpos > 0
+ && cclp->cmdbuff[cclp->cmdpos - 1] == '.') {
+ key = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ } else if (key == K_UP) {
+ // Hitting <Up>: Remove one submenu name in front of the
+ // cursor
+ int found = false;
+
+ int j = (int)(xp->xp_pattern - cclp->cmdbuff);
+ int i = 0;
+ while (--j > 0) {
+ // check for start of menu name
+ if (cclp->cmdbuff[j] == ' '
+ && cclp->cmdbuff[j - 1] != '\\') {
+ i = j + 1;
+ break;
+ }
+ // check for start of submenu name
+ if (cclp->cmdbuff[j] == '.'
+ && cclp->cmdbuff[j - 1] != '\\') {
+ if (found) {
i = j + 1;
break;
- }
-
- // check for start of submenu name
- if (cclp->cmdbuff[j] == '.'
- && cclp->cmdbuff[j - 1] != '\\') {
- if (found) {
- i = j + 1;
- break;
- } else {
- found = true;
- }
+ } else {
+ found = true;
}
}
- if (i > 0) {
- cmdline_del(cclp, i);
- }
- c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- xp->xp_context = EXPAND_NOTHING;
}
+ if (i > 0) {
+ cmdline_del(cclp, i);
+ }
+ key = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ xp->xp_context = EXPAND_NOTHING;
}
- if (xp->xp_context == EXPAND_FILES
- || xp->xp_context == EXPAND_DIRECTORIES
- || xp->xp_context == EXPAND_SHELLCMD) {
- char upseg[5];
-
- upseg[0] = PATHSEP;
- upseg[1] = '.';
- upseg[2] = '.';
- upseg[3] = PATHSEP;
- upseg[4] = NUL;
-
- if (c == K_DOWN
- && cclp->cmdpos > 0
- && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP
- && (cclp->cmdpos < 3
- || cclp->cmdbuff[cclp->cmdpos - 2] != '.'
- || cclp->cmdbuff[cclp->cmdpos - 3] != '.')) {
- // go down a directory
- c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
- } else if (strncmp(xp->xp_pattern, upseg + 1, 3) == 0
- && c == K_DOWN) {
- // If in a direct ancestor, strip off one ../ to go down
- int found = false;
-
- int j = cclp->cmdpos;
- int i = (int)(xp->xp_pattern - cclp->cmdbuff);
- while (--j > i) {
- j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j);
- if (vim_ispathsep(cclp->cmdbuff[j])) {
- found = true;
- break;
- }
- }
- if (found
- && cclp->cmdbuff[j - 1] == '.'
- && cclp->cmdbuff[j - 2] == '.'
- && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2)) {
- cmdline_del(cclp, j - 2);
- c = (int)p_wc;
- KeyTyped = true; // in case the key was mapped
+
+ return key;
+}
+
+/// Handle a key pressed when the wild menu for file names (EXPAND_FILES) or
+/// directory names (EXPAND_DIRECTORIES) or shell command names
+/// (EXPAND_SHELLCMD) is displayed.
+static int wildmenu_process_key_filenames(CmdlineInfo *cclp, int key, expand_T *xp)
+{
+ char upseg[5];
+ upseg[0] = PATHSEP;
+ upseg[1] = '.';
+ upseg[2] = '.';
+ upseg[3] = PATHSEP;
+ upseg[4] = NUL;
+
+ if (key == K_DOWN
+ && cclp->cmdpos > 0
+ && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP
+ && (cclp->cmdpos < 3
+ || cclp->cmdbuff[cclp->cmdpos - 2] != '.'
+ || cclp->cmdbuff[cclp->cmdpos - 3] != '.')) {
+ // go down a directory
+ key = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ } else if (strncmp(xp->xp_pattern, upseg + 1, 3) == 0 && key == K_DOWN) {
+ // If in a direct ancestor, strip off one ../ to go down
+ int found = false;
+
+ int j = cclp->cmdpos;
+ int i = (int)(xp->xp_pattern - cclp->cmdbuff);
+ while (--j > i) {
+ j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j);
+ if (vim_ispathsep(cclp->cmdbuff[j])) {
+ found = true;
+ break;
}
- } else if (c == K_UP) {
- // go up a directory
- int found = false;
-
- int j = cclp->cmdpos - 1;
- int i = (int)(xp->xp_pattern - cclp->cmdbuff);
- while (--j > i) {
- j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j);
- if (vim_ispathsep(cclp->cmdbuff[j])
+ }
+ if (found
+ && cclp->cmdbuff[j - 1] == '.'
+ && cclp->cmdbuff[j - 2] == '.'
+ && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2)) {
+ cmdline_del(cclp, j - 2);
+ key = (int)p_wc;
+ KeyTyped = true; // in case the key was mapped
+ }
+ } else if (key == K_UP) {
+ // go up a directory
+ int found = false;
+
+ int j = cclp->cmdpos - 1;
+ int i = (int)(xp->xp_pattern - cclp->cmdbuff);
+ while (--j > i) {
+ j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j);
+ if (vim_ispathsep(cclp->cmdbuff[j])
#ifdef BACKSLASH_IN_FILENAME
- && vim_strchr((const char_u *)" *?[{`$%#", cclp->cmdbuff[j + 1])
- == NULL
+ && vim_strchr(" *?[{`$%#", (uint8_t)cclp->cmdbuff[j + 1]) == NULL
#endif
- ) {
- if (found) {
- i = j + 1;
- break;
- } else {
- found = true;
- }
+ ) {
+ if (found) {
+ i = j + 1;
+ break;
+ } else {
+ found = true;
}
}
+ }
- if (!found) {
- j = i;
- } else if (strncmp(cclp->cmdbuff + j, upseg, 4) == 0) {
- j += 4;
- } else if (strncmp(cclp->cmdbuff + j, upseg + 1, 3) == 0
- && j == i) {
- j += 3;
- } else {
- j = 0;
- }
-
- if (j > 0) {
- // TODO(tarruda): this is only for DOS/Unix systems - need to put in
- // machine-specific stuff here and in upseg init
- cmdline_del(cclp, j);
- put_on_cmdline((char_u *)upseg + 1, 3, false);
- } else if (cclp->cmdpos > i) {
- cmdline_del(cclp, i);
- }
+ if (!found) {
+ j = i;
+ } else if (strncmp(cclp->cmdbuff + j, upseg, 4) == 0) {
+ j += 4;
+ } else if (strncmp(cclp->cmdbuff + j, upseg + 1, 3) == 0
+ && j == i) {
+ j += 3;
+ } else {
+ j = 0;
+ }
- // Now complete in the new directory. Set KeyTyped in case the
- // Up key came from a mapping.
- c = (int)p_wc;
- KeyTyped = true;
+ if (j > 0) {
+ // TODO(tarruda): this is only for DOS/Unix systems - need to put in
+ // machine-specific stuff here and in upseg init
+ cmdline_del(cclp, j);
+ put_on_cmdline(upseg + 1, 3, false);
+ } else if (cclp->cmdpos > i) {
+ cmdline_del(cclp, i);
}
+
+ // Now complete in the new directory. Set KeyTyped in case the
+ // Up key came from a mapping.
+ key = (int)p_wc;
+ KeyTyped = true;
}
- return c;
+ return key;
+}
+
+/// Handle a key pressed when wild menu is displayed
+int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp)
+{
+ // Special translations for 'wildmenu'
+ if (xp->xp_context == EXPAND_MENUNAMES) {
+ return wildmenu_process_key_menunames(cclp, key, xp);
+ }
+ if (xp->xp_context == EXPAND_FILES
+ || xp->xp_context == EXPAND_DIRECTORIES
+ || xp->xp_context == EXPAND_SHELLCMD) {
+ return wildmenu_process_key_filenames(cclp, key, xp);
+ }
+
+ return key;
}
/// Free expanded names when finished walking through the matches