mirror of
https://github.com/neovim/neovim.git
synced 2026-07-22 00:51:33 +00:00
refactor(lsp): centralize provider capability resolution #37221
- 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.
This commit is contained in:
@@ -615,19 +615,17 @@ end
|
||||
function Client:_process_static_registrations()
|
||||
local static_registrations = {} ---@type lsp.Registration[]
|
||||
|
||||
for method, capability in pairs(lsp.protocol._request_name_to_server_capability) do
|
||||
for method in pairs(lsp.protocol._method_supports_static_registration) do
|
||||
local capability = lsp.protocol._request_name_to_server_capability[method]
|
||||
if
|
||||
vim.tbl_get(self.server_capabilities, unpack(capability), 'id')
|
||||
--- @cast method vim.lsp.protocol.Method
|
||||
vim.tbl_get(self.server_capabilities, capability[1], 'id')
|
||||
and self:_supports_registration(method)
|
||||
then
|
||||
local cap = vim.tbl_get(self.server_capabilities, unpack(capability))
|
||||
local cap = vim.tbl_get(self.server_capabilities, capability[1])
|
||||
static_registrations[#static_registrations + 1] = {
|
||||
id = cap.id,
|
||||
method = method,
|
||||
registerOptions = {
|
||||
documentSelector = cap.documentSelector, ---@type lsp.DocumentSelector|lsp.null
|
||||
},
|
||||
registerOptions = cap or {},
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -936,9 +934,12 @@ end
|
||||
--- Get options for a method that is registered dynamically.
|
||||
--- @param method vim.lsp.protocol.Method | vim.lsp.protocol.Method.Registration
|
||||
function Client:_supports_registration(method)
|
||||
local capability_path = lsp.protocol._request_name_to_client_capability[method] or {}
|
||||
-- dynamicRegistration is at the second level, even in deeply nested capabilities
|
||||
local capability = vim.tbl_get(self.capabilities, capability_path[1], capability_path[2])
|
||||
if lsp.protocol._methods_with_no_registration_options[method] then
|
||||
return true
|
||||
end
|
||||
local provider = self:_registration_provider(method)
|
||||
local capability_path = lsp.protocol._provider_to_client_registration[provider]
|
||||
local capability = vim.tbl_get(self.capabilities, unpack(capability_path))
|
||||
return type(capability) == 'table' and capability.dynamicRegistration
|
||||
end
|
||||
|
||||
@@ -946,7 +947,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] or method
|
||||
return capability_path and capability_path[1]
|
||||
end
|
||||
|
||||
--- @private
|
||||
@@ -1205,7 +1206,7 @@ function Client:supports_method(method, bufnr)
|
||||
|
||||
local provider = self:_registration_provider(method)
|
||||
local regs = self:_get_registrations(provider, bufnr)
|
||||
if lsp.protocol._request_name_allows_registration[method] and not regs then
|
||||
if lsp.protocol._method_supports_dynamic_registration[method] and not regs then
|
||||
return false
|
||||
end
|
||||
if regs then
|
||||
@@ -1214,6 +1215,9 @@ function Client:supports_method(method, bufnr)
|
||||
if vim.tbl_get(reg, 'registerOptions', unpack(required_capability, 2)) then
|
||||
return self:_supports_registration(reg.method)
|
||||
end
|
||||
if lsp.protocol._methods_with_no_registration_options[method] then
|
||||
return true
|
||||
end
|
||||
else
|
||||
return self:_supports_registration(reg.method)
|
||||
end
|
||||
@@ -1226,6 +1230,40 @@ function Client:supports_method(method, bufnr)
|
||||
return required_capability == nil
|
||||
end
|
||||
|
||||
--- Retrieves all capability values for a given LSP method, handling both static and dynamic registrations.
|
||||
--- This function abstracts over differences between capabilities declared in `server_capabilities`
|
||||
--- and those registered dynamically at runtime, returning all matching capability values.
|
||||
--- It also handles cases where the registration method differs from the calling method by abstracting to the Provider.
|
||||
--- For example, `workspace/diagnostic` uses capabilities registered under `textDocument/diagnostic`.
|
||||
--- This is useful for features like diagnostics and formatting, where servers may register multiple providers
|
||||
--- with different options (such as specific filetypes or document selectors).
|
||||
--- @param method vim.lsp.protocol.Method.ClientToServer | vim.lsp.protocol.Method.Registration LSP method name
|
||||
--- @param ... any Additional keys to index into the capability
|
||||
--- @return lsp.LSPAny[] # The capability value if it exists, empty table if not found
|
||||
function Client:_provider_value_get(method, ...)
|
||||
local matched_regs = {} --- @type any[]
|
||||
local provider = self:_registration_provider(method)
|
||||
local dynamic_regs = self:_get_registrations(provider)
|
||||
if not provider then
|
||||
return matched_regs
|
||||
elseif not dynamic_regs then
|
||||
-- First check static capabilities
|
||||
local static_reg = vim.tbl_get(self.server_capabilities, provider)
|
||||
if static_reg then
|
||||
matched_regs[1] = vim.tbl_get(static_reg, ...) or vim.NIL
|
||||
end
|
||||
else
|
||||
local required_capability = lsp.protocol._request_name_to_server_capability[method]
|
||||
for _, reg in ipairs(dynamic_regs) do
|
||||
if vim.tbl_get(reg, 'registerOptions', unpack(required_capability, 2)) then
|
||||
matched_regs[#matched_regs + 1] = vim.tbl_get(reg, 'registerOptions', ...) or vim.NIL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return matched_regs
|
||||
end
|
||||
|
||||
--- @private
|
||||
--- Handles a notification sent by an LSP server by invoking the
|
||||
--- corresponding handler.
|
||||
|
||||
Reference in New Issue
Block a user