commit 8f75c0b58680ed2bcd65571750756bcc13abc0df
parent e5c2ce59058084a1d5c2107d557447e7c5c59ab9
Author: Yi Ming <ofseed@foxmail.com>
Date: Sun, 20 Jul 2025 14:28:35 +0800
refactor(lsp): extract `Client._on_detach` to reduce duplicated code
Diffstat:
2 files changed, 55 insertions(+), 66 deletions(-)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
@@ -175,53 +175,12 @@ local function reuse_client_default(client, config)
return true
end
---- Reset defaults set by `set_defaults`.
---- Must only be called if the last client attached to a buffer exits.
-local function reset_defaults(bufnr)
- if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
- vim.bo[bufnr].tagfunc = nil
- end
- if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
- vim.bo[bufnr].omnifunc = nil
- end
- if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
- vim.bo[bufnr].formatexpr = nil
- end
- vim._with({ buf = bufnr }, function()
- local keymap = vim.fn.maparg('K', 'n', false, true)
- if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
- vim.keymap.del('n', 'K', { buffer = bufnr })
- end
- end)
-end
-
--- @param code integer
--- @param signal integer
--- @param client_id integer
local function on_client_exit(code, signal, client_id)
local client = all_clients[client_id]
- vim.schedule(function()
- for bufnr in pairs(client.attached_buffers) do
- if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
- api.nvim_exec_autocmds('LspDetach', {
- buffer = bufnr,
- modeline = false,
- data = { client_id = client_id },
- })
- end
-
- client.attached_buffers[bufnr] = nil
-
- if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
- reset_defaults(bufnr)
- end
- end
-
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
- vim.diagnostic.reset(namespace)
- end)
-
local name = client.name or 'unknown'
-- Schedule the deletion of the client object so that it exists in the execution of LspDetach
@@ -914,29 +873,6 @@ local function text_document_did_save_handler(bufnr)
end
end
----@param bufnr integer resolved buffer
----@param client vim.lsp.Client
-local function buf_detach_client(bufnr, client)
- api.nvim_exec_autocmds('LspDetach', {
- buffer = bufnr,
- modeline = false,
- data = { client_id = client.id },
- })
-
- changetracking.reset_buf(client, bufnr)
-
- if client:supports_method(ms.textDocument_didClose) then
- local uri = vim.uri_from_bufnr(bufnr)
- local params = { textDocument = { uri = uri } }
- client:notify(ms.textDocument_didClose, params)
- end
-
- client.attached_buffers[bufnr] = nil
-
- local namespace = lsp.diagnostic.get_namespace(client.id)
- vim.diagnostic.reset(namespace, bufnr)
-end
-
--- @type table<integer,true>
local attached_buffers = {}
@@ -1013,7 +949,7 @@ local function buf_attach(bufnr)
on_detach = function()
local clients = lsp.get_clients({ bufnr = bufnr, _uninitialized = true })
for _, client in ipairs(clients) do
- buf_detach_client(bufnr, client)
+ client:_on_detach(bufnr)
end
attached_buffers[bufnr] = nil
util.buf_versions[bufnr] = nil
@@ -1087,7 +1023,7 @@ function lsp.buf_detach_client(bufnr, client_id)
)
return
else
- buf_detach_client(bufnr, client)
+ client:_on_detach(bufnr)
end
end
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
@@ -1186,12 +1186,65 @@ function Client:_on_error(code, err)
end
end
+---@param bufnr integer resolved buffer
+function Client:_on_detach(bufnr)
+ if self.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
+ api.nvim_exec_autocmds('LspDetach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = self.id },
+ })
+ end
+
+ changetracking.reset_buf(self, bufnr)
+
+ if self:supports_method(ms.textDocument_didClose) then
+ local uri = vim.uri_from_bufnr(bufnr)
+ local params = { textDocument = { uri = uri } }
+ self:notify(ms.textDocument_didClose, params)
+ end
+
+ self.attached_buffers[bufnr] = nil
+
+ local namespace = lsp.diagnostic.get_namespace(self.id)
+ vim.diagnostic.reset(namespace, bufnr)
+end
+
+--- Reset defaults set by `set_defaults`.
+--- Must only be called if the last client attached to a buffer exits.
+local function reset_defaults(bufnr)
+ if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
+ vim.bo[bufnr].tagfunc = nil
+ end
+ if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
+ vim.bo[bufnr].omnifunc = nil
+ end
+ if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
+ vim.bo[bufnr].formatexpr = nil
+ end
+ vim._with({ buf = bufnr }, function()
+ local keymap = vim.fn.maparg('K', 'n', false, true)
+ if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
+ vim.keymap.del('n', 'K', { buffer = bufnr })
+ end
+ end)
+end
+
--- @private
--- Invoked on client exit.
---
--- @param code integer) exit code of the process
--- @param signal integer the signal used to terminate (if any)
function Client:_on_exit(code, signal)
+ vim.schedule(function()
+ for bufnr in pairs(self.attached_buffers) do
+ self:_on_detach(bufnr)
+ if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
+ reset_defaults(bufnr)
+ end
+ end
+ end)
+
self:_run_callbacks(
self._on_exit_cbs,
lsp.client_errors.ON_EXIT_CALLBACK_ERROR,