aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-08-24 10:28:32 +0800
committerGitHub <noreply@github.com>2022-08-24 10:28:32 +0800
commit9a100ee169f80cbfe45872939ed9b4f70f6bfe3f (patch)
treed9a3580d0934d46dd594e05d091e09fd4e0cbc4f
parent64d147b4719310093ca2d728ba68b23f7e0660df (diff)
downloadrneovim-9a100ee169f80cbfe45872939ed9b4f70f6bfe3f.tar.gz
rneovim-9a100ee169f80cbfe45872939ed9b4f70f6bfe3f.tar.bz2
rneovim-9a100ee169f80cbfe45872939ed9b4f70f6bfe3f.zip
fix(cmdline): do not trigger completion at wrong time (#19920)
Cherry-picked from Vim patches 8.2.4339, 9.0.0238.
-rw-r--r--src/nvim/ex_getln.c18
-rw-r--r--test/functional/ui/popupmenu_spec.lua16
-rw-r--r--test/functional/ui/wildmode_spec.lua58
3 files changed, 82 insertions, 10 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 0dce2fd2e2..febfff41e1 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1277,8 +1277,11 @@ static int command_line_execute(VimState *state, int key)
// <S-Tab> goes to last match, in a clumsy way
if (s->c == K_S_TAB && KeyTyped) {
if (nextwild(&s->xpc, WILD_EXPAND_KEEP, 0, s->firstc != '@') == OK) {
- // Trigger the popup menu when wildoptions=pum
- showmatches(&s->xpc, p_wmnu && ((wim_flags[s->wim_index] & WIM_LIST) == 0));
+ if (s->xpc.xp_numfiles > 1
+ && ((!s->did_wild_list && (wim_flags[s->wim_index] & WIM_LIST)) || p_wmnu)) {
+ // Trigger the popup menu when wildoptions=pum
+ showmatches(&s->xpc, p_wmnu && ((wim_flags[s->wim_index] & WIM_LIST) == 0));
+ }
nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
return command_line_changed(s);
@@ -1798,13 +1801,16 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s);
case Ctrl_A: // all matches
- if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) {
- break;
- }
if (cmdline_pum_active()) {
+ // As Ctrl-A completes all the matches, close the popup
+ // menu (if present)
cmdline_pum_cleanup(&ccline);
- s->xpc.xp_context = EXPAND_NOTHING;
}
+ if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) {
+ break;
+ }
+ s->xpc.xp_context = EXPAND_NOTHING;
+ s->did_wild_list = false;
return command_line_changed(s);
case Ctrl_L:
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index e11cd1e859..dcd4ad3d9a 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1990,6 +1990,22 @@ describe('builtin popupmenu', function()
efine unplace^ |
]])
+ -- Pressing <Left> after that should move the cursor
+ feed('<Left>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4: }|
+ :sign define jump list place und|
+ efine unplac^e |
+ ]])
+ feed('<End>')
+
-- Pressing <C-D> when the popup menu is displayed should remove the popup
-- menu
feed('<C-U>sign <Tab><C-D>')
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 98398bc7a1..58ffa3bda8 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -461,20 +461,20 @@ end)
describe('command line completion', function()
local screen
before_each(function()
+ clear()
screen = Screen.new(40, 5)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow},
[3] = {bold = true, reverse = true},
})
+ screen:attach()
end)
after_each(function()
os.remove('Xtest-functional-viml-compl-dir')
end)
it('lists directories with empty PATH', function()
- clear()
- screen:attach()
local tmp = funcs.tempname()
command('e '.. tmp)
command('cd %:h')
@@ -491,8 +491,6 @@ describe('command line completion', function()
end)
it('completes env var names #9681', function()
- clear()
- screen:attach()
command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"')
command('set wildmenu wildmode=full')
feed(':!echo $XTEST_<tab>')
@@ -521,6 +519,58 @@ describe('command line completion', function()
:!echo $XTEST_1AaあB^ |
]])
end)
+
+ it('does not leak memory with <S-Tab> with wildmenu and only one match #19874', function()
+ meths.set_option('wildmenu', true)
+ meths.set_option('wildmode', 'full')
+ meths.set_option('wildoptions', 'pum')
+
+ feed(':sign unpla<S-Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace^ |
+ ]])
+
+ feed('<Space>buff<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace buffer=^ |
+ ]])
+ end)
+
+ it('does not show matches with <S-Tab> without wildmenu with wildmode=full', function()
+ meths.set_option('wildmenu', false)
+ meths.set_option('wildmode', 'full')
+
+ feed(':sign <S-Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace^ |
+ ]])
+ end)
+
+ it('shows matches with <S-Tab> without wildmenu with wildmode=list', function()
+ meths.set_option('wildmenu', false)
+ meths.set_option('wildmode', 'list')
+
+ feed(':sign <S-Tab>')
+ screen:expect([[
+ {3: }|
+ :sign define |
+ define list undefine |
+ jump place unplace |
+ :sign unplace^ |
+ ]])
+ end)
end)
describe('ui/ext_wildmenu', function()