commit 2f78ff816b03661b5f74d0624e973eaca0d64ef1
parent 5ef567d13049792cf00e3a50961353908f791d4b
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Sat, 13 Sep 2025 21:51:06 -0400
fix(lsp): misleading logs in non-applicable filetypes #35749
Problem:
LSP logs show misleading "cannot start" messages when editing a filetype
NOT listed in the `config.filetypes` field.
[ERROR][2025-09-13 18:55:56] …/runtime//lua/vim/lsp/log.lua:151
"cannot start cssls due to config error: …/runtime//lua/vim/lsp.lua:423:
cmd: expected expected function or table with executable command,
got table: 0x0104701b18. Info: vscode-css-language-server is not executable"
Solution:
- `can_start`: check `config.filetypes` before checking the rest of the
config.
Diffstat:
2 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
@@ -426,16 +426,21 @@ local function validate_config(config)
end
--- @param bufnr integer
---- @param name string
--- @param config vim.lsp.Config
-local function can_start(bufnr, name, config)
- local config_ok, err = pcall(validate_config, config)
- if not config_ok then
- log.error(('cannot start %s due to config error: %s'):format(name, err))
+--- @param logging boolean
+local function can_start(bufnr, config, logging)
+ if
+ type(config.filetypes) == 'table'
+ and not vim.tbl_contains(config.filetypes, vim.bo[bufnr].filetype)
+ then
return false
end
- if config.filetypes and not vim.tbl_contains(config.filetypes, vim.bo[bufnr].filetype) then
+ local config_ok, err = pcall(validate_config, config)
+ if not config_ok then
+ if logging then
+ log.error(('invalid "%s" config: %s'):format(config.name, err))
+ end
return false
end
@@ -462,9 +467,7 @@ local function lsp_enable_callback(bufnr)
-- Stop any clients that no longer apply to this buffer.
local clients = lsp.get_clients({ bufnr = bufnr, _uninitialized = true })
for _, client in ipairs(clients) do
- if
- lsp.is_enabled(client.name) and not can_start(bufnr, client.name, lsp.config[client.name])
- then
+ if lsp.is_enabled(client.name) and not can_start(bufnr, lsp.config[client.name], false) then
lsp.buf_detach_client(bufnr, client.id)
end
end
@@ -472,7 +475,7 @@ local function lsp_enable_callback(bufnr)
-- Start any clients that apply to this buffer.
for name in vim.spairs(lsp._enabled_configs) do
local config = lsp.config[name]
- if config and can_start(bufnr, name, config) then
+ if config and can_start(bufnr, config, true) then
-- Deepcopy config so changes done in the client
-- do not propagate back to the enabled configs.
config = vim.deepcopy(config)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
@@ -3,7 +3,6 @@ local n = require('test.functional.testnvim')()
local t_lsp = require('test.functional.plugin.lsp.testutil')
-local assert_log = t.assert_log
local buf_lines = n.buf_lines
local command = n.command
local dedent = t.dedent
@@ -278,7 +277,7 @@ describe('LSP', function()
on_exit = function(code, signal)
eq(101, code, 'exit code') -- See fake-lsp-server.lua
eq(0, signal, 'exit signal')
- assert_log(
+ t.assert_log(
pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]),
fake_lsp_logfile
)
@@ -6799,6 +6798,7 @@ describe('LSP', function()
it('validates config on attach', function()
local tmp1 = t.tmpname(true)
exec_lua(function()
+ vim.fn.writefile({ '' }, fake_lsp_logfile)
vim.lsp.log._set_filename(fake_lsp_logfile)
end)
@@ -6808,22 +6808,32 @@ describe('LSP', function()
vim.lsp.config('foo', cfg)
vim.lsp.enable('foo')
vim.cmd.edit(assert(tmp1))
+ vim.bo.filetype = 'non.applicable.filetype'
+ end)
+
+ -- Assert NO log for non-applicable 'filetype'. #35737
+ if type(cfg.filetypes) == 'table' then
+ t.assert_nolog(err, fake_lsp_logfile)
+ end
+
+ exec_lua(function()
vim.bo.filetype = 'foo'
end)
retry(nil, 1000, function()
- assert_log(err, fake_lsp_logfile)
+ t.assert_log(err, fake_lsp_logfile)
end)
end
test_cfg({
+ filetypes = { 'foo' },
cmd = { 'lolling' },
- }, 'cannot start foo due to config error: .* lolling is not executable')
+ }, 'invalid "foo" config: .* lolling is not executable')
test_cfg({
cmd = { 'cat' },
filetypes = true,
- }, 'cannot start foo due to config error: .* filetypes: expected table, got boolean')
+ }, 'invalid "foo" config: .* filetypes: expected table, got boolean')
end)
it('does not start without workspace if workspace_required=true', function()