Commit Graph

4769 Commits

Author SHA1 Message Date
Yi Ming
680ab13951 refactor(lsp): avoid using coroutine when parsing frames 2026-05-22 18:20:55 +08:00
Yi Ming
0e81835fae refactor(lsp): message stream abstraction for message framing 2026-05-22 18:20:51 +08:00
Yi Ming
929e644a5a refactor(lsp): move vim.lsp._transport to vim.net._transport 2026-05-22 18:19:19 +08:00
Justin M. Keyes
b576807410 Merge #39939 from marcuscaisey/lsp-completion-details 2026-05-22 04:39:55 -04:00
Maria Solano
71c72c3409 fix(lsp): validate that workspace_edit isn't nil (#39947) 2026-05-21 19:00:02 -07:00
Marcus Caisey
2845f95171 fix(lsp): advertise that CompletionItem.detail can be resolved (#39934)
Problem:
We can resolve the `CompletionItem.detail` field but don't advertise
this capability.

Solution:
Add `detail` to
`textDocument.completion.completionItem.resolveSupport.properties`.
2026-05-21 13:57:53 -07:00
Marcus Caisey
c75365d22a refactor(lsp): centralise complete item info generation logic
Problem:
The logic for generating the complete item `info` is spread across
`_lsp_to_complete_items`, the `CompleteChanged` event handler, and
`CompletionResolver:request`. This has previously caused the `info`
shown for resolved (via `completionItem/resolve`) and unresolved items
to differ.

Solution:
Centralise the logic in a new `complete_item_info` function which is now
solely responsible for determining:
1. The `info` to show.
2. The markup kind of the `info`.
3. Whether the `info` is complete.

This simplifies the interaction between the 3 functions mentioned in the
problem:
- `_lsp_to_complete_items` calls `complete_item_info` and passes along
  the markup kind and whether the item needs resolving via the complete
  item's `user_data`.
- The `CompleteChanged` consumes the markup kind and whether the
  item needs resolving from the complete item's `user_data`.
- `CompletionResolver:request`, like `_lsp_to_complete_items` calls
  `complete_item_info` again and updates the current `info` if it's
  changed.
2026-05-21 18:22:13 +01:00
Marcus Caisey
d6d03716cf fix(lsp): show detail in popup when server can't completionItem/resolve
Problem:
`CompletionItem.detail` is only shown in the info popup if the server
supports `completionItem/resolve`.

Solution:
If the server doesn't support `completionItem/resolve`, prepend the
complete item `info` with `CompletionItem.detail` in a fenced codeblock,
same as we do when the server supports `completionItem/resolve`.

To ensure that completion items are displayed in the same way,
regardless of whether the server supports `completionItem/resolve`, i've
extracted out the test logic from the `selecting an item triggers
completionItem/resolve + (snippet) preview` case so that we can run the
same tests against a server which supports `completionItem/resolve` and
one which doesn't. Hopefully this should prevent the two behaviours
diverging again.
2026-05-21 18:22:13 +01:00
Marcus Caisey
ce7df01391 fix(lsp): resolve CompletionItem if resolvable fields aren't populated
Problem:
If `CompletionItem.documentation` is populated but `detail` is not, then
`detail` is not resolved.

Solution:
Ensure that we resolve a `CompletionItem` if either `detail` or
`documentation` are not populated.

I've also removed `detail` from the popup menu since otherwise it will
be populated in both the popup menu and the info popup after the
`CompletionItem` has been resolved. I think the info popup is the best
place for it anyway as when there is a completion item with a long popup
menu entry (when `detail` is a medium/long function signature for
instance), the whole popup menu gets widened and this steals horizontal
space that could be used to display the `documentation`. Now with
`detail` and `documentation` in the info popup, they share the same
horizontal space. This also aligns with how VSCode, nvim-cmp, blink.cmp,
and mini.nvim display `detail`.
2026-05-21 18:15:14 +01:00
Marcus Caisey
10a53e7637 fix(lsp): generate snippet preview from resolved textEdit.newText
Problem:
When a resolved `CompletionItem` with kind `Snippet` populates
`textEdit` instead of `insertText`, the contents are not previewed.

Solution:
Generate the snippet preview from `textEdit.newText` as well.
2026-05-21 17:47:08 +01:00
luukvbaal
89431707a0 fix(ui2): unable to stop display of very long message #39823
Problem:  Processing of a very long message may take a long time; there
          is no visual feedback of work being done, and no way to abort
          processing.
          Calculating text height for spill indicator inhibits
          performance for very long message.

Solution: Whenever writing part of a message is taking longer than 100ms,
          show the first part of the message, while checking for CTRL-C.
          Calculate ('wrap'-ed) text height accurately until 'lines',
          use line count beyond that.
2026-05-21 05:24:39 -04:00
Kyle
7337e02563 refactor(docs): generate tui.txt $NVIM_TERMDEFS keys #39836
Problem:
Potential documentation drift in `tui.txt` if fields for
`$NVIM_TERMDEFS` change.

Solution:
Generate docs for `tui.txt`. Add `brief_xform` to `gen_vimdoc.lua` to
allow transforming briefs during generation.
2026-05-21 04:39:45 -04:00
Maria Solano
3883cba996 fix(lsp): flush change notifications on save (#39894) 2026-05-20 16:33:10 -07:00
Justin M. Keyes
9aa4608401 refactor: introduce nvim_on internally #39883
Problem:
`nvim_create_autocmd` is too verbose and its `callback` requires extra
"nesting".

Solution:
Introduce `nvim_on`. Start using it internally. Then we can get a feel
for how it should look before making it public.
2026-05-20 17:33:01 -04:00
Justin M. Keyes
799cbfff85 fix(vim.secure): read() command injection vulnerability #39918
Problem:
Malicious filename can execute code because of ":" cmdline expansion.

Solution:
Use `fnameescape()`.

fix https://github.com/neovim/neovim/issues/39914
2026-05-20 15:27:43 -04:00
Justin M. Keyes
e446779726 fix(health): "Create bug report" button 2026-05-20 14:09:20 +02:00
Justin M. Keyes
74ea3875b4 fix(health): show Nvim-owned checks at the top 2026-05-20 14:09:20 +02:00
Justin M. Keyes
6674329d15 feat(health): highlight current buffer
Problem:
A benefit of the old `:LspInfo` was that it showed info related to the
"current buffer" a bit more clearly.

Solution:
Highlight the "current buffer" in the LSP checkhealth report.
2026-05-20 14:09:20 +02:00
Justin M. Keyes
7812087341 fix(health): cleanup LSP healthcheck
Problem:
filewatcher and position-encoding info is reported after the big list of
client details.

Solution:
- report the info in the top-level, not in dedicated subsections.
2026-05-20 14:09:20 +02:00
Justin M. Keyes
735a7d0c9e feat(fswatch): report filewatchers in :checkhealth 2026-05-20 14:09:20 +02:00
Olivia Kinnear
f0c3cc2398 fix(pack): collect "Removed plugin" into one message #39840 2026-05-20 06:45:05 -04:00
Justin M. Keyes
1f75fef951 Merge #39889 from ofseed/pos-util
refactor(pos,range): drop `to_cursor`, extract `vim.pos._util`
2026-05-20 05:35:09 -04:00
Justin M. Keyes
f1fad32e2e docs: misc, custom text-object #39877
text-object-define is a pattern I found in tpope's plugins (e.g.
https://github.com/tpope/vim-jdaddy) which shows an elegant way to
define a text-object. (Any mistakes in the example are my fault.)
2026-05-20 05:21:27 -04:00
Yi Ming
cd3b544611 refactor(pos,range): add missing validators and improve the docs
Problem:
Our documentation is incomplete or inconsistent in several ways:
- Some public APIs lack corresponding validators.
- Some public APIs lack usage examples.
- The meaning of some return values or parameters is not clearly explained.

Solution:
Add the missing validators, examples, and clarifications.
2026-05-20 16:23:03 +08:00
Yi Ming
b1c1f32089 refactor(pos,range): extract vim.pos._util
Problem:
- To share logic, creating a `vim.Range` currently creates two `vim.Pos` values
  as intermediates, which causes unnecessary table allocations.
- `pos.lua` and `range.lua` contain some overlapping logic.

Solution:
Add `vim.pos._util`, a module for handling
positions represented directly by `row` and `col`.
2026-05-20 16:23:03 +08:00
Yi Ming
8d1233a144 feat(pos,range)!: remove range.cursor() and range:to_cursor(),
Problem:
- A window can only have one cursor, ranges selected by the cursor are typically
  obtained by marks like ">" and "<", instead of calling get_cursor() twice.
- `vim.Range` is described as end-exclusive,
  but the current `range.cursor()`/`range:to_cursor()` are end-inclusive.
- Conversion between `vim.Range` and mark-indexed range can be done by
  `range.mark()`/`range:to_mark()`

Solution:
Remove `range.cursor()` and `range:to_cursor()`,
2026-05-20 16:23:01 +08:00
Barrett Ruth
5181984db9 fix(api): nvim_exec_autocmds({buf=x}) runs in buffer context #39061
Problem: `nvim_exec_autocmds({ buf = ... })` matches the target buffer, but callbacks and modelines run with the caller buffer current rather than the target buffer.

Solution: Execute the buffered path in prepared target-buffer context and restore the caller afterward.
2026-05-20 03:48:55 -04:00
Olivia Kinnear
ea8f1463dd fix(lua): fields of nvim.spellfile.Opts are optional #39902 2026-05-20 02:47:35 -04:00
zeertzjq
f3bb21e71d vim-patch:9.2.0500: filetype: some html files wrongly recognized as htmlangular (#39880)
Problem:  filetype: some html files are wrongly recognized as htmlangular
Solution: Use the \< atom to anchor ng-template and ng-content to start
          of word (truffle)

Prevent false-positive htmlangular detection on words containing
'ng-template' or 'ng-content' as a substring (e.g. 'song-template',
'sing-content'). Anchor both branches with \< to require a word start,
matching the \<DTD\s\+XHTML\s idiom used five lines below.

related: neovim/neovim#39778.
closes:  vim/vim#20246

354ab1a69e

Co-authored-by: truffle <truffleagent@gmail.com>
2026-05-19 08:42:05 +08:00
Justin M. Keyes
d8ec793379 Merge #39822 from ofseed/pos-mark
feat(pos,range): pos:to_mark(), pos.mark(), range:to_mark(), range.mark()
2026-05-18 10:45:21 -04:00
Yi Ming
ff43f1950e feat(lsp)!: deprecate vim.lsp.util.character_offset() 2026-05-18 22:19:07 +08:00
Yi Ming
856bc6d284 fix(range): handle inclusive/exclusive positions on multibyte characters 2026-05-18 22:19:07 +08:00
Yi Ming
f2b031136f feat(pos,range): pos:to_mark(), pos.mark(), range:to_mark(), range.mark()
Problem:
Ranges represented by marks are usually end-inclusive,
but the range utilities we provided are end-exclusive.

Solution:
Add pos:to_mark(), pos.mark(), range:to_mark(), and range.mark().
2026-05-18 22:19:00 +08:00
Justin M. Keyes
b20fa21ac5 Merge #39832 from justinmk/doc2
docs: misc, remove legacy/textobjects_spec.lua
2026-05-18 09:25:05 -04:00
glepnir
3ffe29d679 fix(lsp): preserve trigger chars on completion #39850
Problem:
After 767fbd8, typing trigger chars would open completion but the
chars were removed.

Solution:
Use filterText fallback so selected item respects typed trigger chars.
2026-05-18 05:25:41 -04:00
Justin M. Keyes
82cc02d19f docs: misc, $NVIM_TERMDEFS 2026-05-18 11:20:18 +02:00
Kyle
84d5c5f4bf feat(tui): $NVIM_TERMDEFS can override builtin terminfo #39555
Problem:
- Windows users can't use terminfo to configure their terminal
  capabilities. #37274
- Terminfo definitions sometimes get out of date or are simply
  inaccurate.
- Eventually, we may want to drop terminfo, relying primarily on
  built-in definitions. Users will still need some flexibility.

Solution:
Support $NVIM_TERMDEFS environment variable, which is JSON data that
defines "terminfo" definitions that override our builtin terminfo.
2026-05-17 13:02:46 -04:00
Puneet Dixit
fff9897ce3 fix(startup): emitting useless OptionSet #39830
Problem:
During startup, we manually trigger a useless and misleading `OptionSet`
event, which doesn't set `v:option_*` values (this is a limitation of
`nvim_exec_autocmds`).
ad4bc2d90c/runtime/lua/vim/_core/defaults.lua (L939).

Solution:
The `nvim_exec_autocmds('OptionSet',…)` call does not serve any purpose
since 5cbb9d613b, so just drop it.
2026-05-17 12:18:24 -04:00
glepnir
767fbd88ff fix(lsp): fallback to filterText for non-matching PlainText items #39695
Problem:
PlainText completion items used `textEdit.newText` or `insertText` as
the completion word even when they did not match the typed prefix. This
could break popup completion behavior like 'completeopt+=longest'.

Solution:
Fall back to `filterText` when `newText` or `insertText` does not match
the typed prefix.
2026-05-17 11:58:49 -04:00
Justin M. Keyes
a562fb33ca Merge #39820 from echasnovski/pack-get-more 2026-05-17 11:51:39 -04:00
Evgeni Chasnovski
db0682fe50 feat(ui): vim.ui.input(opts.scope) #39570
Problem: There is no way for a `vim.ui.input` caller to indicate for
  which scope the input is. As in "This input is for something at cursor
  scope". This information can be useful for `vim.ui.input`
  implementation to tweak its behavior and presentation:
  - Show different floating window depending on the scope. For example:
    - Near cursor for "cursor" scope.
    - At line start for "line" scope.
    - In window corner for "buffer" and "window" scopes.
    - In whole editor corner for "tabpage", "editor", "project" scopes.
  - Navigate through history only for inputs with the same scope.

Solution: Document new `opts.scope` for `vim.ui.input`. Use it in the
  codebase.
2026-05-17 11:34:06 -04:00
Justin M. Keyes
846b8b2420 refactor: group nvim_buf_call, nvim_win_call tests #39828 2026-05-17 11:20:54 -04:00
Evgeni Chasnovski
8f379be261 feat(pack): update get() to be able to fetch data from plugin source
Problem: There is currently no convenient way to programmatically check
  for new updates from plugin source. Running `vim.pack.update()` is one
  approach, but it opens a confirmation buffer that requires a manual
  action to close.

Solution: Add `opts.offline` to `vim.pack.get()` that will first fetch
  new updates from plugin source before computing the output.
2026-05-17 18:17:13 +03:00
Evgeni Chasnovski
b9c4329c35 feat(pack): update get() to return revision of a pending update
Problem: No convenient way to programmatically get the revision that
  would be checked out after `vim.pack.update()` (with `offline=true`).
  Doing this manually requires resolving `spec.version` which is not
  trivial.  This data can be useful for custom reporting of pending
  updates or third party confirmation step.

Solution: Make `get()` include a new field for the revision that points
  at the state after applying pending update. This is also the same as
  the revision of resolved `spec.version`.
2026-05-17 18:14:01 +03:00
bfredl
0aa7d2f4d5 feat(api): nvim_buf_call, win_call can has multiple return values #39801
from the "because we can and it is not much code" department. (diffcount
excluding tests is actually negative)

fixes https://github.com/neovim/neovim/issues/39636#issuecomment-4397141270
2026-05-17 10:25:22 -04:00
Justin M. Keyes
e572c9c80a feat(api): tab-local option scope #39811
Problem:
2d795face6 added support for tab-local options ('cmdheight')
to `nvim_get_option_value`, but not to:

    nvim_get_option_info2()
    nvim_set_option_value(…, { tab = … })
    gettabwinvar()

Solution:
- Update `options.lua` to model tab-local options. Introduce `kOptScopeTab`.
- Handle tab scope in the options layer so it works for all options APIs.

Note:
- No change to `gettabvar()`. Not sure if needed/wanted.

fix https://github.com/neovim/neovim/issues/31140
2026-05-17 10:24:46 -04:00
Ayose C.
3ace049c6a feat(vim.hl): vim.hl.hl_op() #39777
Problem:
vim.hl.on_yank() only works for TextYankPost, not TextPutPost.

Solution:
Introduce hl_op().
Deprecate on_yank().
2026-05-17 09:56:37 -04:00
Evgeni Chasnovski
8d100483e0 feat(pack): update get() to take rev from actual repo if info=true
Problem: `vim.pack.get()` always uses lockfile as the source for the
  `rev` field. This is fast, but may be misleading in case of
  a corrupted lockfile.

Solution: Compute revision from Git repo on disk if `info=true`
  (default), use lockfile otherwise. This does increase execution time
  (as a result of one extra `git ...` call for every plugin), but
  `info=true` is already designed to be informative and not necessarily
  fast.
2026-05-17 10:49:48 +03:00
yashlala
7d99104058 feat(events): add TabMoved autocommand event #24137
Problem:
No way to handle a "tab moved" event.
Use-case: tabline plugins may cache tab labels, and need to know when to
invalidate their cache.

Solution:
Add a `TabMoved` event that triggers whenever tabs are reordered via `:tabmove`
or via mouse click-and-drag.
2026-05-16 13:55:42 -04:00
Yi Ming
a7f09db9de refactor(lsp): remove some private utility functions
Problem:
`make_position_params`/`get_line_byte_from_position`/`make_line_range_params`
are private functions and their functionality can be replaced by `vim.pos` now.

Solution:
Remove them, use `vim.pos` instead.
2026-05-16 23:47:38 +08:00