diff options
-rw-r--r-- | runtime/doc/options.txt | 2 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/options.lua | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 13 | ||||
-rw-r--r-- | src/nvim/options.lua | 4 | ||||
-rw-r--r-- | test/functional/options/cursorbind_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/ui/popupmenu_spec.lua | 99 | ||||
-rw-r--r-- | test/functional/ui/wildmode_spec.lua | 79 | ||||
-rw-r--r-- | test/old/testdir/test_cmdline.vim | 59 | ||||
-rw-r--r-- | test/old/testdir/test_options.vim | 5 |
9 files changed, 251 insertions, 13 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e734b62020..c8ea5ce67f 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6920,6 +6920,8 @@ A jump table for the options with a short description can be found at |Q_op|. The character is not recognized when used inside a macro. See 'wildcharm' for that. Some keys will not work, such as CTRL-C, <CR> and Enter. + <Esc> can be used, but hitting it twice in a row will still exit + command-line as a failsafe measure. Although 'wc' is a number option, you can set it to a special key: > :set wc=<Tab> < diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 50146bac50..cc013112b3 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -7466,6 +7466,8 @@ vim.go.ww = vim.go.whichwrap --- The character is not recognized when used inside a macro. See --- 'wildcharm' for that. --- Some keys will not work, such as CTRL-C, <CR> and Enter. +--- <Esc> can be used, but hitting it twice in a row will still exit +--- command-line as a failsafe measure. --- Although 'wc' is a number option, you can set it to a special key: --- ``` --- :set wc=<Tab> diff --git a/src/nvim/option.c b/src/nvim/option.c index 0c8230d7c9..389d5ee218 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2677,6 +2677,19 @@ static const char *did_set_updatecount(optset_T *args) return NULL; } +/// Process the new 'wildchar' / 'wildcharm' option value. +static const char *did_set_wildchar(optset_T *args) +{ + OptInt c = *(OptInt *)args->os_varp; + + // Don't allow key values that wouldn't work as wildchar. + if (c == Ctrl_C || c == '\n' || c == '\r' || c == K_KENTER) { + return e_invarg; + } + + return NULL; +} + /// Process the new 'winblend' option value. static const char *did_set_winblend(optset_T *args) { diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 8d12d860d8..d416b0070f 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -9473,6 +9473,7 @@ return { }, { abbreviation = 'wc', + cb = 'did_set_wildchar', defaults = { if_true = imacros('TAB'), doc = '<Tab>', @@ -9484,6 +9485,8 @@ return { The character is not recognized when used inside a macro. See 'wildcharm' for that. Some keys will not work, such as CTRL-C, <CR> and Enter. + <Esc> can be used, but hitting it twice in a row will still exit + command-line as a failsafe measure. Although 'wc' is a number option, you can set it to a special key: > :set wc=<Tab> < @@ -9496,6 +9499,7 @@ return { }, { abbreviation = 'wcm', + cb = 'did_set_wildchar', defaults = { if_true = 0 }, desc = [=[ 'wildcharm' works exactly like 'wildchar', except that it is diff --git a/test/functional/options/cursorbind_spec.lua b/test/functional/options/cursorbind_spec.lua index 1a03ed099a..498206936a 100644 --- a/test/functional/options/cursorbind_spec.lua +++ b/test/functional/options/cursorbind_spec.lua @@ -8,6 +8,7 @@ local feed = helpers.feed before_each(clear) describe("'cursorbind'", function() + -- oldtest: Test_cursorline_cursorbind_horizontal_scroll() it("behaves consistently whether 'cursorline' is set or not vim-patch:8.2.4795", function() local screen = Screen.new(60, 8) screen:set_default_attr_ids({ diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index bfa4b7f14e..6d5546e0aa 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3768,13 +3768,16 @@ describe('builtin popupmenu', function() ]]) end) - -- oldtest: Test_wildmenu_pum_clear_entries() - it('wildoptions=pum when using odd wildchar', function() + -- oldtest: Test_wildmenu_pum_odd_wildchar() + it('wildoptions=pum with odd wildchar', function() screen:try_resize(30, 10) + -- Test odd wildchar interactions with pum. Make sure they behave properly + -- and don't lead to memory corruption due to improperly cleaned up memory. exec([[ set wildoptions=pum set wildchar=<C-E> ]]) + feed(':sign <C-E>') screen:expect([[ | @@ -3788,7 +3791,97 @@ describe('builtin popupmenu', function() {1:~ }{n: unplace }{1: }| :sign define^ | ]]) - assert_alive() + + -- <C-E> being a wildchar takes priority over its original functionality + feed('<C-E>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{s: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign jump^ | + ]]) + + feed('<Esc>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- Escape key can be wildchar too. Double-<Esc> is hard-coded to escape + -- command-line, and we need to make sure to clean up properly. + command('set wildchar=<Esc>') + feed(':sign <Esc>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + + feed('<Esc>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + + -- <C-\> can also be wildchar. <C-\><C-N> however will still escape cmdline + -- and we again need to make sure we clean up properly. + command([[set wildchar=<C-\>]]) + feed([[:sign <C-\><C-\>]]) + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + + feed('<C-N>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) end) end diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 0355c57b5a..3201135b67 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -17,6 +17,85 @@ describe("'wildmenu'", function() screen:attach() end) + -- oldtest: Test_wildmenu_screendump() + it('works', function() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; -- NonText + [1] = {foreground = Screen.colors.Black, background = Screen.colors.Yellow}; -- WildMenu + [2] = {bold = true, reverse = true}; -- StatusLine + }) + -- Test simple wildmenu + feed(':sign <Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {1:define}{2: jump list > }| + :sign define^ | + ]]} + + feed('<Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define }{1:jump}{2: list > }| + :sign jump^ | + ]]} + + feed('<Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define jump }{1:list}{2: > }| + :sign list^ | + ]]} + + -- Looped back to the original value + feed('<Tab><Tab><Tab><Tab>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2:define jump list > }| + :sign ^ | + ]]} + + -- Test that the wild menu is cleared properly + feed('<Space>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + :sign ^ | + ]]} + + -- Test that a different wildchar still works + feed('<Esc>') + command('set wildchar=<Esc>') + feed(':sign <Esc>') + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {1:define}{2: jump list > }| + :sign define^ | + ]]} + + -- Double-<Esc> is a hard-coded method to escape while wildchar=<Esc>. Make + -- sure clean up is properly done in edge case like this. + feed('<Esc>') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) + it('C-E to cancel wildmenu completion restore original input', function() feed(':sign <tab>') screen:expect([[ diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 61ee59068d..49c14c9c74 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -177,8 +177,9 @@ func Test_wildmenu_screendump() let lines =<< trim [SCRIPT] set wildmenu hlsearch [SCRIPT] - call writefile(lines, 'XTest_wildmenu') + call writefile(lines, 'XTest_wildmenu', 'D') + " Test simple wildmenu let buf = RunVimInTerminal('-S XTest_wildmenu', {'rows': 8}) call term_sendkeys(buf, ":vim\<Tab>") call VerifyScreenDump(buf, 'Test_wildmenu_1', {}) @@ -189,13 +190,26 @@ func Test_wildmenu_screendump() call term_sendkeys(buf, "\<Tab>") call VerifyScreenDump(buf, 'Test_wildmenu_3', {}) - call term_sendkeys(buf, "\<Tab>") + " Looped back to the original value + call term_sendkeys(buf, "\<Tab>\<Tab>") call VerifyScreenDump(buf, 'Test_wildmenu_4', {}) + + " Test that the wild menu is cleared properly + call term_sendkeys(buf, " ") + call VerifyScreenDump(buf, 'Test_wildmenu_5', {}) + + " Test that a different wildchar still works + call term_sendkeys(buf, "\<Esc>:set wildchar=<Esc>\<CR>") + call term_sendkeys(buf, ":vim\<Esc>") + call VerifyScreenDump(buf, 'Test_wildmenu_1', {}) + + " Double-<Esc> is a hard-coded method to escape while wildchar=<Esc>. Make + " sure clean up is properly done in edge case like this. call term_sendkeys(buf, "\<Esc>") + call VerifyScreenDump(buf, 'Test_wildmenu_6', {}) " clean up call StopVimInTerminal(buf) - call delete('XTest_wildmenu') endfunc func Test_redraw_in_autocmd() @@ -2789,7 +2803,7 @@ func Test_wildmenu_pum_from_terminal() let cmds = ['set wildmenu wildoptions=pum'] let pcmd = python .. ' -c "import sys; sys.stdout.write(sys.stdin.read())"' call add(cmds, "call term_start('" .. pcmd .. "')") - call writefile(cmds, 'Xtest') + call writefile(cmds, 'Xtest', 'D') let buf = RunVimInTerminal('-S Xtest', #{rows: 10}) call term_sendkeys(buf, "\r\r\r") call term_wait(buf) @@ -2798,13 +2812,13 @@ func Test_wildmenu_pum_from_terminal() call VerifyScreenDump(buf, 'Test_wildmenu_pum_term_01', {}) call term_wait(buf) call StopVimInTerminal(buf) - call delete('Xtest') endfunc -func Test_wildmenu_pum_clear_entries() +func Test_wildmenu_pum_odd_wildchar() CheckRunVimInTerminal - " This was using freed memory. Run in a terminal to get the pum to update. + " Test odd wildchar interactions with pum. Make sure they behave properly + " and don't lead to memory corruption due to improperly cleaned up memory. let lines =<< trim END set wildoptions=pum set wildchar=<C-E> @@ -2812,10 +2826,35 @@ func Test_wildmenu_pum_clear_entries() call writefile(lines, 'XwildmenuTest', 'D') let buf = RunVimInTerminal('-S XwildmenuTest', #{rows: 10}) - call term_sendkeys(buf, ":\<C-E>\<C-E>") - call VerifyScreenDump(buf, 'Test_wildmenu_pum_clear_entries_1', {}) + call term_sendkeys(buf, ":\<C-E>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_1', {}) + + " <C-E> being a wildchar takes priority over its original functionality + call term_sendkeys(buf, "\<C-E>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_2', {}) + + call term_sendkeys(buf, "\<Esc>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_3', {}) + + " Escape key can be wildchar too. Double-<Esc> is hard-coded to escape + " command-line, and we need to make sure to clean up properly. + call term_sendkeys(buf, ":set wildchar=<Esc>\<CR>") + call term_sendkeys(buf, ":\<Esc>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_1', {}) + + call term_sendkeys(buf, "\<Esc>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_3', {}) - set wildoptions& wildchar& + " <C-\> can also be wildchar. <C-\><C-N> however will still escape cmdline + " and we again need to make sure we clean up properly. + call term_sendkeys(buf, ":set wildchar=<C-\\>\<CR>") + call term_sendkeys(buf, ":\<C-\>\<C-\>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_1', {}) + + call term_sendkeys(buf, "\<C-N>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_odd_wildchar_3', {}) + + call StopVimInTerminal(buf) endfunc " Test for completion after a :substitute command followed by a pipe (|) diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 1a3a909344..418aa81939 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -232,6 +232,11 @@ func Test_keymap_valid() call assert_fails(":set kmp=trunc\x00name", "trunc") endfunc +func Test_wildchar_valid() + call assert_fails("set wildchar=<CR>", "E474:") + call assert_fails("set wildcharm=<C-C>", "E474:") +endfunc + func Check_dir_option(name) " Check that it's possible to set the option. exe 'set ' . a:name . '=/usr/share/dict/words' |