From 44710a91d06cdd6cba01a2d62fc9652f94651363 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 15 Jan 2023 07:00:19 +0800 Subject: vim-patch:8.2.4481: cmdline popup menu not removed when 'lazyredraw' is set Problem: Cmdline popup menu not removed when 'lazyredraw' is set. Solution: Temporarily reset 'lazyredraw' when removing the popup menu. (closes vim/vim#9857) https://github.com/vim/vim/commit/5c52be40fbab14e050d7494d85be9039f07f7f8f Co-authored-by: Bram Moolenaar --- src/nvim/testdir/test_cmdline.vim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 74a5d99ef9..75bcc575d3 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -2331,6 +2331,11 @@ func Test_wildmenu_pum() set tabline=%!MyTabLine() set showtabline=2 endfunc + + func DoFeedKeys() + let &wildcharm = char2nr("\t") + call feedkeys(":edit $VIMRUNTIME/\\\ab\") + endfunc [CODE] call writefile(commands, 'Xtest') @@ -2528,6 +2533,12 @@ func Test_wildmenu_pum() call term_sendkeys(buf, "\") call VerifyScreenDump(buf, 'Test_wildmenu_pum_40', {}) + " popup is cleared also when 'lazyredraw' is set + call term_sendkeys(buf, ":set showtabline=1 laststatus=1 lazyredraw\") + call term_sendkeys(buf, ":call DoFeedKeys()\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {}) + call term_sendkeys(buf, "\") + call term_sendkeys(buf, "\\") call StopVimInTerminal(buf) call delete('Xtest') -- cgit From 066a1a069b2b0d97308ed2bdb18fbef488051e12 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 15 Jan 2023 07:01:14 +0800 Subject: vim-patch:8.2.4579: cannot use page-up and page-down in the cmdline popup menu Problem: Cannot use page-up and page-down in the command line completion popup menu. Solution: Check for to page-up and page-down keys. (Yegappan Lakshmanan, closes vim/vim#9960) https://github.com/vim/vim/commit/5cffa8df7e3c28681b9e5deef6df395784359b6b Co-authored-by: Yegappan Lakshmanan --- src/nvim/cmdexpand.c | 46 ++++++++++++- src/nvim/cmdexpand.h | 4 +- src/nvim/ex_getln.c | 41 ++++++++--- src/nvim/testdir/test_cmdline.vim | 30 ++++++++ test/functional/ui/popupmenu_spec.lua | 124 +++++++++++++++++++++++++++++++++- 5 files changed, 231 insertions(+), 14 deletions(-) diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 422649b67b..a1f15fabb6 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -217,7 +217,9 @@ int nextwild(expand_T *xp, int type, int options, bool escape) assert(ccline->cmdpos >= i); xp->xp_pattern_len = (size_t)ccline->cmdpos - (size_t)i; - if (type == WILD_NEXT || type == WILD_PREV || type == WILD_PUM_WANT) { + if (type == WILD_NEXT || type == WILD_PREV + || type == WILD_PAGEUP || type == WILD_PAGEDOWN + || type == WILD_PUM_WANT) { // Get next/previous match for a previous expanded pattern. p2 = ExpandOne(xp, NULL, NULL, 0, type); } else { @@ -593,6 +595,44 @@ static char *get_next_or_prev_match(int mode, expand_T *xp, int *p_findex, char findex--; } else if (mode == WILD_NEXT) { findex++; + } else if (mode == WILD_PAGEUP) { + if (findex == 0) { + // at the first entry, don't select any entries + findex = -1; + } else if (findex == -1) { + // no entry is selected. select the last entry + findex = xp->xp_numfiles - 1; + } else { + // go up by the pum height + int ht = pum_get_height(); + if (ht > 3) { + ht -= 2; + } + findex -= ht; + if (findex < 0) { + // few entries left, select the first entry + findex = 0; + } + } + } else if (mode == WILD_PAGEDOWN) { + if (findex == xp->xp_numfiles - 1) { + // at the last entry, don't select any entries + findex = -1; + } else if (findex == -1) { + // no entry is selected. select the first entry + findex = 0; + } else { + // go down by the pum height + int ht = pum_get_height(); + if (ht > 3) { + ht -= 2; + } + findex += ht; + if (findex >= xp->xp_numfiles) { + // few entries left, select the last entry + findex = xp->xp_numfiles - 1; + } + } } else { // mode == WILD_PUM_WANT assert(pum_want.active); findex = pum_want.item; @@ -770,7 +810,9 @@ char *ExpandOne(expand_T *xp, char *str, char *orig, int options, int mode) int i; // first handle the case of using an old match - if (mode == WILD_NEXT || mode == WILD_PREV || mode == WILD_PUM_WANT) { + if (mode == WILD_NEXT || mode == WILD_PREV + || mode == WILD_PAGEUP || mode == WILD_PAGEDOWN + || mode == WILD_PUM_WANT) { return get_next_or_prev_match(mode, xp, &findex, orig_save); } diff --git a/src/nvim/cmdexpand.h b/src/nvim/cmdexpand.h index cdd6192086..810e289f7c 100644 --- a/src/nvim/cmdexpand.h +++ b/src/nvim/cmdexpand.h @@ -19,8 +19,8 @@ enum { WILD_ALL_KEEP = 8, WILD_CANCEL = 9, WILD_APPLY = 10, - // WILD_PAGEUP = 11, not ported yet - // WILD_PAGEDOWN = 12, not ported yet + WILD_PAGEUP = 11, + WILD_PAGEDOWN = 12, WILD_PUM_WANT = 13, }; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 72208c976f..fc227f357e 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1234,10 +1234,20 @@ static int command_line_execute(VimState *state, int key) } } + // The wildmenu is cleared if the pressed key is not used for + // navigating the wild menu (i.e. the key is not 'wildchar' or + // '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 + && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A + && s->c != Ctrl_L); + end_wildmenu = end_wildmenu && (!cmdline_pum_active() + || (s->c != K_PAGEDOWN && s->c != K_PAGEUP + && s->c != K_KPAGEDOWN && s->c != K_KPAGEUP)); + // free expanded names when finished walking through matches - if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z - && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A - && s->c != Ctrl_L) { + if (end_wildmenu) { command_line_end_wildmenu(s); } @@ -2016,13 +2026,26 @@ static int command_line_handle_key(CommandLineState *s) case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: - switch (command_line_browse_history(s)) { - case CMDLINE_CHANGED: - return command_line_changed(s); - case GOTO_NORMAL_MODE: - return 0; - default: + if (cmdline_pum_active() + && (s->c == K_PAGEUP || s->c == K_PAGEDOWN + || s->c == K_KPAGEUP || s->c == K_KPAGEDOWN)) { + // If the popup menu is displayed, then PageUp and PageDown + // are used to scroll the menu. + if (nextwild(&s->xpc, + (s->c == K_PAGEUP) ? WILD_PAGEUP : WILD_PAGEDOWN, + 0, s->firstc != '@') == FAIL) { + break; + } return command_line_not_changed(s); + } else { + switch (command_line_browse_history(s)) { + case CMDLINE_CHANGED: + return command_line_changed(s); + case GOTO_NORMAL_MODE: + return 0; + default: + return command_line_not_changed(s); + } } case Ctrl_G: // next match diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 75bcc575d3..50bdfceebd 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -151,6 +151,14 @@ func Test_complete_wildmenu() call assert_equal('"e Xdir1/Xdir2/1', @:) cunmap + " Test for canceling the wild menu by pressing or . + " After this pressing or should not change the selection. + call feedkeys(":sign \\\\\\\"\", 'tx') + call assert_equal('"sign define', @:) + call histadd('cmd', 'TestWildMenu') + call feedkeys(":sign \\\\\\\"\", 'tx') + call assert_equal('"TestWildMenu', @:) + " cleanup %bwipe call delete('Xdir1', 'rf') @@ -2539,6 +2547,28 @@ func Test_wildmenu_pum() call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {}) call term_sendkeys(buf, "\") + " Pressing should scroll the menu downward + call term_sendkeys(buf, ":sign \\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_42', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_43', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_44', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_45', {}) + call term_sendkeys(buf, "\sign \\\\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_46', {}) + + " Pressing should scroll the menu upward + call term_sendkeys(buf, "\sign \\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_47', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_48', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_49', {}) + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_50', {}) + call term_sendkeys(buf, "\\") call StopVimInTerminal(buf) call delete('Xtest') diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 78b2f52c1f..85e6a03872 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -2388,8 +2388,130 @@ describe('builtin popupmenu', function() {1:~ }{n: xyz }{1: }| :e あいう/123^ | ]]) + feed('') - feed('') + -- Pressing should scroll the menu downward + feed(':sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{s: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign undefine^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + feed('') + 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('sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + + -- Pressing should scroll the menu upward + feed('sign ') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + feed('') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + feed('') + 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('') + 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('') -- check positioning with multibyte char in pattern command("e långfile1") -- cgit From 940643aa331e31678467c770b77808e0b4240b34 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 15 Jan 2023 07:23:51 +0800 Subject: vim-patch:8.2.4585: cannot use keypad page-up/down for completion menu Problem: Cannot use keypad page-up/down for completion menu. Solution: Recognize the keypad keys. (Yegappan Lakshmanan, closes vim/vim#9963) https://github.com/vim/vim/commit/155b0882088ff115dcfb6ce466fe7c8cc2bef349 Co-authored-by: Yegappan Lakshmanan --- src/nvim/ex_getln.c | 10 +++++----- src/nvim/testdir/test_cmdline.vim | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index fc227f357e..62586598bf 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2010,8 +2010,8 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_N: // next match case Ctrl_P: // previous match if (s->xpc.xp_numfiles > 0) { - if (nextwild(&s->xpc, (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT, - 0, s->firstc != '@') == FAIL) { + const int wild_type = (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } return command_line_not_changed(s); @@ -2031,9 +2031,9 @@ static int command_line_handle_key(CommandLineState *s) || s->c == K_KPAGEUP || s->c == K_KPAGEDOWN)) { // If the popup menu is displayed, then PageUp and PageDown // are used to scroll the menu. - if (nextwild(&s->xpc, - (s->c == K_PAGEUP) ? WILD_PAGEUP : WILD_PAGEDOWN, - 0, s->firstc != '@') == FAIL) { + const int wild_type = + (s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN) ? WILD_PAGEDOWN : WILD_PAGEUP; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } return command_line_not_changed(s); diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 50bdfceebd..c867639832 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -2206,7 +2206,8 @@ func Test_wildmenu_dirstack() endfunc " Test for recalling newer or older cmdline from history with , , -" , , , , , or . +" , , , , , , , or +" . func Test_recalling_cmdline() CheckFeature cmdline_hist @@ -2214,17 +2215,18 @@ func Test_recalling_cmdline() cnoremap (save-cmdline) let g:cmdlines += [getcmdline()] let histories = [ - \ {'name': 'cmd', 'enter': ':', 'exit': "\"}, - \ {'name': 'search', 'enter': '/', 'exit': "\"}, - \ {'name': 'expr', 'enter': ":\=", 'exit': "\\"}, - \ {'name': 'input', 'enter': ":call input('')\", 'exit': "\"}, + \ #{name: 'cmd', enter: ':', exit: "\"}, + \ #{name: 'search', enter: '/', exit: "\"}, + \ #{name: 'expr', enter: ":\=", exit: "\\"}, + \ #{name: 'input', enter: ":call input('')\", exit: "\"}, "\ TODO: {'name': 'debug', ...} \] let keypairs = [ - \ {'older': "\", 'newer': "\", 'prefixmatch': v:true}, - \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, - \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, - \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, + \ #{older: "\", newer: "\", prefixmatch: v:true}, + \ #{older: "\", newer: "\", prefixmatch: v:false}, + \ #{older: "\", newer: "\", prefixmatch: v:false}, + \ #{older: "\", newer: "\", prefixmatch: v:false}, + \ #{older: "\", newer: "\", prefixmatch: v:false}, \] let prefix = 'vi' for h in histories -- cgit