mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
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)
560dff49c0
Only port cmdexpand.c and test_cmdline.vim changes.
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
@@ -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 != '@');
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user