diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 76766af397..e209f92391 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1278,7 +1278,7 @@ Lua module: vim.lsp.client *lsp-client* See |Client:notify()|. • {cancel_request} (`fun(self: vim.lsp.Client, id: integer): boolean`) See |Client:cancel_request()|. - • {stop} (`fun(self: vim.lsp.Client, force: boolean?)`) + • {stop} (`fun(self: vim.lsp.Client, force: boolean|integer?)`) See |Client:stop()|. • {is_stopped} (`fun(self: vim.lsp.Client): boolean`) See |Client:is_stopped()|. @@ -1531,8 +1531,14 @@ Client:stop({force}) *Client:stop()* you request to stop a client which has previously been requested to shutdown, it will automatically escalate and force shutdown. + If `force` is a number, it will be treated as the time in milliseconds to + wait before forcing the shutdown. + + Note: Forcing shutdown while a server is busy writing out project or index + files can lead to file corruption. + Parameters: ~ - • {force} (`boolean?`) + • {force} (`boolean|integer?`) Client:supports_method({method}, {bufnr}) *Client:supports_method()* Checks if a client supports a given method. Always returns true for diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 2abd4164e4..cec325f6b0 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1208,42 +1208,8 @@ api.nvim_create_autocmd('VimLeavePre', { client:stop() end - local timeouts = {} --- @type table - local max_timeout = 0 - local send_kill = false - - for client_id, client in pairs(active_clients) do - local timeout = client.flags.exit_timeout - if timeout then - send_kill = true - timeouts[client_id] = timeout - max_timeout = math.max(timeout, max_timeout) - end - end - - local poll_time = 50 - - local function check_clients_closed() - for client_id, timeout in pairs(timeouts) do - timeouts[client_id] = timeout - poll_time - end - - for client_id, _ in pairs(active_clients) do - if timeouts[client_id] ~= nil and timeouts[client_id] > 0 then - return false - end - end - return true - end - - if send_kill then - if not vim.wait(max_timeout, check_clients_closed, poll_time) then - for client_id, client in pairs(active_clients) do - if timeouts[client_id] ~= nil then - client:stop(true) - end - end - end + for _, client in pairs(active_clients) do + client:stop(client.flags.exit_timeout) end end, }) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index aaa2409f9c..9a4b8d9c4b 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -804,8 +804,20 @@ end --- you request to stop a client which has previously been requested to --- shutdown, it will automatically escalate and force shutdown. --- ---- @param force? boolean +--- If `force` is a number, it will be treated as the time in milliseconds to +--- wait before forcing the shutdown. +--- +--- Note: Forcing shutdown while a server is busy writing out project or index +--- files can lead to file corruption. +--- +--- @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 @@ -825,7 +837,7 @@ function Client:stop(force) if err == nil then rpc.notify(ms.exit) else - -- If there was an error in the shutdown request, then term to be safe. + -- If there was an error in the shutdown request, then terminate to be safe. rpc.terminate() self._graceful_shutdown_failed = true end