mirror of
https://github.com/folke/snacks.nvim
synced 2025-12-23 08:47:57 +00:00
feat(util): add LSP utility module with dynamic capability handlers
Add `Snacks.util.lsp.on()` to register handlers that fire when LSP clients attach with specific capabilities. Supports filtering by: - LSP method/capability - Client name - Buffer ID - Any vim.lsp.get_clients() filter Features: - Handles both LspAttach and client/registerCapability events - Ensures handlers only fire once per buffer - Lazy-loaded via Snacks.util metatable This provides a foundation for LSP-aware features like conditional keymaps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f75eaf1e18
commit
7a63ba5d37
2 changed files with 95 additions and 1 deletions
|
|
@ -1,5 +1,15 @@
|
|||
---@class snacks.util
|
||||
local M = {}
|
||||
---@field spawn snacks.spawn
|
||||
---@field lsp snacks.lsp
|
||||
local M = setmetatable({}, {
|
||||
---@param M snacks.util
|
||||
__index = function(M, k)
|
||||
if vim.tbl_contains({ "spawn", "lsp" }, k) then
|
||||
M[k] = require("snacks.util." .. k)
|
||||
end
|
||||
return rawget(M, k)
|
||||
end,
|
||||
})
|
||||
|
||||
M.meta = {
|
||||
desc = "Utility functions for Snacks _(library)_",
|
||||
|
|
|
|||
84
lua/snacks/util/lsp.lua
Normal file
84
lua/snacks/util/lsp.lua
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---@class snacks.lsp
|
||||
local M = {}
|
||||
|
||||
---@alias snacks.lsp.handler.cb fun(buf: number, client: vim.lsp.Client):any?
|
||||
|
||||
---@class snacks.lsp.Handler
|
||||
---@field filter vim.lsp.get_clients.Filter
|
||||
---@field cb snacks.lsp.handler.cb
|
||||
---@field done table<number, boolean>
|
||||
|
||||
local _handlers = {} ---@type snacks.lsp.Handler[]
|
||||
|
||||
local did_setup = false
|
||||
|
||||
---@param filter vim.lsp.get_clients.Filter
|
||||
local function _handle(filter)
|
||||
---@param h snacks.lsp.Handler
|
||||
local handlers = vim.tbl_filter(function(h)
|
||||
---@diagnostic disable-next-line: no-unknown
|
||||
for k, v in pairs(filter) do
|
||||
if h.filter[k] ~= nil and h.filter[k] ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end, _handlers)
|
||||
|
||||
if #handlers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
for _, state in ipairs(handlers) do
|
||||
local f = vim.deepcopy(state.filter)
|
||||
f = vim.tbl_extend("force", f, filter)
|
||||
local clients = vim.lsp.get_clients(f)
|
||||
for _, client in ipairs(clients) do
|
||||
for buf in pairs(client.attached_buffers) do
|
||||
if not state.done[buf] then
|
||||
state.done[buf] = true
|
||||
local ok, err = pcall(state.cb, buf, client)
|
||||
if not ok then
|
||||
vim.schedule(function()
|
||||
Snacks.notify.error(("Error in handler:\n%s\n```lua\n%s\n```"):format(err, vim.inspect(state.filter)))
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setup()
|
||||
if did_setup then
|
||||
return
|
||||
end
|
||||
did_setup = true
|
||||
local register_capability = vim.lsp.handlers["client/registerCapability"]
|
||||
vim.lsp.handlers["client/registerCapability"] = function(err, res, ctx)
|
||||
---@cast res lsp.RegistrationParams
|
||||
local ret = register_capability(err, res, ctx) ---@type any
|
||||
vim.schedule(function()
|
||||
for _, m in ipairs(res.registrations or {}) do
|
||||
_handle({ method = m.method, id = ctx.client_id })
|
||||
end
|
||||
end)
|
||||
return ret
|
||||
end
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
group = vim.api.nvim_create_augroup("snacks.lsp.on_attach", { clear = true }),
|
||||
callback = function(ev)
|
||||
_handle({ id = ev.data.client_id, buffer = ev.buf })
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
---@param filter vim.lsp.get_clients.Filter
|
||||
---@param cb snacks.lsp.handler.cb
|
||||
function M.on(filter, cb)
|
||||
setup()
|
||||
table.insert(_handlers, { filter = filter, cb = cb, done = {} })
|
||||
_handle(filter)
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue