diff options
author | Lewis Russell <lewis6991@gmail.com> | 2025-03-31 11:25:37 +0100 |
---|---|---|
committer | Lewis Russell <me@lewisr.dev> | 2025-03-31 16:42:25 +0100 |
commit | 2ee896201c463f57395cffd12a83c18a9a7bfd9b (patch) | |
tree | 8ad8926eac5d02159fdcba20e3593eafa04653bd | |
parent | 04901f4ee784af4124390bf596b951d80b7bd35d (diff) | |
download | rneovim-2ee896201c463f57395cffd12a83c18a9a7bfd9b.tar.gz rneovim-2ee896201c463f57395cffd12a83c18a9a7bfd9b.tar.bz2 rneovim-2ee896201c463f57395cffd12a83c18a9a7bfd9b.zip |
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.
-rw-r--r-- | runtime/lua/vim/lsp.lua | 28 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 31 |
2 files changed, 54 insertions, 5 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 995340d751..2b531cf76e 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -377,6 +377,19 @@ local function invalidate_enabled_config(name) 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 --- @class vim.lsp.config --- @field [string] vim.lsp.Config @@ -386,11 +399,16 @@ lsp.config = setmetatable({ _configs = {} }, { --- @param name string --- @return vim.lsp.Config __index = function(self, name) - validate('name', name, 'string') + validate_config_name(name) local rconfig = lsp._enabled_configs[name] or {} 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 -- Calls to vim.lsp.config in lsp/* have a lower precedence than calls from other sites. local rtp_config --- @type vim.lsp.Config? @@ -400,12 +418,12 @@ lsp.config = setmetatable({ _configs = {} }, { --- @type vim.lsp.Config? rtp_config = vim.tbl_deep_extend('force', rtp_config or {}, config) 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 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 end @@ -425,7 +443,7 @@ lsp.config = setmetatable({ _configs = {} }, { --- @param name string --- @param cfg vim.lsp.Config __newindex = function(self, name, cfg) - validate('name', name, 'string') + validate_config_name(name) validate('cfg', cfg, 'table') invalidate_enabled_config(name) self._configs[name] = cfg @@ -435,7 +453,7 @@ lsp.config = setmetatable({ _configs = {} }, { --- @param name string --- @param cfg vim.lsp.Config __call = function(self, name, cfg) - validate('name', name, 'string') + validate_config_name(name) validate('cfg', cfg, 'table') invalidate_enabled_config(name) self[name] = vim.tbl_deep_extend('force', self._configs[name] or {}, cfg) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 856c086add..ebb8f20aaa 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -6449,5 +6449,36 @@ describe('LSP', function() 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) |