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:
Javier Lopez
2022-02-27 14:35:06 -05:00
committed by GitHub
parent c65d93e60a
commit 1b5767aa34
5 changed files with 109 additions and 11 deletions

View File

@@ -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
/// single table argument that contains the following keys:
/// - 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>|
/// - line1: (number) The starting line of the command range |<line1>|
/// - line2: (number) The final line of the command range |<line2>|

View File

@@ -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>
*/

View File

@@ -1814,8 +1814,31 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap)
lua_pushinteger(lstate, eap->line2);
lua_setfield(lstate, -2, "line2");
lua_newtable(lstate); // f-args table
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_setfield(lstate, -2, "reg");