mirror of
https://github.com/neovim/neovim.git
synced 2026-05-23 21:30:11 +00:00
vim-patch:9.2.0417: completion: no support for "noinsert" with 'wildmode' (#39516)
Problem: completion: no support for "noinsert" with 'wildmode' and
commandline completion
Solution: Add "noinsert" value to the 'wildmode' option, mirroring
'completeopt' "noinsert" behaviour (glepnir).
fixes: vim/vim#16551
closes: vim/vim#20080
af494af5ff
This commit is contained in:
@@ -7423,8 +7423,12 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
applies to buffer name completion.
|
||||
"noselect" If 'wildmenu' is enabled, show the menu but do not
|
||||
preselect the first item.
|
||||
If only one match exists, it is completed fully, unless "noselect" is
|
||||
specified.
|
||||
"noinsert" If 'wildmenu' is enabled, show the menu and preselect
|
||||
the first match, but do not insert it in the
|
||||
command line. If both "noinsert" and "noselect" are
|
||||
present, "noselect" takes precedence.
|
||||
If only one match exists, it is completed fully, unless "noselect" or
|
||||
"noinsert" is specified.
|
||||
|
||||
Some useful combinations of colon-separated values:
|
||||
"longest:full" Start with the longest common string and show
|
||||
|
||||
8
runtime/lua/vim/_meta/options.gen.lua
generated
8
runtime/lua/vim/_meta/options.gen.lua
generated
@@ -8059,8 +8059,12 @@ vim.go.wmnu = vim.go.wildmenu
|
||||
--- applies to buffer name completion.
|
||||
--- "noselect" If 'wildmenu' is enabled, show the menu but do not
|
||||
--- preselect the first item.
|
||||
--- If only one match exists, it is completed fully, unless "noselect" is
|
||||
--- specified.
|
||||
--- "noinsert" If 'wildmenu' is enabled, show the menu and preselect
|
||||
--- the first match, but do not insert it in the
|
||||
--- command line. If both "noinsert" and "noselect" are
|
||||
--- present, "noselect" takes precedence.
|
||||
--- If only one match exists, it is completed fully, unless "noselect" or
|
||||
--- "noinsert" is specified.
|
||||
---
|
||||
--- Some useful combinations of colon-separated values:
|
||||
--- "longest:full" Start with the longest common string and show
|
||||
|
||||
@@ -346,7 +346,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
|
||||
cmdline_orig = cstrn_to_string(ccline->cmdbuff, (size_t)ccline->cmdlen);
|
||||
}
|
||||
|
||||
if (p != NULL && !got_int && !(options & WILD_NOSELECT)) {
|
||||
if (p != NULL && !got_int && !(options & (WILD_NOSELECT | WILD_NOINSERT))) {
|
||||
size_t plen = strlen(p);
|
||||
int difflen = (int)plen - (int)(xp->xp_pattern_len);
|
||||
if (ccline->cmdlen + difflen + 4 > ccline->cmdbufflen) {
|
||||
@@ -373,7 +373,8 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
|
||||
|
||||
if (xp->xp_numfiles <= 0 && p == NULL) {
|
||||
beep_flush();
|
||||
} else if (xp->xp_numfiles == 1 && !(options & WILD_NOSELECT) && !wild_navigate) {
|
||||
} else if (xp->xp_numfiles == 1 && !(options & (WILD_NOSELECT | WILD_NOINSERT))
|
||||
&& !wild_navigate) {
|
||||
// free expanded pattern
|
||||
ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
|
||||
}
|
||||
@@ -385,7 +386,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
|
||||
|
||||
/// Create completion popup menu with items from "matches".
|
||||
static void cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches, int numMatches,
|
||||
bool showtail, bool noselect)
|
||||
bool showtail, bool cmdline_unchanged)
|
||||
{
|
||||
assert(numMatches >= 0);
|
||||
// Add all the completion matches
|
||||
@@ -403,7 +404,7 @@ static void cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches
|
||||
}
|
||||
|
||||
// Compute the popup menu starting column
|
||||
char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, noselect) : xp->xp_pattern;
|
||||
char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, cmdline_unchanged) : xp->xp_pattern;
|
||||
if (ui_has(kUICmdline) && cmdline_win == NULL) {
|
||||
compl_startcol = (int)(endpos - ccline->cmdbuff);
|
||||
} else {
|
||||
@@ -1103,7 +1104,7 @@ static void showmatches_oneline(expand_T *xp, char **matches, int numMatches, in
|
||||
/// Display completion matches.
|
||||
/// Returns EXPAND_NOTHING when the character that triggered expansion should be
|
||||
/// inserted as a normal character.
|
||||
int showmatches(expand_T *xp, bool display_wildmenu, bool display_list, bool noselect)
|
||||
int showmatches(expand_T *xp, bool display_wildmenu, bool display_list, int wim_flags_arg)
|
||||
{
|
||||
CmdlineInfo *const ccline = get_cmdline_info();
|
||||
int numMatches;
|
||||
@@ -1112,6 +1113,9 @@ int showmatches(expand_T *xp, bool display_wildmenu, bool display_list, bool nos
|
||||
int lines;
|
||||
int columns;
|
||||
bool showtail;
|
||||
bool noselect = (wim_flags_arg & kOptWimFlagNoselect);
|
||||
bool noinsert = (wim_flags_arg & kOptWimFlagNoinsert);
|
||||
bool cmdline_unchanged = noselect || noinsert;
|
||||
|
||||
if (xp->xp_numfiles == -1) {
|
||||
set_expand_context(xp);
|
||||
@@ -1131,7 +1135,7 @@ int showmatches(expand_T *xp, bool display_wildmenu, bool display_list, bool nos
|
||||
}
|
||||
|
||||
if (cmdline_compl_use_pum(display_wildmenu && !display_list)) {
|
||||
cmdline_pum_create(ccline, xp, matches, numMatches, showtail, noselect);
|
||||
cmdline_pum_create(ccline, xp, matches, numMatches, showtail, cmdline_unchanged);
|
||||
compl_selected = noselect ? -1 : 0;
|
||||
pum_clear();
|
||||
cmdline_pum_display(true);
|
||||
|
||||
@@ -43,6 +43,7 @@ enum {
|
||||
WILD_NOSELECT = 0x4000,
|
||||
WILD_MAY_EXPAND_PATTERN = 0x8000,
|
||||
WILD_FUNC_TRIGGER = 0x10000, ///< called from wildtrigger()
|
||||
WILD_NOINSERT = 0x20000,
|
||||
};
|
||||
|
||||
#include "cmdexpand.h.generated.h"
|
||||
|
||||
@@ -1153,6 +1153,7 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
bool escape = s->firstc != '@';
|
||||
bool redraw_if_menu_empty = s->c == K_WILD;
|
||||
bool wim_noselect = p_wmnu && (wim_flags[0] & kOptWimFlagNoselect) != 0;
|
||||
bool wim_noinsert = p_wmnu && (wim_flags[0] & kOptWimFlagNoinsert) != 0;
|
||||
|
||||
if (wim_flags[s->wim_index] & kOptWimFlagLastused) {
|
||||
options |= WILD_BUFLASTUSED;
|
||||
@@ -1162,7 +1163,7 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
if (s->xpc.xp_numfiles > 1
|
||||
&& !s->did_wild_list
|
||||
&& (wim_flags[s->wim_index] & kOptWimFlagList)) {
|
||||
showmatches(&s->xpc, false, true, wim_noselect);
|
||||
showmatches(&s->xpc, false, true, p_wmnu ? wim_flags[s->wim_index] : 0);
|
||||
redrawcmd();
|
||||
s->did_wild_list = true;
|
||||
}
|
||||
@@ -1196,6 +1197,9 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
if (wim_noselect || wim_list) {
|
||||
options |= WILD_NOSELECT;
|
||||
}
|
||||
if (wim_noinsert) {
|
||||
options |= WILD_NOINSERT;
|
||||
}
|
||||
res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options, escape);
|
||||
}
|
||||
|
||||
@@ -1214,20 +1218,22 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
}
|
||||
|
||||
// Display matches
|
||||
if (res == OK && s->xpc.xp_numfiles > (wim_noselect ? 0 : 1)) {
|
||||
if (res == OK && s->xpc.xp_numfiles > ((wim_noselect || wim_noinsert) ? 0 : 1)) {
|
||||
if (wim_longest) {
|
||||
bool found_longest_prefix = (ccline.cmdpos != cmdpos_before);
|
||||
if (wim_list || (p_wmnu && wim_full)) {
|
||||
showmatches(&s->xpc, p_wmnu, wim_list, true);
|
||||
showmatches(&s->xpc, p_wmnu, wim_list, kOptWimFlagNoselect);
|
||||
} else if (!found_longest_prefix) {
|
||||
bool wim_list_next = (wim_flags[1] & kOptWimFlagList);
|
||||
bool wim_full_next = (wim_flags[1] & kOptWimFlagFull);
|
||||
bool wim_noselect_next = (wim_flags[1] & kOptWimFlagNoselect);
|
||||
if (wim_list_next || (p_wmnu && (wim_full_next || wim_noselect_next))) {
|
||||
if (wim_full_next && !wim_noselect_next) {
|
||||
bool wim_noinsert_next = (wim_flags[1] & kOptWimFlagNoinsert);
|
||||
if (wim_list_next
|
||||
|| (p_wmnu && (wim_full_next || wim_noselect_next || wim_noinsert_next))) {
|
||||
if (wim_full_next && !wim_noselect_next && !wim_noinsert_next) {
|
||||
nextwild(&s->xpc, WILD_NEXT, options, escape);
|
||||
} else {
|
||||
showmatches(&s->xpc, p_wmnu, wim_list_next, wim_noselect_next);
|
||||
showmatches(&s->xpc, p_wmnu, wim_list_next, p_wmnu ? wim_flags[1] : 0);
|
||||
}
|
||||
if (wim_list_next) {
|
||||
s->did_wild_list = true;
|
||||
@@ -1235,8 +1241,8 @@ static int command_line_wildchar_complete(CommandLineState *s)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (wim_list || (p_wmnu && (wim_full || wim_noselect))) {
|
||||
showmatches(&s->xpc, p_wmnu, wim_list, wim_noselect);
|
||||
if (wim_list || (p_wmnu && (wim_full || wim_noselect || wim_noinsert))) {
|
||||
showmatches(&s->xpc, p_wmnu, wim_list, p_wmnu ? wim_flags[0] : 0);
|
||||
} else {
|
||||
vim_beep(kOptBoFlagWildmode);
|
||||
}
|
||||
@@ -1538,7 +1544,7 @@ static int command_line_execute(VimState *state, int key)
|
||||
&& ((!s->did_wild_list && (wim_flags[s->wim_index] & kOptWimFlagList)) || p_wmnu)) {
|
||||
// Trigger the popup menu when wildoptions=pum
|
||||
showmatches(&s->xpc, p_wmnu, wim_flags[s->wim_index] & kOptWimFlagList,
|
||||
wim_flags[0] & kOptWimFlagNoselect);
|
||||
p_wmnu ? wim_flags[0] : 0);
|
||||
}
|
||||
nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
|
||||
nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
|
||||
@@ -2113,7 +2119,7 @@ static int command_line_handle_key(CommandLineState *s)
|
||||
}
|
||||
|
||||
case Ctrl_D:
|
||||
if (showmatches(&s->xpc, false, true, wim_flags[0] & kOptWimFlagNoselect)
|
||||
if (showmatches(&s->xpc, false, true, p_wmnu ? wim_flags[0] : 0)
|
||||
== EXPAND_NOTHING) {
|
||||
break; // Use ^D as normal char instead
|
||||
}
|
||||
@@ -3060,6 +3066,8 @@ int check_opt_wim(void)
|
||||
new_wim_flags[idx] |= kOptWimFlagLastused;
|
||||
} else if (i == 8 && strncmp(p, "noselect", 8) == 0) {
|
||||
new_wim_flags[idx] |= kOptWimFlagNoselect;
|
||||
} else if (i == 8 && strncmp(p, "noinsert", 8) == 0) {
|
||||
new_wim_flags[idx] |= kOptWimFlagNoinsert;
|
||||
} else {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
@@ -10370,7 +10370,7 @@ local options = {
|
||||
cb = 'did_set_wildmode',
|
||||
defaults = 'full',
|
||||
-- Keep this in sync with check_opt_wim().
|
||||
values = { 'full', 'longest', 'list', 'lastused', 'noselect' },
|
||||
values = { 'full', 'longest', 'list', 'lastused', 'noselect', 'noinsert' },
|
||||
flags = true,
|
||||
deny_duplicates = false,
|
||||
desc = [=[
|
||||
@@ -10396,8 +10396,12 @@ local options = {
|
||||
applies to buffer name completion.
|
||||
"noselect" If 'wildmenu' is enabled, show the menu but do not
|
||||
preselect the first item.
|
||||
If only one match exists, it is completed fully, unless "noselect" is
|
||||
specified.
|
||||
"noinsert" If 'wildmenu' is enabled, show the menu and preselect
|
||||
the first match, but do not insert it in the
|
||||
command line. If both "noinsert" and "noselect" are
|
||||
present, "noselect" takes precedence.
|
||||
If only one match exists, it is completed fully, unless "noselect" or
|
||||
"noinsert" is specified.
|
||||
|
||||
Some useful combinations of colon-separated values:
|
||||
"longest:full" Start with the longest common string and show
|
||||
|
||||
@@ -378,6 +378,7 @@ let test_values = {
|
||||
\ ['xxx']],
|
||||
\ 'wildmode': [['', 'full', 'longest', 'list', 'lastused', 'list:full',
|
||||
\ 'noselect', 'noselect,full', 'noselect:lastused,full',
|
||||
\ 'noinsert', 'noinsert,full', 'noinsert:lastused,full',
|
||||
\ 'full,longest', 'full,full,full,full'],
|
||||
\ ['xxx', 'a4', 'full,full,full,full,full']],
|
||||
\ 'wildoptions': [['', 'tagfile', 'pum', 'fuzzy'], ['xxx']],
|
||||
|
||||
@@ -5321,4 +5321,94 @@ func Test_rulerformat_empty()
|
||||
set rulerformat&
|
||||
endfunc
|
||||
|
||||
func Test_wildmode_noinsert()
|
||||
command! -nargs=1 -complete=custom,T MyCmd echo
|
||||
func T(a, c, p)
|
||||
return "oneA\noneB\noneC"
|
||||
endfunc
|
||||
|
||||
set wildmenu wildoptions=pum wildmode=noinsert,full wildchar=<Tab>
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneB', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneC', @:)
|
||||
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-Y>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneA', @:)
|
||||
|
||||
" CTRL-P from highlighted first item returns to original text
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-P>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
" Another CTRL-P wraps to the last match
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-P>\<C-P>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneC', @:)
|
||||
|
||||
set wildoptions=
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneB', @:)
|
||||
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-Y>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneA', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-E>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
|
||||
" 'nowildmenu' should make 'noinsert' ineffective
|
||||
set nowildmenu
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneA', @:)
|
||||
|
||||
" 'noselect' takes precedence over 'noinsert'
|
||||
set wildmenu wildoptions=pum wildmode=noselect:noinsert,full
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneA', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-Y>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
|
||||
set wildmode=noinsert
|
||||
call feedkeys(":MyCmd o\<Tab>\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
|
||||
set wildmode=noinsert,full
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-N>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd oneB', @:)
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-E>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd o', @:)
|
||||
|
||||
" 'longest' takes precedence over 'noinsert'
|
||||
set wildmode=noinsert:longest
|
||||
call feedkeys(":MyCmd o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd one', @:)
|
||||
|
||||
set wildmode&
|
||||
call feedkeys(":set wildmode=noi\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"set wildmode=noinsert', @:)
|
||||
|
||||
set wildmode=noinsert:lastused,full
|
||||
call assert_equal('noinsert:lastused,full', &wildmode)
|
||||
call assert_fails('set wildmode=noinser', 'E474:')
|
||||
|
||||
" Single match with 'noinsert': item shown highlighted, C-Y commits
|
||||
command! -nargs=1 -complete=custom,T1 MyCmd1 echo
|
||||
func T1(a, c, p)
|
||||
return "oneA"
|
||||
endfunc
|
||||
set wildmenu wildoptions=pum wildmode=noinsert,full
|
||||
call feedkeys(":MyCmd1 o\<Tab>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd1 o', @:)
|
||||
call feedkeys(":MyCmd1 o\<Tab>\<C-Y>\<C-B>\"\<CR>", 'xt')
|
||||
call assert_equal('"MyCmd1 oneA', @:)
|
||||
delcommand MyCmd1
|
||||
delfunc T1
|
||||
|
||||
set wildmenu& wildoptions& wildmode& wildchar&
|
||||
delcommand MyCmd
|
||||
delfunc T
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
Reference in New Issue
Block a user