diff options
-rw-r--r-- | src/nvim/cmdexpand.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 3 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 25 | ||||
-rw-r--r-- | test/functional/fixtures/wildpum/Xnamedir/XdirA/XdirB/XfileC (renamed from test/functional/fixtures/wildpum/Xdir/XdirA/XdirB/XfileC) | 0 | ||||
-rw-r--r-- | test/functional/fixtures/wildpum/Xnamedir/XdirA/XfileB (renamed from test/functional/fixtures/wildpum/Xdir/XdirA/XfileB) | 0 | ||||
-rw-r--r-- | test/functional/fixtures/wildpum/Xnamedir/XfileA (renamed from test/functional/fixtures/wildpum/Xdir/XfileA) | 0 | ||||
-rw-r--r-- | test/functional/ui/popupmenu_spec.lua | 67 | ||||
-rw-r--r-- | test/old/testdir/test_cmdline.vim | 104 | ||||
-rw-r--r-- | test/old/testdir/test_options.vim | 3 |
9 files changed, 148 insertions, 56 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 3cc9515fef..496c047a4a 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -267,7 +267,7 @@ int nextwild(expand_T *xp, int type, int options, bool escape) char *p1; if (cmdline_fuzzy_completion_supported(xp)) { // If fuzzy matching, don't modify the search string - p1 = xstrdup(xp->xp_pattern); + p1 = xstrnsave(xp->xp_pattern, xp->xp_pattern_len); } else { p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index c52937b6c1..98da044bb4 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4241,7 +4241,8 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int // Special handling of "ff" which acts as a short form of // "fileformat", as "ff" is not a substring of it. - if (strcmp(xp->xp_pattern, "ff") == 0) { + if (xp->xp_pattern_len == 2 + && strncmp(xp->xp_pattern, "ff", xp->xp_pattern_len) == 0) { *matches = xmalloc(sizeof(char *)); *numMatches = 1; (*matches)[0] = xstrdup("fileformat="); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 2759dc9bb5..9d0e3d542a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -861,6 +861,16 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear cmdmsg_rl = false; + // We could have reached here without having a chance to clean up wild menu + // if certain special keys like <Esc> or <C-\> were used as wildchar. Make + // sure to still clean up to avoid memory corruption. + if (cmdline_pum_active()) { + cmdline_pum_remove(); + } + wildmenu_cleanup(&ccline); + s->did_wild_list = false; + s->wim_index = 0; + ExpandCleanup(&s->xpc); ccline.xpc = NULL; @@ -1247,13 +1257,14 @@ static int command_line_execute(VimState *state, int key) s->c = wildmenu_translate_key(&ccline, s->c, &s->xpc, s->did_wild_list); } - if (cmdline_pum_active() || s->did_wild_list) { + int wild_type = 0; + const bool key_is_wc = (s->c == p_wc && KeyTyped) || s->c == p_wcm; + if ((cmdline_pum_active() || s->did_wild_list) && !key_is_wc) { // Ctrl-Y: Accept the current selection and close the popup menu. // Ctrl-E: cancel the cmdline popup menu and return the original text. if (s->c == Ctrl_E || s->c == Ctrl_Y) { - const int wild_type = (s->c == Ctrl_E) ? WILD_CANCEL : WILD_APPLY; + wild_type = (s->c == Ctrl_E) ? WILD_CANCEL : WILD_APPLY; (void)nextwild(&s->xpc, wild_type, WILD_NO_BEEP, s->firstc != '@'); - s->c = Ctrl_E; } } @@ -1262,7 +1273,7 @@ static int command_line_execute(VimState *state, int key) // 'wildcharm' or Ctrl-N or Ctrl-P or Ctrl-A or Ctrl-L). // If the popup menu is displayed, then PageDown and PageUp keys are // also used to navigate the menu. - bool end_wildmenu = (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z + bool end_wildmenu = (!key_is_wc && s->c != Ctrl_Z && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A && s->c != Ctrl_L); end_wildmenu = end_wildmenu && (!cmdline_pum_active() @@ -1366,6 +1377,12 @@ static int command_line_execute(VimState *state, int key) } s->do_abbr = true; // default: check for abbreviation + + // If already used to cancel/accept wildmenu, don't process the key further. + if (wild_type == WILD_CANCEL || wild_type == WILD_APPLY) { + return command_line_not_changed(s); + } + return command_line_handle_key(s); } diff --git a/test/functional/fixtures/wildpum/Xdir/XdirA/XdirB/XfileC b/test/functional/fixtures/wildpum/Xnamedir/XdirA/XdirB/XfileC index e69de29bb2..e69de29bb2 100644 --- a/test/functional/fixtures/wildpum/Xdir/XdirA/XdirB/XfileC +++ b/test/functional/fixtures/wildpum/Xnamedir/XdirA/XdirB/XfileC diff --git a/test/functional/fixtures/wildpum/Xdir/XdirA/XfileB b/test/functional/fixtures/wildpum/Xnamedir/XdirA/XfileB index e69de29bb2..e69de29bb2 100644 --- a/test/functional/fixtures/wildpum/Xdir/XdirA/XfileB +++ b/test/functional/fixtures/wildpum/Xnamedir/XdirA/XfileB diff --git a/test/functional/fixtures/wildpum/Xdir/XfileA b/test/functional/fixtures/wildpum/Xnamedir/XfileA index e69de29bb2..e69de29bb2 100644 --- a/test/functional/fixtures/wildpum/Xdir/XfileA +++ b/test/functional/fixtures/wildpum/Xnamedir/XfileA diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 38649a2be3..bfa4b7f14e 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3096,7 +3096,7 @@ describe('builtin popupmenu', function() :sign define culhl= culhl=^ | ]]) - feed('<C-U>e Xdi<Tab><Tab>') + feed('<C-U>e Xnamedi<Tab><Tab>') screen:expect([[ | {1:~ }| @@ -3105,9 +3105,9 @@ describe('builtin popupmenu', function() {1:~ }| {1:~ }| {1:~ }| - {1:~ }{s: XdirA/ }{1: }| - {1:~ }{n: XfileA }{1: }| - :e Xdir/XdirA/^ | + {1:~ }{s: XdirA/ }{1: }| + {1:~ }{n: XfileA }{1: }| + :e Xnamedir/XdirA/^ | ]]) -- Pressing <Down> on a directory name should go into that directory @@ -3120,9 +3120,9 @@ describe('builtin popupmenu', function() {1:~ }| {1:~ }| {1:~ }| - {1:~ }{s: XdirB/ }{1: }| - {1:~ }{n: XfileB }{1: }| - :e Xdir/XdirA/XdirB/^ | + {1:~ }{s: XdirB/ }{1: }| + {1:~ }{n: XfileB }{1: }| + :e Xnamedir/XdirA/XdirB/^ | ]]) -- Pressing <Up> on a directory name should go to the parent directory @@ -3135,9 +3135,9 @@ describe('builtin popupmenu', function() {1:~ }| {1:~ }| {1:~ }| - {1:~ }{s: XdirA/ }{1: }| - {1:~ }{n: XfileA }{1: }| - :e Xdir/XdirA/^ | + {1:~ }{s: XdirA/ }{1: }| + {1:~ }{n: XfileA }{1: }| + :e Xnamedir/XdirA/^ | ]]) -- Pressing <C-A> when the popup menu is displayed should list all the @@ -3511,6 +3511,49 @@ describe('builtin popupmenu', function() :sign define^ | ]]) + -- pressing <C-E> to end completion should work in middle of the line too + feed('<Esc>:set wildchazz<Left><Left><Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }{s: wildchar }{1: }| + {1:~ }{n: wildcharm }{1: }| + :set wildchar^zz | + ]]) + feed('<C-E>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set wildcha^zz | + ]]) + + -- pressing <C-Y> should select the current match and end completion + feed('<Esc>:set wildchazz<Left><Left><Tab><C-Y>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :set wildchar^zz | + ]]) + feed('<Esc>') -- check positioning with multibyte char in pattern @@ -3726,13 +3769,13 @@ describe('builtin popupmenu', function() end) -- oldtest: Test_wildmenu_pum_clear_entries() - it('wildoptions=pum when using Ctrl-E as wildchar vim-patch:9.0.1030', function() + it('wildoptions=pum when using odd wildchar', function() screen:try_resize(30, 10) exec([[ set wildoptions=pum set wildchar=<C-E> ]]) - feed(':sign <C-E><C-E>') + feed(':sign <C-E>') screen:expect([[ | {1:~ }| diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 00c894058e..61ee59068d 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -82,38 +82,38 @@ func Test_complete_list() endfunc func Test_complete_wildmenu() - call mkdir('Xdir1/Xdir2', 'p') - call writefile(['testfile1'], 'Xdir1/Xtestfile1') - call writefile(['testfile2'], 'Xdir1/Xtestfile2') - call writefile(['testfile3'], 'Xdir1/Xdir2/Xtestfile3') - call writefile(['testfile3'], 'Xdir1/Xdir2/Xtestfile4') + call mkdir('Xwilddir1/Xdir2', 'pR') + call writefile(['testfile1'], 'Xwilddir1/Xtestfile1') + call writefile(['testfile2'], 'Xwilddir1/Xtestfile2') + call writefile(['testfile3'], 'Xwilddir1/Xdir2/Xtestfile3') + call writefile(['testfile3'], 'Xwilddir1/Xdir2/Xtestfile4') set wildmenu " Pressing <Tab> completes, and moves to next files when pressing again. - call feedkeys(":e Xdir1/\<Tab>\<Tab>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Tab>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) - call feedkeys(":e Xdir1/\<Tab>\<Tab>\<Tab>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Tab>\<Tab>\<CR>", 'tx') call assert_equal('testfile2', getline(1)) " <S-Tab> is like <Tab> but begin with the last match and then go to " previous. - call feedkeys(":e Xdir1/Xtest\<S-Tab>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/Xtest\<S-Tab>\<CR>", 'tx') call assert_equal('testfile2', getline(1)) - call feedkeys(":e Xdir1/Xtest\<S-Tab>\<S-Tab>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/Xtest\<S-Tab>\<S-Tab>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) " <Left>/<Right> to move to previous/next file. - call feedkeys(":e Xdir1/\<Tab>\<Right>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) - call feedkeys(":e Xdir1/\<Tab>\<Right>\<Right>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<Right>\<CR>", 'tx') call assert_equal('testfile2', getline(1)) - call feedkeys(":e Xdir1/\<Tab>\<Right>\<Right>\<Left>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<Right>\<Left>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) " <Up>/<Down> to go up/down directories. - call feedkeys(":e Xdir1/\<Tab>\<Down>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Down>\<CR>", 'tx') call assert_equal('testfile3', getline(1)) - call feedkeys(":e Xdir1/\<Tab>\<Down>\<Up>\<Right>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<Down>\<Up>\<Right>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) " this fails in some Unix GUIs, not sure why @@ -123,9 +123,9 @@ func Test_complete_wildmenu() set wildcharm=<C-Z> cnoremap <C-J> <Down><C-Z> cnoremap <C-K> <Up><C-Z> - call feedkeys(":e Xdir1/\<Tab>\<C-J>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<C-J>\<CR>", 'tx') call assert_equal('testfile3', getline(1)) - call feedkeys(":e Xdir1/\<Tab>\<C-J>\<C-K>\<CR>", 'tx') + call feedkeys(":e Xwilddir1/\<Tab>\<C-J>\<C-K>\<CR>", 'tx') call assert_equal('testfile1', getline(1)) set wildcharm=0 cunmap <C-J> @@ -134,21 +134,21 @@ func Test_complete_wildmenu() " Test for canceling the wild menu by adding a character redrawstatus - call feedkeys(":e Xdir1/\<Tab>x\<C-B>\"\<CR>", 'xt') - call assert_equal('"e Xdir1/Xdir2/x', @:) + call feedkeys(":e Xwilddir1/\<Tab>x\<C-B>\"\<CR>", 'xt') + call assert_equal('"e Xwilddir1/Xdir2/x', @:) " Completion using a relative path - cd Xdir1/Xdir2 + cd Xwilddir1/Xdir2 call feedkeys(":e ../\<Tab>\<Right>\<Down>\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"e Xtestfile3 Xtestfile4', @:) cd - " test for wildmenumode() cnoremap <expr> <F2> wildmenumode() - call feedkeys(":cd Xdir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx') - call assert_equal('"cd Xdir1/0', @:) - call feedkeys(":e Xdir1/\<Tab>\<F2>\<C-B>\"\<CR>", 'tx') - call assert_equal('"e Xdir1/Xdir2/1', @:) + call feedkeys(":cd Xwilddir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx') + call assert_equal('"cd Xwilddir1/0', @:) + call feedkeys(":e Xwilddir1/\<Tab>\<F2>\<C-B>\"\<CR>", 'tx') + call assert_equal('"e Xwilddir1/Xdir2/1', @:) cunmap <F2> " Test for canceling the wild menu by pressing <PageDown> or <PageUp>. @@ -159,9 +159,15 @@ func Test_complete_wildmenu() call feedkeys(":sign \<Tab>\<PageUp>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"TestWildMenu', @:) + " Test for Ctrl-E/Ctrl-Y being able to cancel / accept a match + call feedkeys(":sign un zz\<Left>\<Left>\<Left>\<Tab>\<C-E> yy\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign un yy zz', @:) + + call feedkeys(":sign un zz\<Left>\<Left>\<Left>\<Tab>\<Tab>\<C-Y> yy\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign unplace yy zz', @:) + " cleanup %bwipe - call delete('Xdir1', 'rf') set nowildmenu endfunc @@ -1046,6 +1052,9 @@ func Test_cmdline_complete_argopt() call assert_equal('edit', getcompletion('read ++bin ++edi', 'cmdline')[0]) call assert_equal(['fileformat='], getcompletion('edit ++ff', 'cmdline')) + " Test ++ff in the middle of the cmdline + call feedkeys(":edit ++ff zz\<Left>\<Left>\<Left>\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal("\"edit ++fileformat= zz", @:) call assert_equal('dos', getcompletion('write ++ff=d', 'cmdline')[0]) call assert_equal('mac', getcompletion('args ++fileformat=m', 'cmdline')[0]) @@ -2513,7 +2522,7 @@ func Test_wildmenu_pum() call feedkeys(":edit $VIMRUNTIME/\<Tab>\<Left>\<C-U>ab\<Tab>") endfunc [CODE] - call writefile(commands, 'Xtest') + call writefile(commands, 'Xtest', 'D') let buf = RunVimInTerminal('-S Xtest', #{rows: 10}) @@ -2571,12 +2580,12 @@ func Test_wildmenu_pum() call VerifyScreenDump(buf, 'Test_wildmenu_pum_13', {}) " Directory name completion - call mkdir('Xdir/XdirA/XdirB', 'p') - call writefile([], 'Xdir/XfileA') - call writefile([], 'Xdir/XdirA/XfileB') - call writefile([], 'Xdir/XdirA/XdirB/XfileC') + call mkdir('Xnamedir/XdirA/XdirB', 'pR') + call writefile([], 'Xnamedir/XfileA') + call writefile([], 'Xnamedir/XdirA/XfileB') + call writefile([], 'Xnamedir/XdirA/XdirB/XfileC') - call term_sendkeys(buf, "\<C-U>e Xdi\<Tab>\<Tab>") + call term_sendkeys(buf, "\<C-U>e Xnamedi\<Tab>\<Tab>") call VerifyScreenDump(buf, 'Test_wildmenu_pum_14', {}) " Pressing <Right> on a directory name should go into that directory @@ -2651,13 +2660,13 @@ func Test_wildmenu_pum() call VerifyScreenDump(buf, 'Test_wildmenu_pum_31', {}) " Tests a directory name contained full-width characters. - call mkdir('Xdir/あいう', 'p') - call writefile([], 'Xdir/あいう/abc') - call writefile([], 'Xdir/あいう/xyz') - call writefile([], 'Xdir/あいう/123') + call mkdir('Xnamedir/あいう', 'p') + call writefile([], 'Xnamedir/あいう/abc') + call writefile([], 'Xnamedir/あいう/xyz') + call writefile([], 'Xnamedir/あいう/123') call term_sendkeys(buf, "\<C-U>set wildmode&\<CR>") - call term_sendkeys(buf, ":\<C-U>e Xdir/あいう/\<Tab>") + call term_sendkeys(buf, ":\<C-U>e Xnamedir/あいう/\<Tab>") call VerifyScreenDump(buf, 'Test_wildmenu_pum_32', {}) " Pressing <C-A> when the popup menu is displayed should list all the @@ -2679,7 +2688,7 @@ func Test_wildmenu_pum() " After using <C-A> to expand all the filename matches, pressing <Up> " should not open the popup menu again. - call term_sendkeys(buf, "\<C-E>\<C-U>:cd Xdir/XdirA\<CR>") + call term_sendkeys(buf, "\<C-E>\<C-U>:cd Xnamedir/XdirA\<CR>") call term_sendkeys(buf, ":e \<Tab>\<C-A>\<Up>") call VerifyScreenDump(buf, 'Test_wildmenu_pum_36', {}) call term_sendkeys(buf, "\<C-E>\<C-U>:cd -\<CR>") @@ -2737,10 +2746,18 @@ func Test_wildmenu_pum() call term_sendkeys(buf, "\<PageUp>") call VerifyScreenDump(buf, 'Test_wildmenu_pum_50', {}) + " pressing <C-E> to end completion should work in middle of the line too + call term_sendkeys(buf, "\<Esc>:set wildchazz\<Left>\<Left>\<Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_51', {}) + call term_sendkeys(buf, "\<C-E>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_52', {}) + + " pressing <C-Y> should select the current match and end completion + call term_sendkeys(buf, "\<Esc>:set wildchazz\<Left>\<Left>\<Tab>\<C-Y>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_53', {}) + call term_sendkeys(buf, "\<C-U>\<CR>") call StopVimInTerminal(buf) - call delete('Xtest') - call delete('Xdir', 'rf') endfunc " Test for wildmenumode() with the cmdline popup menu @@ -3406,6 +3423,17 @@ func Test_fuzzy_completion_custom_func() set wildoptions& endfunc +" Test for fuzzy completion in the middle of a cmdline instead of at the end +func Test_fuzzy_completion_in_middle() + set wildoptions=fuzzy + call feedkeys(":set ildar wrap\<Left>\<Left>\<Left>\<Left>\<Left>\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"set wildchar wildcharm wrap", @:) + + call feedkeys(":args ++odng zz\<Left>\<Left>\<Left>\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"args ++encoding= zz", @:) + set wildoptions& +endfunc + " Test for :breakadd argument completion func Test_cmdline_complete_breakadd() call feedkeys(":breakadd \<C-A>\<C-B>\"\<CR>", 'tx') diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index cc3f21b86b..1a3a909344 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -621,6 +621,9 @@ func Test_set_completion_string_values() " \ {idx, val -> val != ':'}), " \ '') " call assert_equal([], getcompletion('set hl+=8'..hl_display_modes, 'cmdline')) + " Test completion in middle of the line + " call feedkeys(":set hl=8b i\<Left>\<Left>\<Tab>\<C-B>\"\<CR>", 'xt') + " call assert_equal("\"set hl=8bi i", @:) " " Test flag lists |