commit c951fa9eeb599fff2f5542b026c1eadff7d7e042
parent bbfcde3ab20e0a490c9cce9afce97412cb1fde32
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue, 9 Sep 2025 09:14:43 +0800
Merge pull request #35690 from zeertzjq/vim-9.1.1738
vim-patch:9.1.{1738,1744},d7d6a6f
Diffstat:
6 files changed, 146 insertions(+), 53 deletions(-)
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
@@ -384,6 +384,9 @@ word before the cursor. This is available for:
The number of help item matches is limited (currently to 300) to avoid a long
delay when there are very many matches.
+For automatic completion as you type (without pressing a key like <Tab>),
+see |cmdline-autocompletion|.
+
These are the commands that can be used:
*c_CTRL-D*
@@ -456,8 +459,6 @@ When repeating 'wildchar' or CTRL-N you cycle through the matches, eventually
ending up back to what was typed. If the first match is not what you wanted,
you can use <S-Tab> or CTRL-P to go straight back to what you typed.
-See also |wildtrigger()|.
-
The 'wildmenu' option can be set to show the matches just above the command
line.
@@ -1259,4 +1260,83 @@ The character used for the pattern indicates the type of command-line:
@ string for |input()|
`-` text for |:insert| or |:append|
+==============================================================================
+8. Command-line autocompletion *cmdline-autocompletion*
+
+Autocompletion makes the command-line more efficient and easier to navigate by
+automatically showing a popup menu of suggestions as you type, whether
+searching (/ or ?) or entering commands (:).
+
+A basic setup is: >
+ autocmd CmdlineChanged [:/\?] call wildtrigger()
+ set wildmode=noselect:lastused,full
+ set wildoptions=pum
+
+With this configuration, suggestions appear immediately, and you can
+move through them with <Tab> or the arrow keys.
+
+To retain normal command-line history navigation with <Up>/<Down>: >
+ cnoremap <expr> <Up> wildmenumode() ? "\<C-E>\<Up>" : "\<Up>"
+ cnoremap <expr> <Down> wildmenumode() ? "\<C-E>\<Down>" : "\<Down>"
+
+Options can also be applied only for specific command-lines. For
+example, to use a shorter popup menu height only during search: >
+ autocmd CmdlineEnter [/\?] set pumheight=8
+ autocmd CmdlineLeave [/\?] set pumheight&
+
+EXTRAS *fuzzy-file-picker* *live-grep*
+
+Command-line autocompletion can also be extended for advanced uses.
+For example, you can turn the native |:find| command into a fuzzy, interactive
+file picker: >
+
+ set findfunc=Find
+ func Find(arg, _)
+ if get(s:, 'filescache', []) == []
+ let s:filescache = systemlist(
+ \ 'find . -path "*/.git" -prune -o -type f -print')
+ endif
+ return a:arg == '' ? s:filescache : matchfuzzy(s:filescache, a:arg)
+ endfunc
+ autocmd CmdlineEnter : let s:filescache = []
+
+The `:Grep` command searches for lines matching a pattern and updates the
+results dynamically as you type (triggered after two characters; note: needs
+the `CmdlineLeavePre` autocmd from the next section): >
+
+ command! -nargs=+ -complete=customlist,<SID>Grep
+ \ Grep call <SID>VisitFile()
+
+ func s:Grep(arglead, cmdline, cursorpos)
+ let cmd = $'grep -REIHns "{a:arglead}" --exclude-dir=.git
+ \ --exclude=".*"'
+ return len(a:arglead) > 1 ? systemlist(cmd) : []
+ endfunc
+
+ func s:VisitFile()
+ let item = getqflist(#{lines: [s:selected]}).items[0]
+ let pos = '[0,\ item.lnum,\ item.col,\ 0]'
+ exe $':b +call\ setpos(".",\ {pos}) {item.bufnr}'
+ call setbufvar(item.bufnr, '&buflisted', 1)
+ endfunc
+
+Automatically select the first item in the completion list when leaving the
+command-line, and for `:Grep`, add the typed pattern to the command-line
+history: >
+
+ autocmd CmdlineLeavePre :
+ \ if get(cmdcomplete_info(), 'matches', []) != [] |
+ \ let s:info = cmdcomplete_info() |
+ \ if getcmdline() =~ '^\s*fin\%[d]\s' && s:info.selected == -1 |
+ \ call setcmdline($'find {s:info.matches[0]}') |
+ \ endif |
+ \ if getcmdline() =~ '^\s*Grep\s' |
+ \ let s:selected = s:info.selected != -1
+ \ ? s:info.matches[s:info.selected] : s:info.matches[0] |
+ \ call setcmdline(s:info.cmdline_orig) |
+ \ endif |
+ \ endif
+
+For autocompletion in insert mode, see |ins-autocompletion|.
+
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt
@@ -11903,7 +11903,6 @@ wildmenumode() *wildmenumode()*
wildtrigger() *wildtrigger()*
Start wildcard expansion in the command-line, using the
behavior defined by the 'wildmode' and 'wildoptions' settings.
- See |cmdline-completion|.
This function also enables completion in search patterns such
as |/|, |?|, |:s|, |:g|, |:v| and |:vimgrep|.
@@ -11911,22 +11910,15 @@ wildtrigger() *wildtrigger()*
Unlike pressing 'wildchar' manually, this function does not
produce a beep when no matches are found and generally
operates more quietly. This makes it suitable for triggering
- completion automatically, such as from an |:autocmd|.
- *cmdline-autocompletion*
- Example: To make the completion menu pop up automatically as
- you type on the command line, use: >vim
- autocmd CmdlineChanged [:/\?] call wildtrigger()
- set wildmode=noselect:lastused,full wildoptions=pum
-<
- To retain normal history navigation (up/down keys): >vim
- cnoremap <Up> <C-U><Up>
- cnoremap <Down> <C-U><Down>
-<
- To set an option specifically when performing a search, e.g.
- to set 'pumheight': >vim
- autocmd CmdlineEnter [/\?] set pumheight=8
- autocmd CmdlineLeave [/\?] set pumheight&
-<
+ completion automatically.
+
+ Note: After navigating command-line history, the first call to
+ wildtrigger() is a no-op; a second call is needed to start
+ expansion. This is to support history navigation in
+ command-line autocompletion.
+
+ See |cmdline-autocompletion|.
+
Return value is always 0.
Return: ~
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
@@ -10835,7 +10835,6 @@ function vim.fn.wildmenumode() end
--- Start wildcard expansion in the command-line, using the
--- behavior defined by the 'wildmode' and 'wildoptions' settings.
---- See |cmdline-completion|.
---
--- This function also enables completion in search patterns such
--- as |/|, |?|, |:s|, |:g|, |:v| and |:vimgrep|.
@@ -10843,22 +10842,15 @@ function vim.fn.wildmenumode() end
--- Unlike pressing 'wildchar' manually, this function does not
--- produce a beep when no matches are found and generally
--- operates more quietly. This makes it suitable for triggering
---- completion automatically, such as from an |:autocmd|.
---- *cmdline-autocompletion*
---- Example: To make the completion menu pop up automatically as
---- you type on the command line, use: >vim
---- autocmd CmdlineChanged [:/\?] call wildtrigger()
---- set wildmode=noselect:lastused,full wildoptions=pum
---- <
---- To retain normal history navigation (up/down keys): >vim
---- cnoremap <Up> <C-U><Up>
---- cnoremap <Down> <C-U><Down>
---- <
---- To set an option specifically when performing a search, e.g.
---- to set 'pumheight': >vim
---- autocmd CmdlineEnter [/\?] set pumheight=8
---- autocmd CmdlineLeave [/\?] set pumheight&
---- <
+--- completion automatically.
+---
+--- Note: After navigating command-line history, the first call to
+--- wildtrigger() is a no-op; a second call is needed to start
+--- expansion. This is to support history navigation in
+--- command-line autocompletion.
+---
+--- See |cmdline-autocompletion|.
+---
--- Return value is always 0.
---
--- @return number
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
@@ -13092,7 +13092,6 @@ M.funcs = {
desc = [==[
Start wildcard expansion in the command-line, using the
behavior defined by the 'wildmode' and 'wildoptions' settings.
- See |cmdline-completion|.
This function also enables completion in search patterns such
as |/|, |?|, |:s|, |:g|, |:v| and |:vimgrep|.
@@ -13100,22 +13099,15 @@ M.funcs = {
Unlike pressing 'wildchar' manually, this function does not
produce a beep when no matches are found and generally
operates more quietly. This makes it suitable for triggering
- completion automatically, such as from an |:autocmd|.
- *cmdline-autocompletion*
- Example: To make the completion menu pop up automatically as
- you type on the command line, use: >vim
- autocmd CmdlineChanged [:/\?] call wildtrigger()
- set wildmode=noselect:lastused,full wildoptions=pum
- <
- To retain normal history navigation (up/down keys): >vim
- cnoremap <Up> <C-U><Up>
- cnoremap <Down> <C-U><Down>
- <
- To set an option specifically when performing a search, e.g.
- to set 'pumheight': >vim
- autocmd CmdlineEnter [/\?] set pumheight=8
- autocmd CmdlineLeave [/\?] set pumheight&
- <
+ completion automatically.
+
+ Note: After navigating command-line history, the first call to
+ wildtrigger() is a no-op; a second call is needed to start
+ expansion. This is to support history navigation in
+ command-line autocompletion.
+
+ See |cmdline-autocompletion|.
+
Return value is always 0.
]==],
name = 'wildtrigger',
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
@@ -146,6 +146,7 @@ typedef struct {
buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid
int cmdline_type;
bool event_cmdlineleavepre_triggered;
+ bool did_hist_navigate;
} CommandLineState;
typedef struct {
@@ -1254,6 +1255,12 @@ static int command_line_execute(VimState *state, int key)
CommandLineState *s = (CommandLineState *)state;
s->c = key;
+ // Skip wildmenu during history navigation via Up/Down keys
+ if (s->c == K_WILD && s->did_hist_navigate) {
+ s->did_hist_navigate = false;
+ return 1;
+ }
+
if (s->c == K_EVENT || s->c == K_COMMAND || s->c == K_LUA) {
if (s->c == K_EVENT) {
state_handle_k_event();
@@ -2227,6 +2234,7 @@ static int command_line_handle_key(CommandLineState *s)
} else {
switch (command_line_browse_history(s)) {
case CMDLINE_CHANGED:
+ s->did_hist_navigate = true;
return command_line_changed(s);
case GOTO_NORMAL_MODE:
return 0;
diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim
@@ -4986,4 +4986,33 @@ func Test_CmdlineLeave_vchar_keys()
unlet g:leave_key
endfunc
+" Skip wildmenu during history navigation via Up/Down keys
+func Test_skip_wildtrigger_hist_navigation()
+ call Ntest_override("char_avail", 1)
+ set wildmenu wildmode=noselect,full
+ augroup TestSkipWildtrigger | autocmd!
+ autocmd CmdlineChanged : call wildtrigger()
+ augroup END
+ cnoremap <expr> <Up> wildmenumode() ? "\<C-E>\<Up>" : "\<Up>"
+ cnoremap <expr> <Down> wildmenumode() ? "\<C-E>\<Down>" : "\<Down>"
+
+ call feedkeys(":echom \"foo\"", "tx")
+ call feedkeys(":echom \"foobar\"", "tx")
+
+ call feedkeys(":ech\<Up>\<C-B>\"\<CR>", "tx")
+ call assert_equal('"echom "foobar"', @:)
+ call feedkeys(":ech\<Up>\<Up>\<C-B>\"\<CR>", "tx")
+ call assert_equal('"echom "foo"', @:)
+ call feedkeys(":ech\<Up>\<Up>\<Down>\<C-B>\"\<CR>", "tx")
+ call assert_equal('"echom "foobar"', @:)
+ call feedkeys(":ech\<Up>\<Up>\<Down>\<Down>\<C-B>\"\<CR>", "tx")
+ call assert_equal('"ech', @:)
+
+ call Ntest_override("char_avail", 0)
+ set wildmenu& wildmode& wildoptions&
+ augroup TestSkipWildtrigger | autocmd! | augroup END
+ cunmap <Up>
+ cunmap <Down>
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab