From 34815777b28091e6a333ccab4ef2834a84248acb Mon Sep 17 00:00:00 2001 From: Olivia Kinnear Date: Tue, 27 Jan 2026 15:17:45 -0600 Subject: [PATCH] fix(lsp): remove side-effects if `vim.lsp.enable()` raises an error (#37571) Problem: If `vim.lsp.enable()` fails with an error, either because `'*'` is one of the provided names or because there is an error in a config, `vim.lsp.enable()` will still have side-effects: - All names before the one that encountered an error will still be added to `lsp._enabled_configs`, but the autocommand will not get added or run. - Any name which makes `vim.lsp.config[name]` error will be added to `lsp._enabled_configs`, causing all future calls to `vim.lsp.enable()` to fail. This will also break `:che vim.lsp`. Solution: - Check all names for errors before modifying `lsp._enabled_configs`. - Check `vim.lsp.config[name]` does not raise an error before enabling the name. --- runtime/doc/lsp.txt | 8 ++++++++ runtime/lua/vim/lsp.lua | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index ebeec3e73b..a0f0d3420e 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -993,6 +993,14 @@ enable({name}, {enable}) *vim.lsp.enable()* To disable, pass `enable=false`: Stops related clients and servers (force-stops servers after a timeout, unless `exit_timeout=false`). + Raises an error under the following conditions: + • `{name}` is not a valid LSP config name (for example, `'*'`). + • `{name}` corresponds to an LSP config file which raises an error. + + If an error is raised when multiple names are provided, this function will + have no side-effects; it will not enable/disable any configs, including + ones which contain no errors. + Examples: >lua vim.lsp.enable('clangd') vim.lsp.enable({'lua_ls', 'pyright'}) diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 3239d92275..a464ed47df 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -514,6 +514,14 @@ end --- To disable, pass `enable=false`: Stops related clients and servers (force-stops servers after --- a timeout, unless `exit_timeout=false`). --- +--- Raises an error under the following conditions: +--- - `{name}` is not a valid LSP config name (for example, `'*'`). +--- - `{name}` corresponds to an LSP config file which raises an error. +--- +--- If an error is raised when multiple names are provided, this function will +--- have no side-effects; it will not enable/disable any configs, including +--- ones which contain no errors. +--- --- Examples: --- --- ```lua @@ -544,10 +552,22 @@ function lsp.enable(name, enable) validate('name', name, { 'string', 'table' }) local names = vim._ensure_list(name) --[[@as string[] ]] + + -- Check for errors, and abort with no side-effects if there is one. for _, nm in ipairs(names) do - if nm == '*' then - error('Invalid name') + if nm:match('%*') then + error('LSP config name cannot contain wildcard ("*")') end + + -- Raise error if `lsp.config[nm]` raises an error, instead of waiting for + -- the error to be triggered by `lsp_enable_callback()`. + if enable ~= false then + _ = lsp.config[nm] + end + end + + -- Now that there can be no errors, enable/disable all names. + for _, nm in ipairs(names) do lsp._enabled_configs[nm] = enable ~= false and {} or nil end