diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-01-14 17:23:24 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-14 17:23:24 +0800 |
commit | 22e3b155f4b34ab54aacda6c0c96c69780e2b587 (patch) | |
tree | f512a2300f63c4043e340ab53247f15c3ef46311 | |
parent | e89c39d6f016a4140293755250e968e839009617 (diff) | |
download | rneovim-22e3b155f4b34ab54aacda6c0c96c69780e2b587.tar.gz rneovim-22e3b155f4b34ab54aacda6c0c96c69780e2b587.tar.bz2 rneovim-22e3b155f4b34ab54aacda6c0c96c69780e2b587.zip |
vim-patch:partial:8.2.4339: CTRL-A does not work properly with the cmdline popup menu (#21791)
Problem: CTRL-A does not work properly with the cmdline popup menu.
Solution: Fix issues with CTRL-A. Add more tests for the cmdline popup
menu. Remove TermWait() before VeriryScreenDump(). Refactor the
cmdline popup code. (Yegappan Lakshmanan, closes vim/vim#9735)
https://github.com/vim/vim/commit/560dff49c0095111fc96b4b8dd7f4d269aba9473
Only port cmdexpand.c and test_cmdline.vim changes.
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
-rw-r--r-- | src/nvim/cmdexpand.c | 72 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 91 |
3 files changed, 104 insertions, 61 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index be2db2a2e5..589deb6feb 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -89,6 +89,10 @@ static int compl_match_arraysize; static int compl_startcol; static int compl_selected; +#define SHOW_FILE_TEXT(m) (showtail \ + ? showmatches_gettail(files_found[m], false) \ + : files_found[m]) + static int sort_func_compare(const void *s1, const void *s2) { char *p1 = *(char **)s1; @@ -279,19 +283,54 @@ int nextwild(expand_T *xp, int type, int options, bool escape) return OK; } +/// Create and display a cmdline completion popup menu with items from +/// "files_found". +static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **files_found, int num_files, + int showtail) +{ + assert(num_files >= 0); + // Add all the completion matches + compl_match_arraysize = num_files; + compl_match_array = xmalloc(sizeof(pumitem_T) * (size_t)compl_match_arraysize); + for (int i = 0; i < num_files; i++) { + compl_match_array[i] = (pumitem_T){ + .pum_text = SHOW_FILE_TEXT(i), + .pum_info = NULL, + .pum_extra = NULL, + .pum_kind = NULL, + }; + } + + // Compute the popup menu starting column + char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, true) : xp->xp_pattern; + if (ui_has(kUICmdline)) { + compl_startcol = (int)(endpos - ccline->cmdbuff); + } else { + compl_startcol = cmd_screencol((int)(endpos - ccline->cmdbuff)); + } + + // no default selection + compl_selected = -1; + + cmdline_pum_display(true); + + return EXPAND_OK; +} + void cmdline_pum_display(bool changed_array) { pum_display(compl_match_array, compl_match_arraysize, compl_selected, changed_array, compl_startcol); } +/// Returns true if the cmdline completion popup menu is being displayed. bool cmdline_pum_active(void) { // compl_match_array != NULL should already imply pum_visible() in Nvim. return compl_match_array != NULL; } -/// Remove the cmdline completion popup menu +/// Remove the cmdline completion popup menu (if present), free the list of items. void cmdline_pum_remove(void) { pum_undisplay(true); @@ -826,9 +865,6 @@ void ExpandCleanup(expand_T *xp) int showmatches(expand_T *xp, int wildmenu) { CmdlineInfo *const ccline = get_cmdline_info(); -#define L_SHOWFILE(m) (showtail \ - ? showmatches_gettail(files_found[m], false) \ - : files_found[m]) int num_files; char **files_found; int i, j, k; @@ -860,26 +896,8 @@ int showmatches(expand_T *xp, int wildmenu) || ui_has(kUIWildmenu); if (compl_use_pum) { - assert(num_files >= 0); - compl_match_arraysize = num_files; - compl_match_array = xmalloc(sizeof(pumitem_T) * (size_t)compl_match_arraysize); - for (i = 0; i < num_files; i++) { - compl_match_array[i] = (pumitem_T){ - .pum_text = L_SHOWFILE(i), - .pum_info = NULL, - .pum_extra = NULL, - .pum_kind = NULL, - }; - } - char *endpos = showtail ? showmatches_gettail(xp->xp_pattern, true) : xp->xp_pattern; - if (ui_has(kUICmdline)) { - compl_startcol = (int)(endpos - ccline->cmdbuff); - } else { - compl_startcol = cmd_screencol((int)(endpos - ccline->cmdbuff)); - } - compl_selected = -1; - cmdline_pum_display(true); - return EXPAND_OK; + // cmdline completion popup menu (with wildoptions=pum) + return cmdline_pum_create(ccline, xp, files_found, num_files, showtail); } if (!wildmenu) { @@ -906,7 +924,7 @@ int showmatches(expand_T *xp, int wildmenu) home_replace(NULL, files_found[i], NameBuff, MAXPATHL, true); j = vim_strsize(NameBuff); } else { - j = vim_strsize(L_SHOWFILE(i)); + j = vim_strsize(SHOW_FILE_TEXT(i)); } if (j > maxlen) { maxlen = j; @@ -971,14 +989,14 @@ int showmatches(expand_T *xp, int wildmenu) j = os_isdir(files_found[k]); } if (showtail) { - p = L_SHOWFILE(k); + p = SHOW_FILE_TEXT(k); } else { home_replace(NULL, files_found[k], NameBuff, MAXPATHL, true); p = NameBuff; } } else { j = false; - p = L_SHOWFILE(k); + p = SHOW_FILE_TEXT(k); } lastlen = msg_outtrans_attr(p, j ? attr : 0); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b73ed98443..72208c976f 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1225,6 +1225,8 @@ static int command_line_execute(VimState *state, int key) } if (cmdline_pum_active() || s->did_wild_list) { + // 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; (void)nextwild(&s->xpc, wild_type, WILD_NO_BEEP, s->firstc != '@'); diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index b9f32b2db9..12a9b799c2 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -2299,39 +2299,41 @@ func Test_wildmenu_pum() set shm+=I set noruler set noshowcmd + + func CmdCompl(a, b, c) + return repeat(['aaaa'], 120) + endfunc + command -nargs=* -complete=customlist,CmdCompl Tcmd [CODE] call writefile(commands, 'Xtest') let buf = RunVimInTerminal('-S Xtest', #{rows: 10}) call term_sendkeys(buf, ":sign \<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_01', {}) + " going down the popup menu using <Down> call term_sendkeys(buf, "\<Down>\<Down>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_02', {}) + " going down the popup menu using <C-N> call term_sendkeys(buf, "\<C-N>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_03', {}) + " going up the popup menu using <C-P> call term_sendkeys(buf, "\<C-P>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_04', {}) + " going up the popup menu using <Up> call term_sendkeys(buf, "\<Up>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_05', {}) " pressing <C-E> should end completion and go back to the original match call term_sendkeys(buf, "\<C-E>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_06', {}) " pressing <C-Y> should select the current match and end completion call term_sendkeys(buf, "\<Tab>\<C-P>\<C-P>\<C-Y>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_07', {}) " With 'wildmode' set to 'longest,full', completing a match should display @@ -2339,31 +2341,25 @@ func Test_wildmenu_pum() call term_sendkeys(buf, ":\<C-U>set wildmode=longest,full\<CR>") call TermWait(buf) call term_sendkeys(buf, ":sign u\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_08', {}) " pressing <Tab> should display the wildmenu call term_sendkeys(buf, "\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_09', {}) " pressing <Tab> second time should select the next entry in the menu call term_sendkeys(buf, "\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_10', {}) call term_sendkeys(buf, ":\<C-U>set wildmode=full\<CR>") - " " showing popup menu in different columns in the cmdline + " showing popup menu in different columns in the cmdline call term_sendkeys(buf, ":sign define \<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_11', {}) call term_sendkeys(buf, " \<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_12', {}) call term_sendkeys(buf, " \<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_13', {}) " Directory name completion @@ -2373,95 +2369,77 @@ func Test_wildmenu_pum() call writefile([], 'Xdir/XdirA/XdirB/XfileC') call term_sendkeys(buf, "\<C-U>e Xdi\<Tab>\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_14', {}) " Pressing <Right> on a directory name should go into that directory call term_sendkeys(buf, "\<Right>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_15', {}) " Pressing <Left> on a directory name should go to the parent directory call term_sendkeys(buf, "\<Left>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_16', {}) " Pressing <C-A> when the popup menu is displayed should list all the - " matches and remove the popup menu + " matches but the popup menu should still remain call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-A>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_17', {}) " Pressing <C-D> when the popup menu is displayed should remove the popup " menu call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-D>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_18', {}) " Pressing <S-Tab> should open the popup menu with the last entry selected call term_sendkeys(buf, "\<C-U>\<CR>:sign \<S-Tab>\<C-P>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_19', {}) " Pressing <Esc> should close the popup menu and cancel the cmd line call term_sendkeys(buf, "\<C-U>\<CR>:sign \<Tab>\<Esc>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_20', {}) " Typing a character when the popup is open, should close the popup call term_sendkeys(buf, ":sign \<Tab>x") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_21', {}) " When the popup is open, entering the cmdline window should close the popup call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-F>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_22', {}) call term_sendkeys(buf, ":q\<CR>") " After the last popup menu item, <C-N> should show the original string call term_sendkeys(buf, ":sign u\<Tab>\<C-N>\<C-N>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_23', {}) " Use the popup menu for the command name call term_sendkeys(buf, "\<C-U>bu\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_24', {}) " Pressing the left arrow should remove the popup menu call term_sendkeys(buf, "\<Left>\<Left>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_25', {}) " Pressing <BS> should remove the popup menu and erase the last character call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<BS>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_26', {}) " Pressing <C-W> should remove the popup menu and erase the previous word call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-W>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_27', {}) " Pressing <C-U> should remove the popup menu and erase the entire line call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-U>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_28', {}) " Using <C-E> to cancel the popup menu and then pressing <Up> should recall " the cmdline from history call term_sendkeys(buf, "sign xyz\<Esc>:sign \<Tab>\<C-E>\<Up>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_29', {}) " Check "list" still works call term_sendkeys(buf, "\<C-U>set wildmode=longest,list\<CR>") call term_sendkeys(buf, ":cn\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_30', {}) call term_sendkeys(buf, "s") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_31', {}) " Tests a directory name contained full-width characters. @@ -2472,15 +2450,60 @@ func Test_wildmenu_pum() call term_sendkeys(buf, "\<C-U>set wildmode&\<CR>") call term_sendkeys(buf, ":\<C-U>e Xdir/あいう/\<Tab>") - call TermWait(buf) call VerifyScreenDump(buf, 'Test_wildmenu_pum_32', {}) + " Pressing <C-A> when the popup menu is displayed should list all the + " matches and pressing a key after that should remove the popup menu + call term_sendkeys(buf, "\<C-U>set wildmode=full\<CR>") + call term_sendkeys(buf, ":sign \<Tab>\<C-A>x") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_33', {}) + + " Pressing <C-A> when the popup menu is displayed should list all the + " matches and pressing <Left> after that should move the cursor + call term_sendkeys(buf, "\<C-U>abc\<Esc>") + call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<Left>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_34', {}) + + " When <C-A> displays a lot of matches (screen scrolls), all the matches + " should be displayed correctly on the screen. + call term_sendkeys(buf, "\<End>\<C-U>Tcmd \<Tab>\<C-A>\<Left>\<Left>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_35', {}) + + " 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, ":e \<Tab>\<C-A>\<Up>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_36', {}) + call term_sendkeys(buf, "\<C-E>\<C-U>:cd -\<CR>") + + " After using <C-A> to expand all the matches, pressing <S-Tab> used to + " crash Vim + call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<S-Tab>") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_37', {}) + 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 +func Test_wildmenumode_with_pum() + set wildmenu + set wildoptions=pum + cnoremap <expr> <F2> wildmenumode() + call feedkeys(":sign \<Tab>\<F2>\<F2>\<C-B>\"\<CR>", 'xt') + call assert_equal('"sign define10', @:) + call feedkeys(":sign \<Tab>\<C-A>\<F2>\<C-B>\"\<CR>", 'xt') + call assert_equal('"sign define jump list place undefine unplace0', @:) + call feedkeys(":sign \<Tab>\<C-E>\<F2>\<C-B>\"\<CR>", 'xt') + call assert_equal('"sign 0', @:) + call feedkeys(":sign \<Tab>\<C-Y>\<F2>\<C-B>\"\<CR>", 'xt') + call assert_equal('"sign define0', @:) + set nowildmenu wildoptions& + cunmap <F2> +endfunc + func Test_wildmenu_pum_clear_entries() CheckRunVimInTerminal |