diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2026-04-18 17:17:54 +0200 |
|---|---|---|
| committer | Justin M. Keyes <justinkz@gmail.com> | 2026-04-20 02:31:09 +0200 |
| commit | 919a1099510a6998bd7edeaaa0522719687242b7 (patch) | |
| tree | 5e27adf54a7df00e62fdfd9d4f59da6a43639214 /src | |
| parent | b8dcb348391d6364e9d082a0abe8f0e2872f8c48 (diff) | |
refactor(excmd): migrate ex_terminal to Lua
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/ex_docmd.c | 61 | ||||
| -rw-r--r-- | src/nvim/lua/executor.c | 56 |
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) { |
