mirror of
https://github.com/neovim/neovim.git
synced 2026-06-16 00:31:16 +00:00
fix(lsp): dynamic registration for off-spec method #39544
Problem:
LSP clients previously did not handle dynamic registration for off-spec methods
Solution:
Update the client logic to assume support for dynamic registration when
the method is unknown. Adjust the registration provider fallback and
enhance tests to verify correct behaviour for unknown methods and their
registration options. This improves compatibility with servers using
custom dynamic registrations.
AI-assisted: OpenCode
(cherry picked from commit 344d984ed2)
This commit is contained in:
@@ -948,6 +948,10 @@ function Client:_supports_registration(method)
|
||||
end
|
||||
local provider = self:_registration_provider(method)
|
||||
local capability_path = lsp.protocol._provider_to_client_registration[provider]
|
||||
if not capability_path then
|
||||
-- If we don't know about the method, assume the client supports dynamic registration for it.
|
||||
return true
|
||||
end
|
||||
local capability = vim.tbl_get(self.capabilities, unpack(capability_path))
|
||||
return type(capability) == 'table' and capability.dynamicRegistration
|
||||
end
|
||||
@@ -956,7 +960,7 @@ end
|
||||
--- @param method vim.lsp.protocol.Method | vim.lsp.protocol.Method.Registration
|
||||
function Client:_registration_provider(method)
|
||||
local capability_path = lsp.protocol._request_name_to_server_capability[method]
|
||||
return capability_path and capability_path[1]
|
||||
return capability_path and capability_path[1] or method
|
||||
end
|
||||
|
||||
--- @private
|
||||
@@ -1250,6 +1254,10 @@ function Client:supports_method(method, bufnr)
|
||||
return false
|
||||
end
|
||||
|
||||
if required_capability == nil and next(self.registrations[method] or {}) ~= nil then
|
||||
return false
|
||||
end
|
||||
|
||||
-- If we don't know about the method, or if it is a self-mapping(method=required_capability)
|
||||
-- assume that the client supports it.
|
||||
-- This needs to be at the end, so that dynamic_capabilities are checked first.
|
||||
@@ -1280,9 +1288,7 @@ function Client:_provider_foreach(method, fn)
|
||||
local required_capability = lsp.protocol._request_name_to_server_capability[method]
|
||||
local dynamic_regs = self:_get_registrations(provider)
|
||||
local has_subcap = required_capability and #required_capability > 1
|
||||
if not provider then
|
||||
return
|
||||
elseif not dynamic_regs then
|
||||
if not dynamic_regs then
|
||||
-- First check static capabilities
|
||||
local static_reg = vim.tbl_get(self.server_capabilities, provider)
|
||||
if static_reg then
|
||||
|
||||
@@ -3419,10 +3419,42 @@ describe('LSP', function()
|
||||
}, { client_id = client_id })
|
||||
check('workspace/didChangeConfiguration', nil, 'section')
|
||||
|
||||
vim.lsp.handlers['client/registerCapability'](nil, {
|
||||
registrations = {
|
||||
{
|
||||
id = 'unknown-method-id',
|
||||
method = 'unknown-method',
|
||||
registerOptions = {
|
||||
some_opt = 'unknown-dummy-opt',
|
||||
},
|
||||
},
|
||||
},
|
||||
}, { client_id = client_id })
|
||||
check('unknown-method', nil, 'some_opt')
|
||||
|
||||
check('unknown-method-2')
|
||||
vim.lsp.handlers['client/registerCapability'](nil, {
|
||||
registrations = {
|
||||
{
|
||||
id = 'unknown-method-2-id',
|
||||
method = 'unknown-method-2',
|
||||
registerOptions = {
|
||||
documentSelector = {
|
||||
{
|
||||
pattern = root_dir .. '/*.foo',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, { client_id = client_id })
|
||||
check('unknown-method-2')
|
||||
check('unknown-method-2', tmpfile)
|
||||
|
||||
return result
|
||||
end)
|
||||
|
||||
eq(21, #result)
|
||||
eq(25, #result)
|
||||
eq({ method = 'textDocument/formatting', supported = false }, result[1])
|
||||
eq({ method = 'textDocument/formatting', supported = true, fname = tmpfile }, result[2])
|
||||
eq({ method = 'textDocument/rangeFormatting', supported = true }, result[3])
|
||||
@@ -3457,6 +3489,14 @@ describe('LSP', function()
|
||||
{ method = 'workspace/didChangeConfiguration', supported = true, cap = { 'dummy-section' } },
|
||||
result[21]
|
||||
)
|
||||
eq({
|
||||
method = 'unknown-method',
|
||||
supported = true,
|
||||
cap = { 'unknown-dummy-opt' },
|
||||
}, result[22])
|
||||
eq({ method = 'unknown-method-2', supported = true }, result[23])
|
||||
eq({ method = 'unknown-method-2', supported = false }, result[24])
|
||||
eq({ method = 'unknown-method-2', supported = true, fname = tmpfile }, result[25])
|
||||
end)
|
||||
|
||||
it('identifies client dynamic registration capability', function()
|
||||
|
||||
Reference in New Issue
Block a user