aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-01-14 17:23:24 +0800
committerGitHub <noreply@github.com>2023-01-14 17:23:24 +0800
commit22e3b155f4b34ab54aacda6c0c96c69780e2b587 (patch)
treef512a2300f63c4043e340ab53247f15c3ef46311
parente89c39d6f016a4140293755250e968e839009617 (diff)
downloadrneovim-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.c72
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/testdir/test_cmdline.vim91
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