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.c535
1 files changed, 353 insertions, 182 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 870284a0f7..4070e9fe5b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -36,7 +36,6 @@
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/misc2.h"
#include "nvim/keymap.h"
#include "nvim/file_search.h"
#include "nvim/garray.h"
@@ -272,7 +271,7 @@ do_exmode (
int do_cmdline_cmd(char *cmd)
{
return do_cmdline((char_u *)cmd, NULL, NULL,
- DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
+ DOCMD_NOWAIT|DOCMD_KEYTYPED);
}
/*
@@ -345,7 +344,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
msg_list = saved_msg_list;
return FAIL;
}
- ++call_depth;
+ call_depth++;
+ start_batch_changes();
cstack.cs_idx = -1;
cstack.cs_looplevel = 0;
@@ -597,11 +597,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* do_one_cmd() will return NULL if there is no trailing '|'.
* "cmdline_copy" can change, e.g. for '%' and '#' expansion.
*/
- ++recursive;
- next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE,
- &cstack,
- cmd_getline, cmd_cookie);
- --recursive;
+ recursive++;
+ next_cmdline = do_one_cmd(&cmdline_copy, flags,
+ &cstack,
+ cmd_getline, cmd_cookie);
+ recursive--;
if (cmd_cookie == (void *)&cmd_loop_cookie)
/* Use "current_line" from "cmd_loop_cookie", it may have been
@@ -952,7 +952,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
did_endif = FALSE; /* in case do_cmdline used recursively */
- --call_depth;
+ call_depth--;
+ end_batch_changes();
return retval;
}
@@ -1224,7 +1225,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
* This function may be called recursively!
*/
static char_u * do_one_cmd(char_u **cmdlinep,
- int sourcing,
+ int flags,
struct condstack *cstack,
LineGetter fgetline,
void *cookie /* argument for fgetline() */
@@ -1247,7 +1248,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
memset(&ea, 0, sizeof(ea));
ea.line1 = 1;
ea.line2 = 1;
- ++ex_nesting_level;
+ ex_nesting_level++;
/* When the last file has not been edited :q has to be typed twice. */
if (quitmore
@@ -1301,8 +1302,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* 2. Handle command modifiers.
*/
p = ea.cmd;
- if (ascii_isdigit(*ea.cmd))
- p = skipwhite(skipdigits(ea.cmd));
+ p = skip_range(ea.cmd, NULL);
switch (*p) {
/* When adding an entry, also modify cmd_exists(). */
case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3))
@@ -1313,8 +1313,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) {
cmdmod.split |= WSP_BELOW;
continue;
- }
+ }
if (checkforcmd(&ea.cmd, "browse", 3)) {
+ cmdmod.browse = true;
continue;
}
if (!checkforcmd(&ea.cmd, "botright", 2))
@@ -1324,24 +1325,24 @@ static char_u * do_one_cmd(char_u **cmdlinep,
case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4))
break;
- cmdmod.confirm = TRUE;
+ cmdmod.confirm = true;
continue;
case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) {
- cmdmod.keepmarks = TRUE;
+ cmdmod.keepmarks = true;
continue;
}
if (checkforcmd(&ea.cmd, "keepalt", 5)) {
- cmdmod.keepalt = TRUE;
+ cmdmod.keepalt = true;
continue;
}
if (checkforcmd(&ea.cmd, "keeppatterns", 5)) {
- cmdmod.keeppatterns = TRUE;
+ cmdmod.keeppatterns = true;
continue;
}
if (!checkforcmd(&ea.cmd, "keepjumps", 5))
break;
- cmdmod.keepjumps = TRUE;
+ cmdmod.keepjumps = true;
continue;
/* ":hide" and ":hide | cmd" are not modifiers */
@@ -1349,11 +1350,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|| *p == NUL || ends_excmd(*p))
break;
ea.cmd = p;
- cmdmod.hide = TRUE;
+ cmdmod.hide = true;
continue;
case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) {
- cmdmod.lockmarks = TRUE;
+ cmdmod.lockmarks = true;
continue;
}
@@ -1373,7 +1374,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
continue;
}
- if (!checkforcmd(&ea.cmd, "noswapfile", 6)) {
+ if (!checkforcmd(&ea.cmd, "noswapfile", 3)) {
break;
}
cmdmod.noswapfile = true;
@@ -1404,12 +1405,18 @@ static char_u * do_one_cmd(char_u **cmdlinep,
continue;
case 't': if (checkforcmd(&p, "tab", 3)) {
- if (ascii_isdigit(*ea.cmd))
- cmdmod.tab = atoi((char *)ea.cmd) + 1;
- else
- cmdmod.tab = tabpage_index(curtab) + 1;
- ea.cmd = p;
- continue;
+ long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, ea.skip, false);
+ if (tabnr == MAXLNUM) {
+ cmdmod.tab = tabpage_index(curtab) + 1;
+ } else {
+ if (tabnr < 0 || tabnr > LAST_TAB_NR) {
+ errormsg = (char_u *)_(e_invrange);
+ goto doend;
+ }
+ cmdmod.tab = tabnr + 1;
+ }
+ ea.cmd = p;
+ continue;
}
if (!checkforcmd(&ea.cmd, "topleft", 2))
break;
@@ -1535,9 +1542,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
break;
}
ea.cmd = skipwhite(ea.cmd);
- lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0);
- if (ea.cmd == NULL) /* error detected */
+ lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip,
+ ea.addr_count == 0);
+ if (ea.cmd == NULL) { // error detected
goto doend;
+ }
if (lnum == MAXLNUM) {
if (*ea.cmd == '%') { /* '%' - all lines */
++ea.cmd;
@@ -1702,7 +1711,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
xfree(p);
// If the autocommands did something and didn't cause an error, try
// finding the command again.
- p = (ret && !aborting()) ? find_command(&ea, NULL) : NULL;
+ p = (ret && !aborting()) ? find_command(&ea, NULL) : ea.cmd;
}
if (p == NULL) {
@@ -1718,8 +1727,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (ea.cmdidx == CMD_SIZE) {
if (!ea.skip) {
STRCPY(IObuff, _("E492: Not an editor command"));
- if (!sourcing)
+ if (!(flags & DOCMD_VERBOSE)) {
append_command(*cmdlinep);
+ }
errormsg = IObuff;
did_emsg_syntax = TRUE;
}
@@ -1763,11 +1773,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (text_locked() && !(ea.argt & CMDWIN)
&& !IS_USER_CMDIDX(ea.cmdidx)) {
- /* Command not allowed when editing the command line. */
- if (cmdwin_type != 0)
- errormsg = (char_u *)_(e_cmdwin);
- else
- errormsg = (char_u *)_(e_secure);
+ // Command not allowed when editing the command line.
+ errormsg = get_text_locked_msg();
goto doend;
}
/* Disallow editing another buffer when "curbuf_lock" is set.
@@ -1804,7 +1811,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
*/
if (!global_busy && ea.line1 > ea.line2) {
if (msg_silent == 0) {
- if (sourcing || exmode_active) {
+ if ((flags & DOCMD_VERBOSE) || exmode_active) {
errormsg = (char_u *)_("E493: Backwards range given");
goto doend;
}
@@ -2216,7 +2223,7 @@ doend:
curwin->w_cursor.lnum = 1;
if (errormsg != NULL && *errormsg != NUL && !did_emsg) {
- if (sourcing) {
+ if (flags & DOCMD_VERBOSE) {
if (errormsg != IObuff) {
STRCPY(IObuff, errormsg);
errormsg = IObuff;
@@ -3315,6 +3322,11 @@ set_one_cmd_context (
xp->xp_pattern = arg;
break;
+ case CMD_packadd:
+ xp->xp_context = EXPAND_PACKADD;
+ xp->xp_pattern = arg;
+ break;
+
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
p = skiptowhite(arg);
@@ -3842,7 +3854,7 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
ptr = new_cmdline;
while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) {
i = (int)(pos - program);
- STRNCPY(ptr, program, i);
+ memcpy(ptr, program, i);
STRCPY(ptr += i, p);
ptr += len;
program = pos + 2;
@@ -4355,12 +4367,15 @@ static void ex_autocmd(exarg_T *eap)
*/
static void ex_doautocmd(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
int call_do_modelines = check_nomodeline(&arg);
+ bool did_aucmd;
- (void)do_doautocmd(arg, TRUE);
- if (call_do_modelines) /* Only when there is no <nomodeline>. */
+ (void)do_doautocmd(arg, true, &did_aucmd);
+ // Only when there is no <nomodeline>.
+ if (call_do_modelines && did_aucmd) {
do_modelines(0);
+ }
}
/*
@@ -4640,14 +4655,14 @@ static struct {
char *name;
} addr_type_complete[] =
{
- {ADDR_ARGUMENTS, "arguments"},
- {ADDR_LINES, "lines"},
- {ADDR_LOADED_BUFFERS, "loaded_buffers"},
- {ADDR_TABS, "tabs"},
- {ADDR_BUFFERS, "buffers"},
- {ADDR_WINDOWS, "windows"},
- {ADDR_QUICKFIX, "quickfix"},
- {-1, NULL}
+ { ADDR_ARGUMENTS, "arguments" },
+ { ADDR_LINES, "lines" },
+ { ADDR_LOADED_BUFFERS, "loaded_buffers" },
+ { ADDR_TABS, "tabs" },
+ { ADDR_BUFFERS, "buffers" },
+ { ADDR_WINDOWS, "windows" },
+ { ADDR_QUICKFIX, "quickfix" },
+ { -1, NULL }
};
/*
@@ -4659,41 +4674,42 @@ static struct {
char *name;
} command_complete[] =
{
- {EXPAND_AUGROUP, "augroup"},
- {EXPAND_BEHAVE, "behave"},
- {EXPAND_BUFFERS, "buffer"},
- {EXPAND_COLORS, "color"},
- {EXPAND_COMMANDS, "command"},
- {EXPAND_COMPILER, "compiler"},
- {EXPAND_CSCOPE, "cscope"},
- {EXPAND_USER_DEFINED, "custom"},
- {EXPAND_USER_LIST, "customlist"},
- {EXPAND_DIRECTORIES, "dir"},
- {EXPAND_ENV_VARS, "environment"},
- {EXPAND_EVENTS, "event"},
- {EXPAND_EXPRESSION, "expression"},
- {EXPAND_FILES, "file"},
- {EXPAND_FILES_IN_PATH, "file_in_path"},
- {EXPAND_FILETYPE, "filetype"},
- {EXPAND_FUNCTIONS, "function"},
- {EXPAND_HELP, "help"},
- {EXPAND_HIGHLIGHT, "highlight"},
- {EXPAND_HISTORY, "history"},
+ { EXPAND_AUGROUP, "augroup" },
+ { EXPAND_BEHAVE, "behave" },
+ { EXPAND_BUFFERS, "buffer" },
+ { EXPAND_COLORS, "color" },
+ { EXPAND_COMMANDS, "command" },
+ { EXPAND_COMPILER, "compiler" },
+ { EXPAND_CSCOPE, "cscope" },
+ { EXPAND_USER_DEFINED, "custom" },
+ { EXPAND_USER_LIST, "customlist" },
+ { EXPAND_DIRECTORIES, "dir" },
+ { EXPAND_ENV_VARS, "environment" },
+ { EXPAND_EVENTS, "event" },
+ { EXPAND_EXPRESSION, "expression" },
+ { EXPAND_FILES, "file" },
+ { EXPAND_FILES_IN_PATH, "file_in_path" },
+ { EXPAND_FILETYPE, "filetype" },
+ { EXPAND_FUNCTIONS, "function" },
+ { EXPAND_HELP, "help" },
+ { EXPAND_HIGHLIGHT, "highlight" },
+ { EXPAND_HISTORY, "history" },
#ifdef HAVE_WORKING_LIBINTL
- {EXPAND_LOCALES, "locale"},
+ { EXPAND_LOCALES, "locale" },
#endif
- {EXPAND_MAPPINGS, "mapping"},
- {EXPAND_MENUS, "menu"},
- {EXPAND_OWNSYNTAX, "syntax"},
- {EXPAND_SYNTIME, "syntime"},
- {EXPAND_SETTINGS, "option"},
- {EXPAND_SHELLCMD, "shellcmd"},
- {EXPAND_SIGN, "sign"},
- {EXPAND_TAGS, "tag"},
- {EXPAND_TAGS_LISTFILES, "tag_listfiles"},
- {EXPAND_USER, "user"},
- {EXPAND_USER_VARS, "var"},
- {0, NULL}
+ { EXPAND_MAPPINGS, "mapping" },
+ { EXPAND_MENUS, "menu" },
+ { EXPAND_OWNSYNTAX, "syntax" },
+ { EXPAND_SYNTIME, "syntime" },
+ { EXPAND_SETTINGS, "option" },
+ { EXPAND_PACKADD, "packadd" },
+ { EXPAND_SHELLCMD, "shellcmd" },
+ { EXPAND_SIGN, "sign" },
+ { EXPAND_TAGS, "tag" },
+ { EXPAND_TAGS_LISTFILES, "tag_listfiles" },
+ { EXPAND_USER, "user" },
+ { EXPAND_USER_VARS, "var" },
+ { 0, NULL }
};
static void uc_list(char_u *name, size_t name_len)
@@ -5146,6 +5162,24 @@ static char_u *uc_split_args(char_u *arg, size_t *lenp)
return buf;
}
+static size_t add_cmd_modifier(char_u *buf, char *mod_str, bool *multi_mods)
+{
+ size_t result = STRLEN(mod_str);
+ if (*multi_mods) {
+ result++;
+ }
+
+ if (buf != NULL) {
+ if (*multi_mods) {
+ STRCAT(buf, " ");
+ }
+ STRCAT(buf, mod_str);
+ }
+
+ *multi_mods = true;
+ return result;
+}
+
/*
* Check for a <> code in a user command.
* "code" points to the '<'. "len" the length of the <> (inclusive).
@@ -5170,8 +5204,8 @@ uc_check_code (
char_u *p = code + 1;
size_t l = len - 2;
int quote = 0;
- enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_REGISTER,
- ct_LT, ct_NONE } type = ct_NONE;
+ enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_MODS,
+ ct_REGISTER, ct_LT, ct_NONE } type = ct_NONE;
if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') {
quote = (*p == 'q' || *p == 'Q') ? 1 : 2;
@@ -5179,23 +5213,26 @@ uc_check_code (
l -= 2;
}
- ++l;
- if (l <= 1)
+ l++;
+ if (l <= 1) {
type = ct_NONE;
- else if (STRNICMP(p, "args>", l) == 0)
+ } else if (STRNICMP(p, "args>", l) == 0) {
type = ct_ARGS;
- else if (STRNICMP(p, "bang>", l) == 0)
+ } else if (STRNICMP(p, "bang>", l) == 0) {
type = ct_BANG;
- else if (STRNICMP(p, "count>", l) == 0)
+ } else if (STRNICMP(p, "count>", l) == 0) {
type = ct_COUNT;
- else if (STRNICMP(p, "line1>", l) == 0)
+ } else if (STRNICMP(p, "line1>", l) == 0) {
type = ct_LINE1;
- else if (STRNICMP(p, "line2>", l) == 0)
+ } else if (STRNICMP(p, "line2>", l) == 0) {
type = ct_LINE2;
- else if (STRNICMP(p, "lt>", l) == 0)
+ } else if (STRNICMP(p, "lt>", l) == 0) {
type = ct_LT;
- else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0)
+ } else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0) {
type = ct_REGISTER;
+ } else if (STRNICMP(p, "mods>", l) == 0) {
+ type = ct_MODS;
+ }
switch (type) {
case ct_ARGS:
@@ -5303,6 +5340,87 @@ uc_check_code (
break;
}
+ case ct_MODS:
+ {
+ result = quote ? 2 : 0;
+ if (buf != NULL) {
+ if (quote) {
+ *buf++ = '"';
+ }
+ *buf = '\0';
+ }
+
+ bool multi_mods = false;
+
+ // :aboveleft and :leftabove
+ if (cmdmod.split & WSP_ABOVE) {
+ result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
+ }
+ // :belowright and :rightbelow
+ if (cmdmod.split & WSP_BELOW) {
+ result += add_cmd_modifier(buf, "belowright", &multi_mods);
+ }
+ // :botright
+ if (cmdmod.split & WSP_BOT) {
+ result += add_cmd_modifier(buf, "botright", &multi_mods);
+ }
+
+ typedef struct {
+ bool *set;
+ char *name;
+ } mod_entry_T;
+ static mod_entry_T mod_entries[] = {
+ { &cmdmod.browse, "browse" },
+ { &cmdmod.confirm, "confirm" },
+ { &cmdmod.hide, "hide" },
+ { &cmdmod.keepalt, "keepalt" },
+ { &cmdmod.keepjumps, "keepjumps" },
+ { &cmdmod.keepmarks, "keepmarks" },
+ { &cmdmod.keeppatterns, "keeppatterns" },
+ { &cmdmod.lockmarks, "lockmarks" },
+ { &cmdmod.noswapfile, "noswapfile" }
+ };
+ // the modifiers that are simple flags
+ for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) {
+ if (*mod_entries[i].set) {
+ result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods);
+ }
+ }
+
+ // TODO(vim): How to support :noautocmd?
+ // TODO(vim): How to support :sandbox?
+
+ // :silent
+ if (msg_silent > 0) {
+ result += add_cmd_modifier(buf, emsg_silent > 0 ? "silent!" : "silent",
+ &multi_mods);
+ }
+ // :tab
+ if (cmdmod.tab > 0) {
+ result += add_cmd_modifier(buf, "tab", &multi_mods);
+ }
+ // :topleft
+ if (cmdmod.split & WSP_TOP) {
+ result += add_cmd_modifier(buf, "topleft", &multi_mods);
+ }
+
+ // TODO(vim): How to support :unsilent?
+
+ // :verbose
+ if (p_verbose > 0) {
+ result += add_cmd_modifier(buf, "verbose", &multi_mods);
+ }
+ // :vertical
+ if (cmdmod.split & WSP_VERT) {
+ result += add_cmd_modifier(buf, "vertical", &multi_mods);
+ }
+ if (quote && buf != NULL) {
+ buf += result - 2;
+ *buf = '"';
+ }
+ break;
+ }
+
case ct_REGISTER:
result = eap->regname ? 1 : 0;
if (quote)
@@ -5590,6 +5708,17 @@ int parse_compl_arg(char_u *value, int vallen, int *complp,
return OK;
}
+int cmdcomplete_str_to_type(char_u *complete_str)
+{
+ for (int i = 0; command_complete[i].expand != 0; i++) {
+ if (STRCMP(complete_str, command_complete[i].name) == 0) {
+ return command_complete[i].expand;
+ }
+ }
+
+ return EXPAND_NOTHING;
+}
+
static void ex_colorscheme(exarg_T *eap)
{
if (*eap->arg == NUL) {
@@ -6601,11 +6730,6 @@ do_exedit (
old_curwin == NULL ? curwin : NULL);
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|| *eap->arg != NUL) {
- // ":edit <blank>" is a no-op in terminal buffers. #2822
- if (curbuf->terminal != NULL && eap->cmdidx == CMD_edit && *eap->arg == NUL) {
- return;
- }
-
/* Can't edit another file when "curbuf_lock" is set. Only ":edit"
* can bring us here, others are stopped earlier. */
if (*eap->arg != NUL && curbuf_locked())
@@ -6786,9 +6910,10 @@ static void ex_read(exarg_T *eap)
eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
}
- if (i == FAIL) {
- if (!aborting())
+ if (i != OK) {
+ if (!aborting()) {
EMSG2(_(e_notopen), eap->arg);
+ }
} else {
if (empty && exmode_active) {
/* Delete the empty line that remains. Historically ex does
@@ -6865,13 +6990,14 @@ void post_chdir(CdScope scope)
curwin->w_localdir = vim_strsave(NameBuff);
}
break;
+ case kCdScopeInvalid:
+ // We should never get here
+ assert(false);
}
shorten_fnames(TRUE);
}
-
-
/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`.
void ex_cd(exarg_T *eap)
{
@@ -6913,30 +7039,31 @@ void ex_cd(exarg_T *eap)
new_dir = NameBuff;
}
#endif
- if (vim_chdir(new_dir)) {
- EMSG(_(e_failed));
- } else {
- CdScope scope = kCdScopeGlobal; // Depends on command invoked
+ CdScope scope = kCdScopeGlobal; // Depends on command invoked
- switch (eap->cmdidx) {
- case CMD_tcd:
- case CMD_tchdir:
- scope = kCdScopeTab;
- break;
- case CMD_lcd:
- case CMD_lchdir:
- scope = kCdScopeWindow;
- break;
- default:
- break;
- }
+ switch (eap->cmdidx) {
+ case CMD_tcd:
+ case CMD_tchdir:
+ scope = kCdScopeTab;
+ break;
+ case CMD_lcd:
+ case CMD_lchdir:
+ scope = kCdScopeWindow;
+ break;
+ default:
+ break;
+ }
+ if (vim_chdir(new_dir, scope)) {
+ EMSG(_(e_failed));
+ } else {
post_chdir(scope);
-
- /* Echo the new current directory if the command was typed. */
- if (KeyTyped || p_verbose >= 5)
+ // Echo the new current directory if the command was typed.
+ if (KeyTyped || p_verbose >= 5) {
ex_pwd(eap);
+ }
}
+
xfree(tofree);
}
}
@@ -6989,10 +7116,10 @@ static void ex_sleep(exarg_T *eap)
*/
void do_sleep(long msec)
{
- long done;
ui_flush(); // flush before waiting
- for (done = 0; !got_int && done < msec; done += 1000L) {
- os_delay(msec - done > 1000L ? 1000L : msec - done, true);
+ for (long left = msec; !got_int && left > 0; left -= 1000L) {
+ int next = left > 1000l ? 1000 : (int)left;
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, (int)next, got_int);
os_breakcheck();
}
}
@@ -7122,8 +7249,8 @@ static void ex_put(exarg_T *eap)
eap->forceit = TRUE;
}
curwin->w_cursor.lnum = eap->line2;
- do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L,
- PUT_LINE|PUT_CURSLINE);
+ do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1,
+ PUT_LINE|PUT_CURSLINE);
}
/*
@@ -7132,7 +7259,7 @@ static void ex_put(exarg_T *eap)
static void ex_copymove(exarg_T *eap)
{
long n = get_address(eap, &eap->arg, eap->addr_type, false, false);
- if (eap->arg == NULL) { /* error detected */
+ if (eap->arg == NULL) { // error detected
eap->nextcmd = NULL;
return;
}
@@ -7168,15 +7295,13 @@ void ex_may_print(exarg_T *eap)
}
}
-/*
- * ":smagic" and ":snomagic".
- */
+/// ":smagic" and ":snomagic".
static void ex_submagic(exarg_T *eap)
{
int magic_save = p_magic;
p_magic = (eap->cmdidx == CMD_smagic);
- do_sub(eap);
+ ex_substitute(eap);
p_magic = magic_save;
}
@@ -7351,10 +7476,11 @@ static void ex_redir(exarg_T *eap)
/* Can use both "@a" and "@a>". */
if (*arg == '>')
arg++;
- /* Make register empty when not using @A-@Z and the
- * command is valid. */
- if (*arg == NUL && !isupper(redir_reg))
- write_reg_contents(redir_reg, (char_u *)"", -1, FALSE);
+ // Make register empty when not using @A-@Z and the
+ // command is valid.
+ if (*arg == NUL && !isupper(redir_reg)) {
+ write_reg_contents(redir_reg, (char_u *)"", 0, false);
+ }
}
}
if (*arg != NUL) {
@@ -7645,7 +7771,7 @@ open_exfile (
return NULL;
}
#endif
- if (!forceit && *mode != 'a' && os_file_exists(fname)) {
+ if (!forceit && *mode != 'a' && os_path_exists(fname)) {
EMSG2(_("E189: \"%s\" exists (add ! to override)"), fname);
return NULL;
}
@@ -7792,9 +7918,8 @@ static void ex_normal(exarg_T *eap)
if (force_restart_edit) {
force_restart_edit = false;
} else {
- // some function called was aware of ex_normal and decided to override the
- // value of restart_edit anyway. So far only used in terminal mode(see
- // terminal_enter() in edit.c)
+ // Some function (terminal_enter()) was aware of ex_normal and decided to
+ // override the value of restart_edit anyway.
restart_edit = save_restart_edit;
}
p_im = save_insertmode;
@@ -7846,7 +7971,8 @@ static void ex_startinsert(exarg_T *eap)
static void ex_stopinsert(exarg_T *eap)
{
restart_edit = 0;
- stop_insert_mode = TRUE;
+ stop_insert_mode = true;
+ clearmode();
}
/*
@@ -7855,19 +7981,26 @@ static void ex_stopinsert(exarg_T *eap)
*/
void exec_normal_cmd(char_u *cmd, int remap, bool silent)
{
+ // Stuff the argument into the typeahead buffer.
+ ins_typebuf(cmd, remap, 0, true, silent);
+ exec_normal(false);
+}
+
+/// Execute normal_cmd() until there is no typeahead left.
+///
+/// @param was_typed whether or not something was typed
+void exec_normal(bool was_typed)
+{
oparg_T oa;
- /*
- * Stuff the argument into the typeahead buffer.
- * Execute normal_cmd() until there is no typeahead left.
- */
clear_oparg(&oa);
- finish_op = FALSE;
- ins_typebuf(cmd, remap, 0, TRUE, silent);
- while ((!stuff_empty() || (!typebuf_typed() && typebuf.tb_len > 0))
+ finish_op = false;
+ while ((!stuff_empty()
+ || ((was_typed || !typebuf_typed())
+ && typebuf.tb_len > 0))
&& !got_int) {
update_topline_cursor();
- normal_cmd(&oa, TRUE); /* execute a Normal mode cmd */
+ normal_cmd(&oa, true); // execute a Normal mode cmd
}
}
@@ -8622,17 +8755,18 @@ makeopens (
if (put_line(fd, "wincmd t") == FAIL)
return FAIL;
- /*
- * If more than one window, see if sizes can be restored.
- * First set 'winheight' and 'winwidth' to 1 to avoid the windows being
- * resized when moving between windows.
- * Do this before restoring the view, so that the topline and the
- * cursor can be set. This is done again below.
- */
- if (put_line(fd, "set winheight=1 winwidth=1") == FAIL)
+ // If more than one window, see if sizes can be restored.
+ // First set 'winheight' and 'winwidth' to 1 to avoid the windows being
+ // resized when moving between windows.
+ // Do this before restoring the view, so that the topline and the
+ // cursor can be set. This is done again below.
+ if (put_line(fd, "set winminheight=1 winminwidth=1 winheight=1 winwidth=1")
+ == FAIL) {
return FAIL;
- if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
+ }
+ if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) {
return FAIL;
+ }
/*
* Restore the view of the window (options, file, cursor, etc.).
@@ -8696,11 +8830,18 @@ makeopens (
if (put_line(fd, "unlet! s:wipebuf") == FAIL)
return FAIL;
- /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */
- if (fprintf(fd, "set winheight=%" PRId64 " winwidth=%" PRId64 " shortmess=%s",
- (int64_t)p_wh, (int64_t)p_wiw, p_shm) < 0
- || put_eol(fd) == FAIL)
+ // Re-apply options.
+ if (fprintf(fd, "set winheight=%" PRId64 " winwidth=%" PRId64
+ " winminheight=%" PRId64 " winminwidth=%" PRId64
+ " shortmess=%s",
+ (int64_t)p_wh,
+ (int64_t)p_wiw,
+ (int64_t)p_wmh,
+ (int64_t)p_wmw,
+ p_shm) < 0
+ || put_eol(fd) == FAIL) {
return FAIL;
+ }
/*
* Lastly, execute the x.vim file if it exists.
@@ -9318,33 +9459,33 @@ static void ex_filetype(exarg_T *eap)
}
if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) {
if (*arg == 'o' || !filetype_detect) {
- source_runtime((char_u *)FILETYPE_FILE, true);
+ source_runtime((char_u *)FILETYPE_FILE, DIP_ALL);
filetype_detect = kTrue;
if (plugin) {
- source_runtime((char_u *)FTPLUGIN_FILE, true);
+ source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = kTrue;
}
if (indent) {
- source_runtime((char_u *)INDENT_FILE, true);
+ source_runtime((char_u *)INDENT_FILE, DIP_ALL);
filetype_indent = kTrue;
}
}
if (*arg == 'd') {
- (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE);
+ (void)do_doautocmd((char_u *)"filetypedetect BufRead", true, NULL);
do_modelines(0);
}
} else if (STRCMP(arg, "off") == 0) {
if (plugin || indent) {
if (plugin) {
- source_runtime((char_u *)FTPLUGOF_FILE, true);
+ source_runtime((char_u *)FTPLUGOF_FILE, DIP_ALL);
filetype_plugin = kFalse;
}
if (indent) {
- source_runtime((char_u *)INDOFF_FILE, true);
+ source_runtime((char_u *)INDOFF_FILE, DIP_ALL);
filetype_indent = kFalse;
}
} else {
- source_runtime((char_u *)FTOFF_FILE, true);
+ source_runtime((char_u *)FTOFF_FILE, DIP_ALL);
filetype_detect = kFalse;
}
} else
@@ -9481,20 +9622,15 @@ static void ex_foldopen(exarg_T *eap)
static void ex_folddo(exarg_T *eap)
{
- linenr_T lnum;
-
- start_global_changes();
-
- /* First set the marks for all lines closed/open. */
- for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
- if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed))
+ // First set the marks for all lines closed/open.
+ for (linenr_T lnum = eap->line1; lnum <= eap->line2; ++lnum) {
+ if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) {
ml_setmarked(lnum);
+ }
+ }
- /* Execute the command on the marked lines. */
- global_exe(eap->arg);
- ml_clearmarked(); /* clear rest of the marks */
-
- end_global_changes();
+ global_exe(eap->arg); // Execute the command on the marked lines.
+ ml_clearmarked(); // clear rest of the marks
}
static void ex_terminal(exarg_T *eap)
@@ -9520,3 +9656,38 @@ static void ex_terminal(exarg_T *eap)
xfree(name);
}
}
+
+/// Checks if `cmd` is "previewable" (i.e. supported by 'inccommand').
+///
+/// @param[in] cmd Commandline to check. May start with a range.
+///
+/// @return true if `cmd` is previewable
+bool cmd_can_preview(char_u *cmd)
+{
+ if (cmd == NULL) {
+ return false;
+ }
+
+ exarg_T ea;
+ // parse the command line
+ ea.cmd = skip_range(cmd, NULL);
+ if (*ea.cmd == '*') {
+ ea.cmd = skipwhite(ea.cmd + 1);
+ }
+ char_u *end = find_command(&ea, NULL);
+
+ switch (ea.cmdidx) {
+ case CMD_substitute:
+ case CMD_smagic:
+ case CMD_snomagic:
+ // Only preview once the pattern delimiter has been typed
+ if (*end && !ASCII_ISALNUM(*end)) {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}