Problem: cannot get information about command line completion
Solution: add CmdlineLeavePre autocommand and cmdcomplete_info() Vim
script function (Girish Palya)
This commit introduces two features to improve introspection and control
over command-line completion in Vim:
- Add CmdlineLeavePre autocmd event:
A new event triggered just before leaving the command line and before
CmdlineLeave. It allows capturing completion-related state that is
otherwise cleared by the time CmdlineLeave fires.
- Add cmdcomplete_info() Vim script function:
Returns a Dictionary with details about the current command-line
completion state.
These are similar in spirit to InsertLeavePre and complete_info(),
but focused on command-line mode.
**Use case:**
In [[PR vim/vim#16759](https://github.com/vim/vim/pull/16759)], two examples
demonstrate command-line completion: one for live grep, and another for
fuzzy file finding. However, both examples share two key limitations:
1. **Broken history recall (`<Up>`)**
When selecting a completion item via `<Tab>` or `<C-n>`, the original
pattern used for searching (e.g., a regex or fuzzy string) is
overwritten in the command-line history. This makes it impossible to
recall the original query later.
This is especially problematic for interactive grep workflows, where
it’s useful to recall a previous search and simply select a different
match from the menu.
2. **Lack of default selection on `<CR>`**
Often, it’s helpful to allow `<CR>` (Enter) to accept the first match
in the completion list, even when no item is explicitly selected. This
behavior is particularly useful in fuzzy file finding.
----
Below are the updated examples incorporating these improvements:
**Live grep, fuzzy find file, fuzzy find buffer:**
```vim
command! -nargs=+ -complete=customlist,GrepComplete Grep VisitFile()
def GrepComplete(arglead: string, cmdline: string, cursorpos: number):
list<any>
return arglead->len() > 1 ? systemlist($'grep -REIHns "{arglead}"' ..
' --exclude-dir=.git --exclude=".*" --exclude="tags" --exclude="*.swp"') : []
enddef
def VisitFile()
if (selected_match != null_string)
var qfitem = getqflist({lines: [selected_match]}).items[0]
if qfitem->has_key('bufnr') && qfitem.lnum > 0
var pos = qfitem.vcol > 0 ? 'setcharpos' : 'setpos'
exec $':b +call\ {pos}(".",\ [0,\ {qfitem.lnum},\ {qfitem.col},\ 0]) {qfitem.bufnr}'
setbufvar(qfitem.bufnr, '&buflisted', 1)
endif
endif
enddef
nnoremap <leader>g :Grep<space>
nnoremap <leader>G :Grep <c-r>=expand("<cword>")<cr>
command! -nargs=* -complete=customlist,FuzzyFind Find
execute(selected_match != '' ? $'edit {selected_match}' : '')
var allfiles: list<string>
autocmd CmdlineEnter : allfiles = null_list
def FuzzyFind(arglead: string, _: string, _: number): list<string>
if allfiles == null_list
allfiles = systemlist($'find {get(g:, "fzfind_root", ".")} \! \(
-path "*/.git" -prune -o -name "*.swp" \) -type f -follow')
endif
return arglead == '' ? allfiles : allfiles->matchfuzzy(arglead)
enddef
nnoremap <leader><space> :<c-r>=execute('let
fzfind_root="."')\|''<cr>Find<space><c-@>
nnoremap <leader>fv :<c-r>=execute('let
fzfind_root="$HOME/.vim"')\|''<cr>Find<space><c-@>
nnoremap <leader>fV :<c-r>=execute('let
fzfind_root="$VIMRUNTIME"')\|''<cr>Find<space><c-@>
command! -nargs=* -complete=customlist,FuzzyBuffer Buffer execute('b '
.. selected_match->matchstr('\d\+'))
def FuzzyBuffer(arglead: string, _: string, _: number): list<string>
var bufs = execute('buffers', 'silent!')->split("\n")
var altbuf = bufs->indexof((_, v) => v =~ '^\s*\d\+\s\+#')
if altbuf != -1
[bufs[0], bufs[altbuf]] = [bufs[altbuf], bufs[0]]
endif
return arglead == '' ? bufs : bufs->matchfuzzy(arglead)
enddef
nnoremap <leader><bs> :Buffer <c-@>
var selected_match = null_string
autocmd CmdlineLeavePre : SelectItem()
def SelectItem()
selected_match = ''
if getcmdline() =~ '^\s*\%(Grep\|Find\|Buffer\)\s'
var info = cmdcomplete_info()
if info != {} && info.pum_visible && !info.matches->empty()
selected_match = info.selected != -1 ? info.matches[info.selected] : info.matches[0]
setcmdline(info.cmdline_orig). # Preserve search pattern in history
endif
endif
enddef
```
**Auto-completion snippet:**
```vim
set wim=noselect:lastused,full wop=pum wcm=<C-@> wmnu
autocmd CmdlineChanged : CmdComplete()
def CmdComplete()
var [cmdline, curpos] = [getcmdline(), getcmdpos()]
if getchar(1, {number: true}) == 0 # Typehead is empty (no more pasted input)
&& !pumvisible() && curpos == cmdline->len() + 1
&& cmdline =~ '\%(\w\|[*/:.-]\)$' && cmdline !~ '^\d\+$' # Reduce noise
feedkeys("\<C-@>", "ti")
SkipCmdlineChanged() # Suppress redundant completion attempts
# Remove <C-@> that get inserted when no items are available
timer_start(0, (_) => getcmdline()->substitute('\%x00', '', 'g')->setcmdline())
endif
enddef
cnoremap <expr> <up> SkipCmdlineChanged("\<up>")
cnoremap <expr> <down> SkipCmdlineChanged("\<down>")
autocmd CmdlineEnter : set bo+=error
autocmd CmdlineLeave : set bo-=error
def SkipCmdlineChanged(key = ''): string
set ei+=CmdlineChanged
timer_start(0, (_) => execute('set ei-=CmdlineChanged'))
return key != '' ? ((pumvisible() ? "\<c-e>" : '') .. key) : ''
enddef
```
These customizable snippets can serve as *lightweight* and *native*
alternatives to picker plugins like **FZF** or **Telescope** for common,
everyday workflows. Also, live grep snippet can replace **cscope**
without the overhead of building its database.
closes: vim/vim#1711592f68e26ec
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem:
nvim_parse_cmd returns invalid 'range' field for cmd like `:bdelete`.
Solution:
Add the condtion `ea.add_count > 0` as required to put 'range'
into result.
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Problem:
'winblend' does not display text behind blank unicode characters other than 0x20 ascii space.
Solution:
In ui_compositor.c -> compose_line() check for either 0x20 or 0x80A0E2 (utf8 \u2800).
Problem:
Cursor is visible in "hidden" floating window.
Solution:
Hide cursor when curwin is a hidden floating window.
Show cursor after returning to a normal (non-hidden) window.
Problem: Change applied in d3e495ce uses a byte-offset where a virtual
column is expected.
Solution: Set the cursor directly through a <Cmd> mapping, while making
sure the commands are ordered correctly by adding them to the
type-ahead buffer.
This commit fixes the following error message:
```
Compiler not supported: make inc< sw< sts<
```
1. orginal value: `setl com< cms< et< fo<| compiler make inc< sw< sts<`
2. correct value: `setl com< cms< et< fo< inc< sw< sts< | compiler make`
While at it, let's also document the g:yaml_recommended_style variable.
closes: vim/vim#17179229f79c168
Co-authored-by: Vincent Law <vlaw@users.noreply.github.com>
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem:
Neovim disables a number of terminal modes when it exits, some of which
cause the terminal to send asynchronous events to Neovim. It's possible
that Neovim exits before the terminal has received and processed all of
the sequences to disable these modes, causing the terminal to emit one
of these asynchronous sequences after Neovim has already exited. If this
happens, then the sequence is received by the user's shell (or some
other program that is not Neovim).
Solution:
When Neovim exits, it now emits a Device Attributes request (DA1)
after disabling all of the different modes. When the terminal responds
to this request we know that it has already received all of our other
sequences disabling the other modes. At that point, it should not be
emitting any further asynchronous sequences. This means the process of
exiting Neovim is now asynchronous as well since it depends on receiving
the DA1 response from the terminal.
Problem: Transpiled Lua code from vim9script is not amenable to static
analysis, requiring manual cleanup or ignoring parts of our codebase.
Solution: Revert to pre-rewrite version of (low-impact) legacy plugins
and remove the vim9jit shim.
Problem: When iterating in reverse with {start} > {end} in
`nvim_buf_get_extmarks()`, marks that overlap {start} and are
greater than {end} are included in the return value twice.
Marks that overlap {end} and do not overlap {start} are not
not included in the return value at all. Marks are not
actually returned in a meaningful "traversal order".
Solution: Rather than actually iterating in reverse, (also possible but
requires convoluted conditions and would require fetching
overlapping marks for both the {start} and {end} position,
while still ending up with non-traversal ordered marks),
iterate normally and reverse the return value.
Problem:
Default 'statusline' is implemented in C and not representable as
a statusline expression. This makes it hard for user configs/plugins to
extend it.
Solution:
- Change the default 'statusline' slightly to a statusline expression.
- Remove the C implementation.
Problem: We allow setting 'cmdheight' to 0 with ext_messages enabled
since b72931e7. Enabling ext_messages with vim.ui_attach()
implicitly sets 'cmdheight' to 0 for BWC. When non-zero
'cmdheight' is wanted, this behavior make it unnecessarily
hard to keep track of the user configured value.
Solution: Add set_cmdheight to vim.ui_attach() opts table that can be
set to false to avoid setting 'cmdheight' to 0.
Useful to e.g. limit the height to the window height, avoiding unnecessary
work. Or to find out how many buffer lines beyond "start_row" take up a
certain number of logical lines (returned in "end_row" and "end_vcol").
Problem: too many strlen() calls in indent.c
Solution: refactor indent.c slightly and remove strlen() calls
(John Marriott)
closes: vim/vim#17156eac45c558e
Co-authored-by: John Marriott <basilisk@internode.on.net>
Problem: filetype: nroff detection can be improved
Solution: improve nroff detection (Eisuke Kawashima)
- explicitly check roff comments and macros typically found in manpages
- do not try to detect alphabetically-sectioned files, except for n, as
nroff
- l: > 'l' happens to be a section for historical reasons
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=391977>
- n: e.g. /usr/share/man/mann/Tcl.n.gz
- o: unsure (perhaps fedora-specific)
- p: unsure (perhaps fedora-specific)
closes: vim/vim#171602cb42efc18
Co-authored-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
Problem: filetype: some man files are not recognized
(e.g. 1p (POSIX commands))
Solution: update the filetype detection pattern and detect more man
files as nroff (Eisuke Kawashima)
- sections are revised referring to
- debian-12:/etc/manpath.config
- fedora-41:/etc/man_db.conf
- detection logic is improved
- detection test is implemented
closes: vim/vim#17117babdb0554a
Co-authored-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
E749 is given when :print (with any range) is issued on an empty buffer,
like the one you get with :new or :enew. Furthermore, due to Vi
compatibility :| is a synonym.
As a result, mappings intended to include a <bar> separator (esp. in the
case of boolean or "||") between commands can generate E749 on startup
when placed in a vimrc if the bars are not properly encoded or escaped.
[1]. Document this failure mode and synonym near the generated error,
and cross link with :help :bar. Note that one must read or scroll quite
a bit to find the mention of :| behaving like :print!
[1]: https://vi.stackexchange.com/q/46625/10604closes: vim/vim#17173187df69fd1
Co-authored-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Problem: invalid cursor position after 'tagfunc'
(gandalf4a)
Solution: call check_cursor() after executing the 'tagfunc'
9919085491
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: filetype: MS ixx and mpp files are not recognized
Solution: detect *.mpp and *.ixx files as c++ filetype
(Hampus Avekvist)
closes: vim/vim#17155aee34ef23e
Co-authored-by: Hampus Avekvist <hampus.avekvist@hey.com>
Problem: small delete register cannot paste multi-line correctly
(after v8.2.2189)
Solution: caused by 032a2d050b82b146d70d6ff714838ee62c07d8ad, so make
this logic handle charwise only (phanium)
closes: vim/vim#171517e93d4c617
Problem: Various typos in the code, redundant and strange use of
:execute in test_ins_complete.vim (after 9.1.1315).
Solution: Fix typos in the code and in the documentation, use the
executed command directly (zeertzjq).
closes: vim/vim#1714398800979dc
Co-authored-by: Christ van Willegen <cvwillegen@gmail.com>
Improve backslash handling in :set option values. There is no special
handling for options supporting Windows path separators yet.
See :help option-backslash.
Remove the vimSetString syntax group. Option string values cannot be
specified with a quoted string, this is a command terminating tail
comment.
fixes: vim/vim#16913closes: vim/vim#170342a6be83512
Co-authored-by: Doug Kearns <dougkearns@gmail.com>