mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 20:08:17 +00:00
feat(lua): add <f-args> to user commands callback (#17522)
Works similar to ex <f-args>. It only splits the arguments if the command has more than one posible argument. In cases were the command can only have 1 argument opts.fargs = { opts.args }
This commit is contained in:
@@ -651,6 +651,9 @@ nvim_add_user_command({name}, {command}, {*opts})
|
|||||||
that contains the following keys:
|
that contains the following keys:
|
||||||
• args: (string) The args passed to the
|
• args: (string) The args passed to the
|
||||||
command, if any |<args>|
|
command, if any |<args>|
|
||||||
|
• fargs: (table) The args split by unescaped
|
||||||
|
whitespace (when more than one argument is
|
||||||
|
allowed), if any |<f-args>|
|
||||||
• bang: (boolean) "true" if the command was
|
• bang: (boolean) "true" if the command was
|
||||||
executed with a ! modifier |<bang>|
|
executed with a ! modifier |<bang>|
|
||||||
• line1: (number) The starting line of the
|
• line1: (number) The starting line of the
|
||||||
|
@@ -2415,6 +2415,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
|
|||||||
/// from Lua, the command can also be a Lua function. The function is called with a
|
/// from Lua, the command can also be a Lua function. The function is called with a
|
||||||
/// single table argument that contains the following keys:
|
/// single table argument that contains the following keys:
|
||||||
/// - args: (string) The args passed to the command, if any |<args>|
|
/// - args: (string) The args passed to the command, if any |<args>|
|
||||||
|
/// - fargs: (table) The args split by unescaped whitespace (when more than one
|
||||||
|
/// argument is allowed), if any |<f-args>|
|
||||||
/// - bang: (boolean) "true" if the command was executed with a ! modifier |<bang>|
|
/// - bang: (boolean) "true" if the command was executed with a ! modifier |<bang>|
|
||||||
/// - line1: (number) The starting line of the command range |<line1>|
|
/// - line1: (number) The starting line of the command range |<line1>|
|
||||||
/// - line2: (number) The final line of the command range |<line2>|
|
/// - line2: (number) The final line of the command range |<line2>|
|
||||||
|
@@ -5802,6 +5802,30 @@ static void ex_delcommand(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split a string by unescaped whitespace (space & tab), used for f-args on Lua commands callback.
|
||||||
|
/// Similar to uc_split_args(), but does not allocate, add quotes, add commas and is an iterator.
|
||||||
|
///
|
||||||
|
/// @note If no separator is found start = 0 and end = length - 1
|
||||||
|
/// @param[in] arg String to split
|
||||||
|
/// @param[in] iter Iteration counter
|
||||||
|
/// @param[out] start Start of the split
|
||||||
|
/// @param[out] end End of the split
|
||||||
|
/// @param[in] length Length of the string
|
||||||
|
/// @return false if it's the last split (don't call again), true otherwise (call again).
|
||||||
|
bool uc_split_args_iter(const char_u *arg, int iter, int *start, int *end, int length)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
*start = *end + (iter > 1 ? 2 : 0); // Skip whitespace after the first split
|
||||||
|
for (pos = *start; pos < length - 2; pos++) {
|
||||||
|
if (arg[pos] != '\\' && ascii_iswhite(arg[pos + 1])) {
|
||||||
|
*end = pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*end = length - 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* split and quote args for <f-args>
|
* split and quote args for <f-args>
|
||||||
*/
|
*/
|
||||||
|
@@ -1814,8 +1814,31 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap)
|
|||||||
lua_pushinteger(lstate, eap->line2);
|
lua_pushinteger(lstate, eap->line2);
|
||||||
lua_setfield(lstate, -2, "line2");
|
lua_setfield(lstate, -2, "line2");
|
||||||
|
|
||||||
|
lua_newtable(lstate); // f-args table
|
||||||
lua_pushstring(lstate, (const char *)eap->arg);
|
lua_pushstring(lstate, (const char *)eap->arg);
|
||||||
lua_setfield(lstate, -2, "args");
|
lua_pushvalue(lstate, -1); // Reference for potential use on f-args
|
||||||
|
lua_setfield(lstate, -4, "args");
|
||||||
|
|
||||||
|
// Split args by unescaped whitespace |<f-args>| (nargs dependent)
|
||||||
|
if (cmd->uc_argt & EX_NOSPC) {
|
||||||
|
// Commands where nargs = 1 or "?" fargs is the same as args
|
||||||
|
lua_rawseti(lstate, -2, 1);
|
||||||
|
} else {
|
||||||
|
// Commands with more than one possible argument we split
|
||||||
|
lua_pop(lstate, 1); // Pop the reference of opts.args
|
||||||
|
int length = (int)STRLEN(eap->arg);
|
||||||
|
int start = 0;
|
||||||
|
int end = 0;
|
||||||
|
int i = 1;
|
||||||
|
bool res = true;
|
||||||
|
while (res) {
|
||||||
|
res = uc_split_args_iter(eap->arg, i, &start, &end, length);
|
||||||
|
lua_pushlstring(lstate, (const char *)eap->arg + start, (size_t)(end - start + 1));
|
||||||
|
lua_rawseti(lstate, -2, i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_setfield(lstate, -2, "fargs");
|
||||||
|
|
||||||
lua_pushstring(lstate, (const char *)&eap->regname);
|
lua_pushstring(lstate, (const char *)&eap->regname);
|
||||||
lua_setfield(lstate, -2, "reg");
|
lua_setfield(lstate, -2, "reg");
|
||||||
|
@@ -107,7 +107,8 @@ describe('nvim_add_user_command', function()
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
eq({
|
eq({
|
||||||
args = "hello",
|
args = [[hello my\ friend how\ are\ you?]],
|
||||||
|
fargs = {[[hello]], [[my\ friend]], [[how\ are\ you?]]},
|
||||||
bang = false,
|
bang = false,
|
||||||
line1 = 1,
|
line1 = 1,
|
||||||
line2 = 1,
|
line2 = 1,
|
||||||
@@ -115,13 +116,14 @@ describe('nvim_add_user_command', function()
|
|||||||
range = 0,
|
range = 0,
|
||||||
count = 2,
|
count = 2,
|
||||||
reg = "",
|
reg = "",
|
||||||
}, exec_lua [[
|
}, exec_lua [=[
|
||||||
vim.api.nvim_command('CommandWithLuaCallback hello')
|
vim.api.nvim_command([[CommandWithLuaCallback hello my\ friend how\ are\ you?]])
|
||||||
return result
|
return result
|
||||||
]])
|
]=])
|
||||||
|
|
||||||
eq({
|
eq({
|
||||||
args = "",
|
args = 'h\tey',
|
||||||
|
fargs = {[[h]], [[ey]]},
|
||||||
bang = true,
|
bang = true,
|
||||||
line1 = 10,
|
line1 = 10,
|
||||||
line2 = 10,
|
line2 = 10,
|
||||||
@@ -129,13 +131,14 @@ describe('nvim_add_user_command', function()
|
|||||||
range = 1,
|
range = 1,
|
||||||
count = 10,
|
count = 10,
|
||||||
reg = "",
|
reg = "",
|
||||||
}, exec_lua [[
|
}, exec_lua [=[
|
||||||
vim.api.nvim_command('botright 10CommandWithLuaCallback!')
|
vim.api.nvim_command('botright 10CommandWithLuaCallback! h\tey')
|
||||||
return result
|
return result
|
||||||
]])
|
]=])
|
||||||
|
|
||||||
eq({
|
eq({
|
||||||
args = "",
|
args = "h",
|
||||||
|
fargs = {"h"},
|
||||||
bang = false,
|
bang = false,
|
||||||
line1 = 1,
|
line1 = 1,
|
||||||
line2 = 42,
|
line2 = 42,
|
||||||
@@ -144,9 +147,52 @@ describe('nvim_add_user_command', function()
|
|||||||
count = 42,
|
count = 42,
|
||||||
reg = "",
|
reg = "",
|
||||||
}, exec_lua [[
|
}, exec_lua [[
|
||||||
vim.api.nvim_command('CommandWithLuaCallback 42')
|
vim.api.nvim_command('CommandWithLuaCallback 42 h')
|
||||||
return result
|
return result
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
eq({
|
||||||
|
args = "",
|
||||||
|
fargs = {""}, -- fargs works without args
|
||||||
|
bang = false,
|
||||||
|
line1 = 1,
|
||||||
|
line2 = 1,
|
||||||
|
mods = "",
|
||||||
|
range = 0,
|
||||||
|
count = 2,
|
||||||
|
reg = "",
|
||||||
|
}, exec_lua [[
|
||||||
|
vim.api.nvim_command('CommandWithLuaCallback')
|
||||||
|
return result
|
||||||
|
]])
|
||||||
|
|
||||||
|
-- f-args doesn't split when command nargs is 1 or "?"
|
||||||
|
exec_lua [[
|
||||||
|
result = {}
|
||||||
|
vim.api.nvim_add_user_command('CommandWithOneArg', function(opts)
|
||||||
|
result = opts
|
||||||
|
end, {
|
||||||
|
nargs = "?",
|
||||||
|
bang = true,
|
||||||
|
count = 2,
|
||||||
|
})
|
||||||
|
]]
|
||||||
|
|
||||||
|
eq({
|
||||||
|
args = "hello I'm one argmuent",
|
||||||
|
fargs = {"hello I'm one argmuent"}, -- Doesn't split args
|
||||||
|
bang = false,
|
||||||
|
line1 = 1,
|
||||||
|
line2 = 1,
|
||||||
|
mods = "",
|
||||||
|
range = 0,
|
||||||
|
count = 2,
|
||||||
|
reg = "",
|
||||||
|
}, exec_lua [[
|
||||||
|
vim.api.nvim_command('CommandWithOneArg hello I\'m one argmuent')
|
||||||
|
return result
|
||||||
|
]])
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can define buffer-local commands', function()
|
it('can define buffer-local commands', function()
|
||||||
|
Reference in New Issue
Block a user