summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2026-04-18 17:17:54 +0200
committerJustin M. Keyes <justinkz@gmail.com>2026-04-20 02:31:09 +0200
commit919a1099510a6998bd7edeaaa0522719687242b7 (patch)
tree5e27adf54a7df00e62fdfd9d4f59da6a43639214 /src
parentb8dcb348391d6364e9d082a0abe8f0e2872f8c48 (diff)
refactor(excmd): migrate ex_terminal to Lua
Diffstat (limited to 'src')
-rw-r--r--src/nvim/ex_docmd.c61
-rw-r--r--src/nvim/lua/executor.c56
2 files changed, 48 insertions, 69 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 4b962da169..57491e22ae 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8199,7 +8199,7 @@ static void ex_checkhealth(exarg_T *eap)
{
// Suppress the Lua error (E5108) so the VIMRUNTIME diagnostic is the primary error.
emsg_off++;
- bool ok = nlua_call_excmd("vim.health", "_check", eap, &cmdmod);
+ bool ok = nlua_call_excmd("vim.health", "_check", eap, &cmdmod, NULL);
emsg_off--;
if (ok) {
return;
@@ -8220,73 +8220,42 @@ static void ex_checkhealth(exarg_T *eap)
static void ex_terminal(exarg_T *eap)
{
- char ex_cmd[1024];
- size_t len = 0;
const int scroll_save = msg_scroll;
-
- msg_scroll = false; // don't scroll here
+ msg_scroll = false;
autowrite_all();
msg_scroll = scroll_save;
- if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) {
- bool multi_mods = false;
- // ex_cmd must be a null-terminated string before passing to add_win_cmd_modifiers
- ex_cmd[0] = NUL;
- len = add_win_cmd_modifiers(ex_cmd, &cmdmod, &multi_mods);
- assert(len < sizeof(ex_cmd));
- int result = snprintf(ex_cmd + len, sizeof(ex_cmd) - len, " new");
- assert(result > 0);
- len += (size_t)result;
+ if (*eap->arg != NUL) {
+ nlua_call_excmd("vim._core.ex_cmd", "ex_terminal", eap, &cmdmod, NULL);
} else {
- int result = snprintf(ex_cmd, sizeof(ex_cmd), "enew%s", eap->forceit ? "!" : "");
- assert(result > 0);
- len += (size_t)result;
- }
-
- assert(len < sizeof(ex_cmd));
-
- if (*eap->arg != NUL) { // Run {cmd} in 'shell'.
- char *name = vim_strsave_escaped(eap->arg, "\"\\");
- snprintf(ex_cmd + len, sizeof(ex_cmd) - len,
- " | call jobstart(\"%s\",{'term':v:true})", name);
- xfree(name);
- } else { // No {cmd}: run the job with tokenized 'shell'.
+ // No cmd given, run 'shell'.
if (*p_sh == NUL) {
emsg(_(e_shellempty));
return;
}
-
+ // Tokenize 'shell' via shell_build_argv (handles quoting) and pass as arg2.
char **argv = shell_build_argv(NULL, NULL);
- char **p = argv;
- char tempstring[512];
- char shell_argv[512] = { 0 };
-
- while (*p != NULL) {
- char *escaped = vim_strsave_escaped(*p, "\"\\");
- snprintf(tempstring, sizeof(tempstring), ",\"%s\"", escaped);
- xfree(escaped);
- xstrlcat(shell_argv, tempstring, sizeof(shell_argv));
- p++;
+ typval_T shell_tv;
+ tv_list_alloc_ret(&shell_tv, 0);
+ for (char **p = argv; *p; p++) {
+ tv_list_append_allocated_string(shell_tv.vval.v_list, *p);
}
- shell_free_argv(argv);
-
- snprintf(ex_cmd + len, sizeof(ex_cmd) - len,
- " | call jobstart([%s], {'term':v:true})", shell_argv + 1);
+ xfree(argv);
+ nlua_call_excmd("vim._core.ex_cmd", "ex_terminal", eap, &cmdmod, &shell_tv);
+ tv_clear(&shell_tv);
}
-
- do_cmdline_cmd(ex_cmd);
}
/// ":log {name}"
static void ex_log(exarg_T *eap)
{
- nlua_call_excmd("vim._core.ex_cmd", "ex_log", eap, &cmdmod);
+ nlua_call_excmd("vim._core.ex_cmd", "ex_log", eap, &cmdmod, NULL);
}
/// ":lsp {subcmd} {clients}"
static void ex_lsp(exarg_T *eap)
{
- nlua_call_excmd("vim._core.ex_cmd", "ex_lsp", eap, &cmdmod);
+ nlua_call_excmd("vim._core.ex_cmd", "ex_lsp", eap, &cmdmod, NULL);
}
/// ":fclose"
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index d7e3ce6d83..d770cdbb5e 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -194,6 +194,16 @@ static void nlua_push_eap(lua_State *lstate, exarg_T *eap, const cmdmod_T *cmod)
lua_pushstring(lstate, reg);
lua_setfield(lstate, -2, "reg");
+ // Push pre-split args as "fargs" list, if available (set by the command-line parser).
+ if (eap->args != NULL && eap->argc > 0) {
+ lua_createtable(lstate, (int)eap->argc, 0);
+ for (size_t i = 0; i < eap->argc; i++) {
+ lua_pushlstring(lstate, eap->args[i], eap->arglens[i]);
+ lua_rawseti(lstate, -2, (int)i + 1);
+ }
+ lua_setfield(lstate, -2, "fargs");
+ }
+
nlua_push_cmdmod(lstate, cmod);
lua_setfield(lstate, -2, "smods");
}
@@ -1763,10 +1773,12 @@ void nlua_call_vimfn(const char *module, const char *func, typval_T *argvars, ty
///
/// @param module Lua module name, e.g. "vim._core.ex_cmd".
/// @param func Function name in the module, e.g. "ex_log".
-/// @param eap Excmd args.
-/// @param cmod Excmd mods.
+/// @param eap Excmd info, passed as Lua arg1.
+/// @param cmod Excmd mods, included in Lua arg1.
+/// @param extra (Optional) Passed as Lua arg2.
/// @return true on success, false on error (message already emitted).
-bool nlua_call_excmd(const char *module, const char *func, exarg_T *eap, const cmdmod_T *cmod)
+bool nlua_call_excmd(const char *module, const char *func, exarg_T *eap, const cmdmod_T *cmod,
+ typval_T *extra)
{
lua_State *const lstate = global_lstate;
@@ -1783,7 +1795,13 @@ bool nlua_call_excmd(const char *module, const char *func, exarg_T *eap, const c
lua_newtable(lstate);
nlua_push_eap(lstate, eap, cmod);
- if (nlua_pcall(lstate, 1, 0)) {
+ int nargs = 1;
+ if (extra) {
+ nlua_push_typval(lstate, extra, 0);
+ nargs = 2;
+ }
+
+ if (nlua_pcall(lstate, nargs, 0)) {
semsg("E5108: %s", lua_tostring(lstate, -1));
lua_pop(lstate, 1);
return false;
@@ -2420,21 +2438,19 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_setfield(lstate, -2, "count");
}
- lua_newtable(lstate); // f-args table
- lua_pushstring(lstate, eap->arg); // for f-args splitting below
-
- // Split args by unescaped whitespace |<f-args>| (nargs dependent)
+ // Override fargs for user command-specific splitting (nlua_push_eap already set it
+ // for the eap->args!=NULL case, but user commands need special handling for nargs).
if (cmd->uc_argt & EX_NOSPC) {
- if ((cmd->uc_argt & EX_NEEDARG) || strlen(eap->arg)) {
- // For commands where nargs is 1 or "?" and argument is passed, fargs = { args }
+ // nargs=1 or "?": fargs is the whole arg as a single element, or empty.
+ lua_createtable(lstate, 1, 0);
+ if ((cmd->uc_argt & EX_NEEDARG) || *eap->arg != NUL) {
+ lua_pushstring(lstate, eap->arg);
lua_rawseti(lstate, -2, 1);
- } else {
- // if nargs = "?" and no argument is passed, fargs = {}
- lua_pop(lstate, 1); // Pop the reference of opts.args
}
+ lua_setfield(lstate, -2, "fargs");
} else if (eap->args == NULL) {
- // For commands with more than one possible argument, split if argument list isn't available.
- lua_pop(lstate, 1); // Pop the reference of opts.args
+ // Pre-split args not available: tokenize eap->arg by unescaped whitespace.
+ lua_newtable(lstate);
size_t length = strlen(eap->arg);
size_t end = 0;
size_t len = 0;
@@ -2450,15 +2466,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
}
}
xfree(buf);
- } else {
- // If argument list is available, just use it.
- lua_pop(lstate, 1);
- for (size_t i = 0; i < eap->argc; i++) {
- lua_pushlstring(lstate, eap->args[i], eap->arglens[i]);
- lua_rawseti(lstate, -2, (int)i + 1);
- }
+ lua_setfield(lstate, -2, "fargs");
}
- lua_setfield(lstate, -2, "fargs");
+ // else: eap->args was available, nlua_push_eap already set fargs.
char nargs[2];
if (cmd->uc_argt & EX_EXTRA) {