1 -- Absorbed from LazyVim
2 -- TODO: review, understand and adapt
6 ---@alias lsp.Client.filter {id?: number, bufnr?: number, name?: string, method?: string, filter?:fun(client: lsp.Client):boolean}
26 -- you can specify a different filter for each filetype
37 -- "Package", -- remove package since luals uses it for control flow structures
44 ---@param opts? lsp.Client.filter
45 function M.get_clients(opts)
46 local ret = {} ---@type vim.lsp.Client[]
47 if vim.lsp.get_clients then
48 ret = vim.lsp.get_clients(opts)
50 ---@diagnostic disable-next-line: deprecated
51 ret = vim.lsp.get_active_clients(opts)
52 if opts and opts.method then
53 ---@param client vim.lsp.Client
54 ret = vim.tbl_filter(function(client)
55 return client.supports_method(opts.method, { bufnr = opts.bufnr })
59 return opts and opts.filter and vim.tbl_filter(opts.filter, ret) or ret
62 ---@param on_attach fun(client:vim.lsp.Client, buffer)
63 ---@param name? string
64 function M.on_attach(on_attach, name)
65 return vim.api.nvim_create_autocmd("LspAttach", {
66 callback = function(args)
67 local buffer = args.buf ---@type number
68 local client = vim.lsp.get_client_by_id(args.data.client_id)
69 if client and (not name or client.name == name) then
70 return on_attach(client, buffer)
76 ---@type table<string, table<vim.lsp.Client, table<number, boolean>>>
77 M._supports_method = {}
80 local register_capability = vim.lsp.handlers["client/registerCapability"]
81 vim.lsp.handlers["client/registerCapability"] = function(err, res, ctx)
82 ---@diagnostic disable-next-line: no-unknown
83 local ret = register_capability(err, res, ctx)
84 local client = vim.lsp.get_client_by_id(ctx.client_id)
86 for buffer in pairs(client.attached_buffers) do
87 vim.api.nvim_exec_autocmds("User", {
88 pattern = "LspDynamicCapability",
89 data = { client_id = client.id, buffer = buffer },
95 M.on_attach(M._check_methods)
96 M.on_dynamic_capability(M._check_methods)
99 ---@param client vim.lsp.Client
100 function M._check_methods(client, buffer)
101 -- don't trigger on invalid buffers
102 if not vim.api.nvim_buf_is_valid(buffer) then
105 -- don't trigger on non-listed buffers
106 if not vim.bo[buffer].buflisted then
109 -- don't trigger on nofile buffers
110 if vim.bo[buffer].buftype == "nofile" then
113 for method, clients in pairs(M._supports_method) do
114 clients[client] = clients[client] or {}
115 if not clients[client][buffer] then
116 if client.supports_method and client.supports_method(method, { bufnr = buffer }) then
117 clients[client][buffer] = true
118 vim.api.nvim_exec_autocmds("User", {
119 pattern = "LspSupportsMethod",
120 data = { client_id = client.id, buffer = buffer, method = method },
127 ---@param fn fun(client:vim.lsp.Client, buffer):boolean?
128 ---@param opts? {group?: integer}
129 function M.on_dynamic_capability(fn, opts)
130 return vim.api.nvim_create_autocmd("User", {
131 pattern = "LspDynamicCapability",
132 group = opts and opts.group or nil,
133 callback = function(args)
134 local client = vim.lsp.get_client_by_id(args.data.client_id)
135 local buffer = args.data.buffer ---@type number
137 return fn(client, buffer)
143 ---@param method string
144 ---@param fn fun(client:vim.lsp.Client, buffer)
145 function M.on_supports_method(method, fn)
146 M._supports_method[method] = M._supports_method[method] or setmetatable({}, { __mode = "k" })
147 return vim.api.nvim_create_autocmd("User", {
148 pattern = "LspSupportsMethod",
149 callback = function(args)
150 local client = vim.lsp.get_client_by_id(args.data.client_id)
151 local buffer = args.data.buffer ---@type number
152 if client and method == args.data.method then
153 return fn(client, buffer)
159 ---@return _.lspconfig.options
160 function M.get_config(server)
161 local configs = require("lspconfig.configs")
162 return rawget(configs, server)
165 ---@return {default_config:lspconfig.Config}
166 function M.get_raw_config(server)
167 local ok, ret = pcall(require, "lspconfig.configs." .. server)
171 return require("lspconfig.server_configurations." .. server)
174 function M.is_enabled(server)
175 local c = M.get_config(server)
176 return c and c.enabled ~= false
179 ---@param server string
180 ---@param cond fun( root_dir, config): boolean
181 function M.disable(server, cond)
182 local util = require("lspconfig.util")
183 local def = M.get_config(server)
184 ---@diagnostic disable-next-line: undefined-field
185 def.document_config.on_new_config = util.add_hook_before(def.document_config.on_new_config, function(config, root_dir)
186 if cond(root_dir, config) then
187 config.enabled = false
192 M.action = setmetatable({}, {
193 __index = function(_, action)
195 vim.lsp.buf.code_action({