neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit a4b2192690d7ed7c919708d8a50629c5b5cdfb50
parent 28ff4deda7a0c452d3a35de3da5e5ff676824915
Author: Olivia Kinnear <git@superatomic.dev>
Date:   Sat, 29 Nov 2025 14:36:29 -0500

feat(lsp): lsp.enable() auto-escalates forced shutdown  #36458

Problem:
LSP server may not exit even after the client was stopped/disabled via enable(false).

Solution:
Automatically force-stop after a timeout, unless `client.flags.exit_timeout = false`.
Diffstat:
Mruntime/doc/lsp.txt | 4+++-
Mruntime/doc/news.txt | 2++
Mruntime/lua/vim/lsp.lua | 7+++++--
3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt @@ -1048,7 +1048,9 @@ enable({name}, {enable}) *vim.lsp.enable()* Parameters: ~ • {name} (`string|string[]`) Name(s) of client(s) to enable. • {enable} (`boolean?`) `true|nil` to enable, `false` to disable - (actively stops and detaches clients as needed) + (actively stops and detaches clients as needed, and force + stops them if necessary after `client.flags.exit_timeout` + milliseconds, with a default time of 3000 milliseconds) foldclose({kind}, {winid}) *vim.lsp.foldclose()* Close all {kind} of folds in the the window with {winid}. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt @@ -275,6 +275,8 @@ LSP • |Client:stop()| now accepts a numerical `force` argument to be interpreted as the time to wait before forcing the shutdown. • Add cmp field to opts of |vim.lsp.completion.enable()| for custom completion ordering. +• |vim.lsp.enable()| when `enable == false` now force stops the client after + 3000 milliseconds when it takes too long to shutdown after being disabled. LUA diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua @@ -550,7 +550,8 @@ end --- --- @param name string|string[] Name(s) of client(s) to enable. --- @param enable? boolean `true|nil` to enable, `false` to disable (actively stops and detaches ---- clients as needed) +--- clients as needed, and force stops them if necessary after `client.flags.exit_timeout` +--- milliseconds, with a default time of 3000 milliseconds) function lsp.enable(name, enable) validate('name', name, { 'string', 'table' }) @@ -587,7 +588,9 @@ function lsp.enable(name, enable) else for _, nm in ipairs(names) do for _, client in ipairs(lsp.get_clients({ name = nm })) do - client:stop() + local t = client.flags.exit_timeout + local force_timeout = t and tonumber(t) or (t ~= false and 3000 or nil) + client:stop(force_timeout) end end end