mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 03:48:18 +00:00
fix(lsp): do not assume client capability exists in watchfiles check (#24550)
PR #23689 assumes `client.config.capabilities.workspace.didChangeWatchedFiles` exists when checking `dynamicRegistration`, but thats's true only if it was passed to `vim.lsp.start{_client}`. This caused #23806 (still an issue in v0.9.1; needs manual backport), but #23681 fixed it by defaulting `config.capabilities` to `make_client_capabilities` if not passed to `vim.lsp.start{_client}`. However, the bug resurfaces on HEAD if you provide a non-nil `capabilities` to `vim.lsp.start{_client}` with missing fields (e.g: not made via `make_client_capabilities`). From what I see, the spec says such missing fields should be interpreted as an absence of the capability (including those indicated by missing sub-fields): https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#clientCapabilities Also, suggest `vim.empty_dict()` for an empty dict in `:h vim.lsp.start_client()` (`{[vim.type_idx]=vim.types.dictionary}` no longer works anyway, probably since the cjson switch).
This commit is contained in:
@@ -4402,58 +4402,79 @@ describe('LSP', function()
|
||||
|
||||
it("ignores registrations by servers when the client doesn't advertise support", function()
|
||||
exec_lua(create_server_definition)
|
||||
local result = exec_lua([[
|
||||
local server = _create_server()
|
||||
local client_id = vim.lsp.start({
|
||||
name = 'watchfiles-test',
|
||||
cmd = server.cmd,
|
||||
root_dir = 'some_dir',
|
||||
capabilities = {
|
||||
workspace = {
|
||||
didChangeWatchedFiles = {
|
||||
dynamicRegistration = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
local watching = false
|
||||
exec_lua([[
|
||||
server = _create_server()
|
||||
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
|
||||
-- Since the registration is ignored, this should not execute and `watching` should stay false
|
||||
watching = true
|
||||
return function() end
|
||||
end
|
||||
]])
|
||||
|
||||
vim.lsp.handlers['client/registerCapability'](nil, {
|
||||
registrations = {
|
||||
{
|
||||
id = 'watchfiles-test-kind',
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
registerOptions = {
|
||||
watchers = {
|
||||
{
|
||||
globPattern = '**/*',
|
||||
local function check_registered(capabilities)
|
||||
return exec_lua([[
|
||||
watching = false
|
||||
local client_id = vim.lsp.start({
|
||||
name = 'watchfiles-test',
|
||||
cmd = server.cmd,
|
||||
root_dir = 'some_dir',
|
||||
capabilities = ...,
|
||||
}, {
|
||||
reuse_client = function() return false end,
|
||||
})
|
||||
|
||||
vim.lsp.handlers['client/registerCapability'](nil, {
|
||||
registrations = {
|
||||
{
|
||||
id = 'watchfiles-test-kind',
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
registerOptions = {
|
||||
watchers = {
|
||||
{
|
||||
globPattern = '**/*',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, { client_id = client_id })
|
||||
}, { client_id = client_id })
|
||||
|
||||
-- Ensure no errors occur when unregistering something that was never really registered.
|
||||
vim.lsp.handlers['client/unregisterCapability'](nil, {
|
||||
unregisterations = {
|
||||
{
|
||||
id = 'watchfiles-test-kind',
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
-- Ensure no errors occur when unregistering something that was never really registered.
|
||||
vim.lsp.handlers['client/unregisterCapability'](nil, {
|
||||
unregisterations = {
|
||||
{
|
||||
id = 'watchfiles-test-kind',
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
},
|
||||
},
|
||||
}, { client_id = client_id })
|
||||
|
||||
vim.lsp.stop_client(client_id, true)
|
||||
return watching
|
||||
]], capabilities)
|
||||
end
|
||||
|
||||
eq(true, check_registered(nil)) -- start{_client}() defaults to make_client_capabilities().
|
||||
eq(false, check_registered(vim.empty_dict()))
|
||||
eq(false, check_registered({
|
||||
workspace = {
|
||||
ignoreMe = true,
|
||||
},
|
||||
}))
|
||||
eq(false, check_registered({
|
||||
workspace = {
|
||||
didChangeWatchedFiles = {
|
||||
dynamicRegistration = false,
|
||||
},
|
||||
},
|
||||
}, { client_id = client_id })
|
||||
|
||||
return watching
|
||||
]])
|
||||
|
||||
eq(false, result)
|
||||
}))
|
||||
eq(true, check_registered({
|
||||
workspace = {
|
||||
didChangeWatchedFiles = {
|
||||
dynamicRegistration = true,
|
||||
},
|
||||
},
|
||||
}))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
Reference in New Issue
Block a user