diff options
author | phanium <91544758+phanen@users.noreply.github.com> | 2025-03-24 20:14:22 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-24 05:14:22 -0700 |
commit | af4231d4070c8d664b919f5466a827905881ef32 (patch) | |
tree | 8f511f1750b2982af055450a4e8ae7b4b61f7aa0 | |
parent | c98260822699bf622b14caffc908a47039deca51 (diff) | |
download | rneovim-af4231d4070c8d664b919f5466a827905881ef32.tar.gz rneovim-af4231d4070c8d664b919f5466a827905881ef32.tar.bz2 rneovim-af4231d4070c8d664b919f5466a827905881ef32.zip |
fix(cmdline): cmdline completion of _defer_require() modules #33007
Problem:
`:lua vim.lsp.c<tab>` does not list vim.lsp.completion in the completion
list after 24cea4c7f7417c7fe99a98a0487f51dd68c4f409.
Solution:
- Always include `vim.lsp._submodule` keys in candidates.
- Fixes `vim.lsp.c<tab>` -> `vim.lsp.completion`.
- Eager-load `vim.lsp.completion` to get its completion.
- Fixes `vim.lsp.completion.g<tab>` -> `vim.lsp.completion.get`.
-rw-r--r-- | runtime/lua/vim/_editor.lua | 57 | ||||
-rw-r--r-- | test/functional/editor/completion_spec.lua | 7 | ||||
-rw-r--r-- | test/functional/lua/command_line_completion_spec.lua | 37 |
3 files changed, 84 insertions, 17 deletions
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 6a8b23ba40..f0b8587476 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -923,6 +923,39 @@ function vim._expand_pat(pat, env) local final_env = env + --- @private + --- + --- Allows submodules to be defined on a `vim.<module>` table without eager-loading the module. + --- + --- Cmdline completion (`:lua vim.lsp.c<tab>`) accesses `vim.lsp._submodules` when no other candidates. + --- Cmdline completion (`:lua vim.lsp.completion.g<tab>`) will eager-load the module anyway. #33007 + --- + --- @param m table + --- @param k string + --- @return any + local function safe_tbl_get(m, k) + local val = rawget(m, k) + if val ~= nil then + return val + end + + local mt = getmetatable(m) + if not mt then + return m == vim and vim._extra[k] or nil + end + + -- use mt.__index, _submodules as fallback + if type(mt.__index) == 'table' then + return rawget(mt.__index, k) + end + + local sub = rawget(m, '_submodules') + if sub and type(sub) == 'table' and rawget(sub, k) then + -- Access the module to force _defer_require() to load the module. + return m[k] + end + end + for _, part in ipairs(parts) do if type(final_env) ~= 'table' then return {}, 0 @@ -953,16 +986,7 @@ function vim._expand_pat(pat, env) key = result end - local field = rawget(final_env, key) - if field == nil then - local mt = getmetatable(final_env) - if mt and type(mt.__index) == 'table' then - field = rawget(mt.__index, key) - elseif final_env == vim and (vim._submodules[key] or vim._extra[key]) then - field = vim[key] --- @type any - end - end - final_env = field + final_env = safe_tbl_get(final_env, key) if not final_env then return {}, 0 @@ -992,17 +1016,20 @@ function vim._expand_pat(pat, env) if type(final_env) == 'table' then insert_keys(final_env) + local sub = rawget(final_env, '_submodules') + if type(sub) == 'table' then + insert_keys(sub) + end + if final_env == vim then + insert_keys(vim._extra) + end end + local mt = getmetatable(final_env) if mt and type(mt.__index) == 'table' then insert_keys(mt.__index) end - if final_env == vim then - insert_keys(vim._submodules) - insert_keys(vim._extra) - end - -- Completion for dict accessors (special vim variables and vim.fn) if mt and vim.tbl_contains({ vim.g, vim.t, vim.w, vim.b, vim.v, vim.fn }, final_env) then local prefix, type = unpack( diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 106e0df347..3e5d0e48e8 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -928,6 +928,13 @@ describe('completion', function() command('set wildoptions+=fuzzy') eq({ 'vim' }, fn.getcompletion('vi', 'lua')) end) + + it('completes _defer_require() modules', function() + -- vim.lsp.c<tab> -> vim.lsp.completion + ok(vim.tbl_contains(fn.getcompletion('lua vim.lsp.c', 'cmdline'), 'completion')) + -- vim.lsp.completion.g<tab> -> vim.lsp.completion.get + ok(vim.tbl_contains(fn.getcompletion('lua vim.lsp.completion.g', 'cmdline'), 'get')) + end) end) it('cmdline completion supports various string options', function() diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 7dac7448e9..ee3d0325e1 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -24,6 +24,23 @@ describe('nlua_expand_pat', function() it('returns empty table when nothing matches', function() eq({ {}, 0 }, get_completions('foo', { bar = true })) + + -- can access non-exist field + for _, m in ipairs { + 'vim.', + 'vim.lsp.', + 'vim.treesitter.', + 'vim.deepcopy.', + 'vim.fn.', + 'vim.api.', + 'vim.o.', + 'vim.b.', + } do + eq({ {}, m:len() }, get_completions(m .. 'foo')) + eq({ {}, 0 }, get_completions(m .. 'foo.')) + eq({ {}, 0 }, get_completions(m .. 'foo.bar')) + eq({ {}, 0 }, get_completions(m .. 'foo.bar.')) + end end) it('returns nice completions with function call prefix', function() @@ -99,12 +116,28 @@ describe('nlua_expand_pat', function() it('with lazy submodules of "vim" global', function() eq({ { 'inspect', 'inspect_pos' }, 4 }, get_completions('vim.inspec')) - eq({ { 'treesitter' }, 4 }, get_completions('vim.treesi')) - + eq({ { 'dev' }, 15 }, get_completions('vim.treesitter.de')) + eq({ { 'edit_query' }, 19 }, get_completions('vim.treesitter.dev.edit_')) eq({ { 'set' }, 11 }, get_completions('vim.keymap.se')) end) + it('include keys in mt.__index and ._submodules', function() + eq( + { { 'bar1', 'bar2', 'bar3' }, 4 }, + exec_lua(function() -- metatable cannot be serialized + return { + vim._expand_pat('foo.', { + foo = setmetatable( + { bar1 = true, _submodules = { bar2 = true } }, + { __index = { bar3 = true } } + ), + }), + } + end) + ) + end) + it('excludes private fields after "."', function() eq( { { 'bar' }, 4 }, |