aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_docmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r--src/nvim/ex_docmd.c192
1 files changed, 137 insertions, 55 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 0b466bbe4e..2913f6d4e9 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -9,12 +9,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <uv.h>
#include "auto/config.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/arglist.h"
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/change.h"
@@ -28,23 +31,27 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/ex_eval_defs.h"
#include "nvim/ex_getln.h"
#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
+#include "nvim/garray_defs.h"
#include "nvim/getchar.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/input.h"
#include "nvim/keycodes.h"
@@ -52,20 +59,25 @@
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memline_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
+#include "nvim/normal_defs.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/option_defs.h"
#include "nvim/option_vars.h"
#include "nvim/optionstr.h"
#include "nvim/os/fs.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
#include "nvim/popupmenu.h"
@@ -73,16 +85,20 @@
#include "nvim/profile.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
+#include "nvim/regexp_defs.h"
#include "nvim/runtime.h"
+#include "nvim/runtime_defs.h"
#include "nvim/search.h"
#include "nvim/shada.h"
#include "nvim/state.h"
+#include "nvim/state_defs.h"
#include "nvim/statusline.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/undo_defs.h"
#include "nvim/usercmd.h"
#include "nvim/vim_defs.h"
#include "nvim/window.h"
@@ -190,8 +206,8 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp)
trylevel = dsp->trylevel;
force_abort = dsp->force_abort;
caught_stack = dsp->caught_stack;
- (void)v_exception(dsp->vv_exception);
- (void)v_throwpoint(dsp->vv_throwpoint);
+ v_exception(dsp->vv_exception);
+ v_throwpoint(dsp->vv_throwpoint);
did_emsg = dsp->did_emsg;
got_int = dsp->got_int;
did_throw = dsp->did_throw;
@@ -293,6 +309,33 @@ static void msg_verbose_cmd(linenr_T lnum, char *cmd)
no_wait_return--;
}
+static int cmdline_call_depth = 0; ///< recursiveness
+
+/// Start executing an Ex command line.
+///
+/// @return FAIL if too recursive, OK otherwise.
+static int do_cmdline_start(void)
+{
+ assert(cmdline_call_depth >= 0);
+ // It's possible to create an endless loop with ":execute", catch that
+ // here. The value of 200 allows nested function calls, ":source", etc.
+ // Allow 200 or 'maxfuncdepth', whatever is larger.
+ if (cmdline_call_depth >= 200 && cmdline_call_depth >= p_mfd) {
+ return FAIL;
+ }
+ cmdline_call_depth++;
+ start_batch_changes();
+ return OK;
+}
+
+/// End executing an Ex command line.
+static void do_cmdline_end(void)
+{
+ cmdline_call_depth--;
+ assert(cmdline_call_depth >= 0);
+ end_batch_changes();
+}
+
/// Execute a simple command line. Used for translated commands like "*".
int do_cmdline_cmd(const char *cmd)
{
@@ -343,7 +386,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
char *(*cmd_getline)(int, void *, int, bool);
void *cmd_cookie;
struct loop_cookie cmd_loop_cookie;
- static int call_depth = 0; // recursiveness
// For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory
// location for storing error messages to be converted to an exception.
@@ -355,10 +397,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
msg_list = &private_msg_list;
private_msg_list = NULL;
- // It's possible to create an endless loop with ":execute", catch that
- // here. The value of 200 allows nested function calls, ":source", etc.
- // Allow 200 or 'maxfuncdepth', whatever is larger.
- if (call_depth >= 200 && call_depth >= p_mfd) {
+ if (do_cmdline_start() == FAIL) {
emsg(_(e_command_too_recursive));
// When converting to an exception, we do not include the command name
// since this is not an error of the specific command.
@@ -366,8 +405,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
msg_list = saved_msg_list;
return FAIL;
}
- call_depth++;
- start_batch_changes();
ga_init(&lines_ga, (int)sizeof(wcmd_T), 10);
@@ -710,7 +747,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
}
// Convert an interrupt to an exception if appropriate.
- (void)do_intthrow(&cstack);
+ do_intthrow(&cstack);
// Continue executing command lines when:
// - no CTRL-C typed, no aborting error, no exception thrown or try
@@ -868,8 +905,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
did_endif = false; // in case do_cmdline used recursively
- call_depth--;
- end_batch_changes();
+ do_cmdline_end();
return retval;
}
@@ -1653,9 +1689,13 @@ static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool pre
/// @param preview Execute command preview callback instead of actual command
int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
{
- const char *errormsg = NULL;
int retv = 0;
+ if (do_cmdline_start() == FAIL) {
+ emsg(_(e_command_too_recursive));
+ return retv;
+ }
+ const char *errormsg = NULL;
#undef ERROR
#define ERROR(msg) \
do { \
@@ -1703,8 +1743,8 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
&& eap->addr_type == ADDR_LINES) {
// Put the first line at the start of a closed fold, put the last line
// at the end of a closed fold.
- (void)hasFolding(eap->line1, &eap->line1, NULL);
- (void)hasFolding(eap->line2, NULL, &eap->line2);
+ hasFolding(eap->line1, &eap->line1, NULL);
+ hasFolding(eap->line2, NULL, &eap->line2);
}
// Use first argument as count when possible
@@ -1712,6 +1752,9 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
goto end;
}
+ cstack_T cstack = { .cs_idx = -1 };
+ eap->cstack = &cstack;
+
// Execute the command
execute_cmd0(&retv, eap, &errormsg, preview);
@@ -1719,9 +1762,12 @@ end:
if (errormsg != NULL && *errormsg != NUL) {
emsg(errormsg);
}
+
// Undo command modifiers
undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;
+
+ do_cmdline_end();
return retv;
#undef ERROR
}
@@ -1955,7 +2001,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
}
if (!ea.skip && got_int) {
ea.skip = true;
- (void)do_intthrow(cstack);
+ do_intthrow(cstack);
}
// 4. Parse a range specifier of the form: addr [,addr] [;addr] ..
@@ -2167,8 +2213,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
&& ea.addr_type == ADDR_LINES) {
// Put the first line at the start of a closed fold, put the last line
// at the end of a closed fold.
- (void)hasFolding(ea.line1, &ea.line1, NULL);
- (void)hasFolding(ea.line2, NULL, &ea.line2);
+ hasFolding(ea.line1, &ea.line1, NULL);
+ hasFolding(ea.line2, NULL, &ea.line2);
}
// For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg'
@@ -2651,7 +2697,7 @@ static void apply_cmdmod(cmdmod_T *cmod)
// Set 'eventignore' to "all".
// First save the existing option value for restoring it later.
cmod->cmod_save_ei = xstrdup(p_ei);
- set_string_option_direct("ei", -1, "all", OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, "all", 0, SID_NONE);
}
}
@@ -2671,7 +2717,7 @@ void undo_cmdmod(cmdmod_T *cmod)
if (cmod->cmod_save_ei != NULL) {
// Restore 'eventignore' to the value before ":noautocmd".
- set_string_option_direct("ei", -1, cmod->cmod_save_ei, OPT_FREE, SID_NONE);
+ set_string_option_direct(kOptEventignore, cmod->cmod_save_ei, 0, SID_NONE);
free_string_option(cmod->cmod_save_ei);
cmod->cmod_save_ei = NULL;
}
@@ -3256,7 +3302,7 @@ static const char *addr_error(cmd_addr_T addr_type)
/// @param errormsg Error message, if any
///
/// @return MAXLNUM when no Ex address was found.
-static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int skip, bool silent,
+static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool skip, bool silent,
int to_other_file, int address_count, const char **errormsg)
FUNC_ATTR_NONNULL_ALL
{
@@ -3376,7 +3422,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd);
cmd++;
if (fm != NULL && fm->fnum != curbuf->handle) {
- (void)mark_move_to(fm, 0);
+ mark_move_to(fm, 0);
// Jumped to another file.
lnum = curwin->w_cursor.lnum;
} else {
@@ -3550,7 +3596,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
// closed fold after the first address.
if (addr_type == ADDR_LINES && (i == '-' || i == '+')
&& address_count >= 2) {
- (void)hasFolding(lnum, NULL, &lnum);
+ hasFolding(lnum, NULL, &lnum);
}
if (i == '-') {
lnum -= n;
@@ -3777,12 +3823,12 @@ int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp)
// Decide to expand wildcards *before* replacing '%', '#', etc. If
// the file name contains a wildcard it should not cause expanding.
// (it will be expanded anyway if there is a wildcard before replacing).
- int has_wildcards = path_has_wildcard(p);
+ bool has_wildcards = path_has_wildcard(p);
while (*p != NUL) {
// Skip over `=expr`, wildcards in it are not expanded.
if (p[0] == '`' && p[1] == '=') {
p += 2;
- (void)skip_expr(&p, NULL);
+ skip_expr(&p, NULL);
if (*p == '`') {
p++;
}
@@ -3857,9 +3903,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp)
|| eap->cmdidx == CMD_bang
|| eap->cmdidx == CMD_terminal)
&& strpbrk(repl, "!") != NULL) {
- char *l;
-
- l = vim_strsave_escaped(repl, "!");
+ char *l = vim_strsave_escaped(repl, "!");
xfree(repl);
repl = l;
}
@@ -3887,7 +3931,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp)
p = NULL;
}
if (p != NULL) {
- (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep);
+ repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep);
}
}
@@ -3915,7 +3959,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp)
if (p == NULL) {
return FAIL;
}
- (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep);
+ repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep);
xfree(p);
}
}
@@ -4001,7 +4045,7 @@ void separate_nextcmd(exarg_T *eap)
} else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) {
// Skip over `=expr` when wildcards are expanded.
p += 2;
- (void)skip_expr(&p, NULL);
+ skip_expr(&p, NULL);
if (*p == NUL) { // stop at NUL after CTRL-V
break;
}
@@ -4060,7 +4104,7 @@ static char *getargcmd(char **argp)
/// Find end of "+command" argument. Skip over "\ " and "\\".
///
/// @param rembs true to halve the number of backslashes
-char *skip_cmd_arg(char *p, int rembs)
+char *skip_cmd_arg(char *p, bool rembs)
{
while (*p && !ascii_isspace(*p)) {
if (*p == '\\' && p[1] != NUL) {
@@ -4373,7 +4417,7 @@ static void ex_doautocmd(exarg_T *eap)
int call_do_modelines = check_nomodeline(&arg);
bool did_aucmd;
- (void)do_doautocmd(arg, false, &did_aucmd);
+ do_doautocmd(arg, false, &did_aucmd);
// Only when there is no <nomodeline>.
if (call_do_modelines && did_aucmd) {
do_modelines(0);
@@ -4505,7 +4549,7 @@ char *check_nextcmd(char *p)
/// @param message when false check only, no messages
///
/// @return FAIL and give error message if 'message' true, return OK otherwise
-static int check_more(int message, bool forceit)
+static int check_more(bool message, bool forceit)
{
int n = ARGCOUNT - curwin->w_arg_idx - 1;
@@ -5368,9 +5412,9 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
|| eap->cmdidx == CMD_vnew) && *eap->arg == NUL) {
// ":new" or ":tabnew" without argument: edit a new empty buffer
setpcmark();
- (void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE,
- ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0),
- old_curwin == NULL ? curwin : NULL);
+ do_ecmd(0, NULL, NULL, eap, ECMD_ONE,
+ ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0),
+ old_curwin == NULL ? curwin : NULL);
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|| *eap->arg != NUL) {
// Can't edit another file when "textlock" or "curbuf->b_ro_locked" is set.
@@ -5552,7 +5596,7 @@ static void ex_read(exarg_T *eap)
eap->line2, 0, (linenr_T)MAXLNUM, eap, 0, false);
} else {
if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) {
- (void)setaltfname(eap->arg, eap->arg, 1);
+ setaltfname(eap->arg, eap->arg, 1);
}
i = readfile(eap->arg, NULL,
eap->line2, 0, (linenr_T)MAXLNUM, eap, 0, false);
@@ -5823,7 +5867,7 @@ void do_sleep(int64_t msec)
// If CTRL-C was typed to interrupt the sleep, drop the CTRL-C from the
// input buffer, otherwise a following call to input() fails.
if (got_int) {
- (void)vpeekc();
+ vpeekc();
}
}
@@ -5908,7 +5952,7 @@ static void ex_operators(exarg_T *eap)
case CMD_yank:
oa.op_type = OP_YANK;
- (void)op_yank(&oa, true);
+ op_yank(&oa, true);
break;
default: // CMD_rshift or CMD_lshift
@@ -6050,7 +6094,7 @@ static void ex_at(exarg_T *eap)
// Continue until the stuff buffer is empty and all added characters
// have been consumed.
while (!stuff_empty() || typebuf.tb_len > prev_len) {
- (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
}
exec_from_reg = save_efr;
@@ -6210,7 +6254,7 @@ static void ex_redir(exarg_T *eap)
semsg(_(e_invarg2), eap->arg);
}
} else if (*arg == '=' && arg[1] == '>') {
- int append;
+ bool append;
// redirect to a variable
close_redir();
@@ -6224,7 +6268,7 @@ static void ex_redir(exarg_T *eap)
}
if (var_redir_start(skipwhite(arg), append) == OK) {
- redir_vname = 1;
+ redir_vname = true;
}
} else { // TODO(vim): redirect to a buffer
semsg(_(e_invarg2), eap->arg);
@@ -6330,7 +6374,7 @@ static void close_redir(void)
redir_reg = 0;
if (redir_vname) {
var_redir_stop();
- redir_vname = 0;
+ redir_vname = false;
}
}
@@ -7171,7 +7215,7 @@ static void ex_shada(exarg_T *eap)
p_shada = "'100";
}
if (eap->cmdidx == CMD_rviminfo || eap->cmdidx == CMD_rshada) {
- (void)shada_read_everything(eap->arg, eap->forceit, false);
+ shada_read_everything(eap->arg, eap->forceit, false);
} else {
shada_write_file(eap->arg, eap->forceit);
}
@@ -7242,7 +7286,7 @@ static void ex_filetype(exarg_T *eap)
}
}
if (*arg == 'd') {
- (void)do_doautocmd("filetypedetect BufRead", true, NULL);
+ do_doautocmd("filetypedetect BufRead", true, NULL);
do_modelines(0);
}
} else if (strcmp(arg, "off") == 0) {
@@ -7304,7 +7348,7 @@ static void ex_setfiletype(exarg_T *eap)
arg += 9;
}
- set_option_value_give_err("filetype", CSTR_AS_OPTVAL(arg), OPT_LOCAL);
+ set_option_value_give_err(kOptFiletype, CSTR_AS_OPTVAL(arg), OPT_LOCAL);
if (arg != eap->arg) {
did_filetype = false;
}
@@ -7383,6 +7427,44 @@ void set_pressedreturn(bool val)
ex_pressedreturn = 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)) {
+ return;
+ }
+
+ const char *vimruntime_env = os_getenv("VIMRUNTIME");
+ if (vimruntime_env == NULL) {
+ emsg(_("E5009: $VIMRUNTIME is empty or unset"));
+ } else {
+ bool rtp_ok = NULL != strstr(p_rtp, vimruntime_env);
+ if (rtp_ok) {
+ semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env);
+ } else {
+ emsg(_("E5009: Invalid 'runtimepath'"));
+ }
+ }
+ semsg_multiline(err.msg);
+ api_clear_error(&err);
+}
+
static void ex_terminal(exarg_T *eap)
{
char ex_cmd[1024];
@@ -7390,10 +7472,8 @@ static void ex_terminal(exarg_T *eap)
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] = '\0';
-
+ // 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");
@@ -7424,7 +7504,9 @@ static void ex_terminal(exarg_T *eap)
char shell_argv[512] = { 0 };
while (*p != NULL) {
- snprintf(tempstring, sizeof(tempstring), ",\"%s\"", *p);
+ char *escaped = vim_strsave_escaped(*p, "\"\\");
+ snprintf(tempstring, sizeof(tempstring), ",\"%s\"", escaped);
+ xfree(escaped);
xstrlcat(shell_argv, tempstring, sizeof(shell_argv));
p++;
}