forked from aniani/vim
patch 8.2.4398: some command completion functions are too long
Problem: Some command completion functions are too long. Solution: Refactor code into separate functions. Add a few more tests. (Yegappan Lakshmanan, closes #9785)
This commit is contained in:
committed by
Bram Moolenaar
parent
34f8117dec
commit
b31aec3b93
521
src/cmdexpand.c
521
src/cmdexpand.c
@@ -681,6 +681,98 @@ ExpandCleanup(expand_T *xp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* showtail - display only the tail of the full path of a file name
|
||||
* dir_attr - highlight attribute to use for directory names
|
||||
*/
|
||||
static void
|
||||
showmatches_oneline(
|
||||
expand_T *xp,
|
||||
char_u **files_found,
|
||||
int num_files,
|
||||
int lines,
|
||||
int linenr,
|
||||
int maxlen,
|
||||
int showtail,
|
||||
int dir_attr)
|
||||
{
|
||||
int i, j;
|
||||
int isdir;
|
||||
int lastlen;
|
||||
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);
|
||||
msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D));
|
||||
break;
|
||||
}
|
||||
for (i = maxlen - lastlen; --i >= 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)
|
||||
{
|
||||
char_u *halved_slash;
|
||||
char_u *exp_path;
|
||||
char_u *path;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isdir = FALSE;
|
||||
p = SHOW_FILE_TEXT(j);
|
||||
}
|
||||
lastlen = msg_outtrans_attr(p, isdir ? dir_attr : 0);
|
||||
}
|
||||
if (msg_col > 0) // when not wrapped around
|
||||
{
|
||||
msg_clr_eos();
|
||||
msg_putchar('\n');
|
||||
}
|
||||
out_flush(); // show one line at a time
|
||||
}
|
||||
|
||||
/*
|
||||
* Show all matches for completion on the command line.
|
||||
* Returns EXPAND_NOTHING when the character that triggered expansion should
|
||||
@@ -692,12 +784,10 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
|
||||
cmdline_info_T *ccline = get_cmdline_info();
|
||||
int num_files;
|
||||
char_u **files_found;
|
||||
int i, j, k;
|
||||
int i, j;
|
||||
int maxlen;
|
||||
int lines;
|
||||
int columns;
|
||||
char_u *p;
|
||||
int lastlen;
|
||||
int attr;
|
||||
int showtail;
|
||||
|
||||
@@ -709,7 +799,6 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
|
||||
showtail = expand_showtail(xp);
|
||||
if (i != EXPAND_OK)
|
||||
return i;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -789,69 +878,8 @@ showmatches(expand_T *xp, int wildmenu UNUSED)
|
||||
// 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((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)
|
||||
{
|
||||
char_u *halved_slash;
|
||||
char_u *exp_path;
|
||||
char_u *path;
|
||||
|
||||
// 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[k], TRUE);
|
||||
path = exp_path != NULL ? exp_path : files_found[k];
|
||||
halved_slash = backslash_halve_save(path);
|
||||
j = mch_isdir(halved_slash != NULL ? halved_slash
|
||||
: files_found[k]);
|
||||
vim_free(exp_path);
|
||||
if (halved_slash != path)
|
||||
vim_free(halved_slash);
|
||||
}
|
||||
else
|
||||
// Expansion was done here, file names are literal.
|
||||
j = mch_isdir(files_found[k]);
|
||||
if (showtail)
|
||||
p = SHOW_FILE_TEXT(k);
|
||||
else
|
||||
{
|
||||
home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
|
||||
TRUE);
|
||||
p = NameBuff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
j = FALSE;
|
||||
p = SHOW_FILE_TEXT(k);
|
||||
}
|
||||
lastlen = msg_outtrans_attr(p, j ? attr : 0);
|
||||
}
|
||||
if (msg_col > 0) // when not wrapped around
|
||||
{
|
||||
msg_clr_eos();
|
||||
msg_putchar('\n');
|
||||
}
|
||||
out_flush(); // show one line at a time
|
||||
showmatches_oneline(xp, files_found, num_files, lines, i,
|
||||
maxlen, showtail, attr);
|
||||
if (got_int)
|
||||
{
|
||||
got_int = FALSE;
|
||||
@@ -1333,6 +1361,73 @@ set_context_for_wildcard_arg(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the next command after a :substitute or a :& command.
|
||||
* Returns NULL if there is no next command.
|
||||
*/
|
||||
static char_u *
|
||||
find_cmd_after_substitute_cmd(char_u *arg)
|
||||
{
|
||||
int delim;
|
||||
|
||||
delim = *arg;
|
||||
if (delim)
|
||||
{
|
||||
// skip "from" part
|
||||
++arg;
|
||||
arg = skip_regexp(arg, delim, magic_isset());
|
||||
|
||||
if (arg[0] != NUL && arg[0] == delim)
|
||||
{
|
||||
// skip "to" part
|
||||
++arg;
|
||||
while (arg[0] != NUL && arg[0] != delim)
|
||||
{
|
||||
if (arg[0] == '\\' && arg[1] != NUL)
|
||||
++arg;
|
||||
++arg;
|
||||
}
|
||||
if (arg[0] != NUL) // skip delimiter
|
||||
++arg;
|
||||
}
|
||||
}
|
||||
while (arg[0] && vim_strchr((char_u *)"|\"#", 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 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
|
||||
{
|
||||
for (++arg; *arg && *arg != '/'; arg++)
|
||||
if (*arg == '\\' && arg[1] != NUL)
|
||||
arg++;
|
||||
if (*arg)
|
||||
{
|
||||
arg = skipwhite(arg + 1);
|
||||
|
||||
// Check for trailing illegal characters
|
||||
if (*arg == NUL || vim_strchr((char_u *)"|\"\n", *arg) == NULL)
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
else
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
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'.
|
||||
@@ -1467,32 +1562,7 @@ set_context_by_cmdname(
|
||||
break;
|
||||
case CMD_and:
|
||||
case CMD_substitute:
|
||||
delim = *arg;
|
||||
if (delim)
|
||||
{
|
||||
// skip "from" part
|
||||
++arg;
|
||||
arg = skip_regexp(arg, delim, magic_isset());
|
||||
|
||||
if (arg[0] != NUL && arg[0] == delim)
|
||||
{
|
||||
// skip "to" part
|
||||
++arg;
|
||||
while (arg[0] != NUL && arg[0] != delim)
|
||||
{
|
||||
if (arg[0] == '\\' && arg[1] != NUL)
|
||||
++arg;
|
||||
++arg;
|
||||
}
|
||||
if (arg[0] != NUL) // skip delimiter
|
||||
++arg;
|
||||
}
|
||||
}
|
||||
while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
|
||||
++arg;
|
||||
if (arg[0] != NUL)
|
||||
return arg;
|
||||
break;
|
||||
return find_cmd_after_substitute_cmd(arg);
|
||||
case CMD_isearch:
|
||||
case CMD_dsearch:
|
||||
case CMD_ilist:
|
||||
@@ -1502,26 +1572,7 @@ set_context_by_cmdname(
|
||||
case CMD_djump:
|
||||
case CMD_isplit:
|
||||
case CMD_dsplit:
|
||||
arg = skipwhite(skipdigits(arg)); // skip count
|
||||
if (*arg == '/') // Match regexp, not just whole words
|
||||
{
|
||||
for (++arg; *arg && *arg != '/'; arg++)
|
||||
if (*arg == '\\' && arg[1] != NUL)
|
||||
arg++;
|
||||
if (*arg)
|
||||
{
|
||||
arg = skipwhite(arg + 1);
|
||||
|
||||
// Check for trailing illegal characters
|
||||
if (*arg == NUL ||
|
||||
vim_strchr((char_u *)"|\"\n", *arg) == NULL)
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
else
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
return find_cmd_after_isearch_cmd(arg, xp);
|
||||
case CMD_autocmd:
|
||||
return set_context_in_autocmd(xp, arg, FALSE);
|
||||
case CMD_doautocmd:
|
||||
@@ -1652,36 +1703,8 @@ set_context_by_cmdname(
|
||||
#endif
|
||||
case CMD_USER:
|
||||
case CMD_USER_BUF:
|
||||
if (compl != EXPAND_NOTHING)
|
||||
{
|
||||
// EX_XFILE: file names are handled above
|
||||
if (!(argt & EX_XFILE))
|
||||
{
|
||||
#ifdef FEAT_MENU
|
||||
if (compl == EXPAND_MENUS)
|
||||
return set_context_in_menu_cmd(xp, cmd, arg, forceit);
|
||||
#endif
|
||||
if (compl == EXPAND_COMMANDS)
|
||||
return arg;
|
||||
if (compl == EXPAND_MAPPINGS)
|
||||
return set_context_in_map_cmd(xp, (char_u *)"map",
|
||||
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 = arg;
|
||||
}
|
||||
xp->xp_context = compl;
|
||||
}
|
||||
break;
|
||||
return set_context_in_user_cmdarg(cmd, arg, argt, compl, xp,
|
||||
forceit);
|
||||
|
||||
case CMD_map: case CMD_noremap:
|
||||
case CMD_nmap: case CMD_nnoremap:
|
||||
@@ -2312,6 +2335,31 @@ ExpandOther(
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map wild expand options to flags for expand_wildcards()
|
||||
*/
|
||||
static int
|
||||
map_wildopts_to_ewflags(int options)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = EW_DIR; // include directories
|
||||
if (options & WILD_LIST_NOTFOUND)
|
||||
flags |= EW_NOTFOUND;
|
||||
if (options & WILD_ADD_SLASH)
|
||||
flags |= EW_ADDSLASH;
|
||||
if (options & WILD_KEEP_ALL)
|
||||
flags |= EW_KEEPALL;
|
||||
if (options & WILD_SILENT)
|
||||
flags |= EW_SILENT;
|
||||
if (options & WILD_NOERROR)
|
||||
flags |= EW_NOERROR;
|
||||
if (options & WILD_ALLLINKS)
|
||||
flags |= EW_ALLLINKS;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the expansion based on xp->xp_context and "pat".
|
||||
*/
|
||||
@@ -2328,19 +2376,7 @@ ExpandFromContext(
|
||||
int flags;
|
||||
char_u *tofree = NULL;
|
||||
|
||||
flags = EW_DIR; // include directories
|
||||
if (options & WILD_LIST_NOTFOUND)
|
||||
flags |= EW_NOTFOUND;
|
||||
if (options & WILD_ADD_SLASH)
|
||||
flags |= EW_ADDSLASH;
|
||||
if (options & WILD_KEEP_ALL)
|
||||
flags |= EW_KEEPALL;
|
||||
if (options & WILD_SILENT)
|
||||
flags |= EW_SILENT;
|
||||
if (options & WILD_NOERROR)
|
||||
flags |= EW_NOERROR;
|
||||
if (options & WILD_ALLLINKS)
|
||||
flags |= EW_ALLLINKS;
|
||||
flags = map_wildopts_to_ewflags(options);
|
||||
|
||||
if (xp->xp_context == EXPAND_FILES
|
||||
|| xp->xp_context == EXPAND_DIRECTORIES
|
||||
@@ -2549,6 +2585,64 @@ ExpandGeneric(
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand shell command matches in one directory of $PATH.
|
||||
*/
|
||||
static void
|
||||
expand_shellcmd_onedir(
|
||||
char_u *buf,
|
||||
char_u *s,
|
||||
size_t l,
|
||||
char_u *pat,
|
||||
char_u ***files,
|
||||
int *num_files,
|
||||
int flags,
|
||||
hashtab_T *ht,
|
||||
garray_T *gap)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
hash_T hash;
|
||||
hashitem_T *hi;
|
||||
|
||||
vim_strncpy(buf, s, l);
|
||||
add_pathsep(buf);
|
||||
l = STRLEN(buf);
|
||||
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)
|
||||
{
|
||||
// Check if this name was already found.
|
||||
hash = hash_hash(name + l);
|
||||
hi = hash_lookup(ht, name + l, hash);
|
||||
if (HASHITEM_EMPTY(hi))
|
||||
{
|
||||
// Remove the path that was prepended.
|
||||
STRMOVE(name, name + l);
|
||||
((char_u **)gap->ga_data)[gap->ga_len++] = name;
|
||||
hash_add_item(ht, hi, name, hash);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
vim_free(name);
|
||||
}
|
||||
vim_free(*files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Complete a shell command.
|
||||
* Returns FAIL or OK;
|
||||
@@ -2569,11 +2663,8 @@ expand_shellcmd(
|
||||
size_t l;
|
||||
char_u *s, *e;
|
||||
int flags = flagsarg;
|
||||
int ret;
|
||||
int did_curdir = FALSE;
|
||||
hashtab_T found_ht;
|
||||
hashitem_T *hi;
|
||||
hash_T hash;
|
||||
|
||||
buf = alloc(MAXPATHL);
|
||||
if (buf == NULL)
|
||||
@@ -2640,42 +2731,10 @@ expand_shellcmd(
|
||||
l = e - s;
|
||||
if (l > MAXPATHL - 5)
|
||||
break;
|
||||
vim_strncpy(buf, s, l);
|
||||
add_pathsep(buf);
|
||||
l = STRLEN(buf);
|
||||
vim_strncpy(buf + l, pat, MAXPATHL - 1 - l);
|
||||
|
||||
// Expand matches in one directory of $PATH.
|
||||
ret = expand_wildcards(1, &buf, num_file, file, flags);
|
||||
if (ret == OK)
|
||||
{
|
||||
if (ga_grow(&ga, *num_file) == FAIL)
|
||||
FreeWild(*num_file, *file);
|
||||
else
|
||||
{
|
||||
for (i = 0; i < *num_file; ++i)
|
||||
{
|
||||
char_u *name = (*file)[i];
|
||||
expand_shellcmd_onedir(buf, s, l, pat, file, num_file, flags,
|
||||
&found_ht, &ga);
|
||||
|
||||
if (STRLEN(name) > l)
|
||||
{
|
||||
// Check if this name was already found.
|
||||
hash = hash_hash(name + l);
|
||||
hi = hash_lookup(&found_ht, name + l, hash);
|
||||
if (HASHITEM_EMPTY(hi))
|
||||
{
|
||||
// Remove the path that was prepended.
|
||||
STRMOVE(name, name + l);
|
||||
((char_u **)ga.ga_data)[ga.ga_len++] = name;
|
||||
hash_add_item(&found_ht, hi, name, hash);
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
vim_free(name);
|
||||
}
|
||||
vim_free(*file);
|
||||
}
|
||||
}
|
||||
if (*e != NUL)
|
||||
++e;
|
||||
}
|
||||
@@ -2924,7 +2983,7 @@ wildmenu_translate_key(
|
||||
}
|
||||
#endif
|
||||
|
||||
if (did_wild_list && p_wmnu)
|
||||
if (did_wild_list)
|
||||
{
|
||||
if (c == K_LEFT)
|
||||
c = Ctrl_P;
|
||||
@@ -2933,7 +2992,7 @@ wildmenu_translate_key(
|
||||
}
|
||||
|
||||
// Hitting CR after "emenu Name.": complete submenu
|
||||
if (xp->xp_context == EXPAND_MENUNAMES && p_wmnu
|
||||
if (xp->xp_context == EXPAND_MENUNAMES
|
||||
&& cclp->cmdpos > 1
|
||||
&& cclp->cmdbuff[cclp->cmdpos - 1] == '.'
|
||||
&& cclp->cmdbuff[cclp->cmdpos - 2] != '\\'
|
||||
@@ -2957,29 +3016,23 @@ cmdline_del(cmdline_info_T *cclp, int from)
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a key pressed when wild menu is displayed
|
||||
* Handle a key pressed when the wild menu for the menu names
|
||||
* (EXPAND_MENUNAMES) is displayed.
|
||||
*/
|
||||
int
|
||||
wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
static int
|
||||
wildmenu_process_key_menunames(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
{
|
||||
int c = key;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (!p_wmnu)
|
||||
return c;
|
||||
|
||||
// Special translations for 'wildmenu'
|
||||
if (xp->xp_context == EXPAND_MENUNAMES)
|
||||
{
|
||||
// Hitting <Down> after "emenu Name.": complete submenu
|
||||
if (c == K_DOWN && cclp->cmdpos > 0
|
||||
if (key == K_DOWN && cclp->cmdpos > 0
|
||||
&& cclp->cmdbuff[cclp->cmdpos - 1] == '.')
|
||||
{
|
||||
c = p_wc;
|
||||
key = p_wc;
|
||||
KeyTyped = TRUE; // in case the key was mapped
|
||||
}
|
||||
else if (c == K_UP)
|
||||
else if (key == K_UP)
|
||||
{
|
||||
// Hitting <Up>: Remove one submenu name in front of the
|
||||
// cursor
|
||||
@@ -3011,15 +3064,24 @@ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
}
|
||||
if (i > 0)
|
||||
cmdline_del(cclp, i);
|
||||
c = p_wc;
|
||||
key = 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))
|
||||
{
|
||||
|
||||
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(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char_u upseg[5];
|
||||
|
||||
upseg[0] = PATHSEP;
|
||||
@@ -3028,7 +3090,7 @@ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
upseg[3] = PATHSEP;
|
||||
upseg[4] = NUL;
|
||||
|
||||
if (c == K_DOWN
|
||||
if (key == K_DOWN
|
||||
&& cclp->cmdpos > 0
|
||||
&& cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP
|
||||
&& (cclp->cmdpos < 3
|
||||
@@ -3036,10 +3098,10 @@ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
|| cclp->cmdbuff[cclp->cmdpos - 3] != '.'))
|
||||
{
|
||||
// go down a directory
|
||||
c = p_wc;
|
||||
key = p_wc;
|
||||
KeyTyped = TRUE; // in case the key was mapped
|
||||
}
|
||||
else if (STRNCMP(xp->xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN)
|
||||
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;
|
||||
@@ -3062,11 +3124,11 @@ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
&& (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2))
|
||||
{
|
||||
cmdline_del(cclp, j - 2);
|
||||
c = p_wc;
|
||||
key = p_wc;
|
||||
KeyTyped = TRUE; // in case the key was mapped
|
||||
}
|
||||
}
|
||||
else if (c == K_UP)
|
||||
else if (key == K_UP)
|
||||
{
|
||||
// go up a directory
|
||||
int found = FALSE;
|
||||
@@ -3115,12 +3177,27 @@ wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
|
||||
// Now complete in the new directory. Set KeyTyped in case the
|
||||
// Up key came from a mapping.
|
||||
c = p_wc;
|
||||
key = p_wc;
|
||||
KeyTyped = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a key pressed when the wild menu is displayed
|
||||
*/
|
||||
int
|
||||
wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp)
|
||||
{
|
||||
if (xp->xp_context == EXPAND_MENUNAMES)
|
||||
return wildmenu_process_key_menunames(cclp, key, xp);
|
||||
else 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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -1856,6 +1856,7 @@ getcmdline_int(
|
||||
c = Ctrl_P;
|
||||
|
||||
#ifdef FEAT_WILDMENU
|
||||
if (p_wmnu)
|
||||
c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list);
|
||||
|
||||
if (cmdline_pum_active())
|
||||
@@ -1900,6 +1901,7 @@ getcmdline_int(
|
||||
}
|
||||
|
||||
#ifdef FEAT_WILDMENU
|
||||
if (p_wmnu)
|
||||
c = wildmenu_process_key(&ccline, c, &xpc);
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* usercmd.c */
|
||||
char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *complp);
|
||||
char_u *set_context_in_user_cmdarg(char_u *cmd, char_u *arg, long argt, int compl, expand_T *xp, int forceit);
|
||||
char_u *set_context_in_user_cmd(expand_T *xp, char_u *arg_in);
|
||||
char_u *expand_user_command_name(int idx);
|
||||
char_u *get_user_commands(expand_T *xp, int idx);
|
||||
|
@@ -53,9 +53,13 @@ func Test_complete_list()
|
||||
set completeslash=backslash
|
||||
call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xtest\', @:)
|
||||
call feedkeys(":e Xtest/\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xtest\a.', @:)
|
||||
set completeslash=slash
|
||||
call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xtest/', @:)
|
||||
call feedkeys(":e Xtest\\\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xtest/a.', @:)
|
||||
set completeslash&
|
||||
endif
|
||||
|
||||
@@ -139,6 +143,7 @@ func Test_complete_wildmenu()
|
||||
call assert_equal('"e Xtestfile3 Xtestfile4', @:)
|
||||
cd -
|
||||
|
||||
" test for wildmenumode()
|
||||
cnoremap <expr> <F2> wildmenumode()
|
||||
call feedkeys(":cd Xdir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"cd Xdir1/0', @:)
|
||||
@@ -148,12 +153,7 @@ func Test_complete_wildmenu()
|
||||
|
||||
" cleanup
|
||||
%bwipe
|
||||
call delete('Xdir1/Xdir2/Xtestfile4')
|
||||
call delete('Xdir1/Xdir2/Xtestfile3')
|
||||
call delete('Xdir1/Xtestfile2')
|
||||
call delete('Xdir1/Xtestfile1')
|
||||
call delete('Xdir1/Xdir2', 'd')
|
||||
call delete('Xdir1', 'd')
|
||||
call delete('Xdir1', 'rf')
|
||||
set nowildmenu
|
||||
endfunc
|
||||
|
||||
@@ -1100,6 +1100,10 @@ func Test_cmdline_complete_various()
|
||||
call feedkeys(":e Xx\*\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xx\*Yy', @:)
|
||||
call delete('Xx*Yy')
|
||||
|
||||
" use a literal star
|
||||
call feedkeys(":e \\*\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e \*', @:)
|
||||
endif
|
||||
|
||||
call feedkeys(":py3f\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
@@ -2005,28 +2009,34 @@ endfunc
|
||||
func Test_wildmenu_dirstack()
|
||||
CheckUnix
|
||||
%bw!
|
||||
call mkdir('Xdir1/dir2/dir3', 'p')
|
||||
call mkdir('Xdir1/dir2/dir3/dir4', 'p')
|
||||
call writefile([], 'Xdir1/file1_1.txt')
|
||||
call writefile([], 'Xdir1/file1_2.txt')
|
||||
call writefile([], 'Xdir1/dir2/file2_1.txt')
|
||||
call writefile([], 'Xdir1/dir2/file2_2.txt')
|
||||
call writefile([], 'Xdir1/dir2/dir3/file3_1.txt')
|
||||
call writefile([], 'Xdir1/dir2/dir3/file3_2.txt')
|
||||
cd Xdir1/dir2/dir3
|
||||
call writefile([], 'Xdir1/dir2/dir3/dir4/file4_1.txt')
|
||||
call writefile([], 'Xdir1/dir2/dir3/dir4/file4_2.txt')
|
||||
set wildmenu
|
||||
|
||||
cd Xdir1/dir2/dir3/dir4
|
||||
call feedkeys(":e \<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e file3_1.txt', @:)
|
||||
call assert_equal('"e file4_1.txt', @:)
|
||||
call feedkeys(":e \<Tab>\<Up>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e ../dir3/', @:)
|
||||
call assert_equal('"e ../dir4/', @:)
|
||||
call feedkeys(":e \<Tab>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e ../../dir2/', @:)
|
||||
call assert_equal('"e ../../dir3/', @:)
|
||||
call feedkeys(":e \<Tab>\<Up>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e ../../../dir2/', @:)
|
||||
call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e ../../dir2/dir3/', @:)
|
||||
call assert_equal('"e ../../dir3/dir4/', @:)
|
||||
call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e ../../dir2/dir3/file3_1.txt', @:)
|
||||
|
||||
call assert_equal('"e ../../dir3/dir4/file4_1.txt', @:)
|
||||
cd -
|
||||
call feedkeys(":e Xdir1/\<Tab>\<Down>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"e Xdir1/dir2/dir3/dir4/file4_1.txt', @:)
|
||||
|
||||
call delete('Xdir1', 'rf')
|
||||
set wildmenu&
|
||||
endfunc
|
||||
|
@@ -231,6 +231,9 @@ find_ucmd(
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set completion context for :command
|
||||
*/
|
||||
char_u *
|
||||
set_context_in_user_cmd(expand_T *xp, char_u *arg_in)
|
||||
{
|
||||
@@ -292,6 +295,56 @@ set_context_in_user_cmd(expand_T *xp, char_u *arg_in)
|
||||
return skipwhite(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the completion context for the argument of a user defined command.
|
||||
*/
|
||||
char_u *
|
||||
set_context_in_user_cmdarg(
|
||||
char_u *cmd UNUSED,
|
||||
char_u *arg,
|
||||
long argt,
|
||||
int compl,
|
||||
expand_T *xp,
|
||||
int forceit)
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (compl == EXPAND_NOTHING)
|
||||
return NULL;
|
||||
|
||||
if (argt & EX_XFILE)
|
||||
{
|
||||
// EX_XFILE: file names are handled before this call
|
||||
xp->xp_context = compl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef FEAT_MENU
|
||||
if (compl == EXPAND_MENUS)
|
||||
return set_context_in_menu_cmd(xp, cmd, arg, forceit);
|
||||
#endif
|
||||
if (compl == EXPAND_COMMANDS)
|
||||
return arg;
|
||||
if (compl == EXPAND_MAPPINGS)
|
||||
return set_context_in_map_cmd(xp, (char_u *)"map", 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 = arg;
|
||||
xp->xp_context = compl;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_u *
|
||||
expand_user_command_name(int idx)
|
||||
{
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
4398,
|
||||
/**/
|
||||
4397,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user