Problem: During initial "bootstrap" via lockfile synchronization, the
whole plugin specification is reconstructed from the lockfile data,
ignoring potential user changes added in the first `vim.pack.add()`.
This is enough in most situations since it is the only data needed
for actual installation.
However, this affects specification passed to `PackChanged[Pre]`
events. In particular, `data` field is missing which can be a problem
if there is a `PackChanged kind=install` hook that uses that field
(like with some kind of `build` method used during install).
And there might be different `version` set in `vim.pack.add()`.
Solution: Pass the `specs` input of the first `vim.pack.add()` down to
lockfile synchronization and use it to reconstruct plugin
specification for the to-be-installed plugin. If present among the
user's `specs`, it is used but with forced `src` from the lockfile (as
it is the one used during installation).
Note that this still has a caveat when using separate
`vim.pack.add()`, as only the specs from the first input (when the
lockfile synchronization happens) is taken into account.
Problem: Color completion items display as plain text without visual preview
Solution: Parse RGB/hex colors from documentation and render with colored symbol ■
Closing the quickfix window previously triggered a WinClosed autocmd
that deleted all difftool autocmds and pushed an empty quickfix list,
making the difftool non-functional. Users who close the quickfix window
to gain screen real estate for viewing diffs had no way to continue
navigating entries.
Remove the qf_win tracking and its associated WinClosed autocmd so that
closing the quickfix window no longer tears down the difftool state.
Closing either diff window still performs full cleanup as before.
The BufWinEnter handler no longer passes with_qf to diff_files, so
navigating entries while the quickfix window is closed reuses the
existing diff layout without forcing a layout rebuild.
Fixes#37388
Problem:
Regression from b99cdd0:
Pull diagnostics (from `textDocument/diagnostic`) and push diagnostics
(from `textDocument/publishDiagnostics`) use the same namespace, which
is a problem when using language servers that publish two different sets
of diagnostics on push vs pull, like rust-analyzer (see
https://github.com/rust-lang/rust-analyzer/issues/18709#issuecomment-2551394047).
Solution:
Rename `is_pull` to `pull_id` which accepts a pull namespace instead of
just a boolean.
The wait added in #37853 doesn't seem to do anything as request is sent
immediately on InsertLeave, and the number 4 also seems wrong. Instead,
the actual cause for the flakiness that the feed() (and hence the buffer
change) may arrive before the scheduled initialization of capabilities,
causing there be only only one textDocument/semanticTokens/full request
instead of two.
This is a better way to prevent parallel tests from interfering with
each other, as there are many ways files can be created and deleted in
tests, so enforcing different file names is hard.
Using $TMPDIR can also work in most cases, but 'backipskip' etc. have
special defaults for $TMPDIR.
Symlink runtime/, src/, test/ and README.md to Xtest_xdg dir to make
tests more convenient (and symlinking test/ is required for busted).
Also, use README.md instead of test/README.md in the Ex mode inccommand
test, as test/README.md no longer contains 'N' char.
Problem: Fake LSP server does not timeout or respond to SIGTERM as it
does not run the event loop.
Solution: Instead of io.read(), use stdioopen()'s on_stdin callback to
accumulate input and use vim.wait() to wait for input.
Also, in the test suite, don't stop a session when it's not running, as
calling uv.stop() outside uv.run() will instead cause the next uv.run()
to stop immediately, which cancels the next RPC request.
Define a CMake target for every subdirectory of test/functional that
contains functional tests, and a functionaltest_parallel target that
depends on all those targets, allowing multiple test runners to run in
parallel.
On CI, use at most 2 parallel test runners, as using more may increase
system load and make tests unstable.
The [spec for `workspace/configuration`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration)
marks the `section` property of each item in `items` optional.
Therefore, I believe it violates the spec to skip over items without
a section, because then the length of the results won't match the length
of a valid `items` input. The spec does not elaborate on _what_ to
return in this case, but I don't think it would be controversial to say
that returning the full configuration, as done for an empty string, is
the most natural interpretation.
That empty string case, by the way, was initially [added in
response](5da124fc82)
to a real world implementation requesting it. I don't have a similar
real world implementation to point to for the omitted `section`, but
I would note that `getConfiguration()` from `vscode-languageserver-node`
[defaults to a request with no section](d859bb14d1/server/src/common/configuration.ts (L24-L26))
when called with no arguments. I surmise that this is intended as a way
to retrieve the full configuration.
- Refactor LSP client to use unified provider-based capability lookup for
diagnostics and other features.
- Introduce `_provider_value_get` to abstract capability retrieval,
supporting both static and dynamic registrations.
- Update diagnostic handling and protocol mappings to leverage
provider-centric logic.
Problem: Executing `nvim_buf_delete()` does not guarantee that the
window which shows the buffer is going to close after `:write` or
`:quit`. In particular, if there is no listed buffer present.
Solution: Explicitly close the window that was created for confirmation
buffer. Use `pcall` to catch cases when the window was already closed
or when it is the last window.
Problem:
After eaacdc9, complete with emmylua_ls error with:
runtime/lua/vim/lsp/completion.lua:586: attempt to get length of field
'items' (a nil value)
Solution:
Result can be CompletionItem[] according the spec:
> If a `CompletionItem[]` is provided, it is interpreted to be complete,
> so it is the same as `{ isIncomplete: false, items }`
Problem:
Empty response affects server start boundary computed before.
Solution:
Ignore empty responses. This is mostly micro-optimization that avoids
extending existing results with empty responses.
Problem:
Diagnostic lifecycle invariants (clearing on empty publish and buffer
deletion) were previously implicit and not directly covered by functional
tests, allowing regressions to go unnoticed.
Solution:
Add functional regression tests asserting that diagnostics are cleared
when an LSP server publishes an empty diagnostic set and when the
associated buffer is deleted. Assertions are scoped to the client
diagnostic namespace and use public diagnostic APIs only.
Problem: Code lenses currently display as virtual text on the same line
and after the relevant item. While the spec does not say how lenses
should be rendered, above the line is most typical. For longer lines,
lenses rendered as virtual text can run off the side of the screen.
Solution: Display lenses as virtual lines above the text.
Closes https://github.com/neovim/neovim/issues/33923
Co-authored-by: Yi Ming <ofseed@foxmail.com>
From the LSP Spec:
> There are two uses cases where it can be beneficial to only compute
> semantic tokens for a visible range:
>
> - for faster rendering of the tokens in the user interface when a user
> opens a file. In this use case, servers should also implement the
> textDocument/semanticTokens/full request as well to allow for flicker
> free scrolling and semantic coloring of a minimap.
> - if computing semantic tokens for a full document is too expensive,
> servers can only provide a range call. In this case, the client might
> not render a minimap correctly or might even decide to not show any
> semantic tokens at all.
This commit unifies the usage of range and full/delta requests as
recommended by the LSP spec and aligns neovim with the way other LSP
clients use these request types for semantic tokens.
When a server supports range requests, neovim will simultaneously send a
range request and a full/delta request when first opening a file, and
will continue to issue range requests until a full response is
processed. At that point, range requests cease and full (or delta)
requests are used going forward. The range request should allow servers
to return a result faster for quicker highlighting of the file while it
works on the potentially more expensive full result. If a server decides
the full result is too expensive, it can just error out that request,
and neovim will continue to use range requests.
This commit also fixes and cleans up some other things:
- gen_lsp: registrationMethod or registrationOptions imply dynamic
registration support
- move autocmd creation/deletion to on_attach/on_detach
- debounce requests due to server refresh notifications
- fix off by one issue in tokens_to_ranges() iteration
Previously, adjust_start_col returned nil when completion items had
different start position from lsp textEdit range
This caused the completion to fall back to \k*$ which ignores the
non-keyword characters
Changes:
- adjust_start_col: now returns the minimum start postion among all
items instead of nil
- _lsp_to_complete_items - normalizes the items by adding the gap between
current and minimum start
Fixes: https://github.com/neovim/neovim/issues/37441
Problem:
Two cases lsp.enable() won't work in the first FileType event
1. lsp.enable luals inside FileType or ftplugin/lua.lua, then:
```
nvim a.lua
```
2. lsp.enable luals inside FileType or ftplugin/lua.lua, then:
```
nvim -> :edit a.lua -> :mksession! | restart +qa! so Session.vim
```
Solution:
Currently `v:vim_did_enter` is used to detected two cases:
1. "maunally enabled" (lsp.enable() or `:lsp enable`)
2. "inside FileType event"
To detect 2. correctly we use did_filetype().
* cache all tokens from various range requests for a given document
version
- all new token highlights are merged with previous highlights to
maintain order and the "marked" property
- this allows the tokens to stop flickering once they've loaded once
per document version
* abandon the processing coroutine if the request_id has changed instead
of relying only on the document version
- this will improve efficiency if a new range request is made while a
previous one was processing its result
* apply new highlights from processing coroutine directly to the current
result when the version hasn't changed
- this allows new highlights to be immediately drawable once they've
processed instead of waiting for the whole response to be processed
at once
* rpc layer was changed to provide the request ID back in success
callbacks, which is then provided as a request_id field on the handler
context to lsp handlers
Problem: A lot of test cases require executing `vim.pack.add()` inside
`testnvim` instance to install and/or add plugins. This requires
access to the information about tested repo sources (stored in a Lua
variable inside a runner instance), so it needs to go
`exec_lua(function() vim.pack.add({...}) end)` route, which in
formatted form adds two more lines. Since it is very frequent, it pads
test files with (mostly avoidable and unncessary) lines.
Solution: Add `vim_pack_add()` helper specifically to execute
`vim.pack.add` inside `testnvim` instance. Use it where possible:
usually when `vim.pack.add` is not a subject of the test. It is not
quite doable for some cases, though:
- When error in `vim.pack.add` is tested.
- When specification includes `vim.version.range` (since `exec_lua`
seems to not transfer necessary class metatables).
This removes ~100 lines from the file at the cost of sometimes using
`vim_pack_add` and sometimes having to reside to `vim.pack.add`.
Which seems like a positive trade-off.
This also allows making a more compact `exec_lua('vim.pack.update()')`
instructions since `vim.pack.update` doesn't depend on the upvalues
stored in test runner instance.
Problem: `vim.pack` tests might benefit from a cleanup
Solution: Do the cleanup:
- Use `t.retry` instead of full `vim.uv.sleep` to make tests quicker.
- Use `pack_assert_content` helper for a common task of checking the
content of a special Lua file inside an installed plugin. This is
used as a proxy of installed plugin's state on the disk.
- Use `([[...]]):format()` approach (instead of array of strings) in
one more place. Should improve readability.
Problem: Installing plugin with submodules doesn't check out their
state (due to `git clone --no-checkout` to not end up with default
branch code in case of invalid `version`).
Updating a plugin with submodules doesn't update their state.
Solution: Update `git_checkout` helper to account for submodules.
Another approach would be `git checkout --recurse-submodules ...`,
but that doesn't seem to allow `--filter=blob:none` for submodules,
which is nice to have.
Also make `git_clone` wrapper simpler since `--no-checkout` makes
`--recurse-submodules` and `--also-filter-submodules` do nothing.
Problem: The `add` startup tests mock startup process which requires
*some* amount of time to be done. Previous solution with `vim.wait`
to wait just enough time to register that startup script has finished
doesn't seem to work as intended (it just wait full time). Its timeout
is also seems to be barely enough to pass on Windows CI. Which will be
a problem with more `git` actions done on startup in the future/next
commit.
Solution: Just sleep predetermined amount of time and explicitly check
if startup script finished executing.
Problem: Installing plugin is done via `git clone --no-checkout ...`
(to not end up with default branch code in case of invalid `version`).
This leaves cloned repo in a state that `git stash` will actually add
an entry to the stash list. Although not critical, better to not have
that if possible.
Solution: explicitly skip `git stash` step in checkout during install.
Problem:
vim.lsp.tagfunc looks for the presence of 'c' (cursor) flag and issues
sync textDocument/definition requests to all clients, otherwise
workspace/symbol requests. But 'c' flag can also be set during the
insert mode completion, e.g. with an empty tag completion query, the tag
func receives pattern of '\<\k\k' with flags 'cir'.
Solution:
check for 'i' (insert mode completion) flag and don't issue any LSP
requests, return vim.NIL for immediate fallback to tags.
Problem:
The `"Running healthchecks..."` message doesn't inform the user much and
is a hack from before we got a way to emit actual progress messages.
Solution:
Use `nvim_echo` to emit progress messages showing the name of the report
that is currently running.
Work on #37166
- Dynamic Registration Tracking via Provider
- Supports_Method
- Multiple Registrations
- RegistrationOptions may dictate support for a method
Problem: Deleting active plugins can lead to a situation when it is
reinstalled after restart.
Solution: Suggest "delete" code action only for not active plugins.
Whether a plugin is not active is visible by a hint in its header.