feat(api): nvim_get_commands returns function fields #36415

Problem:
nvim_get_commands does not return callbacks defined for
"preview", "complete", or the command itself.

Solution:
- Return Lua function as "callback" field in a Lua context.
- Return "preview" function in a Lua context.
- BREAKING: Return "complete" as a function instead of a boolean.
This commit is contained in:
Rob Pilling
2025-11-26 05:12:39 +00:00
committed by GitHub
parent 7e09fedf43
commit 612b2e7850
3 changed files with 69 additions and 16 deletions

View File

@@ -52,6 +52,9 @@ These changes may require adaptations in your config or plugins.
API API
• Decoration provider has `on_range()` callback. • Decoration provider has `on_range()` callback.
• nvim_get_commands()'s dictionaries' `complete` member is now a Lua function,
if that is how the command was created. `preview` and `callback`
have also been added, if they were specified in `nvim_create_user_command()`
BUILD BUILD

View File

@@ -1777,7 +1777,7 @@ Dict commands_array(buf_T *buf, Arena *arena)
Dict rv = arena_dict(arena, (size_t)gap->ga_len); Dict rv = arena_dict(arena, (size_t)gap->ga_len);
for (int i = 0; i < gap->ga_len; i++) { for (int i = 0; i < gap->ga_len; i++) {
char arg[2] = { 0, 0 }; char arg[2] = { 0, 0 };
Dict d = arena_dict(arena, 14); Dict d = arena_dict(arena, 16);
ucmd_T *cmd = USER_CMD_GA(gap, i); ucmd_T *cmd = USER_CMD_GA(gap, i);
PUT_C(d, "name", CSTR_AS_OBJ(cmd->uc_name)); PUT_C(d, "name", CSTR_AS_OBJ(cmd->uc_name));
@@ -1787,7 +1787,14 @@ Dict commands_array(buf_T *buf, Arena *arena)
PUT_C(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR))); PUT_C(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR)));
PUT_C(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR))); PUT_C(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR)));
PUT_C(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT))); PUT_C(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT)));
PUT_C(d, "preview", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_PREVIEW)));
if (cmd->uc_preview_luaref != LUA_NOREF) {
PUT_C(d, "preview", LUAREF_OBJ(api_new_luaref(cmd->uc_preview_luaref)));
}
if (cmd->uc_luaref != LUA_NOREF) {
PUT_C(d, "callback", LUAREF_OBJ(api_new_luaref(cmd->uc_luaref)));
}
switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
case 0: case 0:
@@ -1803,9 +1810,14 @@ Dict commands_array(buf_T *buf, Arena *arena)
} }
PUT_C(d, "nargs", CSTR_TO_ARENA_OBJ(arena, arg)); PUT_C(d, "nargs", CSTR_TO_ARENA_OBJ(arena, arg));
char *cmd_compl = get_command_complete(cmd->uc_compl); if (cmd->uc_compl_luaref != LUA_NOREF) {
PUT_C(d, "complete", (cmd_compl == NULL PUT_C(d, "complete", LUAREF_OBJ(api_new_luaref(cmd->uc_compl_luaref)));
? NIL : CSTR_AS_OBJ(cmd_compl))); } else {
char *cmd_compl = get_command_complete(cmd->uc_compl);
PUT_C(d, "complete", (cmd_compl == NULL
? NIL : CSTR_AS_OBJ(cmd_compl)));
}
PUT_C(d, "complete_arg", cmd->uc_compl_arg == NULL PUT_C(d, "complete_arg", cmd->uc_compl_arg == NULL
? NIL : CSTR_AS_OBJ(cmd->uc_compl_arg)); ? NIL : CSTR_AS_OBJ(cmd->uc_compl_arg));

View File

@@ -25,7 +25,6 @@ describe('nvim_get_commands', function()
definition = 'echo "Hello World"', definition = 'echo "Hello World"',
name = 'Hello', name = 'Hello',
nargs = '1', nargs = '1',
preview = false,
range = NIL, range = NIL,
register = false, register = false,
keepscript = false, keepscript = false,
@@ -41,7 +40,6 @@ describe('nvim_get_commands', function()
definition = 'pwd', definition = 'pwd',
name = 'Pwd', name = 'Pwd',
nargs = '?', nargs = '?',
preview = false,
range = NIL, range = NIL,
register = false, register = false,
keepscript = false, keepscript = false,
@@ -96,7 +94,6 @@ describe('nvim_get_commands', function()
definition = 'pwd <args>', definition = 'pwd <args>',
name = 'TestCmd', name = 'TestCmd',
nargs = '1', nargs = '1',
preview = false,
range = '10', range = '10',
register = false, register = false,
keepscript = false, keepscript = false,
@@ -112,7 +109,6 @@ describe('nvim_get_commands', function()
definition = '!finger <args>', definition = '!finger <args>',
name = 'Finger', name = 'Finger',
nargs = '+', nargs = '+',
preview = false,
range = NIL, range = NIL,
register = false, register = false,
keepscript = false, keepscript = false,
@@ -128,7 +124,6 @@ describe('nvim_get_commands', function()
definition = 'call \128\253R2_foo(<q-args>)', definition = 'call \128\253R2_foo(<q-args>)',
name = 'Cmd2', name = 'Cmd2',
nargs = '*', nargs = '*',
preview = false,
range = NIL, range = NIL,
register = false, register = false,
keepscript = false, keepscript = false,
@@ -144,7 +139,6 @@ describe('nvim_get_commands', function()
definition = 'call \128\253R3_ohyeah()', definition = 'call \128\253R3_ohyeah()',
name = 'Cmd3', name = 'Cmd3',
nargs = '0', nargs = '0',
preview = false,
range = NIL, range = NIL,
register = false, register = false,
keepscript = false, keepscript = false,
@@ -160,7 +154,6 @@ describe('nvim_get_commands', function()
definition = 'call \128\253R4_just_great()', definition = 'call \128\253R4_just_great()',
name = 'Cmd4', name = 'Cmd4',
nargs = '0', nargs = '0',
preview = false,
range = NIL, range = NIL,
register = true, register = true,
keepscript = false, keepscript = false,
@@ -189,11 +182,56 @@ describe('nvim_get_commands', function()
endfunction endfunction
command -register Cmd4 call <SID>just_great() command -register Cmd4 call <SID>just_great()
]]) ]])
source([[
function! s:cpt() abort
return 1
endfunction
command -nargs=1 -complete=customlist,s:cpt CmdWithPreview
]])
source([[
lua << EOF
vim.api.nvim_create_user_command(
'CmdWithPreviewLua',
function() end,
{
nargs = 1,
complete = function() return 3 end,
preview = function() return 4 end,
}
)
EOF
]])
-- TODO(justinmk): Order is stable but undefined. Sort before return? -- TODO(justinmk): Order is stable but undefined. Sort before return?
eq( local commands = api.nvim_get_commands({ builtin = false })
{ Cmd2 = cmd2, Cmd3 = cmd3, Cmd4 = cmd4, Finger = cmd1, TestCmd = cmd0 }, local cmd_with_preview = commands.CmdWithPreview
api.nvim_get_commands({ builtin = false }) commands.CmdWithPreview = nil
) local cmd_with_preview_lua = commands.CmdWithPreviewLua
commands.CmdWithPreviewLua = nil
eq({ Cmd2 = cmd2, Cmd3 = cmd3, Cmd4 = cmd4, Finger = cmd1, TestCmd = cmd0 }, commands)
eq(cmd_with_preview.complete, 'customlist')
eq(cmd_with_preview.preview, nil)
-- user data (NIL), because these are passed through RPC:
eq(cmd_with_preview_lua.complete, NIL)
eq(cmd_with_preview_lua.preview, NIL)
end)
it('gets callbacks defined as Lua functions', function()
exec_lua [[
vim.api.nvim_create_user_command('CommandWithLuaCallback', function(opts)
return 3
end, {
nargs = 1,
preview = function() return 4 end,
complete = function() return 5 end,
})
local cmd = vim.api.nvim_get_commands({})["CommandWithLuaCallback"]
assert(cmd["callback"]() == 3)
assert(cmd["preview"]() == 4)
assert(cmd["complete"]() == 5)
]]
end) end)
end) end)