mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
fix(lsp): better handling of "*" configs
Problem:
If a config name contains "*" it causes rtp discovery of `lsp/` to
consider the `*` as a wildcard and could lead to strange and unintended
behaviour. For example, accessing the `'*'` config from a `lsp/` file
would cause an infinite loop.
Solution:
- Explicitly disallow a config name from containing wildcards, with the
exception of `'*'`.
- When Resolving `'*'` config, skip the rtp step.
(cherry picked from commit 2ee896201c
)
This commit is contained in:

committed by
Lewis Russell

parent
a4b6705e87
commit
1e8e74dbff
@@ -362,6 +362,19 @@ local function invalidate_enabled_config(name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param name any
|
||||||
|
local function validate_config_name(name)
|
||||||
|
validate('name', name, function(value)
|
||||||
|
if type(value) ~= 'string' then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if value ~= '*' and value:match('%*') then
|
||||||
|
return false, 'LSP config name cannot contain wildcard ("*")'
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end, 'non-wildcard string')
|
||||||
|
end
|
||||||
|
|
||||||
--- @nodoc
|
--- @nodoc
|
||||||
--- @class vim.lsp.config
|
--- @class vim.lsp.config
|
||||||
--- @field [string] vim.lsp.Config
|
--- @field [string] vim.lsp.Config
|
||||||
@@ -371,11 +384,16 @@ lsp.config = setmetatable({ _configs = {} }, {
|
|||||||
--- @param name string
|
--- @param name string
|
||||||
--- @return vim.lsp.Config
|
--- @return vim.lsp.Config
|
||||||
__index = function(self, name)
|
__index = function(self, name)
|
||||||
validate('name', name, 'string')
|
validate_config_name(name)
|
||||||
|
|
||||||
local rconfig = lsp._enabled_configs[name] or {}
|
local rconfig = lsp._enabled_configs[name] or {}
|
||||||
|
|
||||||
if not rconfig.resolved_config then
|
if not rconfig.resolved_config then
|
||||||
|
if name == '*' then
|
||||||
|
rconfig.resolved_config = lsp.config._configs['*'] or {}
|
||||||
|
return rconfig.resolved_config
|
||||||
|
end
|
||||||
|
|
||||||
-- Resolve configs from lsp/*.lua
|
-- Resolve configs from lsp/*.lua
|
||||||
-- Calls to vim.lsp.config in lsp/* have a lower precedence than calls from other sites.
|
-- Calls to vim.lsp.config in lsp/* have a lower precedence than calls from other sites.
|
||||||
local rtp_config --- @type vim.lsp.Config?
|
local rtp_config --- @type vim.lsp.Config?
|
||||||
@@ -385,12 +403,12 @@ lsp.config = setmetatable({ _configs = {} }, {
|
|||||||
--- @type vim.lsp.Config?
|
--- @type vim.lsp.Config?
|
||||||
rtp_config = vim.tbl_deep_extend('force', rtp_config or {}, config)
|
rtp_config = vim.tbl_deep_extend('force', rtp_config or {}, config)
|
||||||
else
|
else
|
||||||
log.warn(string.format('%s does not return a table, ignoring', v))
|
log.warn(('%s does not return a table, ignoring'):format(v))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not rtp_config and not self._configs[name] then
|
if not rtp_config and not self._configs[name] then
|
||||||
log.warn(string.format('%s does not have a configuration', name))
|
log.warn(('%s does not have a configuration'):format(name))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -410,7 +428,7 @@ lsp.config = setmetatable({ _configs = {} }, {
|
|||||||
--- @param name string
|
--- @param name string
|
||||||
--- @param cfg vim.lsp.Config
|
--- @param cfg vim.lsp.Config
|
||||||
__newindex = function(self, name, cfg)
|
__newindex = function(self, name, cfg)
|
||||||
validate('name', name, 'string')
|
validate_config_name(name)
|
||||||
validate('cfg', cfg, 'table')
|
validate('cfg', cfg, 'table')
|
||||||
invalidate_enabled_config(name)
|
invalidate_enabled_config(name)
|
||||||
self._configs[name] = cfg
|
self._configs[name] = cfg
|
||||||
@@ -420,7 +438,7 @@ lsp.config = setmetatable({ _configs = {} }, {
|
|||||||
--- @param name string
|
--- @param name string
|
||||||
--- @param cfg vim.lsp.Config
|
--- @param cfg vim.lsp.Config
|
||||||
__call = function(self, name, cfg)
|
__call = function(self, name, cfg)
|
||||||
validate('name', name, 'string')
|
validate_config_name(name)
|
||||||
validate('cfg', cfg, 'table')
|
validate('cfg', cfg, 'table')
|
||||||
invalidate_enabled_config(name)
|
invalidate_enabled_config(name)
|
||||||
self[name] = vim.tbl_deep_extend('force', self._configs[name] or {}, cfg)
|
self[name] = vim.tbl_deep_extend('force', self._configs[name] or {}, cfg)
|
||||||
|
@@ -6414,5 +6414,36 @@ describe('LSP', function()
|
|||||||
filetypes = true,
|
filetypes = true,
|
||||||
}, 'cannot start foo due to config error: .* filetypes: expected table, got boolean')
|
}, 'cannot start foo due to config error: .* filetypes: expected table, got boolean')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('does not allow wildcards in config name', function()
|
||||||
|
local err =
|
||||||
|
'.../lsp.lua:0: name: expected non%-wildcard string, got foo%*%. Info: LSP config name cannot contain wildcard %("%*"%)'
|
||||||
|
|
||||||
|
matches(
|
||||||
|
err,
|
||||||
|
pcall_err(exec_lua, function()
|
||||||
|
local _ = vim.lsp.config['foo*']
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
|
||||||
|
matches(
|
||||||
|
err,
|
||||||
|
pcall_err(exec_lua, function()
|
||||||
|
vim.lsp.config['foo*'] = {}
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
|
||||||
|
matches(
|
||||||
|
err,
|
||||||
|
pcall_err(exec_lua, function()
|
||||||
|
vim.lsp.config('foo*', {})
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Exception for '*'
|
||||||
|
pcall(exec_lua, function()
|
||||||
|
vim.lsp.config('*', {})
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user