commit f2bda1effc17fd18b2a1552697c3ff4083b1258f
parent 1359578abbcf56036c46cc424a508a131147218f
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sun, 7 Sep 2025 13:17:29 +0800
vim-patch:9.1.1737: Patch v9.1.1714 introduce a regression for wildmenu
Problem: Patch v9.1.1714 introduce a regression for wildmenu (zeertzjq)
Solution: Restore behavior of "longest" in 'wildmode' (Girish Palya)
- Fixed a regression caused by PR vim/vim#18125 selecting wrong item
- Fixed another regression where the first pasted text did not appear on
the command-line after starting Vim.
closes: vim/vim#18212
https://github.com/vim/vim/commit/8fec92d631cf9d852ad794863721c2710ee2ff9e
Co-authored-by: Girish Palya <girishji@gmail.com>
Diffstat:
3 files changed, 149 insertions(+), 21 deletions(-)
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
@@ -1179,16 +1179,25 @@ static int command_line_wildchar_complete(CommandLineState *s)
// Display matches
if (res == OK && s->xpc.xp_numfiles > (wim_noselect ? 0 : 1)) {
- // If "longest" fails to identify the longest item, try other
- // 'wim' values if available
- if (wim_longest && ccline.cmdpos == cmdpos_before) {
- if (wim_full) {
- nextwild(&s->xpc, WILD_NEXT, options, escape);
- }
+ 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, false);
+ showmatches(&s->xpc, p_wmnu, wim_list, true);
+ } 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_noselect_next) {
+ options |= WILD_NOSELECT;
+ }
+ if (wim_full_next || wim_noselect_next) {
+ nextwild(&s->xpc, WILD_NEXT, options, escape);
+ }
+ showmatches(&s->xpc, p_wmnu, wim_list_next, wim_noselect_next);
+ }
}
- } else if (!wim_longest) {
+ } else {
if (wim_list || (p_wmnu && (wim_full || wim_noselect))) {
showmatches(&s->xpc, p_wmnu, wim_list, wim_noselect);
} else {
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
@@ -1060,6 +1060,7 @@ describe('builtin popupmenu', function()
[110] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkYellow },
[111] = { background = Screen.colors.Plum1, foreground = Screen.colors.DarkBlue },
[112] = { background = Screen.colors.Plum1, foreground = Screen.colors.DarkGreen },
+ [113] = { background = Screen.colors.Yellow, foreground = Screen.colors.Black },
-- popup non-selected item
n = { background = Screen.colors.Plum1 },
-- popup scrollbar knob
@@ -4694,6 +4695,107 @@ describe('builtin popupmenu', function()
feed('<Esc>')
+ -- "longest:list" shows list whether it finds a candidate or not
+ command('set wildmode=longest:list,full wildoptions=')
+ feed(':cn<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*3
+ {3: }|
+ :cn |
+ cnewer cnoreabbrev |
+ cnext cnoremap |
+ cnfile cnoremenu |
+ :cn^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*2
+ {3: }|
+ :cn |
+ cnewer cnoreabbrev |
+ cnext cnoremap |
+ cnfile cnoremenu |
+ {113:cnewer}{3: cnext cnfile > }|
+ :cnewer^ |
+ ]])
+ feed('<Esc>:sign u<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {3: }|
+ :sign un |
+ undefine unplace |
+ :sign un^ |
+ ]])
+
+ -- "longest:full" shows wildmenu whether it finds a candidate or not;
+ -- item not selected
+ feed('<Esc>')
+ command('set wildmode=longest:full,full')
+ feed(':sign u<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {3:undefine unplace }|
+ :sign un^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {113:undefine}{3: unplace }|
+ :sign undefine^ |
+ ]])
+
+ feed('<Esc>:cn<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {3:cnewer cnext cnfile > }|
+ :cn^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {113:cnewer}{3: cnext cnfile > }|
+ :cnewer^ |
+ ]])
+
+ -- If "longest,full" finds a candidate, wildmenu is not shown
+ feed('<Esc>')
+ command('set wildmode=longest,full')
+ feed(':sign u<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*8
+ :sign un^ |
+ ]])
+ -- Subsequent wildchar shows wildmenu
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {113:undefine}{3: unplace }|
+ :sign undefine^ |
+ ]])
+
+ -- 'longest' does not find candidate, and displays menu without selecting item
+ feed('<Esc>')
+ command('set wildmode=longest,noselect')
+ feed(':cn<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*7
+ {3:cnewer cnext cnfile > }|
+ :cn^ |
+ ]])
+
+ feed('<C-U><Esc>')
+ command('set wildmode& wildoptions=pum')
+
-- check positioning with multibyte char in pattern
command('e långfile1')
command('sp långfile2')
diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim
@@ -2900,7 +2900,7 @@ func Test_wildmenu_pum()
call term_sendkeys(buf, "\<C-U>set wildmode=longest,list\<CR>")
call term_sendkeys(buf, ":cn\<Tab>")
call VerifyScreenDump(buf, 'Test_wildmenu_pum_30', {})
- call term_sendkeys(buf, "\<Tab>")
+ call term_sendkeys(buf, "s")
call VerifyScreenDump(buf, 'Test_wildmenu_pum_31', {})
" Tests a directory name contained full-width characters.
@@ -3002,28 +3002,45 @@ func Test_wildmenu_pum()
call term_sendkeys(buf, "\<Esc>:set showtabline& laststatus& lazyredraw&\<CR>")
- " Verify that if "longest" finds nothing, wildmenu is still shown
- call term_sendkeys(buf, ":set wildmode=longest:full,full wildoptions&\<CR>")
- call term_sendkeys(buf, ":cn\<Tab>")
- call TermWait(buf, 50)
- call VerifyScreenDump(buf, 'Test_wildmenu_pum_54', {})
-
- " Verify that if "longest" finds nothing, "list" is still shown
- call term_sendkeys(buf, "\<Esc>:set wildmode=longest:list,full\<CR>")
+ " "longest:list" shows list whether it finds a candidate or not
+ call term_sendkeys(buf, ":set wildmode=longest:list,full wildoptions&\<CR>")
call term_sendkeys(buf, ":cn\<Tab>")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_55', {})
call term_sendkeys(buf, "\<Tab>")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_56', {})
+ call term_sendkeys(buf, "\<Esc>:sign u\<Tab>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_57', {})
- " Verify that if "longest" finds a candidate, wildmenu is not shown
- call term_sendkeys(buf, "\<Esc>:set wildmode=longest:full,full wildoptions&\<CR>")
+ " "longest:full" shows wildmenu whether it finds a candidate or not; item not selected
+ call term_sendkeys(buf, "\<Esc>:set wildmode=longest:full,full\<CR>")
call term_sendkeys(buf, ":sign u\<Tab>")
- call VerifyScreenDump(buf, 'Test_wildmenu_pum_57', {})
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_58', {})
+ call term_sendkeys(buf, "\<Tab>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_59', {})
+ call term_sendkeys(buf, "\<Esc>:cn\<Tab>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_60', {})
+ call term_sendkeys(buf, "\<Tab>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_61', {})
+
+ " If "longest,full" finds a candidate, wildmenu is not shown
+ call term_sendkeys(buf, "\<Esc>:set wildmode=longest,full\<CR>")
+ call term_sendkeys(buf, ":sign u\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_62', {})
" Subsequent wildchar shows wildmenu
call term_sendkeys(buf, "\<Tab>")
- call VerifyScreenDump(buf, 'Test_wildmenu_pum_58', {})
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_63', {})
+
+ " 'longest' does not find candidate, and displays menu without selecting item
+ call term_sendkeys(buf, "\<Esc>:set wildmode=longest,noselect\<CR>")
+ call term_sendkeys(buf, ":cn\<Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_64', {})
call term_sendkeys(buf, "\<C-U>\<Esc>")
call StopVimInTerminal(buf)