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:
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