From f2bda1effc17fd18b2a1552697c3ff4083b1258f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 7 Sep 2025 13:17:29 +0800 Subject: [PATCH] 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 --- src/nvim/ex_getln.c | 25 +++++-- test/functional/ui/popupmenu_spec.lua | 102 ++++++++++++++++++++++++++ test/old/testdir/test_cmdline.vim | 45 ++++++++---- 3 files changed, 150 insertions(+), 22 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 85af5647f2..a110a116ed 100644 --- 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 index ff1e2ca238..c0bf1421bb 100644 --- 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('') + -- "longest:list" shows list whether it finds a candidate or not + command('set wildmode=longest:list,full wildoptions=') + feed(':cn') + screen:expect([[ + | + {1:~ }|*3 + {3: }| + :cn | + cnewer cnoreabbrev | + cnext cnoremap | + cnfile cnoremenu | + :cn^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*2 + {3: }| + :cn | + cnewer cnoreabbrev | + cnext cnoremap | + cnfile cnoremenu | + {113:cnewer}{3: cnext cnfile > }| + :cnewer^ | + ]]) + feed(':sign u') + 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('') + command('set wildmode=longest:full,full') + feed(':sign u') + screen:expect([[ + | + {1:~ }|*7 + {3:undefine unplace }| + :sign un^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*7 + {113:undefine}{3: unplace }| + :sign undefine^ | + ]]) + + feed(':cn') + screen:expect([[ + | + {1:~ }|*7 + {3:cnewer cnext cnfile > }| + :cn^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }|*7 + {113:cnewer}{3: cnext cnfile > }| + :cnewer^ | + ]]) + + -- If "longest,full" finds a candidate, wildmenu is not shown + feed('') + command('set wildmode=longest,full') + feed(':sign u') + screen:expect([[ + | + {1:~ }|*8 + :sign un^ | + ]]) + -- Subsequent wildchar shows wildmenu + feed('') + screen:expect([[ + | + {1:~ }|*7 + {113:undefine}{3: unplace }| + :sign undefine^ | + ]]) + + -- 'longest' does not find candidate, and displays menu without selecting item + feed('') + command('set wildmode=longest,noselect') + feed(':cn') + screen:expect([[ + | + {1:~ }|*7 + {3:cnewer cnext cnfile > }| + :cn^ | + ]]) + + feed('') + 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 index 4cac0e1eba..e9a719978a 100644 --- 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, "\set wildmode=longest,list\") call term_sendkeys(buf, ":cn\") call VerifyScreenDump(buf, 'Test_wildmenu_pum_30', {}) - call term_sendkeys(buf, "\") + 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, "\:set showtabline& laststatus& lazyredraw&\") - " Verify that if "longest" finds nothing, wildmenu is still shown - call term_sendkeys(buf, ":set wildmode=longest:full,full wildoptions&\") - call term_sendkeys(buf, ":cn\") - 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, "\:set wildmode=longest:list,full\") + " "longest:list" shows list whether it finds a candidate or not + call term_sendkeys(buf, ":set wildmode=longest:list,full wildoptions&\") call term_sendkeys(buf, ":cn\") call TermWait(buf, 50) call VerifyScreenDump(buf, 'Test_wildmenu_pum_55', {}) call term_sendkeys(buf, "\") call TermWait(buf, 50) call VerifyScreenDump(buf, 'Test_wildmenu_pum_56', {}) - - " Verify that if "longest" finds a candidate, wildmenu is not shown - call term_sendkeys(buf, "\:set wildmode=longest:full,full wildoptions&\") - call term_sendkeys(buf, ":sign u\") + call term_sendkeys(buf, "\:sign u\") + call TermWait(buf, 50) call VerifyScreenDump(buf, 'Test_wildmenu_pum_57', {}) + + " "longest:full" shows wildmenu whether it finds a candidate or not; item not selected + call term_sendkeys(buf, "\:set wildmode=longest:full,full\") + call term_sendkeys(buf, ":sign u\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_58', {}) + call term_sendkeys(buf, "\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_59', {}) + call term_sendkeys(buf, "\:cn\") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_60', {}) + call term_sendkeys(buf, "\") + 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, "\:set wildmode=longest,full\") + call term_sendkeys(buf, ":sign u\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_62', {}) " Subsequent wildchar shows wildmenu call term_sendkeys(buf, "\") - 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, "\:set wildmode=longest,noselect\") + call term_sendkeys(buf, ":cn\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_64', {}) call term_sendkeys(buf, "\\") call StopVimInTerminal(buf)