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>
* 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>
Problem: values from completionList.itemDefaults always replace the
item's own commitCharacters and data. Since 3.18 a server can ask for
them to be merged instead.
Solution: Handle CompletionList.applyKind and advertise applyKindSupport.
Drop itemDefaults once folded into the items: get_items() runs twice on
the same result and a Merge isn't idempotent.
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#completionItemApplyKinds
Problem:
`nvim__ui_detach` was added in 85e0559d46 in order to implement
`detach_others` from Lua. Using Lua in this case is doing more harm than
good.
Solution:
Extract `ui_detach_channel`, which also allows it to be used for the
"self detach" path from `ex_detach`.
Bonus: the old MSWIN path always called `os_swap_to_hidden_console()`;
now `ui_detach_channel` only does so for a stdio channel. For the common
stdio TUI this is identical; for a socket UI it's more correct (no
parent console to swap).
Problem: LSP completion commitCharacters are not handled. Typing a
commit character (e.g. `.`, `(`, `;`) while a completion item is
selected does not accept the item first.
Solution: Store commit characters as a flat string in complete-items.
Check it before completion stops, accept the match and let
the character be inserted normally.
Problem: Every LSP capability that sends a request on a document change
to update its state was using its own buffer-local autocmd to do so.
That means there is a separate autocmd per buffer per active
capability/feature, and the actual code inside the autocmd callback was
virtually identical. The same problem occurred for capabilities that had
components to draw on the screen that had their own decoration providers.
Solution: Introduce a central `LspNotify` autocmd and decoration
provider in the capability module itself. New base class methods
`on_close` and `on_change` that take a client_id have been provided, for
`didClose` and `didOpen`/`didChange` notifications respectively. New
base class method `on_win` that takes topline and botline has been
provided to add extmarks or perform other work when lines of a buffer
are being drawn.
The autocmd callback loops through each active capability instance for
the buffer and calls a corresponding method with the triggering
client_id if it is currently attached to the buffer that triggered the
autocmd. The decoration provider just calls on_win for all active
capabilities on the buffer.
This slightly tweaks folding range to make use of these new client-id
specific callbacks.
Problem
The current list of properties for inlay hint resolve support includes a
non-existent "location". This field should be "label.location" according
to the specification. Tooltips and commands for inlay hint "parts"
aren't advertised as being resolvable.
Solution
Remove "location" and add "label.location", "label.tooltip", and
"label.command".
Closes#40740
Problem:
- No UI for listing extmarks.
- `:marks` doesn't support cmdline-completion.
Solution:
- Add completion and extmarks support to `:marks`.
- Update `get_buf_local_marks` to include the ":" (prompt-buffer) mark.
Problem:
This functions are most likely never used in the wild.
- They are redundant with `nvim_get_context` + `nvim_load_context`.
- The "context" concept was never fully developed and hasn't gained
traction.
Solution:
Drop these vimscript aliases, they are just extra cruft.
Problem:
After 25439dad7e, `opts` is optional, but not params that follow it.
Solution:
- Update `gen_api_dispatch.lua`, docs, tests.
- Enhance the `nvim_get_api_info()` api-metadata to include a boolean
flag indicating whether a parameter is optional:
```
[type, name, optional]
```
Note: Currently, optional params are assumed to be Dict/Array. Since we
don't yet have any use-cases of optional params following `opts`, the
build just checks this assumption and we can deal with it later if we
ever care to:
nvim_get_hl: optional param "foo" has type "Integer" but (currently)
we assume Dict/Array
Problem:
Continue separators normalization, and try to keep it at the
nvim <-> external boundary, e.g., `fn.xxx`, `api.xxx`, `:xxx`
Solution:
some key changes
- normalize `$HOME-windows`
- normalize entry points of changing directory
- `nvim_set_current_dir()`, `chdir()`
- normalize the named pipe
- `--listen` arg, `--server` arg, `:restart`
- `serverstart()`, `sockconnect()`, `serverstop()`
- make `expand()` respect 'shellslash' again
- clean up `did_set_shellslash`
- replace `forward_slash` with `TO_SLASH`
- remove obsolete `TMP_PATHSEPSTR`
- remove `slash_adjust` in `do_autocmd_dirchanged`?
- make `fnamemodify()` always return `/` (except when substituting
separators via `:s`, `:gs` ?)
Note:
- these funcs still apply `slash_adjust` on return, as before:
`:pwd`, `chdir()`, `exepath()`, `getcwd()`
- these funcs alwarys return `/`, unlike before the normalization PRs
- `getcompletion()`, `finddir()`, `findfile()`
Also
- clean up code, comments, formatting and tests
- move `TO_SLASH` from `f_chdir` to `changedir_func`
- move `TO_SLASH` from `f_bufadd` to `buflist_new`
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
Malformed server responses with `null` (vim.NIL) values, do not show
clear error messages.
Solution:
Assert two known, specific cases, to avoid user confusion.
Problem:
URI buffer names can end with a slash, but slash-ended directory
matching should not preempt URI filetype patterns.
Solution:
Do not use the slash shortcut for names with URI schemes, so those
continue through normal filetype matching.
Co-authored-by: Adam Karafyllidis <akisarou90@gmail.com>