From a702534c501f413b7d81461fbb141ff3bbc1c2d7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 3 Dec 2025 07:44:27 +0800 Subject: [PATCH] fix(lsp): close timer when client exits (#36795) Also, don't start the timer at all when a previous shutdown failed, as in this case a forced shutdown is used and no timer is needed. This fixes most of the delays caused by #36750. The delays caused by #36378 still seem to remain. --- runtime/lua/vim/lsp/client.lua | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 5f007ee6ee..a362d9f8b3 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -219,6 +219,9 @@ local all_clients = {} --- Whether on-type formatting is enabled for this client. --- @field _otf_enabled boolean? --- +--- Timer for stop() with timeout. +--- @field private _shutdown_timer uv.uv_timer_t? +--- --- Track this so that we can escalate automatically if we've already tried a --- graceful shutdown --- @field private _graceful_shutdown_failed true? @@ -882,12 +885,6 @@ end --- --- @param force? boolean|integer function Client:stop(force) - if type(force) == 'number' then - vim.defer_fn(function() - self:stop(true) - end, force) - end - local rpc = self.rpc if rpc.is_closing() then return @@ -902,6 +899,13 @@ function Client:stop(force) return end + if type(force) == 'number' then + self._shutdown_timer = vim.defer_fn(function() + self._shutdown_timer = nil + self:stop(true) + end, force) + end + -- Sending a signal after a process has exited is acceptable. rpc.request('shutdown', nil, function(err, _) if err == nil then @@ -1309,6 +1313,11 @@ end --- @param code integer) exit code of the process --- @param signal integer the signal used to terminate (if any) function Client:_on_exit(code, signal) + if self._shutdown_timer and not self._shutdown_timer:is_closing() then + self._shutdown_timer:close() + self._shutdown_timer = nil + end + vim.schedule(function() for bufnr in pairs(self.attached_buffers) do self:_on_detach(bufnr)