diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 556634b5ec..c8fd7d3c1c 100644 --- 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 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 index bdc9b9d67c..838779ca35 100644 --- 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,