Problem: Installing plugins during lockfile synchronization always
writes the lockfile, even though its content is used during install.
This might be a problem if the lockfile (itself or its parent
directory) is not writeable (can only be read).
Solution: Do not write the lockfile when installing directly from it.
This is okay since the `src` and `rev` are used directly from the
lockfile and don't change at this step. While potential change in
`version` (that must be written to the lockfile) is handled in other
code path.
Problem:
commit_chars_str() reads a 0x80-0xBF byte as a 2-byte lead, so
"\xA9x" makes "x" a commit character. nvim_get_hl() returns
a dict, so `#` on it is 0 whether or not the group exists
Solution:
use vim.str_utf_end() and drop entries that are not one whole
character. use next check dict length.
Problem:
Tree-sitter uses UINT32_MAX for full-document ranges, which becomes -1 on 32-bit platforms and reaches _foldupdate as an invalid end row.
Solution:
Treat negative changed-range end rows as unbounded and clamp them to the buffer line count. Add a regression test that simulates the 32-bit sentinel.
AI-assisted: Codex
Problem:
Want `gQ` for _le multicursor_.
Solution:
- Don't use `gQ` for exmode.
- Introduce `:exmode`.
- Introduce `[count]q:` as an alias to `:exmode`.
Problem:
On NetBSD, `man -w open` can return the exact manpage path, but `:Man`
may still fail when man directories cannot be discovered from `manpath
-q`, bare `man -w`, or `$MANPATH`.
Solution:
Fall back to the direct manpage lookup when directory discovery fails.
Add a test for resolving `open(2)` through `goto_tag()` without manpath
data.
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
that can be achieved with `cmdwin`, which also gains extra UX
benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
"Entering Ex mode" message).
Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
cmdwin" in Lua.
- "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
- Drop POSIX Ex-mode quirks.
Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
(deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).
Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=>stdout
- -V1=>stderr
- CRLF input
- continue-after-error and exit codes
Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
answers: Nvim stops at end-of-input, skipping the rest of the script,
exit 0. Use ":lua io.read()" instead.
- If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
cmdline input from stdin.
## Flicker cause
ui2's `check_targets()` function creates the hidden ui2 windows with this call chain:
```
nvim_open_win()
win_set_buf()
do_buffer()
set_curbuf()
enter_buffer()
```
and `enter_buffer()` sets `need_fileinfo`:
fdc09be03c/src/nvim/buffer.c (L1837-L1839)
This is then picked up by `normal_redraw`:
fdc09be03c/src/nvim/normal.c (L1381-L1385)
The fileinfo message then causes a ui2 window to appear to display it:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L325-L330)
... which ends up calling `set_pos`, which registers an `on_key` handler:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L726-L728)
This handler closes the ui2 window when the user presses, for example, `l` (because the user's not focusing said window).
The handler eventually calls `check_targets()`:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L594-L595)
and `check_targets()` takes us back to the beginning, causing the ui2 window flicker
## Repro
```vim
=require("vim._core.ui2").enable()
set ch=0 shm-=F ve=all
e /tmp/x
```
Then hit `Ctrl-G` to show fileinfo (if not already shown) and hold `l`
## Fix
Effectively surround the ui2 window creating with `:silent`
Problem:
After expanding tabs with the `expandtab` option, if the old indent
matches the requested one, `vim.text.indent()` returns the input
unchanged.
The optimization path assumes that if old_indent == size, the input
wouldn't be changed, which is not correct when old_indent is formed by
expanded tabs.
Solution:
Apply the optimization only when `expandtab` is not set.
Changes:
- Removed the blank line before the first healthcheck header.
- Fixed a bug where the entire "Terminal" section of `vim.health` would
not appear if the `infocmp` executable was not found.
- Fixed a typo in `vim.lsp` when displaying the LSP log level.
Problem:
Options parsing is still painful for dict-style options.
Solution:
schema-maxxing => better `opt:get()` (will be the basis for `vim.o()`),
unified (and more-detailed) err msgs.
- Drop bespoke structure-builder in `_core/options.lua`.
- Define `schema` for all non-primitive options (except 'guicursor' and
statusline-style options); generate reified keysets `OptKeyDict`).
- Generate 'fillchars' => `fcs_tab`, 'listchars' => `lcs_tab`.
- `nvim_set_option_value`:
- Return the improved structures. Also from `vim.opt.x:get()`.
- Eliminate api <=> lua roundtrip, centralize option structure
handling.
- Improve/unify errors.
- Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated.
- Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`)
Error samples:
Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt):
E474: Unknown item 'foo'
E474: 'context' requires a number
E474: 'ver' number is out of range
E474: 'algorithm' must be one of: myers, minimal, patience, histogram
E474: 'filler' does not take a value
Related:
- #31084
- #34661
- #31820
- #14739
- #20107
- fix#18875
- :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}`
- Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options.
- fix#30296
- instead of `E474: Invalid argument`, errors now look like:
```
E474: Invalid value 'x', expected one of: single, double: ambiwidth=x
E474: Unknown item 'foo': diffopt=foo
E474: 'context' requires a number: diffopt=context:x
```
simplify `win_float_parse_option` from #26799.
Problem:
The preview-window (:pedit, etc.) always uses a split, but it would be
useful as a floatwin (or "popup").
Solution:
Support Vim's 'previewpopup' option.
Problem: When the terminal reports no colors ("t_Co" is 0 or 1) the
insert mode completion popup menu is not shown at all, while
the command line completion popup menu ('wildoptions' contains
"pum") is shown. In 'wildmenu' completion the current match
cannot be told apart from the other matches (Maxim Kim)
Solution: Show the insert mode completion popup menu regardless of the
number of colors and add "term" attributes to the default
highlighting of Pmenu, PmenuSel and PmenuThumb. The wildmenu
is drawn with the attributes of the status line, which is
reversed, and on most terminals the standout mode is the same
as the reverse mode, thus use the underline mode for the
default highlighting of WildMenu (Hirohito Higashi).
fixes: vim/vim#20800closes: vim/vim#2080352485e0d24
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem: filetype: .git-blame-ignore-revs file is not recognized
Solution: Detect .git-blame-ignore-revs file as gitrevlist filetype,
include syntax and filetype plugins (Fionn Fitzmaurice)
A Git revision list is
> a list of object names (i.e. one unabbreviated SHA-1 per line)...,
> comments (#), empty lines, and any leading and trailing whitespace are
> ignored.
(from Git's fsck.skipList documentation).
The default output of git rev-list will match this. It is also suitable
as input to git blame --ignore-revs-file.
This adds filetype detection matching .git-blame-ignore-revs files,
syntax highlighting and basic filetype settings.
closes: vim/vim#20702a8d5be9284
Co-authored-by: Fionn Fitzmaurice <fionn@github.com>
Problem:
The core behaviors of `nvim.dir` cannot be reused by consumers
such as the archive plugin, ssh browser, etc.
Solution:
- Define a basic "provider" shape.
- Extract the filesystem provider.
* fix(help): preserve multi-letter CTRL modifiers in :help subject
Problem: After PR 39537 normalized `CTRL-U-default` by excluding
`-` from the trigger char class, the regex `(CTRL%-[^{])([^-_\\])`
also fires between `CTRL-S` and the `H` of the `SHIFT` modifier
in tags like `c_CTRL-SHIFT-V`, splitting it into the non-existent
`c_CTRL-S_HIFT-V`.
Solution: Exclude uppercase letters from the char class so a
multi-letter modifier following `CTRL-X` (e.g. `SHIFT`, `ALT`) is
no longer split. The `-` exclusion from 39537 is preserved so
`i_CTRL-U-default` still works.
* fix(help): escape ~ in expr-=~? exception to keep regex valid
Problem: The `expr-=~?` exception in the tag alias table maps to
`=~?`, but in Vim's regex engine `~` refers to the previous
substitute pattern. With no prior substitute the pattern fails to
compile, so `:help expr-=~?` returns E149 even though the tag exists.
Solution: Escape `~` as \\\~` so the alias expands to a valid
regex (`=\\\~?`) that substring-matches the `expr-=~?` tag. Other
`expr-X?` entries are unaffected since they don't contain `~`.
* fix(help): don't insert _ before CTRL- when preceded by -
Problem: The rule `([^_])CTRL%- -> %1_CTRL-` inserts an underscore
between any non-underscore char and `CTRL-`, which wrongly rewrites
tags like `map-CTRL-C` and `telnet-CTRL-]` (where `CTRL-` is
literal text in the tag, not a key chord).
Solution: Exclude `-` from the trigger char class so a hyphen
immediately before `CTRL-` is preserved. The existing behavior for
`iCTRL-GCTRL-J` -> `i_CTRL-G_CTRL-J` is unaffected because the
`G` before `CTRL-J` is not `-`.
* fix(help): only treat ^X as caret notation for valid control chars
Problem: The regex `%^([^_])` converts any `^X` to `CTRL-X`,
including `:set^=` where `^=` is literal text in the tag, not a
caret-notation control character.
Solution: Restrict the transformation to caret-notation chars
(`%a` or one of `?@[\\]^{}`). This matches the C reference
behavior where `^X` is only converted when X is alphanumeric or one
of the control-notation punctuation chars. `{` is retained so
`^{char}` still maps to the `CTRL-{char}` placeholder tag.
Problem:
on_attach() calls refresh(), but there is no guarantee the attached
buffer is the current buffer. This can make linked editing request
handling assume the wrong window.
Solution:
Call refresh() only if the current buffer is attached. This keeps the
initial highlighting behavior while avoiding making incorrect request.
Problem:
When 'shellslash' is set, exepath() returns forward-slashed paths.
Passing that path to vim.system() can prevent cmd.exe from launching.
Solution:
Convert the resolved executable path to native separators before spawning.
Add a Windows regression test for cmd.exe with 'shellslash' enabled.
Problem:
The existing `showmode` overlay can immediately cover messages emitted while
Visual mode is active, including the `g CTRL-G` word count.
Solution:
Protect Visual mode messages with the existing message delay and temporarily
hide the previous last-line overlay until it is restored.
Problem:
LSP hover erroneously drops blank lines before a 4-space-indented
codeblock, which is not valid Markdown. This causes incorrect parsing
and wrong display.
Solution:
Fix `split_lines` so that it doesn't drop the blank line just before
a 4-space-indented codeblock.
fix https://github.com/neovim/neovim/issues/40860
Problem:
`vim.diagnostic.handlers.underline.show` throws `E565: Index out of bounds` when
it tries to underline a diagnostic whose `lnum` is past the end of the buffer.
This happens with stale diagnostics set on an unloaded buffer (e.g. via
`bufadd()`) that are drawn only after the buffer is loaded: by then the file on
disk can be shorter than the `lnum` the diagnostic carried. File pickers
(snacks.nvim) that open files via `bufadd` + `:buffer` hit this whenever an LSP
server has already emitted diagnostics for that URI.
Solution:
Skip diagnostics with an out-of-range `lnum` in the underline handler.
Other handlers `M.virtual_text.show()`, `M.signs.show()`, have a similar condition.
Problem:
A floating preview window (hover, signature help) converted to a normal
window (e.g. with CTRL-W_H or nvim_win_set_config()) is still closed by
the open_floating_preview() autocommands, and a later preview may focus
or close it as if it were still a float.
Solution:
When the preview window is no longer floating, remove its auto-close
autocommands and stop tracking it as the buffer's floating preview.
Closes#36659
Problems:
1. Can't get individual parts of a key-chord separately: modifiers, key.
2. Can't separate a key-combo into individual key-chords.
Solution:
Enhance `vim.keycode()` to optionally return a structured parse result
as a list of key-chords:
- `key_raw` the key-chord (problem 2)
- `mod` the modifiers of `key_raw` (problem 1)
- `key_orig` the key part of the key-chord, only here if differing from `key`
(this doesn't solve any of the above mentioned problems, but it may provide
useful and it's (in terms of code) free)
- `key` a normalized version of `key_orig` (solving problem 1), example(the
first is `key_orig` and second is `key`): `lt` and `<`, `Bar` and `|` (in
`<C-Bar>`)
Problem: filetype: hip files are not recognized
Solution: Detect *.hip files as hip filetype, include filetype, syntax
and indent plugins, update makemenu.vim and synmenu.vim (Young)
Round out HIP (Heterogeneous-compute Interface for Portability) support
to mirror the existing CUDA files:
- autoload/dist/ft.vim: detect the ".hip" extension as filetype "hip"
- ftplugin/hip.vim: behave like C++ by sourcing ftplugin/cpp.vim
- indent/hip.vim: use cindent, like indent/cuda.vim
- makemenu.vim / synmenu.vim: add a Syntax menu entry
The syntax/hip.vim file already sources syntax/cpp.vim and adds the
HIP-specific keywords, matching syntax/cuda.vim.
closes: vim/vim#20773b3ad239038
Co-authored-by: Young <young20050727@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>