diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 47b6e5c145..1f88524ce2 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -554,6 +554,8 @@ function Client:initialize() assert(result.capabilities, "initialize result doesn't contain capabilities") self.server_capabilities = assert(lsp.protocol.resolve_capabilities(self.server_capabilities)) + self:_process_static_registrations() + if self.server_capabilities.positionEncoding then self.offset_encoding = self.server_capabilities.positionEncoding end @@ -585,6 +587,48 @@ function Client:initialize() end) end +-- Server capabilities for methods that support static registration. +local static_registration_capabilities = { + [ms.textDocument_prepareCallHierarchy] = 'callHierarchyProvider', + [ms.textDocument_documentColor] = 'colorProvider', + [ms.textDocument_declaration] = 'declarationProvider', + [ms.textDocument_diagnostic] = 'diagnosticProvider', + [ms.textDocument_foldingRange] = 'foldingRangeProvider', + [ms.textDocument_implementation] = 'implementationProvider', + [ms.textDocument_inlayHint] = 'inlayHintProvider', + [ms.textDocument_inlineValue] = 'inlineValueProvider', + [ms.textDocument_linkedEditingRange] = 'linkedEditingRangeProvider', + [ms.textDocument_moniker] = 'monikerProvider', + [ms.textDocument_selectionRange] = 'selectionRangeProvider', + [ms.textDocument_semanticTokens_full] = 'semanticTokensProvider', + [ms.textDocument_typeDefinition] = 'typeDefinitionProvider', + [ms.textDocument_prepareTypeHierarchy] = 'typeHierarchyProvider', +} + +--- @private +function Client:_process_static_registrations() + local static_registrations = {} ---@type lsp.Registration[] + + for method, capability in pairs(static_registration_capabilities) do + if + vim.tbl_get(self.server_capabilities, capability, 'id') + and self:_supports_registration(method) + then + static_registrations[#static_registrations + 1] = { + id = self.server_capabilities[capability].id, + method = method, + registerOptions = { + documentSelector = self.server_capabilities[capability].documentSelector, ---@type lsp.DocumentSelector? + }, + } + end + end + + if next(static_registrations) then + self:_register_dynamic(static_registrations) + end +end + --- @private --- Returns the handler associated with an LSP method. --- Returns the default handler if the user hasn't set a custom one. diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index a4fa20accd..96b1f12f44 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -5727,6 +5727,28 @@ describe('LSP', function() eq({ method = 'textDocument/rangeFormatting', supported = true, fname = tmpfile }, result[4]) eq({ method = 'textDocument/completion', supported = false }, result[5]) end) + + it('supports static registration', function() + exec_lua(create_server_definition) + + local client_id = exec_lua(function() + local server = _G._create_server({ + capabilities = { + colorProvider = { id = 'color-registration' }, + }, + }) + + return assert(vim.lsp.start({ name = 'dynamic-test', cmd = server.cmd })) + end) + + eq( + true, + exec_lua(function() + local client = assert(vim.lsp.get_client_by_id(client_id)) + return client.dynamic_capabilities:get('textDocument/documentColor') ~= nil + end) + ) + end) end) describe('vim.lsp._watchfiles', function()