diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2026-04-20 04:23:54 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-20 04:23:54 -0400 |
| commit | c7d4892ce6615e83113035823979cf424f0c12f5 (patch) | |
| tree | c9604b577d69ffa7ba544a2ed183d22f67d88a12 | |
| parent | 2e8f285f6c1be6a55a9aae2fab64421f24bd7df0 (diff) | |
| parent | ea45e6f6ba5ead412053285ca3737bca6ce273f4 (diff) | |
Merge #39194 from justinmk/luavimfn
| -rw-r--r-- | runtime/lua/vim/_core/ex_cmd.lua | 23 | ||||
| -rw-r--r-- | runtime/lua/vim/health.lua | 25 | ||||
| -rw-r--r-- | runtime/lua/vim/health/health.lua | 38 | ||||
| -rw-r--r-- | scripts/linterrcodes.lua | 2 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 13 | ||||
| -rw-r--r-- | src/nvim/ex_docmd.c | 83 | ||||
| -rw-r--r-- | src/nvim/ex_eval.c | 4 | ||||
| -rw-r--r-- | src/nvim/help.c | 53 | ||||
| -rw-r--r-- | src/nvim/lua/executor.c | 111 | ||||
| -rw-r--r-- | test/functional/ex_cmds/excmd_spec.lua | 15 | ||||
| -rw-r--r-- | test/functional/ex_cmds/lsp_spec.lua | 2 |
11 files changed, 183 insertions, 186 deletions
diff --git a/runtime/lua/vim/_core/ex_cmd.lua b/runtime/lua/vim/_core/ex_cmd.lua index 1fe78d1e14..cd33a11662 100644 --- a/runtime/lua/vim/_core/ex_cmd.lua +++ b/runtime/lua/vim/_core/ex_cmd.lua @@ -233,4 +233,27 @@ function M.log_complete() return names end +--- `:terminal [cmd]` +--- @param eap vim._core.ExCmdArgs +--- @param shell_argv? string[] Tokenized 'shell' from C (shell_build_argv), for the no-cmd case. +M.ex_terminal = function(eap, shell_argv) + local smods = eap.smods + local has_mods = (smods.tab or 0) > 0 + or (smods.split or '') ~= '' + or smods.horizontal + or smods.vertical + + if has_mods then + vim.cmd.new { mods = smods } + else + vim.cmd.enew { bang = eap.bang } + end + + if shell_argv then -- No `cmd`, run 'shell'. + vim.fn.jobstart(shell_argv, { term = true }) + else -- Run [cmd] in 'shell'. + vim.fn.jobstart(eap.args, { term = true }) + end +end + return M diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index 55dccc847f..10b066b4d3 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -387,14 +387,15 @@ local function progress_report(len) end end ---- Runs the specified healthchecks. ---- Runs all discovered healthchecks if plugin_names is empty. +--- Runs the specified healthchecks, or all discovered healthchecks if eap.args is empty. --- ---- @param mods string command modifiers that affect splitting a window. ---- @param plugin_names string glob of plugin names, split on whitespace. For example, using ---- `:checkhealth vim.* nvim` will healthcheck `vim.lsp`, `vim.treesitter` ---- and `nvim` modules. -function M._check(mods, plugin_names) +--- Specified healthchecks are given as plugin names, split on whitespace. For example using +--- `:checkhealth vim.* nvim` will check `vim.lsp`, `vim.treesitter` and `nvim` modules. +--- +--- @param eap vim._core.ExCmdArgs +function M._check(eap) + local plugin_names = eap.args + local smods = eap.smods local healthchecks = plugin_names == '' and get_healthcheck('*') or get_healthcheck(plugin_names) local emptybuf = vim.fn.bufnr('$') == 1 and vim.fn.getline(1) == '' and 1 == vim.fn.line('$') @@ -421,8 +422,14 @@ function M._check(mods, plugin_names) -- When no command modifiers are used: -- - If the current buffer is empty, open healthcheck directly. -- - If not specified otherwise open healthcheck in a tab. - local buf_cmd = #mods > 0 and (mods .. ' sbuffer') or emptybuf and 'buffer' or 'tab sbuffer' - vim.cmd(buf_cmd .. ' ' .. bufnr) + local has_mods = smods.tab > 0 or smods.split ~= '' or smods.horizontal or smods.vertical + if has_mods then + vim.cmd.sbuffer { bufnr, mods = smods } + elseif emptybuf then + vim.cmd.buffer(bufnr) + else + vim.cmd.sbuffer { bufnr, mods = { tab = 1 } } + end end if vim.fn.bufexists('health://') == 1 then diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua index a744f1b750..74cad281ac 100644 --- a/runtime/lua/vim/health/health.lua +++ b/runtime/lua/vim/health/health.lua @@ -3,10 +3,14 @@ local health = require('vim.health') ---Run a system command and return ok and its stdout and stderr combined. ---@param cmd string[] +---@param timeout? integer Timeout in ms (default: no timeout). ---@return boolean ---@return string -local function system(cmd) - local result = vim.system(cmd, { text = true }):wait() +local function system(cmd, timeout) + local result = vim.system(cmd, { text = true, timeout = timeout }):wait() + if not result then -- Workaround https://github.com/neovim/neovim/issues/37922 + return false, 'command failed' + end return result.code == 0, vim.trim(('%s\n%s'):format(result.stdout, result.stderr)) end @@ -551,21 +555,15 @@ end ---@param nvim_version string local function check_stable_version(nvim_version) - local result = vim - .system( - { 'git', 'ls-remote', '--tags', 'https://github.com/neovim/neovim' }, - { text = true, timeout = 5000 } - ) - :wait() - if result.code ~= 0 or not result.stdout or result.stdout == '' then + local ok, output = + system({ 'git', 'ls-remote', '--tags', 'https://github.com/neovim/neovim' }, 5000) + if not ok or output == '' then return end local stable_sha = assert( - result.stdout:match('(%x+)%s+refs/tags/stable%^{}') - or result.stdout:match('(%x+)%s+refs/tags/stable\n') + output:match('(%x+)%s+refs/tags/stable%^{}') or output:match('(%x+)%s+refs/tags/stable\n') ) - local latest_version = - assert(result.stdout:match(stable_sha .. '%s+refs/tags/v?(%d+%.%d+%.%d+)%^{}')) + local latest_version = assert(output:match(stable_sha .. '%s+refs/tags/v?(%d+%.%d+%.%d+)%^{}')) local current_version = assert(nvim_version:match('v?(%d+%.%d+%.%d+)')) local current = vim.version.parse(current_version) local latest = vim.version.parse(latest_version) @@ -578,18 +576,16 @@ end ---@param commit string local function check_head_hash(commit) - local result = vim - .system( - { 'git', 'ls-remote', 'https://github.com/neovim/neovim', 'HEAD', 'refs/tags/nightly' }, - { text = true, timeout = 5000 } - ) - :wait() - if result.code ~= 0 or not result.stdout or result.stdout == '' then + local ok, output = system( + { 'git', 'ls-remote', 'https://github.com/neovim/neovim', 'HEAD', 'refs/tags/nightly' }, + 5000 + ) + if not ok or output == '' then return end local refs = {} ---@type table<string, string> - for line in result.stdout:gmatch('[^\n]+') do + for line in output:gmatch('[^\n]+') do local sha, ref = line:match('^(%x+)%s+(%S+)$') if sha and ref then refs[ref] = sha diff --git a/scripts/linterrcodes.lua b/scripts/linterrcodes.lua index e6767fbeba..ed2ca92b6c 100644 --- a/scripts/linterrcodes.lua +++ b/scripts/linterrcodes.lua @@ -48,7 +48,7 @@ local dup_allowed = { E509 = 2, E5101 = 2, E5102 = 2, - E5108 = 6, + E5108 = 5, E5111 = 2, E513 = 2, E521 = 2, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index ea017b5954..a04671030a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3382,13 +3382,14 @@ dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, cons dict_T *env = tv_dict_alloc(); if (!clear_env) { - typval_T temp_env = TV_INITIAL_VALUE; - typval_T no_args[] = { { .v_type = VAR_UNKNOWN } }; - nlua_call_vimfn("vim._core.vimfn", "f_environ", no_args, &temp_env); - if (temp_env.v_type == VAR_DICT) { - tv_dict_extend(env, temp_env.vval.v_dict, "force"); + uv_env_item_t *envitems; + int envcount; + if (uv_os_environ(&envitems, &envcount) == 0) { + for (int i = 0; i < envcount; i++) { + tv_dict_add_str(env, envitems[i].name, strlen(envitems[i].name), envitems[i].value); + } + uv_os_free_environ(envitems, envcount); } - tv_clear(&temp_env); if (pty) { // These env vars shouldn't propagate to the child process. #6764 diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e527b38b6a..bd011aa407 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8197,23 +8197,11 @@ void set_pressedreturn(bool val) /// ":checkhealth [plugins]" static void ex_checkhealth(exarg_T *eap) { - Error err = ERROR_INIT; - MAXSIZE_TEMP_ARRAY(args, 2); - - char mods[1024]; - size_t mods_len = 0; - mods[0] = NUL; - - if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) { - bool multi_mods = false; - mods_len = add_win_cmd_modifiers(mods, &cmdmod, &multi_mods); - assert(mods_len < sizeof(mods)); - } - ADD_C(args, STRING_OBJ(((String){ .data = mods, .size = mods_len }))); - ADD_C(args, CSTR_AS_OBJ(eap->arg)); - - NLUA_EXEC_STATIC("vim.health._check(...)", args, kRetNilBool, NULL, &err); - if (!ERROR_SET(&err)) { + // 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, NULL); + emsg_off--; + if (ok) { return; } @@ -8228,79 +8216,46 @@ static void ex_checkhealth(exarg_T *eap) emsg(_("E5009: Invalid 'runtimepath'")); } } - semsg_multiline("emsg", err.msg); - api_clear_error(&err); } 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/ex_eval.c b/src/nvim/ex_eval.c index cedb58b4d0..ebbb940422 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -378,7 +378,9 @@ bool do_intthrow(cstack_T *cstack) return true; } -/// Get an exception message that is to be stored in current_exception->value. +/// Gets an exception message that is to be stored in current_exception->value. +/// +/// For error exceptions (ET_ERROR), formats the message as "Vim(cmdname):Exx: …". char *get_exception_string(void *value, except_type_T type, char *cmdname, bool *should_free) { char *ret; diff --git a/src/nvim/help.c b/src/nvim/help.c index 2928647e6b..78e2690772 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -14,6 +14,7 @@ #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" #include "nvim/errors.h" +#include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" @@ -105,16 +106,14 @@ void ex_help(exarg_T *eap) // ":help!" (bang, no args): DWIM help, resolve best tag at cursor via Lua. char *allocated_arg = NULL; if (helpbang) { - Error err = ERROR_INIT; - Object res = NLUA_EXEC_STATIC("return require'vim._core.help'.resolve_tag()", - (Array)ARRAY_DICT_INIT, kRetObject, NULL, &err); - if (!ERROR_SET(&err) && res.type == kObjectTypeString && res.data.string.size > 0) { - allocated_arg = xstrdup(res.data.string.data); + typval_T no_args[] = { { .v_type = VAR_UNKNOWN } }; + typval_T rettv; + nlua_call_vimfn("vim._core.help", "resolve_tag", no_args, &rettv); + if (rettv.v_type == VAR_STRING && rettv.vval.v_string != NULL && *rettv.vval.v_string != NUL) { + allocated_arg = rettv.vval.v_string; // takes ownership arg = allocated_arg; - } - api_free_object(res); - api_clear_error(&err); - if (allocated_arg == NULL) { + } else { + tv_clear(&rettv); emsg(_(e_noident)); return; } @@ -335,24 +334,18 @@ static int help_compare(const void *s1, const void *s2) /// When "keep_lang" is true try keeping the language of the current buffer. int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep_lang) { - Error err = ERROR_INIT; - MAXSIZE_TEMP_ARRAY(args, 1); - - ADD_C(args, CSTR_AS_OBJ(arg)); - - Object res = NLUA_EXEC_STATIC("return require'vim._core.help'.escape_subject(...)", - args, kRetObject, NULL, &err); - - if (ERROR_SET(&err)) { - emsg_multiline(err.msg, "lua_error", HLF_E, true); - api_clear_error(&err); + typval_T tv_args[] = { + { .v_type = VAR_STRING, .vval.v_string = (char *)arg }, + { .v_type = VAR_UNKNOWN }, + }; + typval_T rettv; + nlua_call_vimfn("vim._core.help", "escape_subject", tv_args, &rettv); + if (rettv.v_type != VAR_STRING || rettv.vval.v_string == NULL) { + tv_clear(&rettv); return FAIL; } - api_clear_error(&err); - - assert(res.type == kObjectTypeString); - xstrlcpy(IObuff, res.data.string.data, sizeof(IObuff)); - api_free_object(res); + xstrlcpy(IObuff, rettv.vval.v_string, sizeof(IObuff)); + tv_clear(&rettv); *matches = NULL; *num_matches = 0; @@ -467,14 +460,8 @@ void prepare_help_buffer(void) /// Populate *local-additions* in help.txt void get_local_additions(void) { - Error err = ERROR_INIT; - Object res = NLUA_EXEC_STATIC("return require'vim._core.help'.local_additions()", - (Array)ARRAY_DICT_INIT, kRetNilBool, NULL, &err); - if (ERROR_SET(&err)) { - emsg_multiline(err.msg, "lua_error", HLF_E, true); - } - api_free_object(res); - api_clear_error(&err); + typval_T no_args[] = { { .v_type = VAR_UNKNOWN } }; + nlua_call_vimfn("vim._core.help", "local_additions", no_args, NULL); } /// ":exusage" diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index e0e3f5ef9f..1771a01565 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -194,38 +194,18 @@ static void nlua_push_eap(lua_State *lstate, exarg_T *eap, const cmdmod_T *cmod) lua_pushstring(lstate, reg); lua_setfield(lstate, -2, "reg"); - nlua_push_cmdmod(lstate, cmod); - lua_setfield(lstate, -2, "smods"); -} - -/// Calls Lua to implement an excmd. Passes `eap` + `cmdmod` to Lua as a dict arg, which is arranged -/// to match the Lua type `vim.api.keyset.create_user_command.command_args`. -/// -/// @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. -void nlua_call_excmd(const char *module, const char *func, exarg_T *eap, const cmdmod_T *cmod) -{ - lua_State *const lstate = global_lstate; - - lua_getglobal(lstate, "require"); - lua_pushstring(lstate, module); - if (lua_pcall(lstate, 1, 1, 0) != 0) { - semsg("E5108: %s", lua_tostring(lstate, -1)); - lua_pop(lstate, 1); - return; + // 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"); } - lua_getfield(lstate, -1, func); - lua_remove(lstate, -2); - - lua_newtable(lstate); - nlua_push_eap(lstate, eap, cmod); - if (nlua_pcall(lstate, 1, 0)) { - semsg("E5108: %s", lua_tostring(lstate, -1)); - lua_pop(lstate, 1); - } + nlua_push_cmdmod(lstate, cmod); + lua_setfield(lstate, -2, "smods"); } #if __has_feature(address_sanitizer) @@ -1788,6 +1768,47 @@ void nlua_call_vimfn(const char *module, const char *func, typval_T *argvars, ty nlua_typval_exec(buf, strlen(buf), module, argvars, argcount, false, rettv); } +/// Calls Lua to implement an excmd. Passes `eap` + `cmdmod` to Lua as a dict arg, which is arranged +/// to match the Lua type `vim.api.keyset.create_user_command.command_args`. +/// +/// @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 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, + typval_T *extra) +{ + lua_State *const lstate = global_lstate; + + lua_getglobal(lstate, "require"); + lua_pushstring(lstate, module); + if (lua_pcall(lstate, 1, 1, 0) != 0) { + nlua_error(lstate, "E5108: %s"); + return false; + } + lua_getfield(lstate, -1, func); + lua_remove(lstate, -2); + + lua_newtable(lstate); + nlua_push_eap(lstate, eap, cmod); + + int nargs = 1; + if (extra) { + nlua_push_typval(lstate, extra, 0); + nargs = 2; + } + + if (nlua_pcall(lstate, nargs, 0)) { + // Not "E5108" because this is a logical/application error, not a "Lua error". + emsg(lua_tostring(lstate, -1)); + lua_pop(lstate, 1); + return false; + } + return true; +} + /// Checks if a LuaRef refers to a function. bool nlua_ref_is_function(LuaRef ref) { @@ -2417,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; @@ -2447,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) { diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua index 7c67222cb3..4e86420101 100644 --- a/test/functional/ex_cmds/excmd_spec.lua +++ b/test/functional/ex_cmds/excmd_spec.lua @@ -8,7 +8,20 @@ local fn = n.fn local pcall_err = t.pcall_err local assert_alive = n.assert_alive -describe('Ex cmds', function() +describe('nlua_call_excmd excmds', function() + -- Exercise nlua_call_excmd by testing commands implemented with it (:log, :lsp). + + before_each(function() + clear() + end) + + it('error propagation, formatting', function() + t.eq('Vim(lsp):E5800: Invalid :lsp subcommand: bogus', pcall_err(command, 'lsp bogus')) + t.matches('Vim%(log%):E5200: No such log.*', pcall_err(command, 'log bogus')) + end) +end) + +describe('excmds', function() before_each(function() clear() end) diff --git a/test/functional/ex_cmds/lsp_spec.lua b/test/functional/ex_cmds/lsp_spec.lua index 2cef077b30..3922c55b14 100644 --- a/test/functional/ex_cmds/lsp_spec.lua +++ b/test/functional/ex_cmds/lsp_spec.lua @@ -29,7 +29,7 @@ describe(':lsp', function() env = { VIMRUNTIME = 'non-existent' }, } t.matches( - [[Vim%(lsp%):E%d+: .*module 'vim%.lsp' not found:]], + [[.*module 'vim%.lsp' not found:]], vim.split(t.pcall_err(n.command, 'lsp enable dummy'), '\n')[1] ) end) |
