vim-patch:8.2.4325: 'wildmenu' only shows few matches (#19876)

Problem:    'wildmenu' only shows few matches.
Solution:   Add the "pum" option: use a popup menu to show the matches.
            (Yegappan Lakshmanan et al., closes vim/vim#9707)
3908ef5017

Omit p_wmnu check in cmdline_pum_active() as it can cause problems.
Omit vim_strchr() flags as that isn't really better than bitmasks.
Omit key translations and document it in vim_diff.txt.
This commit is contained in:
zeertzjq
2022-08-21 21:31:25 +08:00
committed by GitHub
parent dde90f0ca4
commit e3eb6967bc
12 changed files with 520 additions and 17 deletions

View File

@@ -7020,7 +7020,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'wildoptions'* *'wop'*
'wildoptions' 'wop' string (default "pum,tagfile")
global
List of words that change how |cmdline-completion| is done.
A list of words that change how |cmdline-completion| is done.
The following values are supported:
pum Display the completion matches using the popup menu
in the same style as the |ins-completion-menu|.
tagfile When using CTRL-D to list matching tags, the kind of

View File

@@ -207,7 +207,6 @@ Commands:
|:checkhealth|
|:drop| is always available
|:Man| is available by default, with many improvements such as completion
|:sign-define| accepts a `numhl` argument, to highlight the line number
|:match| can be invoked before highlight group is defined
|:source| works with Lua
User commands can support |:command-preview| to show results as you type
@@ -374,6 +373,9 @@ Commands:
|:doautocmd| does not warn about "No matching autocommands".
|:wincmd| accepts a count.
Command line completion:
The meanings of arrow keys do not change depending on 'wildoptions'.
Functions:
|input()| and |inputdialog()| support for each others features (return on
cancel and completion respectively) via dictionary argument (replaces all

View File

@@ -258,7 +258,7 @@ void cmdline_pum_display(bool changed_array)
bool cmdline_pum_active(void)
{
// return p_wmnu && pum_visible() && compl_match_array != NULL;
// compl_match_array != NULL should already imply pum_visible() in Nvim.
return compl_match_array != NULL;
}
@@ -269,6 +269,12 @@ void cmdline_pum_remove(void)
XFREE_CLEAR(compl_match_array);
}
void cmdline_pum_cleanup(CmdlineInfo *cclp)
{
cmdline_pum_remove();
wildmenu_cleanup(cclp);
}
/// Do wildcard expansion on the string 'str'.
/// Chars that should not be expanded must be preceded with a backslash.
/// Return a pointer to allocated memory containing the new string.

View File

@@ -9633,7 +9633,7 @@ static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "wildmenumode()" function
static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
if (wild_menu_showing || ((State & MODE_CMDLINE) && pum_visible())) {
if (wild_menu_showing || ((State & MODE_CMDLINE) && cmdline_pum_active())) {
rettv->vval.v_number = 1;
}
}

View File

@@ -1801,6 +1801,10 @@ static int command_line_handle_key(CommandLineState *s)
if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) {
break;
}
if (cmdline_pum_active()) {
cmdline_pum_cleanup(&ccline);
s->xpc.xp_context = EXPAND_NOTHING;
}
return command_line_changed(s);
case Ctrl_L:

View File

@@ -1857,6 +1857,179 @@ func Test_recalling_cmdline()
cunmap <Plug>(save-cmdline)
endfunc
" Test for using a popup menu for the command line completion matches
" (wildoptions=pum)
func Test_wildmenu_pum()
CheckRunVimInTerminal
let commands =<< trim [CODE]
set wildmenu
set wildoptions=pum
set shm+=I
set noruler
set noshowcmd
[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', {})
call term_sendkeys(buf, "\<Down>\<Down>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_02', {})
call term_sendkeys(buf, "\<C-N>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_03', {})
call term_sendkeys(buf, "\<C-P>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_04', {})
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
" the longest match, the wildmenu should not be displayed.
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
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
call mkdir('Xdir/XdirA/XdirB', 'p')
call writefile([], 'Xdir/XfileA')
call writefile([], 'Xdir/XdirA/XfileB')
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
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', {})
call term_sendkeys(buf, "\<C-U>\<CR>")
call StopVimInTerminal(buf)
call delete('Xtest')
call delete('Xdir', 'rf')
endfunc
" this was going over the end of IObuff
func Test_report_error_with_composing()
let caught = 'no'

View File

@@ -7,7 +7,6 @@ local insert = helpers.insert
local meths = helpers.meths
local command = helpers.command
local funcs = helpers.funcs
local get_pathsep = helpers.get_pathsep
local eq = helpers.eq
local pcall_err = helpers.pcall_err
local exec_lua = helpers.exec_lua
@@ -1785,6 +1784,8 @@ describe('builtin popupmenu', function()
screen:try_resize(32,10)
command('set wildmenu')
command('set wildoptions=pum')
command('set shellslash')
command("cd test/functional/fixtures/wildpum")
feed(':sign ')
screen:expect([[
@@ -1800,7 +1801,7 @@ describe('builtin popupmenu', function()
:sign ^ |
]])
feed('<tab>')
feed('<Tab>')
screen:expect([[
|
{1:~ }|
@@ -1814,21 +1815,199 @@ describe('builtin popupmenu', function()
:sign define^ |
]])
feed('<left>')
feed('<Right><Right>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }{n: define }{1: }|
{1:~ }{n: jump }{1: }|
{1:~ }{s: list }{1: }|
{1:~ }{n: place }{1: }|
{1:~ }{n: undefine }{1: }|
{1:~ }{n: unplace }{1: }|
:sign list^ |
]])
feed('<C-N>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }{n: define }{1: }|
{1:~ }{n: jump }{1: }|
{1:~ }{n: list }{1: }|
{1:~ }{s: place }{1: }|
{1:~ }{n: undefine }{1: }|
{1:~ }{n: unplace }{1: }|
:sign place^ |
]])
feed('<C-P>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }{n: define }{1: }|
{1:~ }{n: jump }{1: }|
{1:~ }{s: list }{1: }|
{1:~ }{n: place }{1: }|
{1:~ }{n: undefine }{1: }|
{1:~ }{n: unplace }{1: }|
:sign list^ |
]])
feed('<Left>')
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^ |
]])
-- pressing <C-E> should end completion and go back to the original match
feed('<C-E>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:sign ^ |
]])
feed('<left>')
-- pressing <C-Y> should select the current match and end completion
feed('<Tab><C-P><C-P><C-Y>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:sign unplace^ |
]])
-- showing popup menu in different columns in the cmdline
feed('<C-U>sign define <Tab>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }|
{1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }|
:sign define culhl=^ |
]])
feed('<Space><Tab>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }|
{1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }|
:sign define culhl= culhl=^ |
]])
feed('<C-U>e Xdi<Tab><Tab>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }{s: XdirA/ }{1: }|
{1:~ }{n: XfileA }{1: }|
:e Xdir/XdirA/^ |
]])
-- Pressing <Down> on a directory name should go into that directory
feed('<Down>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }{s: XdirB/ }{1: }|
{1:~ }{n: XfileB }{1: }|
:e Xdir/XdirA/XdirB/^ |
]])
-- Pressing <Up> on a directory name should go to the parent directory
feed('<Up>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }{s: XdirA/ }{1: }|
{1:~ }{n: XfileA }{1: }|
:e Xdir/XdirA/^ |
]])
-- Pressing <C-A> when the popup menu is displayed should list all the
-- matches and remove the popup menu
feed(':<C-U>sign <Tab><C-A>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{4: }|
:sign define jump list place und|
efine unplace^ |
]])
-- Pressing <C-D> when the popup menu is displayed should remove the popup
-- menu
feed('<C-U>sign <Tab><C-D>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{4: }|
:sign define |
define |
:sign define^ |
]])
-- Pressing <S-Tab> should open the popup menu with the last entry selected
feed('<C-U><CR>:sign <S-Tab><C-P>')
screen:expect([[
|
{1:~ }|
@@ -1837,12 +2016,28 @@ describe('builtin popupmenu', function()
{1:~ }{n: jump }{1: }|
{1:~ }{n: list }{1: }|
{1:~ }{n: place }{1: }|
{1:~ }{n: undefine }{1: }|
{1:~ }{s: unplace }{1: }|
:sign unplace^ |
{1:~ }{s: undefine }{1: }|
{1:~ }{n: unplace }{1: }|
:sign undefine^ |
]])
feed('x')
-- Pressing <Esc> should close the popup menu and cancel the cmd line
feed('<C-U><CR>:sign <Tab><Esc>')
screen:expect([[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]])
-- Typing a character when the popup is open, should close the popup
feed(':sign <Tab>x')
screen:expect([[
|
{1:~ }|
@@ -1853,7 +2048,114 @@ describe('builtin popupmenu', function()
{1:~ }|
{1:~ }|
{1:~ }|
:sign unplacex^ |
:sign definex^ |
]])
-- When the popup is open, entering the cmdline window should close the popup
feed('<C-U>sign <Tab><C-F>')
screen:expect([[
|
{3:[No Name] }|
{1::}sign define |
{1::}sign define^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{4:[Command Line] }|
:sign define |
]])
feed(':q<CR>')
-- After the last popup menu item, <C-N> should show the original string
feed(':sign u<Tab><C-N><C-N>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }{n: undefine }{1: }|
{1:~ }{n: unplace }{1: }|
:sign u^ |
]])
-- Use the popup menu for the command name
feed('<C-U>bu<Tab>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{s: bufdo }{1: }|
{n: buffer }{1: }|
{n: buffers }{1: }|
{n: bunload }{1: }|
:bufdo^ |
]])
-- Pressing <BS> should remove the popup menu and erase the last character
feed('<C-E><C-U>sign <Tab><BS>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:sign defin^ |
]])
-- Pressing <C-W> should remove the popup menu and erase the previous word
feed('<C-E><C-U>sign <Tab><C-W>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:sign ^ |
]])
-- Pressing <C-U> should remove the popup menu and erase the entire line
feed('<C-E><C-U>sign <Tab><C-U>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:^ |
]])
-- Using <C-E> to cancel the popup menu and then pressing <Up> should recall
-- the cmdline from history
feed('sign xyz<Esc>:sign <Tab><C-E><Up>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
:sign xyz^ |
]])
feed('<esc>')
@@ -1932,7 +2234,6 @@ describe('builtin popupmenu', function()
feed('<esc>')
command("close")
command('set wildmode=full')
command("cd test/functional/fixtures/")
feed(':e compdir/<tab>')
screen:expect([[
|
@@ -1949,7 +2250,7 @@ describe('builtin popupmenu', function()
{1:~ }|
{1:~ }{s: file1 }{1: }|
{1:~ }{n: file2 }{1: }|
:e compdir]]..get_pathsep()..[[file1^ |
:e compdir/file1^ |
]])
end)
@@ -2007,7 +2308,9 @@ describe('builtin popupmenu', function()
command('set wildoptions=pum')
command('set wildmode=longest,full')
feed(':sign u<tab>')
-- With 'wildmode' set to 'longest,full', completing a match should display
-- the longest match, the wildmenu should not be displayed.
feed(':sign u<Tab>')
screen:expect{grid=[[
|
{1:~ }|
@@ -2020,7 +2323,8 @@ describe('builtin popupmenu', function()
]]}
eq(0, funcs.wildmenumode())
feed('<tab>')
-- pressing <Tab> should display the wildmenu
feed('<Tab>')
screen:expect{grid=[[
|
{1:~ }|
@@ -2032,6 +2336,19 @@ describe('builtin popupmenu', function()
:sign undefine^ |
]]}
eq(1, funcs.wildmenumode())
-- pressing <Tab> second time should select the next entry in the menu
feed('<Tab>')
screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }{n: undefine }{1: }|
{1:~ }{s: unplace }{1: }|
:sign unplace^ |
]]}
end)
it("'pumblend' RGB-color", function()