neovim/runtime/lua/vim/lsp/_dynamic.lua
Steven Arcangeli 92204b06e7
refactor(lsp): move glob parsing to util (#26519)
refactor(lsp): move glob parsing to vim.glob

Moving the logic for using vim.lpeg to create a match pattern from a
glob into `vim.glob`. There are several places in the LSP spec that
use globs, and it's very useful to have glob matching as a
generally-available utility.
2023-12-22 11:40:01 +01:00

110 lines
2.8 KiB
Lua

local glob = require('vim.glob')
--- @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 glob.to_lpeg(filter.pattern):match(fname) then
matches = false
end
if matches then
return true
end
end
end
return M