diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 7692759fb8..f413cc812a 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -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 diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index b9bbfba7c0..2e68f2cbfe 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -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()