mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
feat(lsp): initial support for dynamic capabilities (#23681)
- `client.dynamic_capabilities` is an object that tracks client register/unregister
- `client.supports_method` will additionally check if a dynamic capability supports the method, taking document filters into account. But only if the client enabled `dynamicRegistration` for the capability
- updated the default client capabilities to include dynamicRegistration for:
- formatting
- rangeFormatting
- hover
- codeAction
- hover
- rename
This commit is contained in:
109
runtime/lua/vim/lsp/_dynamic.lua
Normal file
109
runtime/lua/vim/lsp/_dynamic.lua
Normal file
@@ -0,0 +1,109 @@
|
||||
local wf = require('vim.lsp._watchfiles')
|
||||
|
||||
--- @class lsp.DynamicCapabilities
|
||||
--- @field capabilities table<string, lsp.Registration[]>
|
||||
--- @field client_id number
|
||||
local M = {}
|
||||
|
||||
--- @param client_id number
|
||||
function M.new(client_id)
|
||||
return setmetatable({
|
||||
capabilities = {},
|
||||
client_id = client_id,
|
||||
}, { __index = M })
|
||||
end
|
||||
|
||||
function M:supports_registration(method)
|
||||
local client = vim.lsp.get_client_by_id(self.client_id)
|
||||
if not client then
|
||||
return false
|
||||
end
|
||||
local capability = vim.tbl_get(client.config.capabilities, unpack(vim.split(method, '/')))
|
||||
return type(capability) == 'table' and capability.dynamicRegistration
|
||||
end
|
||||
|
||||
--- @param registrations lsp.Registration[]
|
||||
--- @private
|
||||
function M:register(registrations)
|
||||
-- remove duplicates
|
||||
self:unregister(registrations)
|
||||
for _, reg in ipairs(registrations) do
|
||||
local method = reg.method
|
||||
if not self.capabilities[method] then
|
||||
self.capabilities[method] = {}
|
||||
end
|
||||
table.insert(self.capabilities[method], reg)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param unregisterations lsp.Unregistration[]
|
||||
--- @private
|
||||
function M:unregister(unregisterations)
|
||||
for _, unreg in ipairs(unregisterations) do
|
||||
local method = unreg.method
|
||||
if not self.capabilities[method] then
|
||||
return
|
||||
end
|
||||
local id = unreg.id
|
||||
for i, reg in ipairs(self.capabilities[method]) do
|
||||
if reg.id == id then
|
||||
table.remove(self.capabilities[method], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param method string
|
||||
--- @param opts? {bufnr?: number}
|
||||
--- @return lsp.Registration? (table|nil) the registration if found
|
||||
--- @private
|
||||
function M:get(method, opts)
|
||||
opts = opts or {}
|
||||
opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
|
||||
for _, reg in ipairs(self.capabilities[method] or {}) do
|
||||
if not reg.registerOptions then
|
||||
return reg
|
||||
end
|
||||
local documentSelector = reg.registerOptions.documentSelector
|
||||
if not documentSelector then
|
||||
return reg
|
||||
end
|
||||
if M.match(opts.bufnr, documentSelector) then
|
||||
return reg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param method string
|
||||
--- @param opts? {bufnr?: number}
|
||||
--- @private
|
||||
function M:supports(method, opts)
|
||||
return self:get(method, opts) ~= nil
|
||||
end
|
||||
|
||||
--- @param bufnr number
|
||||
--- @param documentSelector lsp.DocumentSelector
|
||||
--- @private
|
||||
function M.match(bufnr, documentSelector)
|
||||
local ft = vim.bo[bufnr].filetype
|
||||
local uri = vim.uri_from_bufnr(bufnr)
|
||||
local fname = vim.uri_to_fname(uri)
|
||||
for _, filter in ipairs(documentSelector) do
|
||||
local matches = true
|
||||
if filter.language and ft ~= filter.language then
|
||||
matches = false
|
||||
end
|
||||
if matches and filter.scheme and not vim.startswith(uri, filter.scheme .. ':') then
|
||||
matches = false
|
||||
end
|
||||
if matches and filter.pattern and not wf._match(filter.pattern, fname) then
|
||||
matches = false
|
||||
end
|
||||
if matches then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user