aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/cmdexpand.c2
-rw-r--r--src/nvim/ex_docmd.c3
-rw-r--r--src/nvim/ex_getln.c25
-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.lua67
-rw-r--r--test/old/testdir/test_cmdline.vim104
-rw-r--r--test/old/testdir/test_options.vim3
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