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.c3570
1 files changed, 1933 insertions, 1637 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 3a285cdf90..c4d2821e79 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -38,12 +38,15 @@
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/hardcopy.h"
+#include "nvim/highlight_group.h"
#include "nvim/if_cscope.h"
#include "nvim/input.h"
-#include "nvim/keymap.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
+#include "nvim/match.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -59,6 +62,7 @@
#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
@@ -74,21 +78,28 @@
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/undo_defs.h"
#include "nvim/version.h"
#include "nvim/vim.h"
#include "nvim/window.h"
+static char e_no_such_user_defined_command_str[]
+ = N_("E184: No such user-defined command: %s");
+static char e_ambiguous_use_of_user_defined_command[]
+ = N_("E464: Ambiguous use of user-defined command");
+static char e_not_an_editor_command[]
+ = N_("E492: Not an editor command");
+static char e_no_such_user_defined_command_in_current_buffer_str[]
+ = N_("E1237: No such user-defined command in current buffer: %s");
+
static int quitmore = 0;
static bool ex_pressedreturn = false;
garray_T ucmds = { 0, 0, sizeof(ucmd_T), 4, NULL };
-// Whether a command index indicates a user command.
-#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
-
// Struct for storing a line inside a while/for loop
typedef struct {
- char_u *line; // command line
+ char *line; // command line
linenr_T lnum; // sourcing_lnum of the line
} wcmd_T;
@@ -104,18 +115,17 @@ struct loop_cookie {
int current_line; // last read line from growarray
int repeating; // TRUE when looping a second time
// When "repeating" is FALSE use "getline" and "cookie" to get lines
- char_u *(*getline)(int, void *, int, bool);
+ char *(*getline)(int, void *, int, bool);
void *cookie;
};
-
// Struct to save a few things while debugging. Used in do_cmdline() only.
struct dbg_stuff {
int trylevel;
int force_abort;
except_T *caught_stack;
- char_u *vv_exception;
- char_u *vv_throwpoint;
+ char *vv_exception;
+ char *vv_throwpoint;
int did_emsg;
int got_int;
int need_rethrow;
@@ -138,7 +148,7 @@ struct dbg_stuff {
# include "ex_cmds_defs.generated.h"
#endif
-static char_u dollar_command[2] = { '$', 0 };
+static char dollar_command[2] = { '$', 0 };
static void save_dbg_stuff(struct dbg_stuff *dsp)
{
@@ -177,11 +187,11 @@ void do_exmode(void)
int save_msg_scroll;
int prev_msg_row;
linenr_T prev_line;
- int changedtick;
+ varnumber_T changedtick;
exmode_active = true;
- State = NORMAL;
- trigger_modechanged();
+ State = MODE_NORMAL;
+ may_trigger_modechanged();
// When using ":global /pat/ visual" and then "Q" we return to continue
// the :global command.
@@ -217,6 +227,8 @@ void do_exmode(void)
emsg(_(e_emptybuf));
} else {
if (ex_pressedreturn) {
+ // Make sure the message overwrites the right line and isn't throttled.
+ msg_scroll_flush();
// go up one line, to overwrite the ":<CR>" line, so the
// output doesn't contain empty lines.
msg_row = prev_msg_row;
@@ -245,9 +257,10 @@ void do_exmode(void)
msg_scroll = save_msg_scroll;
}
-// Print the executed command for when 'verbose' is set.
-// When "lnum" is 0 only print the command.
-static void msg_verbose_cmd(linenr_T lnum, char_u *cmd)
+/// Print the executed command for when 'verbose' is set.
+///
+/// @param lnum if 0, only print the command.
+static void msg_verbose_cmd(linenr_T lnum, char *cmd)
FUNC_ATTR_NONNULL_ALL
{
no_wait_return++;
@@ -266,13 +279,10 @@ static void msg_verbose_cmd(linenr_T lnum, char_u *cmd)
no_wait_return--;
}
-/*
- * Execute a simple command line. Used for translated commands like "*".
- */
+/// Execute a simple command line. Used for translated commands like "*".
int do_cmdline_cmd(const char *cmd)
{
- return do_cmdline((char_u *)cmd, NULL, NULL,
- DOCMD_NOWAIT|DOCMD_KEYTYPED);
+ return do_cmdline((char *)cmd, NULL, NULL, DOCMD_NOWAIT|DOCMD_KEYTYPED);
}
/// do_cmdline(): execute one Ex command line
@@ -290,15 +300,14 @@ int do_cmdline_cmd(const char *cmd)
/// DOCMD_KEYTYPED - Don't reset KeyTyped.
/// DOCMD_EXCRESET - Reset the exception environment (used for debugging).
/// DOCMD_KEEPLINE - Store first typed line (for repeating with ".").
-/// DOCMD_PREVIEW - During 'inccommand' preview.
///
/// @param cookie argument for fgetline()
///
/// @return FAIL if cmdline could not be executed, OK otherwise
-int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
+int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
{
- char_u *next_cmdline; // next cmd to execute
- char_u *cmdline_copy = NULL; // copy of cmd line
+ char *next_cmdline; // next cmd to execute
+ char *cmdline_copy = NULL; // copy of cmd line
bool used_getline = false; // used "fgetline" to obtain command
static int recursive = 0; // recursive depth
bool msg_didout_before_start = false;
@@ -310,7 +319,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
};
garray_T lines_ga; // keep lines for ":while"/":for"
int current_line = 0; // active line in lines_ga
- char_u *fname = NULL; // function or script name
+ char *fname = NULL; // function or script name
linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie
int *dbg_tick = NULL; // ptr to dbg_tick field in cookie
struct dbg_stuff debug_saved; // saved things for debug mode
@@ -319,7 +328,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
struct msglist *private_msg_list;
// "fgetline" and "cookie" passed to do_one_cmd()
- char_u *(*cmd_getline)(int, void *, int, bool);
+ char *(*cmd_getline)(int, void *, int, bool);
void *cmd_cookie;
struct loop_cookie cmd_loop_cookie;
void *real_cookie;
@@ -340,10 +349,10 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// 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) {
- emsg(_("E169: Command too recursive"));
+ 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.
- do_errthrow((cstack_T *)NULL, (char_u *)NULL);
+ do_errthrow((cstack_T *)NULL, NULL);
msg_list = saved_msg_list;
return FAIL;
}
@@ -363,7 +372,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// Get the function or script name and the address where the next breakpoint
// line and the debug tick for a function or script are stored.
if (getline_is_func) {
- fname = func_name(real_cookie);
+ fname = (char *)func_name(real_cookie);
breakpoint = func_breakpoint(real_cookie);
dbg_tick = func_dbg_tick(real_cookie);
} else if (getline_equal(fgetline, cookie, getsourceline)) {
@@ -460,7 +469,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
if (breakpoint != NULL && dbg_tick != NULL
&& *dbg_tick != debug_tick) {
*breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ (char_u *)fname, sourcing_lnum);
*dbg_tick = debug_tick;
}
@@ -470,10 +479,10 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// Did we encounter a breakpoint?
if (breakpoint != NULL && *breakpoint != 0
&& *breakpoint <= sourcing_lnum) {
- dbg_breakpoint(fname, sourcing_lnum);
+ dbg_breakpoint((char_u *)fname, sourcing_lnum);
// Find next breakpoint.
*breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ (char_u *)fname, sourcing_lnum);
*dbg_tick = debug_tick;
}
if (do_profiling == PROF_YES) {
@@ -534,15 +543,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
if (flags & DOCMD_KEEPLINE) {
xfree(repeat_cmdline);
if (count == 0) {
- repeat_cmdline = vim_strsave(next_cmdline);
+ repeat_cmdline = vim_strsave((char_u *)next_cmdline);
} else {
repeat_cmdline = NULL;
}
}
- }
- // 3. Make a copy of the command so we can mess with it.
- else if (cmdline_copy == NULL) {
- next_cmdline = vim_strsave(next_cmdline);
+ } else if (cmdline_copy == NULL) {
+ // 3. Make a copy of the command so we can mess with it.
+ next_cmdline = xstrdup(next_cmdline);
}
cmdline_copy = next_cmdline;
@@ -587,16 +595,9 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
* "cmdline_copy" can change, e.g. for '%' and '#' expansion.
*/
recursive++;
- next_cmdline = do_one_cmd(&cmdline_copy, flags,
- &cstack,
- cmd_getline, cmd_cookie);
+ next_cmdline = do_one_cmd(&cmdline_copy, flags, &cstack, cmd_getline, cmd_cookie);
recursive--;
- // Ignore trailing '|'-separated commands in preview-mode ('inccommand').
- if ((State & CMDPREVIEW) && (flags & DOCMD_PREVIEW)) {
- next_cmdline = NULL;
- }
-
if (cmd_cookie == (void *)&cmd_loop_cookie) {
// Use "current_line" from "cmd_loop_cookie", it may have been
// incremented when defining a function.
@@ -622,7 +623,6 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
next_cmdline = cmdline_copy;
}
-
// reset did_emsg for a function that is not aborted by an error
if (did_emsg && !force_abort
&& getline_equal(fgetline, cookie, get_func_line)
@@ -661,8 +661,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// or ":for".
if (breakpoint != NULL) {
*breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
- fname,
- ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1);
+ (char_u *)fname,
+ ((wcmd_T *)lines_ga.ga_data)[current_line].lnum - 1);
*dbg_tick = debug_tick;
}
} else {
@@ -795,8 +795,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory
// lack was reported above and the error message is to be converted to an
// exception, do this now after rewinding the cstack.
- do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line)
- ? (char_u *)"endfunction" : (char_u *)NULL);
+ do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line) ? "endfunction" : NULL);
if (trylevel == 0) {
// When an exception is being thrown out of the outermost try
@@ -805,8 +804,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// commands are executed.
if (current_exception) {
char *p = NULL;
- char_u *saved_sourcing_name;
- int saved_sourcing_lnum;
+ char *saved_sourcing_name;
+ linenr_T saved_sourcing_lnum;
struct msglist *messages = NULL;
struct msglist *next;
@@ -911,6 +910,15 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
msg_list = saved_msg_list;
+ // Cleanup if "cs_emsg_silent_list" remains.
+ if (cstack.cs_emsg_silent_list != NULL) {
+ eslist_T *elem, *temp;
+ for (elem = cstack.cs_emsg_silent_list; elem != NULL; elem = temp) {
+ temp = elem->next;
+ xfree(elem);
+ }
+ }
+
/*
* If there was too much output to fit on the command line, ask the user to
* hit return before redrawing the screen. With the ":global" command we do
@@ -947,14 +955,12 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
return retval;
}
-/*
- * Obtain a line when inside a ":while" or ":for" loop.
- */
-static char_u *get_loop_line(int c, void *cookie, int indent, bool do_concat)
+/// Obtain a line when inside a ":while" or ":for" loop.
+static char *get_loop_line(int c, void *cookie, int indent, bool do_concat)
{
struct loop_cookie *cp = (struct loop_cookie *)cookie;
wcmd_T *wp;
- char_u *line;
+ char *line;
if (cp->current_line + 1 >= cp->lines_gap->ga_len) {
if (cp->repeating) {
@@ -962,7 +968,7 @@ static char_u *get_loop_line(int c, void *cookie, int indent, bool do_concat)
}
// First time inside the ":while"/":for": get line normally.
if (cp->getline == NULL) {
- line = getcmdline(c, 0L, indent, do_concat);
+ line = (char *)getcmdline(c, 0L, indent, do_concat);
} else {
line = cp->getline(c, cp->cookie, indent, do_concat);
}
@@ -978,16 +984,14 @@ static char_u *get_loop_line(int c, void *cookie, int indent, bool do_concat)
cp->current_line++;
wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line;
sourcing_lnum = wp->lnum;
- return vim_strsave(wp->line);
+ return xstrdup(wp->line);
}
-/*
- * Store a line in "gap" so that a ":while" loop can execute it again.
- */
-static void store_loop_line(garray_T *gap, char_u *line)
+/// Store a line in "gap" so that a ":while" loop can execute it again.
+static void store_loop_line(garray_T *gap, char *line)
{
wcmd_T *p = GA_APPEND_VIA_PTR(wcmd_T, gap);
- p->line = vim_strsave(line);
+ p->line = xstrdup(line);
p->lnum = sourcing_lnum;
}
@@ -1033,16 +1037,15 @@ void *getline_cookie(LineGetter fgetline, void *cookie)
return cp;
}
-/*
- * Helper function to apply an offset for buffer commands, i.e. ":bdelete",
- * ":bwipeout", etc.
- * Returns the buffer number.
- */
-static int compute_buffer_local_count(int addr_type, int lnum, int offset)
+/// Helper function to apply an offset for buffer commands, i.e. ":bdelete",
+/// ":bwipeout", etc.
+///
+/// @return the buffer number.
+static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, long offset)
{
buf_T *buf;
buf_T *nextbuf;
- int count = offset;
+ long count = offset;
buf = firstbuf;
while (buf->b_next != NULL && buf->b_fnum < lnum) {
@@ -1079,8 +1082,8 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset)
return buf->b_fnum;
}
-// Return the window number of "win".
-// When "win" is NULL return the number of windows.
+/// @return the window number of "win" or,
+/// the number of windows if "win" is NULL
static int current_win_nr(const win_T *win)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -1113,9 +1116,8 @@ static int current_tab_nr(tabpage_T *tab)
#define CURRENT_TAB_NR current_tab_nr(curtab)
#define LAST_TAB_NR current_tab_nr(NULL)
-
/// Figure out the address type for ":wincmd".
-static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
+static void get_wincmd_addr_type(char *arg, exarg_T *eap)
{
switch (*arg) {
case 'S':
@@ -1206,7 +1208,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
/// non-colon, non-whitespace character.
//
/// @param skipleadingwhite Skip leading whitespace too
-static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
+static char *skip_colon_white(const char *p, bool skipleadingwhite)
{
if (skipleadingwhite) {
p = skipwhite(p);
@@ -1216,7 +1218,489 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
p = skipwhite(p + 1);
}
- return (char_u *)p;
+ return (char *)p;
+}
+
+/// Set the addr type for command
+///
+/// @param p pointer to character after command name in cmdline
+void set_cmd_addr_type(exarg_T *eap, char *p)
+{
+ // ea.addr_type for user commands is set by find_ucmd
+ if (IS_USER_CMDIDX(eap->cmdidx)) {
+ return;
+ }
+ if (eap->cmdidx != CMD_SIZE) {
+ eap->addr_type = cmdnames[(int)eap->cmdidx].cmd_addr_type;
+ } else {
+ eap->addr_type = ADDR_LINES;
+ }
+ // :wincmd range depends on the argument
+ if (eap->cmdidx == CMD_wincmd && p != NULL) {
+ get_wincmd_addr_type(skipwhite(p), eap);
+ }
+ // :.cc in quickfix window uses line number
+ if ((eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) && bt_quickfix(curbuf)) {
+ eap->addr_type = ADDR_OTHER;
+ }
+}
+
+/// Get default range number for command based on its address type
+linenr_T get_cmd_default_range(exarg_T *eap)
+{
+ switch (eap->addr_type) {
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ // Default is the cursor line number. Avoid using an invalid
+ // line number though.
+ return MIN(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count);
+ break;
+ case ADDR_WINDOWS:
+ return CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ return MIN(curwin->w_arg_idx + 1, ARGCOUNT);
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ return curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ return CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ return 1;
+ break;
+ case ADDR_QUICKFIX:
+ return (linenr_T)qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
+ return qf_get_cur_valid_idx(eap);
+ break;
+ default:
+ return 0;
+ // Will give an error later if a range is found.
+ break;
+ }
+}
+
+/// Set default command range for -range=% based on the addr type of the command
+void set_cmd_dflall_range(exarg_T *eap)
+{
+ buf_T *buf;
+
+ eap->line1 = 1;
+ switch (eap->addr_type) {
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = firstbuf;
+ while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_next;
+ }
+ eap->line1 = buf->b_fnum;
+ buf = lastbuf;
+ while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_prev;
+ }
+ eap->line2 = buf->b_fnum;
+ break;
+ case ADDR_BUFFERS:
+ eap->line1 = firstbuf->b_fnum;
+ eap->line2 = lastbuf->b_fnum;
+ break;
+ case ADDR_WINDOWS:
+ eap->line2 = LAST_WIN_NR;
+ break;
+ case ADDR_TABS:
+ eap->line2 = LAST_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ eap->line2 = 1;
+ break;
+ case ADDR_ARGUMENTS:
+ if (ARGCOUNT == 0) {
+ eap->line1 = eap->line2 = 0;
+ } else {
+ eap->line2 = ARGCOUNT;
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ eap->line2 = (linenr_T)qf_get_valid_size(eap);
+ if (eap->line2 == 0) {
+ eap->line2 = 1;
+ }
+ break;
+ case ADDR_NONE:
+ case ADDR_UNSIGNED:
+ case ADDR_QUICKFIX:
+ iemsg(_("INTERNAL: Cannot use EX_DFLALL "
+ "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
+ break;
+ }
+}
+
+static void parse_register(exarg_T *eap)
+{
+ // Accept numbered register only when no count allowed (:put)
+ if ((eap->argt & EX_REGSTR)
+ && *eap->arg != NUL
+ // Do not allow register = for user commands
+ && (!IS_USER_CMDIDX(eap->cmdidx) || *eap->arg != '=')
+ && !((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg))) {
+ if (valid_yank_reg(*eap->arg, (eap->cmdidx != CMD_put
+ && !IS_USER_CMDIDX(eap->cmdidx)))) {
+ eap->regname = (uint8_t)(*eap->arg++);
+ // for '=' register: accept the rest of the line as an expression
+ if (eap->arg[-1] == '=' && eap->arg[0] != NUL) {
+ if (!eap->skip) {
+ set_expr_line(vim_strsave((char_u *)eap->arg));
+ }
+ eap->arg += STRLEN(eap->arg);
+ }
+ eap->arg = skipwhite(eap->arg);
+ }
+ }
+}
+
+// Change line1 and line2 of Ex command to use count
+void set_cmd_count(exarg_T *eap, long count, bool validate)
+{
+ if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3
+ eap->line2 = (linenr_T)count;
+ if (eap->addr_count == 0) {
+ eap->addr_count = 1;
+ }
+ } else {
+ eap->line1 = eap->line2;
+ eap->line2 += (linenr_T)count - 1;
+ eap->addr_count++;
+ // Be vi compatible: no error message for out of range.
+ if (validate && eap->line2 > curbuf->b_ml.ml_line_count) {
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ }
+ }
+}
+
+static int parse_count(exarg_T *eap, char **errormsg, bool validate)
+{
+ // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a
+ // count, it's a buffer name.
+ char *p;
+ long n;
+
+ if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg)
+ && (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL
+ || ascii_iswhite(*p))) {
+ n = getdigits_long((char_u **)&eap->arg, false, -1);
+ eap->arg = skipwhite(eap->arg);
+ if (n <= 0 && (eap->argt & EX_ZEROR) == 0) {
+ if (errormsg != NULL) {
+ *errormsg = _(e_zerocount);
+ }
+ return FAIL;
+ }
+ set_cmd_count(eap, n, validate);
+ }
+
+ return OK;
+}
+
+/// Check if command is not implemented
+bool is_cmd_ni(cmdidx_T cmdidx)
+{
+ return !IS_USER_CMDIDX(cmdidx) && (cmdnames[cmdidx].cmd_func == ex_ni
+ || cmdnames[cmdidx].cmd_func == ex_script_ni);
+}
+
+/// Parse command line and return information about the first command.
+/// If parsing is done successfully, need to free cmod_filter_pat and cmod_filter_regmatch.regprog
+/// after calling, usually done using undo_cmdmod() or execute_cmd().
+///
+/// @param cmdline Command line string
+/// @param[out] eap Ex command arguments
+/// @param[out] cmdinfo Command parse information
+/// @param[out] errormsg Error message, if any
+///
+/// @return Success or failure
+bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg)
+{
+ char *cmd;
+ char *p;
+ char *after_modifier = NULL;
+
+ // Initialize cmdinfo
+ memset(cmdinfo, 0, sizeof(*cmdinfo));
+
+ // Initialize eap
+ memset(eap, 0, sizeof(*eap));
+ eap->line1 = 1;
+ eap->line2 = 1;
+ eap->cmd = cmdline;
+ eap->cmdlinep = &cmdline;
+ eap->getline = NULL;
+ eap->cookie = NULL;
+
+ const bool save_ex_pressedreturn = ex_pressedreturn;
+ // Parse command modifiers
+ if (parse_command_modifiers(eap, errormsg, &cmdinfo->cmdmod, false) == FAIL) {
+ ex_pressedreturn = save_ex_pressedreturn;
+ goto err;
+ }
+ ex_pressedreturn = save_ex_pressedreturn;
+ after_modifier = eap->cmd;
+
+ // Save location after command modifiers
+ cmd = eap->cmd;
+ // Skip ranges to find command name since we need the command to know what kind of range it uses
+ eap->cmd = skip_range(eap->cmd, NULL);
+ if (*eap->cmd == '*') {
+ eap->cmd = skipwhite(eap->cmd + 1);
+ }
+ p = find_ex_command(eap, NULL);
+ if (p == NULL) {
+ *errormsg = _(e_ambiguous_use_of_user_defined_command);
+ goto err;
+ }
+
+ // Set command address type and parse command range
+ set_cmd_addr_type(eap, p);
+ eap->cmd = cmd;
+ if (parse_cmd_address(eap, errormsg, false) == FAIL) {
+ goto err;
+ }
+
+ // Skip colon and whitespace
+ eap->cmd = skip_colon_white(eap->cmd, true);
+ // Fail if command is a comment or if command doesn't exist
+ if (*eap->cmd == NUL || *eap->cmd == '"') {
+ goto err;
+ }
+ // Fail if command is invalid
+ if (eap->cmdidx == CMD_SIZE) {
+ STRCPY(IObuff, _(e_not_an_editor_command));
+ // If the modifier was parsed OK the error must be in the following command
+ char *cmdname = after_modifier ? after_modifier : cmdline;
+ append_command(cmdname);
+ *errormsg = (char *)IObuff;
+ goto err;
+ }
+
+ // Correctly set 'forceit' for commands
+ if (*p == '!' && eap->cmdidx != CMD_substitute
+ && eap->cmdidx != CMD_smagic && eap->cmdidx != CMD_snomagic) {
+ p++;
+ eap->forceit = true;
+ } else {
+ eap->forceit = false;
+ }
+
+ // Parse arguments.
+ if (!IS_USER_CMDIDX(eap->cmdidx)) {
+ eap->argt = cmdnames[(int)eap->cmdidx].cmd_argt;
+ }
+ // Skip to start of argument.
+ // Don't do this for the ":!" command, because ":!! -l" needs the space.
+ if (eap->cmdidx == CMD_bang) {
+ eap->arg = p;
+ } else {
+ eap->arg = skipwhite(p);
+ }
+
+ // Don't treat ":r! filter" like a bang
+ if (eap->cmdidx == CMD_read) {
+ if (eap->forceit) {
+ eap->forceit = false; // :r! filter
+ }
+ }
+
+ // Check for '|' to separate commands and '"' to start comments.
+ // Don't do this for ":read !cmd" and ":write !cmd".
+ if ((eap->argt & EX_TRLBAR)) {
+ separate_nextcmd(eap);
+ }
+ // Fail if command doesn't support bang but is used with a bang
+ if (!(eap->argt & EX_BANG) && eap->forceit) {
+ *errormsg = _(e_nobang);
+ goto err;
+ }
+ // Fail if command doesn't support a range but it is given a range
+ if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
+ *errormsg = _(e_norange);
+ goto err;
+ }
+ // Set default range for command if required
+ if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) {
+ set_cmd_dflall_range(eap);
+ }
+
+ // Parse register and count
+ parse_register(eap);
+ if (parse_count(eap, errormsg, false) == FAIL) {
+ goto err;
+ }
+
+ // Remove leading whitespace and colon from next command
+ if (eap->nextcmd) {
+ eap->nextcmd = skip_colon_white(eap->nextcmd, true);
+ }
+
+ // Set the "magic" values (characters that get treated specially)
+ if (eap->argt & EX_XFILE) {
+ cmdinfo->magic.file = true;
+ }
+ if (eap->argt & EX_TRLBAR) {
+ cmdinfo->magic.bar = true;
+ }
+
+ return true;
+err:
+ undo_cmdmod(&cmdinfo->cmdmod);
+ return false;
+}
+
+/// Execute an Ex command using parsed command line information.
+/// Does not do any validation of the Ex command arguments.
+///
+/// @param eap Ex-command arguments
+/// @param cmdinfo Command parse information
+/// @param preview Execute command preview callback instead of actual command
+int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
+{
+ char *errormsg = NULL;
+ int retv = 0;
+
+#define ERROR(msg) \
+ do { \
+ errormsg = msg; \
+ goto end; \
+ } while (0)
+
+ cmdmod_T save_cmdmod = cmdmod;
+ cmdmod = cmdinfo->cmdmod;
+
+ // Apply command modifiers
+ apply_cmdmod(&cmdmod);
+
+ if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY)
+ // allow :put in terminals
+ && !(curbuf->terminal && eap->cmdidx == CMD_put)) {
+ ERROR(_(e_modifiable));
+ }
+ if (!IS_USER_CMDIDX(eap->cmdidx)) {
+ if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) {
+ // Command not allowed in the command line window
+ ERROR(_(e_cmdwin));
+ }
+ if (text_locked() && !(eap->argt & EX_LOCK_OK)) {
+ // Command not allowed when text is locked
+ ERROR(_(get_text_locked_msg()));
+ }
+ }
+ // Disallow editing another buffer when "curbuf->b_ro_locked" is set.
+ // Do allow ":checktime" (it is postponed).
+ // Do allow ":edit" (check for an argument later).
+ // Do allow ":file" with no arguments
+ if (!(eap->argt & EX_CMDWIN)
+ && eap->cmdidx != CMD_checktime
+ && eap->cmdidx != CMD_edit
+ && !(eap->cmdidx == CMD_file && *eap->arg == NUL)
+ && !IS_USER_CMDIDX(eap->cmdidx)
+ && curbuf_locked()) {
+ ERROR(_(e_cannot_edit_other_buf));
+ }
+
+ if (((eap->argt & EX_WHOLEFOLD) || eap->addr_count >= 2) && !global_busy
+ && 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);
+ }
+
+ // If filename expansion is enabled, expand filenames
+ if (cmdinfo->magic.file) {
+ if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) {
+ goto end;
+ }
+ }
+
+ // Accept buffer name. Cannot be used at the same time with a buffer
+ // number. Don't do this for a user command.
+ if ((eap->argt & EX_BUFNAME) && *eap->arg != NUL && eap->addr_count == 0
+ && !IS_USER_CMDIDX(eap->cmdidx)) {
+ if (eap->args == NULL) {
+ // If argument positions are not specified, search the argument for the buffer name.
+ // :bdelete, :bwipeout and :bunload take several arguments, separated by spaces:
+ // find next space (skipping over escaped characters).
+ // The others take one argument: ignore trailing spaces.
+ char *p;
+
+ if (eap->cmdidx == CMD_bdelete || eap->cmdidx == CMD_bwipeout
+ || eap->cmdidx == CMD_bunload) {
+ p = skiptowhite_esc(eap->arg);
+ } else {
+ p = eap->arg + STRLEN(eap->arg);
+ while (p > eap->arg && ascii_iswhite(p[-1])) {
+ p--;
+ }
+ }
+ eap->line2 = buflist_findpat(eap->arg, p, (eap->argt & EX_BUFUNL) != 0,
+ false, false);
+ eap->addr_count = 1;
+ eap->arg = skipwhite(p);
+ } else {
+ // If argument positions are specified, just use the first argument
+ eap->line2 = buflist_findpat(eap->args[0],
+ eap->args[0] + eap->arglens[0],
+ (eap->argt & EX_BUFUNL) != 0, false, false);
+ eap->addr_count = 1;
+ // Shift each argument by 1
+ for (size_t i = 0; i < eap->argc - 1; i++) {
+ eap->args[i] = eap->args[i + 1];
+ }
+ // Make the last argument point to the NUL terminator at the end of string
+ eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
+ eap->argc -= 1;
+
+ eap->arg = eap->args[0];
+ }
+ if (eap->line2 < 0) { // failed
+ goto end;
+ }
+ }
+
+ // Execute the command
+ if (IS_USER_CMDIDX(eap->cmdidx)) {
+ // Execute a user-defined command.
+ retv = do_ucmd(eap, preview);
+ } else {
+ // Call the function to execute the command or the preview callback.
+ eap->errmsg = NULL;
+
+ if (preview) {
+ retv = (cmdnames[eap->cmdidx].cmd_preview_func)(eap, cmdpreview_get_ns(),
+ cmdpreview_get_bufnr());
+ } else {
+ (cmdnames[eap->cmdidx].cmd_func)(eap);
+ }
+ if (eap->errmsg != NULL) {
+ errormsg = _(eap->errmsg);
+ }
+ }
+
+end:
+ if (errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
+ // Undo command modifiers
+ undo_cmdmod(&cmdmod);
+ cmdmod = save_cmdmod;
+ return retv;
+#undef ERROR
}
/// Execute one Ex command.
@@ -1236,19 +1720,18 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
/// This function may be called recursively!
///
/// @param cookie argument for fgetline()
-static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline,
- void *cookie)
+static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline,
+ void *cookie)
{
- char_u *p;
+ char *p;
linenr_T lnum;
- long n;
char *errormsg = NULL; // error message
- char_u *after_modifier = NULL;
+ char *after_modifier = NULL;
exarg_T ea;
- const int save_msg_scroll = msg_scroll;
cmdmod_T save_cmdmod;
const int save_reg_executing = reg_executing;
- char_u *cmd;
+ const bool save_pending_end_reg_executing = pending_end_reg_executing;
+ char *cmd;
memset(&ea, 0, sizeof(ea));
ea.line1 = 1;
@@ -1286,9 +1769,10 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
ea.cookie = cookie;
ea.cstack = cstack;
- if (parse_command_modifiers(&ea, &errormsg, false) == FAIL) {
+ if (parse_command_modifiers(&ea, &errormsg, &cmdmod, false) == FAIL) {
goto doend;
}
+ apply_cmdmod(&cmdmod);
after_modifier = ea.cmd;
@@ -1306,7 +1790,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
if (*ea.cmd == '*') {
ea.cmd = skipwhite(ea.cmd + 1);
}
- p = find_command(&ea, NULL);
+ p = find_ex_command(&ea, NULL);
// Count this line for profiling if skip is TRUE.
if (do_profiling == PROF_YES
@@ -1363,23 +1847,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
// The ea.cmd pointer is updated to point to the first character following the
// range spec. If an initial address is found, but no second, the upper bound
// is equal to the lower.
-
- // ea.addr_type for user commands is set by find_ucmd
- if (!IS_USER_CMDIDX(ea.cmdidx)) {
- if (ea.cmdidx != CMD_SIZE) {
- ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type;
- } else {
- ea.addr_type = ADDR_LINES;
- }
- // :wincmd range depends on the argument
- if (ea.cmdidx == CMD_wincmd && p != NULL) {
- get_wincmd_addr_type(skipwhite(p), &ea);
- }
- // :.cc in quickfix window uses line number
- if ((ea.cmdidx == CMD_cc || ea.cmdidx == CMD_ll) && bt_quickfix(curbuf)) {
- ea.addr_type = ADDR_OTHER;
- }
- }
+ set_cmd_addr_type(&ea, p);
ea.cmd = cmd;
if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
@@ -1400,7 +1868,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
* If we find a '|' or '\n' we set ea.nextcmd.
*/
if (*ea.cmd == NUL || *ea.cmd == '"'
- || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) {
+ || (ea.nextcmd = (char *)check_nextcmd((char_u *)ea.cmd)) != NULL) {
// strange vi behaviour:
// ":3" jumps to line 3
// ":3|..." prints line 3
@@ -1443,27 +1911,27 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
while (ASCII_ISALNUM(*p)) {
++p;
}
- p = vim_strnsave(ea.cmd, p - ea.cmd);
+ p = xstrnsave(ea.cmd, (size_t)(p - ea.cmd));
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
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) : ea.cmd;
+ p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd;
}
if (p == NULL) {
if (!ea.skip) {
- errormsg = _("E464: Ambiguous use of user-defined command");
+ errormsg = _(e_ambiguous_use_of_user_defined_command);
}
goto doend;
}
// Check for wrong commands.
if (ea.cmdidx == CMD_SIZE) {
if (!ea.skip) {
- STRCPY(IObuff, _("E492: Not an editor command"));
+ STRCPY(IObuff, _(e_not_an_editor_command));
// If the modifier was parsed OK the error must be in the following
// command
- char_u *cmdname = after_modifier ? after_modifier : *cmdlinep;
+ char *cmdname = after_modifier ? after_modifier : *cmdlinep;
if (!(flags & DOCMD_VERBOSE)) {
append_command(cmdname);
}
@@ -1475,10 +1943,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
}
// set when Not Implemented
- const int ni = !IS_USER_CMDIDX(ea.cmdidx)
- && (cmdnames[ea.cmdidx].cmd_func == ex_ni
- || cmdnames[ea.cmdidx].cmd_func == ex_script_ni);
-
+ const int ni = is_cmd_ni(ea.cmdidx);
// Forced commands.
if (*p == '!' && ea.cmdidx != CMD_substitute
@@ -1508,11 +1973,17 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
goto doend;
}
- if (text_locked() && !(ea.argt & EX_CMDWIN)
- && !IS_USER_CMDIDX(ea.cmdidx)) {
- // Command not allowed when editing the command line.
- errormsg = _(get_text_locked_msg());
- goto doend;
+ if (!IS_USER_CMDIDX(ea.cmdidx)) {
+ if (cmdwin_type != 0 && !(ea.argt & EX_CMDWIN)) {
+ // Command not allowed in the command line window
+ errormsg = _(e_cmdwin);
+ goto doend;
+ }
+ if (text_locked() && !(ea.argt & EX_LOCK_OK)) {
+ // Command not allowed when text is locked
+ errormsg = _(get_text_locked_msg());
+ goto doend;
+ }
}
// Disallow editing another buffer when "curbuf->b_ro_locked" is set.
@@ -1626,7 +2097,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
goto doend;
}
ea.arg = skipwhite(ea.arg + 1);
- ea.append = TRUE;
+ ea.append = true;
} else if (*ea.arg == '!' && ea.cmdidx == CMD_write) { // :w !filter
++ea.arg;
ea.usefilter = TRUE;
@@ -1646,8 +2117,8 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) {
ea.amount = 1;
while (*ea.arg == *ea.cmd) { // count number of '>' or '<'
- ++ea.arg;
- ++ea.amount;
+ ea.arg++;
+ ea.amount++;
}
ea.arg = skipwhite(ea.arg);
}
@@ -1692,106 +2163,13 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
}
if ((ea.argt & EX_DFLALL) && ea.addr_count == 0) {
- buf_T *buf;
-
- ea.line1 = 1;
- switch (ea.addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- ea.line2 = curbuf->b_ml.ml_line_count;
- break;
- case ADDR_LOADED_BUFFERS:
- buf = firstbuf;
- while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_next;
- }
- ea.line1 = buf->b_fnum;
- buf = lastbuf;
- while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_prev;
- }
- ea.line2 = buf->b_fnum;
- break;
- case ADDR_BUFFERS:
- ea.line1 = firstbuf->b_fnum;
- ea.line2 = lastbuf->b_fnum;
- break;
- case ADDR_WINDOWS:
- ea.line2 = LAST_WIN_NR;
- break;
- case ADDR_TABS:
- ea.line2 = LAST_TAB_NR;
- break;
- case ADDR_TABS_RELATIVE:
- ea.line2 = 1;
- break;
- case ADDR_ARGUMENTS:
- if (ARGCOUNT == 0) {
- ea.line1 = ea.line2 = 0;
- } else {
- ea.line2 = ARGCOUNT;
- }
- break;
- case ADDR_QUICKFIX_VALID:
- ea.line2 = qf_get_valid_size(&ea);
- if (ea.line2 == 0) {
- ea.line2 = 1;
- }
- break;
- case ADDR_NONE:
- case ADDR_UNSIGNED:
- case ADDR_QUICKFIX:
- iemsg(_("INTERNAL: Cannot use EX_DFLALL "
- "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
- break;
- }
- }
-
- // accept numbered register only when no count allowed (:put)
- if ((ea.argt & EX_REGSTR)
- && *ea.arg != NUL
- // Do not allow register = for user commands
- && (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
- && !((ea.argt & EX_COUNT) && ascii_isdigit(*ea.arg))) {
- if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
- && !IS_USER_CMDIDX(ea.cmdidx)))) {
- ea.regname = *ea.arg++;
- // for '=' register: accept the rest of the line as an expression
- if (ea.arg[-1] == '=' && ea.arg[0] != NUL) {
- set_expr_line(vim_strsave(ea.arg));
- ea.arg += STRLEN(ea.arg);
- }
- ea.arg = skipwhite(ea.arg);
- }
+ set_cmd_dflall_range(&ea);
}
- //
- // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a
- // count, it's a buffer name.
- ///
- if ((ea.argt & EX_COUNT) && ascii_isdigit(*ea.arg)
- && (!(ea.argt & EX_BUFNAME) || *(p = skipdigits(ea.arg + 1)) == NUL
- || ascii_iswhite(*p))) {
- n = getdigits_long(&ea.arg, false, -1);
- ea.arg = skipwhite(ea.arg);
- if (n <= 0 && !ni && (ea.argt & EX_ZEROR) == 0) {
- errormsg = _(e_zerocount);
- goto doend;
- }
- if (ea.addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3
- ea.line2 = n;
- if (ea.addr_count == 0) {
- ea.addr_count = 1;
- }
- } else {
- ea.line1 = ea.line2;
- ea.line2 += n - 1;
- ++ea.addr_count;
- // Be vi compatible: no error message for out of range.
- if (ea.line2 > curbuf->b_ml.ml_line_count) {
- ea.line2 = curbuf->b_ml.ml_line_count;
- }
- }
+ // Parse register and count
+ parse_register(&ea);
+ if (parse_count(&ea, &errormsg, true) == FAIL) {
+ goto doend;
}
/*
@@ -1911,7 +2289,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
}
if (ea.argt & EX_XFILE) {
- if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) {
+ if (expand_filename(&ea, (char_u **)cmdlinep, &errormsg) == FAIL) {
goto doend;
}
}
@@ -1933,7 +2311,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
} else {
p = ea.arg + STRLEN(ea.arg);
while (p > ea.arg && ascii_iswhite(p[-1])) {
- --p;
+ p--;
}
}
ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & EX_BUFUNL) != 0,
@@ -1947,12 +2325,12 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
// The :try command saves the emsg_silent flag, reset it here when
// ":silent! try" was used, it should only apply to :try itself.
- if (ea.cmdidx == CMD_try && ea.did_esilent > 0) {
- emsg_silent -= ea.did_esilent;
+ if (ea.cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) {
+ emsg_silent -= cmdmod.cmod_did_esilent;
if (emsg_silent < 0) {
emsg_silent = 0;
}
- ea.did_esilent = 0;
+ cmdmod.cmod_did_esilent = 0;
}
// 7. Execute the command.
@@ -1960,7 +2338,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
/*
* Execute a user-defined command.
*/
- do_ucmd(&ea);
+ do_ucmd(&ea, false);
} else {
/*
* Call the function to execute the command.
@@ -1989,7 +2367,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
do_return(&ea, TRUE, FALSE, NULL);
}
}
- need_rethrow = check_cstack = FALSE;
+ need_rethrow = check_cstack = false;
doend:
// can happen with zero line number
@@ -2009,17 +2387,13 @@ doend:
emsg(errormsg);
}
do_errthrow(cstack,
- (ea.cmdidx != CMD_SIZE && !IS_USER_CMDIDX(ea.cmdidx))
- ? cmdnames[(int)ea.cmdidx].cmd_name
- : (char_u *)NULL);
+ (ea.cmdidx != CMD_SIZE
+ && !IS_USER_CMDIDX(ea.cmdidx)) ? cmdnames[(int)ea.cmdidx].cmd_name : NULL);
- undo_cmdmod(&ea, save_msg_scroll);
+ undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;
reg_executing = save_reg_executing;
-
- if (ea.did_sandbox) {
- sandbox--;
- }
+ pending_end_reg_executing = save_pending_end_reg_executing;
if (ea.nextcmd && *ea.nextcmd == NUL) { // not really a next command
ea.nextcmd = NULL;
@@ -2030,25 +2404,40 @@ doend:
return ea.nextcmd;
}
-// Parse and skip over command modifiers:
-// - update eap->cmd
-// - store flags in "cmdmod".
-// - Set ex_pressedreturn for an empty command line.
-// - set msg_silent for ":silent"
-// - set 'eventignore' to "all" for ":noautocmd"
-// - set p_verbose for ":verbose"
-// - Increment "sandbox" for ":sandbox"
-// When "skip_only" is true the global variables are not changed, except for
-// "cmdmod".
-// Return FAIL when the command is not to be executed.
-// May set "errormsg" to an error message.
-int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
+static char ex_error_buf[MSG_BUF_LEN];
+
+/// @return an error message with argument included.
+/// Uses a static buffer, only the last error will be kept.
+/// "msg" will be translated, caller should use N_().
+char *ex_errmsg(const char *const msg, const char *const arg)
+ FUNC_ATTR_NONNULL_ALL
+{
+ vim_snprintf(ex_error_buf, MSG_BUF_LEN, _(msg), arg);
+ return ex_error_buf;
+}
+
+/// Parse and skip over command modifiers:
+/// - update eap->cmd
+/// - store flags in "cmod".
+/// - Set ex_pressedreturn for an empty command line.
+///
+/// @param skip_only if false, undo_cmdmod() must be called later to free
+/// any cmod_filter_pat and cmod_filter_regmatch.regprog,
+/// and ex_pressedreturn may be set.
+/// @param[out] errormsg potential error message.
+///
+/// Call apply_cmdmod() to get the side effects of the modifiers:
+/// - Increment "sandbox" for ":sandbox"
+/// - set p_verbose for ":verbose"
+/// - set msg_silent for ":silent"
+/// - set 'eventignore' to "all" for ":noautocmd"
+///
+/// @return FAIL when the command is not to be executed.
+int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool skip_only)
{
- char_u *p;
+ char *p;
- memset(&cmdmod, 0, sizeof(cmdmod));
- eap->verbose_save = -1;
- eap->save_msg_silent = -1;
+ CLEAR_POINTER(cmod);
// Repeat until no more command modifiers are found.
for (;;) {
@@ -2062,7 +2451,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
if (*eap->cmd == NUL && exmode_active
&& getline_equal(eap->getline, eap->cookie, getexline)
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- eap->cmd = (char_u *)"+";
+ eap->cmd = "+";
if (!skip_only) {
ex_pressedreturn = true;
}
@@ -2086,58 +2475,58 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
if (!checkforcmd(&eap->cmd, "aboveleft", 3)) {
break;
}
- cmdmod.split |= WSP_ABOVE;
+ cmod->cmod_split |= WSP_ABOVE;
continue;
case 'b':
if (checkforcmd(&eap->cmd, "belowright", 3)) {
- cmdmod.split |= WSP_BELOW;
+ cmod->cmod_split |= WSP_BELOW;
continue;
}
if (checkforcmd(&eap->cmd, "browse", 3)) {
- cmdmod.browse = true;
+ cmod->cmod_flags |= CMOD_BROWSE;
continue;
}
if (!checkforcmd(&eap->cmd, "botright", 2)) {
break;
}
- cmdmod.split |= WSP_BOT;
+ cmod->cmod_split |= WSP_BOT;
continue;
case 'c':
if (!checkforcmd(&eap->cmd, "confirm", 4)) {
break;
}
- cmdmod.confirm = true;
+ cmod->cmod_flags |= CMOD_CONFIRM;
continue;
case 'k':
if (checkforcmd(&eap->cmd, "keepmarks", 3)) {
- cmdmod.keepmarks = true;
+ cmod->cmod_flags |= CMOD_KEEPMARKS;
continue;
}
if (checkforcmd(&eap->cmd, "keepalt", 5)) {
- cmdmod.keepalt = true;
+ cmod->cmod_flags |= CMOD_KEEPALT;
continue;
}
if (checkforcmd(&eap->cmd, "keeppatterns", 5)) {
- cmdmod.keeppatterns = true;
+ cmod->cmod_flags |= CMOD_KEEPPATTERNS;
continue;
}
if (!checkforcmd(&eap->cmd, "keepjumps", 5)) {
break;
}
- cmdmod.keepjumps = true;
+ cmod->cmod_flags |= CMOD_KEEPJUMPS;
continue;
case 'f': { // only accept ":filter {pat} cmd"
- char_u *reg_pat;
+ char *reg_pat;
if (!checkforcmd(&p, "filter", 4) || *p == NUL || ends_excmd(*p)) {
break;
}
if (*p == '!') {
- cmdmod.filter_force = true;
+ cmod->cmod_filter_force = true;
p = skipwhite(p + 1);
if (*p == NUL || ends_excmd(*p)) {
break;
@@ -2153,8 +2542,9 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
break;
}
if (!skip_only) {
- cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
- if (cmdmod.filter_regmatch.regprog == NULL) {
+ cmod->cmod_filter_pat = xstrdup(reg_pat);
+ cmod->cmod_filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
+ if (cmod->cmod_filter_regmatch.regprog == NULL) {
break;
}
}
@@ -2169,87 +2559,69 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
break;
}
eap->cmd = p;
- cmdmod.hide = true;
+ cmod->cmod_flags |= CMOD_HIDE;
continue;
case 'l':
if (checkforcmd(&eap->cmd, "lockmarks", 3)) {
- cmdmod.lockmarks = true;
+ cmod->cmod_flags |= CMOD_LOCKMARKS;
continue;
}
if (!checkforcmd(&eap->cmd, "leftabove", 5)) {
break;
}
- cmdmod.split |= WSP_ABOVE;
+ cmod->cmod_split |= WSP_ABOVE;
continue;
case 'n':
if (checkforcmd(&eap->cmd, "noautocmd", 3)) {
- if (cmdmod.save_ei == NULL && !skip_only) {
- // Set 'eventignore' to "all". Restore the
- // existing option value later.
- cmdmod.save_ei = vim_strsave(p_ei);
- set_string_option_direct("ei", -1,
- (char_u *)"all", OPT_FREE, SID_NONE);
- }
+ cmod->cmod_flags |= CMOD_NOAUTOCMD;
continue;
}
if (!checkforcmd(&eap->cmd, "noswapfile", 3)) {
break;
}
- cmdmod.noswapfile = true;
+ cmod->cmod_flags |= CMOD_NOSWAPFILE;
continue;
case 'r':
if (!checkforcmd(&eap->cmd, "rightbelow", 6)) {
break;
}
- cmdmod.split |= WSP_BELOW;
+ cmod->cmod_split |= WSP_BELOW;
continue;
case 's':
if (checkforcmd(&eap->cmd, "sandbox", 3)) {
- if (!skip_only) {
- if (!eap->did_sandbox) {
- sandbox++;
- }
- eap->did_sandbox = true;
- }
+ cmod->cmod_flags |= CMOD_SANDBOX;
continue;
}
if (!checkforcmd(&eap->cmd, "silent", 3)) {
break;
}
- if (!skip_only) {
- if (eap->save_msg_silent == -1) {
- eap->save_msg_silent = msg_silent;
- }
- msg_silent++;
- }
+ cmod->cmod_flags |= CMOD_SILENT;
if (*eap->cmd == '!' && !ascii_iswhite(eap->cmd[-1])) {
// ":silent!", but not "silent !cmd"
eap->cmd = skipwhite(eap->cmd + 1);
- if (!skip_only) {
- emsg_silent++;
- eap->did_esilent++;
- }
+ cmod->cmod_flags |= CMOD_ERRSILENT;
}
continue;
case 't':
if (checkforcmd(&p, "tab", 3)) {
if (!skip_only) {
- long tabnr = get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1);
+ int tabnr = (int)get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only,
+ false, 1);
if (tabnr == MAXLNUM) {
- cmdmod.tab = tabpage_index(curtab) + 1;
+ cmod->cmod_tab = tabpage_index(curtab) + 1;
} else {
if (tabnr < 0 || tabnr > LAST_TAB_NR) {
*errormsg = _(e_invrange);
return false;
}
- cmdmod.tab = tabnr + 1;
+ cmod->cmod_tab = tabnr + 1;
}
}
eap->cmd = p;
@@ -2258,38 +2630,29 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
if (!checkforcmd(&eap->cmd, "topleft", 2)) {
break;
}
- cmdmod.split |= WSP_TOP;
+ cmod->cmod_split |= WSP_TOP;
continue;
case 'u':
if (!checkforcmd(&eap->cmd, "unsilent", 3)) {
break;
}
- if (!skip_only) {
- if (eap->save_msg_silent == -1) {
- eap->save_msg_silent = msg_silent;
- }
- msg_silent = 0;
- }
+ cmod->cmod_flags |= CMOD_UNSILENT;
continue;
case 'v':
if (checkforcmd(&eap->cmd, "vertical", 4)) {
- cmdmod.split |= WSP_VERT;
+ cmod->cmod_split |= WSP_VERT;
continue;
}
if (!checkforcmd(&p, "verbose", 4)) {
break;
}
- if (!skip_only) {
- if (eap->verbose_save < 0) {
- eap->verbose_save = p_verbose;
- }
- if (ascii_isdigit(*eap->cmd)) {
- p_verbose = atoi((char *)eap->cmd);
- } else {
- p_verbose = 1;
- }
+ if (ascii_isdigit(*eap->cmd)) {
+ // zero means not set, one is verbose == 0, etc.
+ cmod->cmod_verbose = atoi(eap->cmd) + 1;
+ } else {
+ cmod->cmod_verbose = 2; // default: verbose == 1
}
eap->cmd = p;
continue;
@@ -2300,98 +2663,116 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
return OK;
}
-// Undo and free contents of "cmdmod".
-static void undo_cmdmod(const exarg_T *eap, int save_msg_scroll)
+/// Apply the command modifiers. Saves current state in "cmdmod", call
+/// undo_cmdmod() later.
+static void apply_cmdmod(cmdmod_T *cmod)
+{
+ if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) {
+ sandbox++;
+ cmod->cmod_did_sandbox = true;
+ }
+ if (cmod->cmod_verbose > 0) {
+ if (cmod->cmod_verbose_save == 0) {
+ cmod->cmod_verbose_save = p_verbose + 1;
+ }
+ p_verbose = cmod->cmod_verbose - 1;
+ }
+
+ if ((cmod->cmod_flags & (CMOD_SILENT | CMOD_UNSILENT))
+ && cmod->cmod_save_msg_silent == 0) {
+ cmod->cmod_save_msg_silent = msg_silent + 1;
+ cmod->cmod_save_msg_scroll = msg_scroll;
+ }
+ if (cmod->cmod_flags & CMOD_SILENT) {
+ msg_silent++;
+ }
+ if (cmod->cmod_flags & CMOD_UNSILENT) {
+ msg_silent = 0;
+ }
+
+ if (cmod->cmod_flags & CMOD_ERRSILENT) {
+ emsg_silent++;
+ cmod->cmod_did_esilent++;
+ }
+
+ if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmod->cmod_save_ei == NULL) {
+ // Set 'eventignore' to "all".
+ // First save the existing option value for restoring it later.
+ cmod->cmod_save_ei = (char *)vim_strsave(p_ei);
+ set_string_option_direct("ei", -1, "all", OPT_FREE, SID_NONE);
+ }
+}
+
+/// Undo and free contents of "cmod".
+void undo_cmdmod(cmdmod_T *cmod)
FUNC_ATTR_NONNULL_ALL
{
- if (eap->verbose_save >= 0) {
- p_verbose = eap->verbose_save;
+ if (cmod->cmod_verbose_save > 0) {
+ p_verbose = cmod->cmod_verbose_save - 1;
+ cmod->cmod_verbose_save = 0;
+ }
+
+ if (cmod->cmod_did_sandbox) {
+ sandbox--;
+ cmod->cmod_did_sandbox = false;
}
- if (cmdmod.save_ei != NULL) {
+ if (cmod->cmod_save_ei != NULL) {
// Restore 'eventignore' to the value before ":noautocmd".
- set_string_option_direct("ei", -1, cmdmod.save_ei, OPT_FREE, SID_NONE);
- free_string_option(cmdmod.save_ei);
+ set_string_option_direct("ei", -1, cmod->cmod_save_ei, OPT_FREE, SID_NONE);
+ free_string_option((char_u *)cmod->cmod_save_ei);
+ cmod->cmod_save_ei = NULL;
}
- vim_regfree(cmdmod.filter_regmatch.regprog);
+ xfree(cmod->cmod_filter_pat);
+ vim_regfree(cmod->cmod_filter_regmatch.regprog);
- if (eap->save_msg_silent != -1) {
+ if (cmod->cmod_save_msg_silent > 0) {
// messages could be enabled for a serious error, need to check if the
// counters don't become negative
- if (!did_emsg || msg_silent > eap->save_msg_silent) {
- msg_silent = eap->save_msg_silent;
+ if (!did_emsg || msg_silent > cmod->cmod_save_msg_silent - 1) {
+ msg_silent = cmod->cmod_save_msg_silent - 1;
}
- emsg_silent -= eap->did_esilent;
+ emsg_silent -= cmod->cmod_did_esilent;
if (emsg_silent < 0) {
emsg_silent = 0;
}
// Restore msg_scroll, it's set by file I/O commands, even when no
// message is actually displayed.
- msg_scroll = save_msg_scroll;
+ msg_scroll = cmod->cmod_save_msg_scroll;
// "silent reg" or "silent echo x" inside "redir" leaves msg_col
// somewhere in the line. Put it back in the first column.
if (redirecting()) {
msg_col = 0;
}
+
+ cmod->cmod_save_msg_silent = 0;
+ cmod->cmod_did_esilent = 0;
}
}
-
-// Parse the address range, if any, in "eap".
-// May set the last search pattern, unless "silent" is true.
-// Return FAIL and set "errormsg" or return OK.
+/// Parse the address range, if any, in "eap".
+/// May set the last search pattern, unless "silent" is true.
+///
+/// @return FAIL and set "errormsg" or return OK.
int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
FUNC_ATTR_NONNULL_ALL
{
int address_count = 1;
linenr_T lnum;
+ bool need_check_cursor = false;
+ int ret = FAIL;
// Repeat for all ',' or ';' separated addresses.
for (;;) {
eap->line1 = eap->line2;
- switch (eap->addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- // default is current line number
- eap->line2 = curwin->w_cursor.lnum;
- break;
- case ADDR_WINDOWS:
- eap->line2 = CURRENT_WIN_NR;
- break;
- case ADDR_ARGUMENTS:
- eap->line2 = curwin->w_arg_idx + 1;
- if (eap->line2 > ARGCOUNT) {
- eap->line2 = ARGCOUNT;
- }
- break;
- case ADDR_LOADED_BUFFERS:
- case ADDR_BUFFERS:
- eap->line2 = curbuf->b_fnum;
- break;
- case ADDR_TABS:
- eap->line2 = CURRENT_TAB_NR;
- break;
- case ADDR_TABS_RELATIVE:
- case ADDR_UNSIGNED:
- eap->line2 = 1;
- break;
- case ADDR_QUICKFIX:
- eap->line2 = qf_get_cur_idx(eap);
- break;
- case ADDR_QUICKFIX_VALID:
- eap->line2 = qf_get_cur_valid_idx(eap);
- break;
- case ADDR_NONE:
- // Will give an error later if a range is found.
- break;
- }
+ eap->line2 = get_cmd_default_range(eap);
eap->cmd = skipwhite(eap->cmd);
lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
eap->addr_count == 0, address_count++);
if (eap->cmd == NULL) { // error detected
- return FAIL;
+ goto theend;
}
if (lnum == MAXLNUM) {
if (*eap->cmd == '%') { // '%' - all lines
@@ -2430,14 +2811,14 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
// there is no Vim command which uses '%' and
// ADDR_WINDOWS or ADDR_TABS
*errormsg = _(e_invrange);
- return FAIL;
+ goto theend;
}
break;
case ADDR_TABS_RELATIVE:
case ADDR_UNSIGNED:
case ADDR_QUICKFIX:
*errormsg = _(e_invrange);
- return FAIL;
+ goto theend;
case ADDR_ARGUMENTS:
if (ARGCOUNT == 0) {
eap->line1 = eap->line2 = 0;
@@ -2448,7 +2829,7 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
break;
case ADDR_QUICKFIX_VALID:
eap->line1 = 1;
- eap->line2 = qf_get_valid_size(eap);
+ eap->line2 = (linenr_T)qf_get_valid_size(eap);
if (eap->line2 == 0) {
eap->line2 = 1;
}
@@ -2462,21 +2843,21 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
// '*' - visual area
if (eap->addr_type != ADDR_LINES) {
*errormsg = _(e_invrange);
- return FAIL;
+ goto theend;
}
eap->cmd++;
if (!eap->skip) {
- pos_T *fp = getmark('<', false);
- if (check_mark(fp) == FAIL) {
- return FAIL;
+ fmark_T *fm = mark_get_visual(curbuf, '<');
+ if (!mark_check(fm)) {
+ goto theend;
}
- eap->line1 = fp->lnum;
- fp = getmark('>', false);
- if (check_mark(fp) == FAIL) {
- return FAIL;
+ eap->line1 = fm->mark.lnum;
+ fm = mark_get_visual(curbuf, '>');
+ if (!mark_check(fm)) {
+ goto theend;
}
- eap->line2 = fp->lnum;
+ eap->line2 = fm->mark.lnum;
eap->addr_count++;
}
}
@@ -2488,11 +2869,17 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
if (*eap->cmd == ';') {
if (!eap->skip) {
curwin->w_cursor.lnum = eap->line2;
+
// Don't leave the cursor on an illegal line or column, but do
- // accept zero as address, so 0;/PATTERN/ works correctly.
+ // accept zero as address, so 0;/PATTERN/ works correctly
+ // (where zero usually means to use the first line).
+ // Check the cursor position before returning.
if (eap->line2 > 0) {
check_cursor();
+ } else {
+ check_cursor_col();
}
+ need_check_cursor = true;
}
} else if (*eap->cmd != ',') {
break;
@@ -2508,7 +2895,13 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
eap->addr_count = 0;
}
}
- return OK;
+ ret = OK;
+
+theend:
+ if (need_check_cursor) {
+ check_cursor();
+ }
+ return ret;
}
/// Check for an Ex command with optional tail.
@@ -2517,56 +2910,64 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent)
/// @param pp start of command
/// @param cmd name of command
/// @param len required length
-int checkforcmd(char_u **pp, char *cmd, int len)
+int checkforcmd(char **pp, char *cmd, int len)
{
int i;
- for (i = 0; cmd[i] != NUL; ++i) {
- if (((char_u *)cmd)[i] != (*pp)[i]) {
+ for (i = 0; cmd[i] != NUL; i++) {
+ if ((cmd)[i] != (*pp)[i]) {
break;
}
}
if (i >= len && !isalpha((*pp)[i])) {
*pp = skipwhite(*pp + i);
- return TRUE;
+ return true;
}
return FALSE;
}
-/*
- * Append "cmd" to the error message in IObuff.
- * Takes care of limiting the length and handling 0xa0, which would be
- * invisible otherwise.
- */
-static void append_command(char_u *cmd)
+/// Append "cmd" to the error message in IObuff.
+/// Takes care of limiting the length and handling 0xa0, which would be
+/// invisible otherwise.
+static void append_command(char *cmd)
{
- char_u *s = cmd;
- char_u *d;
+ size_t len = STRLEN(IObuff);
+ char *s = cmd;
+ char *d;
+ if (len > IOSIZE - 100) {
+ // Not enough space, truncate and put in "...".
+ d = (char *)IObuff + IOSIZE - 100;
+ d -= utf_head_off(IObuff, (const char_u *)d);
+ STRCPY(d, "...");
+ }
STRCAT(IObuff, ": ");
- d = IObuff + STRLEN(IObuff);
- while (*s != NUL && d - IObuff < IOSIZE - 7) {
- if (s[0] == 0xc2 && s[1] == 0xa0) {
+ d = (char *)IObuff + STRLEN(IObuff);
+ while (*s != NUL && (char_u *)d - IObuff + 5 < IOSIZE) {
+ if ((char_u)s[0] == 0xc2 && (char_u)s[1] == 0xa0) {
s += 2;
STRCPY(d, "<a0>");
d += 4;
+ } else if ((char_u *)d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) {
+ break;
} else {
- mb_copy_char((const char_u **)&s, &d);
+ mb_copy_char((const char_u **)&s, (char_u **)&d);
}
}
*d = NUL;
}
-// Find an Ex command by its name, either built-in or user.
-// Start of the name can be found at eap->cmd.
-// Sets eap->cmdidx and returns a pointer to char after the command name.
-// "full" is set to TRUE if the whole command name matched.
-// Returns NULL for an ambiguous user command.
-static char_u *find_command(exarg_T *eap, int *full)
+/// Find an Ex command by its name, either built-in or user.
+/// Start of the name can be found at eap->cmd.
+/// Sets eap->cmdidx and returns a pointer to char after the command name.
+/// "full" is set to TRUE if the whole command name matched.
+///
+/// @return NULL for an ambiguous user command.
+char *find_ex_command(exarg_T *eap, int *full)
FUNC_ATTR_NONNULL_ARG(1)
{
int len;
- char_u *p;
+ char *p;
int i;
/*
@@ -2606,15 +3007,15 @@ static char_u *find_command(exarg_T *eap, int *full)
}
// check for non-alpha command
- if (p == eap->cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL) {
- ++p;
+ if (p == eap->cmd && vim_strchr("@!=><&~#", *p) != NULL) {
+ p++;
}
len = (int)(p - eap->cmd);
if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) {
// Check for ":dl", ":dell", etc. to ":deletel": that's
// :delete with the 'l' flag. Same for 'p'.
for (i = 0; i < len; i++) {
- if (eap->cmd[i] != ((char_u *)"delete")[i]) {
+ if (eap->cmd[i] != ("delete")[i]) {
break;
}
}
@@ -2629,7 +3030,7 @@ static char_u *find_command(exarg_T *eap, int *full)
}
if (ASCII_ISLOWER(eap->cmd[0])) {
- const int c1 = eap->cmd[0];
+ const int c1 = (char_u)eap->cmd[0];
const int c2 = len == 1 ? NUL : eap->cmd[1];
if (command_count != CMD_SIZE) {
@@ -2639,17 +3040,19 @@ static char_u *find_command(exarg_T *eap, int *full)
// Use a precomputed index for fast look-up in cmdnames[]
// taking into account the first 2 letters of eap->cmd.
- eap->cmdidx = cmdidxs1[CharOrdLow(c1)];
+ eap->cmdidx = cmdidxs1[CHAR_ORD_LOW(c1)];
if (ASCII_ISLOWER(c2)) {
- eap->cmdidx += cmdidxs2[CharOrdLow(c1)][CharOrdLow(c2)];
+ eap->cmdidx += cmdidxs2[CHAR_ORD_LOW(c1)][CHAR_ORD_LOW(c2)];
}
+ } else if (ASCII_ISUPPER(eap->cmd[0])) {
+ eap->cmdidx = CMD_Next;
} else {
eap->cmdidx = CMD_bang;
}
for (; (int)eap->cmdidx < CMD_SIZE;
eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) {
- if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd,
+ if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd,
(size_t)len) == 0) {
if (full != NULL
&& cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) {
@@ -2685,27 +3088,25 @@ static char_u *find_command(exarg_T *eap, int *full)
/// @param full set to TRUE for a full match
/// @param xp used for completion, NULL otherwise
/// @param complp completion flags or NULL
-static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *complp)
+static char *find_ucmd(exarg_T *eap, char *p, int *full, expand_T *xp, int *complp)
{
int len = (int)(p - eap->cmd);
int j, k, matchlen = 0;
ucmd_T *uc;
bool found = false;
bool possible = false;
- char_u *cp, *np; // Point into typed cmd and test name
+ char *cp, *np; // Point into typed cmd and test name
garray_T *gap;
bool amb_local = false; // Found ambiguous buffer-local command,
// only full match global is accepted.
- /*
- * Look for buffer-local user commands first, then global ones.
- */
- gap = &curbuf->b_ucmds;
+ // Look for buffer-local user commands first, then global ones.
+ gap = &prevwin_curwin()->w_buffer->b_ucmds;
for (;;) {
for (j = 0; j < gap->ga_len; j++) {
uc = USER_CMD_GA(gap, j);
cp = eap->cmd;
- np = uc->uc_name;
+ np = (char *)uc->uc_name;
k = 0;
while (k < len && *np != NUL && *cp++ == *np++) {
k++;
@@ -2746,7 +3147,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *
}
if (xp != NULL) {
xp->xp_luaref = uc->uc_compl_luaref;
- xp->xp_arg = uc->uc_compl_arg;
+ xp->xp_arg = (char *)uc->uc_compl_arg;
xp->xp_script_ctx = uc->uc_script_ctx;
xp->xp_script_ctx.sc_lnum += sourcing_lnum;
}
@@ -2817,13 +3218,11 @@ static struct cmdmod {
{ "vertical", 4, false },
};
-/*
- * Return length of a command modifier (including optional count).
- * Return zero when it's not a modifier.
- */
-int modifier_len(char_u *cmd)
+/// @return length of a command modifier (including optional count) or,
+/// zero when it's not a modifier.
+int modifier_len(char *cmd)
{
- char_u *p = cmd;
+ char *p = cmd;
if (ascii_isdigit(*cmd)) {
p = skipwhite(skipdigits(cmd + 1));
@@ -2844,15 +3243,13 @@ int modifier_len(char_u *cmd)
return 0;
}
-/*
- * Return > 0 if an Ex command "name" exists.
- * Return 2 if there is an exact match.
- * Return 3 if there is an ambiguous match.
- */
+/// @return > 0 if an Ex command "name" exists or,
+/// 2 if there is an exact match or,
+/// 3 if there is an ambiguous match.
int cmd_exists(const char *const name)
{
exarg_T ea;
- char_u *p;
+ char *p;
// Check command modifiers.
for (int i = 0; i < (int)ARRAY_SIZE(cmdmods); i++) {
@@ -2869,10 +3266,10 @@ int cmd_exists(const char *const name)
// Check built-in commands and user defined commands.
// For ":2match" and ":3match" we need to skip the number.
- ea.cmd = (char_u *)((*name == '2' || *name == '3') ? name + 1 : name);
+ ea.cmd = (char *)((*name == '2' || *name == '3') ? name + 1 : name);
ea.cmdidx = (cmdidx_T)0;
int full = false;
- p = find_command(&ea, &full);
+ p = find_ex_command(&ea, &full);
if (p == NULL) {
return 3;
}
@@ -2885,29 +3282,34 @@ int cmd_exists(const char *const name)
return ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1);
}
-// "fullcommand" function
+/// "fullcommand" function
void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
exarg_T ea;
- char_u *name = argvars[0].vval.v_string;
+ char *name = argvars[0].vval.v_string;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (name == NULL) {
+ return;
+ }
- while (name[0] != NUL && name[0] == ':') {
+ while (*name == ':') {
name++;
}
name = skip_range(name, NULL);
- rettv->v_type = VAR_STRING;
-
ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name;
ea.cmdidx = (cmdidx_T)0;
- char_u *p = find_command(&ea, NULL);
+ char *p = find_ex_command(&ea, NULL);
if (p == NULL || ea.cmdidx == CMD_SIZE) {
return;
}
- rettv->vval.v_string = vim_strsave(IS_USER_CMDIDX(ea.cmdidx)
- ? get_user_commands(NULL, ea.useridx)
- : cmdnames[ea.cmdidx].cmd_name);
+ rettv->vval.v_string = (char *)vim_strsave(IS_USER_CMDIDX(ea.cmdidx)
+ ? (char_u *)get_user_command_name(ea.useridx,
+ ea.cmdidx)
+ : (char_u *)cmdnames[ea.cmdidx].cmd_name);
}
/// This is all pretty much copied from do_one_cmd(), with all the extra stuff
@@ -2926,16 +3328,15 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
bool usefilter = false; // Filter instead of file name.
ExpandInit(xp);
- xp->xp_pattern = (char_u *)buff;
- xp->xp_line = (char_u *)buff;
+ xp->xp_pattern = (char *)buff;
+ xp->xp_line = (char *)buff;
xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
ea.argt = 0;
// 2. skip comment lines and leading space, colons or bars
const char *cmd;
- for (cmd = buff; vim_strchr((const char_u *)" \t:|", *cmd) != NULL; cmd++) {
- }
- xp->xp_pattern = (char_u *)cmd;
+ for (cmd = buff; vim_strchr(" \t:|", *cmd) != NULL; cmd++) {}
+ xp->xp_pattern = (char *)cmd;
if (*cmd == NUL) {
return NULL;
@@ -2948,12 +3349,12 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
/*
* 3. parse a range specifier of the form: addr [,addr] [;addr] ..
*/
- cmd = (const char *)skip_range((const char_u *)cmd, &xp->xp_context);
+ cmd = (const char *)skip_range(cmd, &xp->xp_context);
/*
* 4. parse command
*/
- xp->xp_pattern = (char_u *)cmd;
+ xp->xp_pattern = (char *)cmd;
if (*cmd == NUL) {
return NULL;
}
@@ -2995,7 +3396,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
}
// check for non-alpha command
- if (p == cmd && vim_strchr((const char_u *)"@*!=><&~#", *p) != NULL) {
+ if (p == cmd && vim_strchr("@*!=><&~#", *p) != NULL) {
p++;
}
len = (size_t)(p - cmd);
@@ -3027,12 +3428,12 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
if (ea.cmdidx == CMD_SIZE) {
- if (*cmd == 's' && vim_strchr((const char_u *)"cgriI", cmd[1]) != NULL) {
+ if (*cmd == 's' && vim_strchr("cgriI", cmd[1]) != NULL) {
ea.cmdidx = CMD_substitute;
p = cmd + 1;
} else if (cmd[0] >= 'A' && cmd[0] <= 'Z') {
- ea.cmd = (char_u *)cmd;
- p = (const char *)find_ucmd(&ea, (char_u *)p, NULL, xp, &context);
+ ea.cmd = (char *)cmd;
+ p = (const char *)find_ucmd(&ea, (char *)p, NULL, xp, &context);
if (p == NULL) {
ea.cmdidx = CMD_SIZE; // Ambiguous user command.
}
@@ -3058,7 +3459,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt;
}
- const char *arg = (const char *)skipwhite((const char_u *)p);
+ const char *arg = (const char *)skipwhite(p);
// Skip over ++argopt argument
if ((ea.argt & EX_ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) {
@@ -3066,7 +3467,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
while (*p && !ascii_isspace(*p)) {
MB_PTR_ADV(p);
}
- arg = (const char *)skipwhite((const char_u *)p);
+ arg = (const char *)skipwhite(p);
}
if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) {
@@ -3074,7 +3475,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
if (*++arg == '>') {
arg++;
}
- arg = (const char *)skipwhite((const char_u *)arg);
+ arg = (const char *)skipwhite(arg);
} else if (*arg == '!' && ea.cmdidx == CMD_write) { // :w !filter
arg++;
usefilter = true;
@@ -3093,14 +3494,14 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
while (*arg == *cmd) { // allow any number of '>' or '<'
arg++;
}
- arg = (const char *)skipwhite((const char_u *)arg);
+ arg = (const char *)skipwhite(arg);
}
// Does command allow "+command"?
if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') {
// Check if we're in the +command
p = arg + 1;
- arg = (const char *)skip_cmd_arg((char_u *)arg, false);
+ arg = (const char *)skip_cmd_arg((char *)arg, false);
// Still touching the command after '+'?
if (*arg == NUL) {
@@ -3108,7 +3509,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
// Skip space(s) after +command to get to the real argument.
- arg = (const char *)skipwhite((const char_u *)arg);
+ arg = (const char *)skipwhite(arg);
}
/*
@@ -3147,12 +3548,12 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
// Find start of last argument (argument just before cursor):
p = buff;
- xp->xp_pattern = (char_u *)p;
+ xp->xp_pattern = (char *)p;
len = strlen(buff);
while (*p && p < buff + len) {
if (*p == ' ' || *p == TAB) {
// Argument starts after a space.
- xp->xp_pattern = (char_u *)++p;
+ xp->xp_pattern = (char *)++p;
} else {
if (*p == '\\' && *(p + 1) != NUL) {
p++; // skip over escaped character
@@ -3170,15 +3571,15 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
* Allow spaces within back-quotes to count as part of the argument
* being expanded.
*/
- xp->xp_pattern = skipwhite((const char_u *)arg);
+ xp->xp_pattern = skipwhite(arg);
p = (const char *)xp->xp_pattern;
while (*p != NUL) {
- c = utf_ptr2char((const char_u *)p);
+ c = utf_ptr2char(p);
if (c == '\\' && p[1] != NUL) {
p++;
} else if (c == '`') {
if (!in_quote) {
- xp->xp_pattern = (char_u *)p;
+ xp->xp_pattern = (char *)p;
bow = p + 1;
}
in_quote = !in_quote;
@@ -3191,17 +3592,17 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
|| ascii_iswhite(c)) {
len = 0; // avoid getting stuck when space is in 'isfname'
while (*p != NUL) {
- c = utf_ptr2char((const char_u *)p);
+ c = utf_ptr2char(p);
if (c == '`' || vim_isfilec_or_wc(c)) {
break;
}
- len = (size_t)utfc_ptr2len((const char_u *)p);
+ len = (size_t)utfc_ptr2len(p);
MB_PTR_ADV(p);
}
if (in_quote) {
bow = p;
} else {
- xp->xp_pattern = (char_u *)p;
+ xp->xp_pattern = (char *)p;
}
p -= len;
}
@@ -3213,7 +3614,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
* expand from there.
*/
if (bow != NULL && in_quote) {
- xp->xp_pattern = (char_u *)bow;
+ xp->xp_pattern = (char *)bow;
}
xp->xp_context = EXPAND_FILES;
@@ -3223,7 +3624,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
xp->xp_shell = TRUE;
#endif
// When still after the command name expand executables.
- if (xp->xp_pattern == skipwhite((const char_u *)arg)) {
+ if (xp->xp_pattern == skipwhite(arg)) {
xp->xp_context = EXPAND_SHELLCMD;
}
}
@@ -3246,13 +3647,12 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
// Check for user names.
if (*xp->xp_pattern == '~') {
- for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {
- }
+ for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {}
// Complete ~user only if it partially matches a user name.
// A full match ~user<Tab> will be replaced by user's home
// directory i.e. something like ~user<Tab> -> /home/user/
if (*p == NUL && p > (const char *)xp->xp_pattern + 1
- && match_user(xp->xp_pattern + 1) >= 1) {
+ && match_user((char_u *)xp->xp_pattern + 1) >= 1) {
xp->xp_context = EXPAND_USER;
++xp->xp_pattern;
}
@@ -3282,7 +3682,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
break;
case CMD_help:
xp->xp_context = EXPAND_HELP;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
/* Command modifiers: return the argument.
@@ -3323,19 +3723,19 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_filter:
if (*arg != NUL) {
- arg = (const char *)skip_vimgrep_pat((char_u *)arg, NULL, NULL);
+ arg = (const char *)skip_vimgrep_pat((char *)arg, NULL, NULL);
}
if (arg == NULL || *arg == NUL) {
xp->xp_context = EXPAND_NOTHING;
return NULL;
}
- return (const char *)skipwhite((const char_u *)arg);
+ return (const char *)skipwhite(arg);
case CMD_match:
if (*arg == NUL || !ends_excmd(*arg)) {
// also complete "None"
set_context_in_echohl_cmd(xp, arg);
- arg = (const char *)skipwhite(skiptowhite((const char_u *)arg));
+ arg = (const char *)skipwhite((char *)skiptowhite((const char_u *)arg));
if (*arg != NUL) {
xp->xp_context = EXPAND_NOTHING;
arg = (const char *)skip_regexp((char_u *)arg + 1, (uint8_t)(*arg),
@@ -3359,7 +3759,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
if (p == NULL) {
// No "=", so complete attribute names.
xp->xp_context = EXPAND_USER_CMD_FLAGS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
return NULL;
}
@@ -3367,36 +3767,36 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
// their arguments as well.
if (STRNICMP(arg, "complete", p - arg) == 0) {
xp->xp_context = EXPAND_USER_COMPLETE;
- xp->xp_pattern = (char_u *)p + 1;
+ xp->xp_pattern = (char *)p + 1;
return NULL;
} else if (STRNICMP(arg, "nargs", p - arg) == 0) {
xp->xp_context = EXPAND_USER_NARGS;
- xp->xp_pattern = (char_u *)p + 1;
+ xp->xp_pattern = (char *)p + 1;
return NULL;
} else if (STRNICMP(arg, "addr", p - arg) == 0) {
xp->xp_context = EXPAND_USER_ADDR_TYPE;
- xp->xp_pattern = (char_u *)p + 1;
+ xp->xp_pattern = (char *)p + 1;
return NULL;
}
return NULL;
}
- arg = (const char *)skipwhite((char_u *)p);
+ arg = (const char *)skipwhite(p);
}
// After the attributes comes the new command name.
p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) {
xp->xp_context = EXPAND_USER_COMMANDS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
}
// And finally comes a normal command.
- return (const char *)skipwhite((const char_u *)p);
+ return (const char *)skipwhite(p);
case CMD_delcommand:
xp->xp_context = EXPAND_USER_COMMANDS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_global:
@@ -3453,7 +3853,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_isplit:
case CMD_dsplit:
// Skip count.
- arg = (const char *)skipwhite(skipdigits((const char_u *)arg));
+ arg = (const char *)skipwhite(skipdigits(arg));
if (*arg == '/') { // Match regexp, not just whole words.
for (++arg; *arg && *arg != '/'; arg++) {
if (*arg == '\\' && arg[1] != NUL) {
@@ -3461,7 +3861,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
}
if (*arg) {
- arg = (const char *)skipwhite((const char_u *)arg + 1);
+ arg = (const char *)skipwhite(arg + 1);
// Check for trailing illegal characters.
if (*arg && strchr("|\"\n", *arg) == NULL) {
@@ -3473,11 +3873,11 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
break;
case CMD_autocmd:
- return (const char *)set_context_in_autocmd(xp, (char_u *)arg, false);
+ return (const char *)set_context_in_autocmd(xp, (char *)arg, false);
case CMD_doautocmd:
case CMD_doautoall:
- return (const char *)set_context_in_autocmd(xp, (char_u *)arg, true);
+ return (const char *)set_context_in_autocmd(xp, (char *)arg, true);
case CMD_set:
set_context_in_set_cmd(xp, (char_u *)arg, 0);
break;
@@ -3502,11 +3902,11 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
} else {
xp->xp_context = EXPAND_TAGS;
}
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_augroup:
xp->xp_context = EXPAND_AUGROUP;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_syntax:
set_context_in_syntax_cmd(xp, arg);
@@ -3530,16 +3930,16 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_lexpr:
case CMD_laddexpr:
case CMD_lgetexpr:
- set_context_for_expression(xp, (char_u *)arg, ea.cmdidx);
+ set_context_for_expression(xp, (char *)arg, ea.cmdidx);
break;
case CMD_unlet:
- while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
+ while ((xp->xp_pattern = strchr(arg, ' ')) != NULL) {
arg = (const char *)xp->xp_pattern + 1;
}
xp->xp_context = EXPAND_USER_VARS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
if (*xp->xp_pattern == '$') {
xp->xp_context = EXPAND_ENV_VARS;
@@ -3551,7 +3951,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_function:
case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_echohl:
@@ -3571,7 +3971,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_bdelete:
case CMD_bwipeout:
case CMD_bunload:
- while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
+ while ((xp->xp_pattern = strchr(arg, ' ')) != NULL) {
arg = (const char *)xp->xp_pattern + 1;
}
FALLTHROUGH;
@@ -3579,14 +3979,14 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_sbuffer:
case CMD_checktime:
xp->xp_context = EXPAND_BUFFERS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_diffget:
case CMD_diffput:
// If current buffer is in diff mode, complete buffer names
// which are in diff mode, and different than current buffer.
xp->xp_context = EXPAND_DIFF_BUFFERS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_USER:
case CMD_USER_BUF:
@@ -3594,8 +3994,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
// EX_XFILE: file names are handled above.
if (!(ea.argt & EX_XFILE)) {
if (context == EXPAND_MENUS) {
- return (const char *)set_context_in_menu_cmd(xp, cmd,
- (char_u *)arg, forceit);
+ return (const char *)set_context_in_menu_cmd(xp, cmd, (char *)arg, forceit);
} else if (context == EXPAND_COMMANDS) {
return arg;
} else if (context == EXPAND_MAPPINGS) {
@@ -3614,7 +4013,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
}
MB_PTR_ADV(p);
}
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
}
xp->xp_context = context;
}
@@ -3660,7 +4059,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_smapclear:
case CMD_xmapclear:
xp->xp_context = EXPAND_MAPCLEAR;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_abbreviate:
@@ -3697,35 +4096,38 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
case CMD_cmenu:
case CMD_cnoremenu:
case CMD_cunmenu:
+ case CMD_tlmenu:
+ case CMD_tlnoremenu:
+ case CMD_tlunmenu:
case CMD_tmenu:
case CMD_tunmenu:
case CMD_popup:
case CMD_emenu:
- return (const char *)set_context_in_menu_cmd(xp, cmd, (char_u *)arg, forceit);
+ return (const char *)set_context_in_menu_cmd(xp, cmd, (char *)arg, forceit);
case CMD_colorscheme:
xp->xp_context = EXPAND_COLORS;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_compiler:
xp->xp_context = EXPAND_COMPILER;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_ownsyntax:
xp->xp_context = EXPAND_OWNSYNTAX;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_setfiletype:
xp->xp_context = EXPAND_FILETYPE;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_packadd:
xp->xp_context = EXPAND_PACKADD;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
#ifdef HAVE_WORKING_LIBINTL
@@ -3733,14 +4135,14 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) {
xp->xp_context = EXPAND_LANGUAGE;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
} else {
- if (strncmp(arg, "messages", p - arg) == 0
- || strncmp(arg, "ctype", p - arg) == 0
- || strncmp(arg, "time", p - arg) == 0
- || strncmp(arg, "collate", p - arg) == 0) {
+ if (strncmp(arg, "messages", (size_t)(p - arg)) == 0
+ || strncmp(arg, "ctype", (size_t)(p - arg)) == 0
+ || strncmp(arg, "time", (size_t)(p - arg)) == 0
+ || strncmp(arg, "collate", (size_t)(p - arg)) == 0) {
xp->xp_context = EXPAND_LOCALES;
- xp->xp_pattern = skipwhite((const char_u *)p);
+ xp->xp_pattern = skipwhite(p);
} else {
xp->xp_context = EXPAND_NOTHING;
}
@@ -3752,33 +4154,33 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
break;
case CMD_checkhealth:
xp->xp_context = EXPAND_CHECKHEALTH;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_behave:
xp->xp_context = EXPAND_BEHAVE;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_messages:
xp->xp_context = EXPAND_MESSAGES;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_history:
xp->xp_context = EXPAND_HISTORY;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_syntime:
xp->xp_context = EXPAND_SYNTIME;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_argdelete:
- while ((xp->xp_pattern = vim_strchr((const char_u *)arg, ' ')) != NULL) {
+ while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) {
arg = (const char *)(xp->xp_pattern + 1);
}
xp->xp_context = EXPAND_ARGLIST;
- xp->xp_pattern = (char_u *)arg;
+ xp->xp_pattern = (char *)arg;
break;
case CMD_lua:
@@ -3801,11 +4203,11 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
/// @param ctx pointer to xp_context or NULL
///
/// @return the "cmd" pointer advanced to beyond the range.
-char_u *skip_range(const char_u *cmd, int *ctx)
+char *skip_range(const char *cmd, int *ctx)
{
unsigned delim;
- while (vim_strchr((char_u *)" \t0123456789.$%'/?-+,;\\", *cmd) != NULL) {
+ while (vim_strchr(" \t0123456789.$%'/?-+,;\\", *cmd) != NULL) {
if (*cmd == '\\') {
if (cmd[1] == '?' || cmd[1] == '/' || cmd[1] == '&') {
cmd++;
@@ -3817,8 +4219,8 @@ char_u *skip_range(const char_u *cmd, int *ctx)
*ctx = EXPAND_NOTHING;
}
} else if (*cmd == '/' || *cmd == '?') {
- delim = *cmd++;
- while (*cmd != NUL && *cmd != delim) {
+ delim = (unsigned)(*cmd++);
+ while (*cmd != NUL && *cmd != (char)delim) {
if (*cmd++ == '\\' && *cmd != NUL) {
++cmd;
}
@@ -3833,9 +4235,9 @@ char_u *skip_range(const char_u *cmd, int *ctx)
}
// Skip ":" and white space.
- cmd = skip_colon_white(cmd, false);
+ cmd = skip_colon_white((char *)cmd, false);
- return (char_u *)cmd;
+ return (char *)cmd;
}
static void addr_error(cmd_addr_T addr_type)
@@ -3859,16 +4261,15 @@ static void addr_error(cmd_addr_T addr_type)
/// @param address_count 1 for first, >1 after comma
///
/// @return MAXLNUM when no Ex address was found.
-static linenr_T get_address(exarg_T *eap, char_u **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, int skip, bool silent,
int to_other_file, int address_count)
FUNC_ATTR_NONNULL_ALL
{
int c;
int i;
- long n;
- char_u *cmd;
+ linenr_T n;
+ char *cmd;
pos_T pos;
- pos_T *fp;
linenr_T lnum;
buf_T *buf;
@@ -3904,7 +4305,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
goto error;
break;
case ADDR_QUICKFIX:
- lnum = qf_get_cur_idx(eap);
+ lnum = (linenr_T)qf_get_cur_idx(eap);
break;
case ADDR_QUICKFIX_VALID:
lnum = qf_get_cur_valid_idx(eap);
@@ -3949,13 +4350,13 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
goto error;
break;
case ADDR_QUICKFIX:
- lnum = qf_get_size(eap);
+ lnum = (linenr_T)qf_get_size(eap);
if (lnum == 0) {
lnum = 1;
}
break;
case ADDR_QUICKFIX_VALID:
- lnum = qf_get_valid_size(eap);
+ lnum = (linenr_T)qf_get_valid_size(eap);
if (lnum == 0) {
lnum = 1;
}
@@ -3978,31 +4379,32 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
} else {
// Only accept a mark in another file when it is
// used by itself: ":'M".
- fp = getmark(*cmd, to_other_file && cmd[1] == NUL);
- ++cmd;
- if (fp == (pos_T *)-1) {
+ MarkGet flag = to_other_file && cmd[1] == NUL ? kMarkAll : kMarkBufLocal;
+ fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd);
+ cmd++;
+ if (fm != NULL && fm->fnum != curbuf->handle) {
// Jumped to another file.
lnum = curwin->w_cursor.lnum;
} else {
- if (check_mark(fp) == FAIL) {
+ if (!mark_check(fm)) {
cmd = NULL;
goto error;
}
- lnum = fp->lnum;
+ lnum = fm->mark.lnum;
}
}
break;
case '/':
case '?': // '/' or '?' - search
- c = *cmd++;
+ c = (char_u)(*cmd++);
if (addr_type != ADDR_LINES) {
addr_error(addr_type);
cmd = NULL;
goto error;
}
if (skip) { // skip "/pat/"
- cmd = skip_regexp(cmd, c, p_magic, NULL);
+ cmd = (char *)skip_regexp((char_u *)cmd, c, p_magic, NULL);
if (*cmd == c) {
++cmd;
}
@@ -4013,8 +4415,9 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
// When '/' or '?' follows another address, start from
// there.
- if (lnum != MAXLNUM) {
- curwin->w_cursor.lnum = lnum;
+ if (lnum > 0 && lnum != MAXLNUM) {
+ curwin->w_cursor.lnum
+ = lnum > curbuf->b_ml.ml_line_count ? curbuf->b_ml.ml_line_count : lnum;
}
// Start a forward search at the end of the line (unless
@@ -4030,7 +4433,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
}
searchcmdlen = 0;
flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
- if (!do_search(NULL, c, c, cmd, 1L, flags, NULL)) {
+ if (!do_search(NULL, c, c, (char_u *)cmd, 1L, flags, NULL)) {
curwin->w_cursor = pos;
cmd = NULL;
goto error;
@@ -4079,7 +4482,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
default:
if (ascii_isdigit(*cmd)) { // absolute line number
- lnum = getdigits_long(&cmd, false, 0);
+ lnum = (linenr_T)getdigits((char_u **)&cmd, false, 0);
}
}
@@ -4113,7 +4516,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
lnum = 1;
break;
case ADDR_QUICKFIX:
- lnum = qf_get_cur_idx(eap);
+ lnum = (linenr_T)qf_get_cur_idx(eap);
break;
case ADDR_QUICKFIX_VALID:
lnum = qf_get_cur_valid_idx(eap);
@@ -4128,12 +4531,16 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
if (ascii_isdigit(*cmd)) {
i = '+'; // "number" is same as "+number"
} else {
- i = *cmd++;
+ i = (char_u)(*cmd++);
}
if (!ascii_isdigit(*cmd)) { // '+' is '+1', but '+0' is not '+1'
n = 1;
} else {
- n = getdigits(&cmd, true, 0);
+ n = getdigits_int32(&cmd, false, MAXLNUM);
+ if (n == MAXLNUM) {
+ emsg(_(e_line_number_out_of_range));
+ goto error;
+ }
}
if (addr_type == ADDR_TABS_RELATIVE) {
@@ -4152,6 +4559,10 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
if (i == '-') {
lnum -= n;
} else {
+ if (n >= INT32_MAX - lnum) {
+ emsg(_(e_line_number_out_of_range));
+ goto error;
+ }
lnum += n;
}
}
@@ -4163,12 +4574,10 @@ error:
return lnum;
}
-/*
- * Get flags from an Ex command argument.
- */
+/// Get flags from an Ex command argument.
static void get_flags(exarg_T *eap)
{
- while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL) {
+ while (vim_strchr("lp#", *eap->arg) != NULL) {
if (*eap->arg == 'l') {
eap->flags |= EXFLAG_LIST;
} else if (*eap->arg == 'p') {
@@ -4200,11 +4609,10 @@ static void ex_script_ni(exarg_T *eap)
}
}
-/*
- * Check range in Ex command for validity.
- * Return NULL when valid, error message when invalid.
- */
-static char *invalid_range(exarg_T *eap)
+/// Check range in Ex command for validity.
+///
+/// @return NULL when valid, error message when invalid.
+char *invalid_range(exarg_T *eap)
{
buf_T *buf;
if (eap->line1 < 0 || eap->line2 < 0 || eap->line1 > eap->line2) {
@@ -4226,8 +4634,9 @@ static char *invalid_range(exarg_T *eap)
}
break;
case ADDR_BUFFERS:
- if (eap->line1 < firstbuf->b_fnum
- || eap->line2 > lastbuf->b_fnum) {
+ // Only a boundary check, not whether the buffers actually
+ // exist.
+ if (eap->line1 < 1 || eap->line2 > get_highest_fnum()) {
return _(e_invrange);
}
break;
@@ -4289,9 +4698,7 @@ static char *invalid_range(exarg_T *eap)
return NULL;
}
-/*
- * Correct the range for zero line number, if required.
- */
+/// Correct the range for zero line number, if required.
static void correct_range(exarg_T *eap)
{
if (!(eap->argt & EX_ZEROR)) { // zero in range not allowed
@@ -4304,14 +4711,11 @@ static void correct_range(exarg_T *eap)
}
}
-
-/*
- * For a ":vimgrep" or ":vimgrepadd" command return a pointer past the
- * pattern. Otherwise return eap->arg.
- */
-static char_u *skip_grep_pat(exarg_T *eap)
+/// For a ":vimgrep" or ":vimgrepadd" command return a pointer past the
+/// pattern. Otherwise return eap->arg.
+static char *skip_grep_pat(exarg_T *eap)
{
- char_u *p = eap->arg;
+ char *p = eap->arg;
if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep
|| eap->cmdidx == CMD_vimgrepadd
@@ -4325,18 +4729,16 @@ static char_u *skip_grep_pat(exarg_T *eap)
return p;
}
-/*
- * For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option
- * in the command line, so that things like % get expanded.
- */
-static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
+/// For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option
+/// in the command line, so that things like % get expanded.
+char *replace_makeprg(exarg_T *eap, char *p, char **cmdlinep)
{
- char_u *new_cmdline;
- char_u *program;
- char_u *pos;
- char_u *ptr;
+ char *new_cmdline;
+ char *program;
+ char *pos;
+ char *ptr;
int len;
- int i;
+ size_t i;
/*
* Don't do it when ":vimgrep" is used for ":grep".
@@ -4349,31 +4751,31 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
|| eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) {
if (*curbuf->b_p_gp == NUL) {
- program = p_gp;
+ program = (char *)p_gp;
} else {
- program = curbuf->b_p_gp;
+ program = (char *)curbuf->b_p_gp;
}
} else {
if (*curbuf->b_p_mp == NUL) {
- program = p_mp;
+ program = (char *)p_mp;
} else {
- program = curbuf->b_p_mp;
+ program = (char *)curbuf->b_p_mp;
}
}
p = skipwhite(p);
- if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) {
+ if ((pos = strstr(program, "$*")) != NULL) {
// replace $* by given arguments
i = 1;
- while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL) {
- ++i;
+ while ((pos = strstr(pos + 2, "$*")) != NULL) {
+ i++;
}
len = (int)STRLEN(p);
- new_cmdline = xmalloc(STRLEN(program) + (size_t)i * (len - 2) + 1);
+ new_cmdline = xmalloc(STRLEN(program) + i * (size_t)(len - 2) + 1);
ptr = new_cmdline;
- while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) {
- i = (int)(pos - program);
+ while ((pos = strstr(program, "$*")) != NULL) {
+ i = (size_t)(pos - program);
memcpy(ptr, program, i);
STRCPY(ptr += i, p);
ptr += len;
@@ -4386,7 +4788,7 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
STRCAT(new_cmdline, " ");
STRCAT(new_cmdline, p);
}
- msg_make(p);
+ msg_make((char_u *)p);
// 'eap->cmd' is not set here, because it is not used at CMD_make
xfree(*cmdlinep);
@@ -4396,15 +4798,16 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
return p;
}
-// Expand file name in Ex command argument.
-// When an error is detected, "errormsgp" is set to a non-NULL pointer.
-// Return FAIL for failure, OK otherwise.
+/// Expand file name in Ex command argument.
+/// When an error is detected, "errormsgp" is set to a non-NULL pointer.
+///
+/// @return FAIL for failure, OK otherwise.
int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
{
int has_wildcards; // need to expand wildcards
- char_u *repl;
+ char *repl;
size_t srclen;
- char_u *p;
+ char *p;
int escaped;
// Skip a regexp pattern for ":vimgrep[add] pat file..."
@@ -4415,7 +4818,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
* the file name contains a wildcard it should not cause expanding.
* (it will be expanded anyway if there is a wildcard before replacing).
*/
- has_wildcards = path_has_wildcard(p);
+ has_wildcards = path_has_wildcard((char_u *)p);
while (*p != NUL) {
// Skip over `=expr`, wildcards in it are not expanded.
if (p[0] == '`' && p[1] == '=') {
@@ -4430,16 +4833,16 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
* Quick check if this cannot be the start of a special string.
* Also removes backslash before '%', '#' and '<'.
*/
- if (vim_strchr((char_u *)"%#<", *p) == NULL) {
- ++p;
+ if (vim_strchr("%#<", *p) == NULL) {
+ p++;
continue;
}
/*
* Try to find a match at this position.
*/
- repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum),
- errormsgp, &escaped);
+ repl = (char *)eval_vars((char_u *)p, (char_u *)eap->arg, &srclen, &(eap->do_ecmd_lnum),
+ errormsgp, &escaped);
if (*errormsgp != NULL) { // error detected
return FAIL;
}
@@ -4451,7 +4854,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
// Wildcards won't be expanded below, the replacement is taken
// literally. But do expand "~/file", "~user/file" and "$HOME/file".
if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL) {
- char_u *l = repl;
+ char *l = repl;
repl = expand_env_save(repl);
xfree(l);
@@ -4473,19 +4876,19 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
&& eap->cmdidx != CMD_make
&& eap->cmdidx != CMD_terminal
&& !(eap->argt & EX_NOSPC)) {
- char_u *l;
+ char *l;
#ifdef BACKSLASH_IN_FILENAME
// Don't escape a backslash here, because rem_backslash() doesn't
// remove it later.
- static char_u *nobslash = (char_u *)" \t\"|";
+ static char *nobslash = " \t\"|";
# define ESCAPE_CHARS nobslash
#else
# define ESCAPE_CHARS escape_chars
#endif
- for (l = repl; *l; ++l) {
- if (vim_strchr(ESCAPE_CHARS, *l) != NULL) {
- l = vim_strsave_escaped(repl, ESCAPE_CHARS);
+ for (l = repl; *l; l++) {
+ if (vim_strchr((char *)ESCAPE_CHARS, *l) != NULL) {
+ l = (char *)vim_strsave_escaped((char_u *)repl, ESCAPE_CHARS);
xfree(repl);
repl = l;
break;
@@ -4497,15 +4900,15 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
if ((eap->usefilter
|| eap->cmdidx == CMD_bang
|| eap->cmdidx == CMD_terminal)
- && vim_strpbrk(repl, (char_u *)"!") != NULL) {
- char_u *l;
+ && strpbrk(repl, "!") != NULL) {
+ char *l;
- l = vim_strsave_escaped(repl, (char_u *)"!");
+ l = (char *)vim_strsave_escaped((char_u *)repl, (char_u *)"!");
xfree(repl);
repl = l;
}
- p = repl_cmdline(eap, p, srclen, repl, cmdlinep);
+ p = repl_cmdline(eap, p, srclen, repl, (char **)cmdlinep);
xfree(repl);
}
@@ -4525,14 +4928,14 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
*/
if (vim_strchr(eap->arg, '$') != NULL
|| vim_strchr(eap->arg, '~') != NULL) {
- expand_env_esc(eap->arg, NameBuff, MAXPATHL, true, true, NULL);
+ expand_env_esc((char_u *)eap->arg, NameBuff, MAXPATHL, true, true, NULL);
has_wildcards = path_has_wildcard(NameBuff);
- p = NameBuff;
+ p = (char *)NameBuff;
} else {
p = NULL;
}
if (p != NULL) {
- (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep);
+ (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, (char **)cmdlinep);
}
}
@@ -4544,7 +4947,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
#ifdef UNIX
if (!has_wildcards)
#endif
- backslash_halve(eap->arg);
+ backslash_halve((char_u *)eap->arg);
if (has_wildcards) {
expand_T xpc;
@@ -4555,26 +4958,24 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp)
if (p_wic) {
options += WILD_ICASE;
}
- p = ExpandOne(&xpc, eap->arg, NULL, options, WILD_EXPAND_FREE);
+ p = (char *)ExpandOne(&xpc, (char_u *)eap->arg, NULL, options, WILD_EXPAND_FREE);
if (p == NULL) {
return FAIL;
}
- (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep);
+ (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, (char **)cmdlinep);
xfree(p);
}
}
return OK;
}
-/*
- * Replace part of the command line, keeping eap->cmd, eap->arg and
- * eap->nextcmd correct.
- * "src" points to the part that is to be replaced, of length "srclen".
- * "repl" is the replacement string.
- * Returns a pointer to the character after the replaced string.
- */
-static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *repl,
- char_u **cmdlinep)
+/// Replace part of the command line, keeping eap->cmd, eap->arg, eap->args and
+/// eap->nextcmd correct.
+/// "src" points to the part that is to be replaced, of length "srclen".
+/// "repl" is the replacement string.
+///
+/// @return a pointer to the character after the replaced string.
+static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, char **cmdlinep)
{
/*
* The new command line is build in new_cmdline[].
@@ -4586,7 +4987,8 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *re
if (eap->nextcmd != NULL) {
i += STRLEN(eap->nextcmd); // add space for next command
}
- char_u *new_cmdline = xmalloc(i);
+ char *new_cmdline = xmalloc(i);
+ size_t offset = (size_t)(src - *cmdlinep);
/*
* Copy the stuff before the expanded part.
@@ -4594,7 +4996,7 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *re
* Copy what came after the expanded part.
* Copy the next commands, if there are any.
*/
- i = (size_t)(src - *cmdlinep); // length of part before match
+ i = offset; // length of part before match
memmove(new_cmdline, *cmdlinep, i);
memmove(new_cmdline + i, repl, len);
@@ -4609,6 +5011,19 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *re
}
eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
eap->arg = new_cmdline + (eap->arg - *cmdlinep);
+
+ for (size_t j = 0; j < eap->argc; j++) {
+ if (offset >= (size_t)(eap->args[j] - *cmdlinep)) {
+ // If replaced text is after or in the same position as the argument,
+ // the argument's position relative to the beginning of the cmdline stays the same.
+ eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep);
+ } else {
+ // Otherwise, argument gets shifted alongside the replaced text.
+ // The amount of the shift is equal to the difference of the old and new string length.
+ eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep) + (len - srclen);
+ }
+ }
+
if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) {
eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep);
}
@@ -4618,14 +5033,10 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *re
return src;
}
-/*
- * Check for '|' to separate commands and '"' to start comments.
- */
+/// Check for '|' to separate commands and '"' to start comments.
void separate_nextcmd(exarg_T *eap)
{
- char_u *p;
-
- p = skip_grep_pat(eap);
+ char *p = skip_grep_pat(eap);
for (; *p; MB_PTR_ADV(p)) {
if (*p == Ctrl_V) {
@@ -4653,9 +5064,7 @@ void separate_nextcmd(exarg_T *eap)
&& !(eap->argt & EX_NOTRLCOM)
&& (eap->cmdidx != CMD_at || p != eap->arg)
&& (eap->cmdidx != CMD_redir
- || p != eap->arg + 1 || p[-1] != '@'))
- || *p == '|'
- || *p == '\n') {
+ || p != eap->arg + 1 || p[-1] != '@')) || *p == '|' || *p == '\n') {
// We remove the '\' before the '|', unless EX_CTRLV is used
// AND 'b' is present in 'cpoptions'.
if ((vim_strchr(p_cpo, CPO_BAR) == NULL
@@ -4663,7 +5072,7 @@ void separate_nextcmd(exarg_T *eap)
STRMOVE(p - 1, p); // remove the '\'
p--;
} else {
- eap->nextcmd = check_nextcmd(p);
+ eap->nextcmd = (char *)check_nextcmd((char_u *)p);
*p = NUL;
break;
}
@@ -4671,22 +5080,20 @@ void separate_nextcmd(exarg_T *eap)
}
if (!(eap->argt & EX_NOTRLCOM)) { // remove trailing spaces
- del_trailing_spaces(eap->arg);
+ del_trailing_spaces((char_u *)eap->arg);
}
}
-/*
- * get + command from ex argument
- */
-static char_u *getargcmd(char_u **argp)
+/// get + command from ex argument
+static char *getargcmd(char **argp)
{
- char_u *arg = *argp;
- char_u *command = NULL;
+ char *arg = *argp;
+ char *command = NULL;
if (*arg == '+') { // +[command]
++arg;
if (ascii_isspace(*arg) || *arg == '\0') {
- command = dollar_command;
+ command = (char *)dollar_command;
} else {
command = arg;
arg = skip_cmd_arg(command, TRUE);
@@ -4704,7 +5111,7 @@ static char_u *getargcmd(char_u **argp)
/// Find end of "+command" argument. Skip over "\ " and "\\".
///
/// @param rembs TRUE to halve the number of backslashes
-static char_u *skip_cmd_arg(char_u *p, int rembs)
+static char *skip_cmd_arg(char *p, int rembs)
{
while (*p && !ascii_isspace(*p)) {
if (*p == '\\' && p[1] != NUL) {
@@ -4734,16 +5141,15 @@ int get_bad_opt(const char_u *p, exarg_T *eap)
return OK;
}
-/*
- * Get "++opt=arg" argument.
- * Return FAIL or OK.
- */
+/// Get "++opt=arg" argument.
+///
+/// @return FAIL or OK.
static int getargopt(exarg_T *eap)
{
- char_u *arg = eap->arg + 2;
+ char *arg = eap->arg + 2;
int *pp = NULL;
int bad_char_idx;
- char_u *p;
+ char *p;
// ":edit ++[no]bin[ary] file"
if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0) {
@@ -4762,7 +5168,7 @@ static int getargopt(exarg_T *eap)
// ":read ++edit file"
if (STRNCMP(arg, "edit", 4) == 0) {
- eap->read_edit = TRUE;
+ eap->read_edit = true;
eap->arg = skipwhite(arg + 4);
return OK;
}
@@ -4789,26 +5195,26 @@ static int getargopt(exarg_T *eap)
return FAIL;
}
- ++arg;
+ arg++;
*pp = (int)(arg - eap->cmd);
- arg = skip_cmd_arg(arg, FALSE);
+ arg = skip_cmd_arg(arg, false);
eap->arg = skipwhite(arg);
*arg = NUL;
if (pp == &eap->force_ff) {
- if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) {
+ if (check_ff_value((char_u *)eap->cmd + eap->force_ff) == FAIL) {
return FAIL;
}
- eap->force_ff = eap->cmd[eap->force_ff];
+ eap->force_ff = (char_u)eap->cmd[eap->force_ff];
} else if (pp == &eap->force_enc) {
// Make 'fileencoding' lower case.
- for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) {
- *p = TOLOWER_ASC(*p);
+ for (p = eap->cmd + eap->force_enc; *p != NUL; p++) {
+ *p = (char)TOLOWER_ASC(*p);
}
} else {
// Check ++bad= argument. Must be a single-byte character, "keep" or
// "drop".
- if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL) {
+ if (get_bad_opt((char_u *)eap->cmd + bad_char_idx, eap) == FAIL) {
return FAIL;
}
}
@@ -4817,16 +5223,17 @@ static int getargopt(exarg_T *eap)
}
/// Handle the argument for a tabpage related ex command.
-/// Returns a tabpage number.
/// When an error is encountered then eap->errmsg is set.
+///
+/// @return a tabpage number.
static int get_tabpage_arg(exarg_T *eap)
{
int tab_number = 0;
int unaccept_arg0 = (eap->cmdidx == CMD_tabmove) ? 0 : 1;
if (eap->arg && *eap->arg != NUL) {
- char_u *p = eap->arg;
- char_u *p_save;
+ char *p = eap->arg;
+ char *p_save;
int relative = 0; // argument +N/-N means: go to N places to the
// right/left relative to the current position.
@@ -4839,13 +5246,19 @@ static int get_tabpage_arg(exarg_T *eap)
}
p_save = p;
- tab_number = getdigits(&p, false, tab_number);
+ tab_number = (int)getdigits((char_u **)&p, false, tab_number);
if (relative == 0) {
if (STRCMP(p, "$") == 0) {
tab_number = LAST_TAB_NR;
} else if (STRCMP(p, "#") == 0) {
- tab_number = tabpage_index(lastused_tabpage);
+ if (valid_tabpage(lastused_tabpage)) {
+ tab_number = tabpage_index(lastused_tabpage);
+ } else {
+ eap->errmsg = ex_errmsg(e_invargval, eap->arg);
+ tab_number = 0;
+ goto theend;
+ }
} else if (p == p_save || *p_save == '-' || *p != NUL
|| tab_number > LAST_TAB_NR) {
// No numbers as argument.
@@ -4873,8 +5286,10 @@ static int get_tabpage_arg(exarg_T *eap)
eap->errmsg = e_invrange;
tab_number = 0;
} else {
- tab_number = eap->line2;
- if (!unaccept_arg0 && *skipwhite(*eap->cmdlinep) == '-') {
+ tab_number = (int)eap->line2;
+ char *cmdp = eap->cmd;
+ while (--cmdp > *eap->cmdlinep && (*cmdp == ' ' || ascii_isdigit(*cmdp))) {}
+ if (!unaccept_arg0 && *cmdp == '-') {
tab_number--;
if (tab_number < unaccept_arg0) {
eap->errmsg = e_invarg;
@@ -4901,55 +5316,6 @@ theend:
return tab_number;
}
-/*
- * ":abbreviate" and friends.
- */
-static void ex_abbreviate(exarg_T *eap)
-{
- do_exmap(eap, TRUE); // almost the same as mapping
-}
-
-/*
- * ":map" and friends.
- */
-static void ex_map(exarg_T *eap)
-{
- /*
- * If we are sourcing .exrc or .vimrc in current directory we
- * print the mappings for security reasons.
- */
- if (secure) {
- secure = 2;
- msg_outtrans(eap->cmd);
- msg_putchar('\n');
- }
- do_exmap(eap, FALSE);
-}
-
-/*
- * ":unmap" and friends.
- */
-static void ex_unmap(exarg_T *eap)
-{
- do_exmap(eap, FALSE);
-}
-
-/*
- * ":mapclear" and friends.
- */
-static void ex_mapclear(exarg_T *eap)
-{
- map_clear_mode(eap->cmd, eap->arg, eap->forceit, false);
-}
-
-/*
- * ":abclear" and friends.
- */
-static void ex_abclear(exarg_T *eap)
-{
- map_clear_mode(eap->cmd, eap->arg, true, true);
-}
-
static void ex_autocmd(exarg_T *eap)
{
// Disallow autocommands from .exrc and .vimrc in current
@@ -4964,12 +5330,10 @@ static void ex_autocmd(exarg_T *eap)
}
}
-/*
- * ":doautocmd": Apply the automatic commands to the current buffer.
- */
+/// ":doautocmd": Apply the automatic commands to the current buffer.
static void ex_doautocmd(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char *arg = eap->arg;
int call_do_modelines = check_nomodeline(&arg);
bool did_aucmd;
@@ -4980,24 +5344,22 @@ static void ex_doautocmd(exarg_T *eap)
}
}
-/*
- * :[N]bunload[!] [N] [bufname] unload buffer
- * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list
- * :[N]bwipeout[!] [N] [bufname] delete buffer really
- */
+/// :[N]bunload[!] [N] [bufname] unload buffer
+/// :[N]bdelete[!] [N] [bufname] delete buffer from buffer list
+/// :[N]bwipeout[!] [N] [bufname] delete buffer really
static void ex_bunload(exarg_T *eap)
{
- eap->errmsg = do_bufdel(eap->cmdidx == CMD_bdelete ? DOBUF_DEL
- : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE
- : DOBUF_UNLOAD,
- eap->arg,
- eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit);
+ eap->errmsg = do_bufdel(eap->cmdidx == CMD_bdelete
+ ? DOBUF_DEL
+ : eap->cmdidx == CMD_bwipeout
+ ? DOBUF_WIPE
+ : DOBUF_UNLOAD,
+ eap->arg, eap->addr_count, (int)eap->line1, (int)eap->line2,
+ eap->forceit);
}
-/*
- * :[N]buffer [N] to buffer N
- * :[N]sbuffer [N] to buffer N
- */
+/// :[N]buffer [N] to buffer N
+/// :[N]sbuffer [N] to buffer N
static void ex_buffer(exarg_T *eap)
{
if (*eap->arg) {
@@ -5009,72 +5371,62 @@ static void ex_buffer(exarg_T *eap)
goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2);
}
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
}
-/*
- * :[N]bmodified [N] to next mod. buffer
- * :[N]sbmodified [N] to next mod. buffer
- */
+/// :[N]bmodified [N] to next mod. buffer
+/// :[N]sbmodified [N] to next mod. buffer
static void ex_bmodified(exarg_T *eap)
{
goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2);
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
-/*
- * :[N]bnext [N] to next buffer
- * :[N]sbnext [N] split and to next buffer
- */
+/// :[N]bnext [N] to next buffer
+/// :[N]sbnext [N] split and to next buffer
static void ex_bnext(exarg_T *eap)
{
goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2);
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
-/*
- * :[N]bNext [N] to previous buffer
- * :[N]bprevious [N] to previous buffer
- * :[N]sbNext [N] split and to previous buffer
- * :[N]sbprevious [N] split and to previous buffer
- */
+/// :[N]bNext [N] to previous buffer
+/// :[N]bprevious [N] to previous buffer
+/// :[N]sbNext [N] split and to previous buffer
+/// :[N]sbprevious [N] split and to previous buffer
static void ex_bprevious(exarg_T *eap)
{
goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2);
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
-/*
- * :brewind to first buffer
- * :bfirst to first buffer
- * :sbrewind split and to first buffer
- * :sbfirst split and to first buffer
- */
+/// :brewind to first buffer
+/// :bfirst to first buffer
+/// :sbrewind split and to first buffer
+/// :sbfirst split and to first buffer
static void ex_brewind(exarg_T *eap)
{
goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
-/*
- * :blast to last buffer
- * :sblast split and to last buffer
- */
+/// :blast to last buffer
+/// :sblast split and to last buffer
static void ex_blast(exarg_T *eap)
{
goto_buffer(eap, DOBUF_LAST, BACKWARD, 0);
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
}
@@ -5083,10 +5435,8 @@ int ends_excmd(int c) FUNC_ATTR_CONST
return c == NUL || c == '|' || c == '"' || c == '\n';
}
-/*
- * Return the next command, after the first '|' or '\n'.
- * Return NULL if not found.
- */
+/// @return the next command, after the first '|' or '\n' or,
+/// NULL if not found.
char_u *find_nextcmd(const char_u *p)
{
while (*p != '|' && *p != '\n') {
@@ -5099,13 +5449,14 @@ char_u *find_nextcmd(const char_u *p)
}
/// Check if *p is a separator between Ex commands, skipping over white space.
-/// Return NULL if it isn't, the following character if it is.
+///
+/// @return NULL if it isn't, the following character if it is.
char_u *check_nextcmd(char_u *p)
{
- char_u *s = skipwhite(p);
+ char *s = skipwhite((char *)p);
if (*s == '|' || *s == '\n') {
- return (s + 1);
+ return (char_u *)(s + 1);
} else {
return NULL;
}
@@ -5115,9 +5466,10 @@ char_u *check_nextcmd(char_u *p)
/// - and this is the last window
/// - and forceit not used
/// - and not repeated twice on a row
-/// @return FAIL and give error message if 'message' TRUE, return OK otherwise
///
/// @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)
{
int n = ARGCOUNT - curwin->w_arg_idx - 1;
@@ -5125,13 +5477,13 @@ static int check_more(int message, bool forceit)
if (!forceit && only_one_window()
&& ARGCOUNT > 1 && !arg_had_last && n > 0 && quitmore == 0) {
if (message) {
- if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL) {
- char_u buff[DIALOG_MSG_SIZE];
+ if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && curbuf->b_fname != NULL) {
+ char buff[DIALOG_MSG_SIZE];
vim_snprintf((char *)buff, DIALOG_MSG_SIZE,
NGETTEXT("%d more file to edit. Quit anyway?",
"%d more files to edit. Quit anyway?", (unsigned long)n), n);
- if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) {
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 1) == VIM_YES) {
return OK;
}
return FAIL;
@@ -5145,33 +5497,53 @@ static int check_more(int message, bool forceit)
return OK;
}
-/*
- * Function given to ExpandGeneric() to obtain the list of command names.
- */
-char_u *get_command_name(expand_T *xp, int idx)
+/// Function given to ExpandGeneric() to obtain the list of command names.
+char *get_command_name(expand_T *xp, int idx)
{
if (idx >= CMD_SIZE) {
- return get_user_command_name(idx);
+ return expand_user_command_name(idx);
}
return cmdnames[idx].cmd_name;
}
-int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def, int flags,
- int compl, char_u *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type,
- LuaRef luaref, bool force)
+/// Check for a valid user command name
+///
+/// If the given {name} is valid, then a pointer to the end of the valid name is returned.
+/// Otherwise, returns NULL.
+char *uc_validate_name(char *name)
+{
+ if (ASCII_ISALPHA(*name)) {
+ while (ASCII_ISALNUM(*name)) {
+ name++;
+ }
+ }
+ if (!ends_excmd(*name) && !ascii_iswhite(*name)) {
+ return NULL;
+ }
+
+ return name;
+}
+
+/// Create a new user command {name}, if one doesn't already exist.
+///
+/// This function takes ownership of compl_arg, compl_luaref, and luaref.
+///
+/// @return OK if the command is created, FAIL otherwise.
+int uc_add_command(char *name, size_t name_len, char *rep, uint32_t argt, long def, int flags,
+ int compl, char *compl_arg, LuaRef compl_luaref, LuaRef preview_luaref,
+ cmd_addr_T addr_type, LuaRef luaref, bool force)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
ucmd_T *cmd = NULL;
int i;
int cmp = 1;
- char_u *rep_buf = NULL;
+ char *rep_buf = NULL;
garray_T *gap;
- replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, true,
- CPO_TO_CPO_FLAGS);
+ replace_termcodes(rep, STRLEN(rep), &rep_buf, 0, NULL, CPO_TO_CPO_FLAGS);
if (rep_buf == NULL) {
// Can't replace termcodes - try using the string as is
- rep_buf = vim_strsave(rep);
+ rep_buf = xstrdup(rep);
}
// get address of growarray: global or in curbuf
@@ -5214,6 +5586,7 @@ int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, lo
XFREE_CLEAR(cmd->uc_compl_arg);
NLUA_CLEAR_REF(cmd->uc_luaref);
NLUA_CLEAR_REF(cmd->uc_compl_luaref);
+ NLUA_CLEAR_REF(cmd->uc_preview_luaref);
break;
}
@@ -5227,24 +5600,26 @@ int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, lo
if (cmp != 0) {
ga_grow(gap, 1);
- char_u *const p = vim_strnsave(name, name_len);
+ char *const p = xstrnsave(name, name_len);
cmd = USER_CMD_GA(gap, i);
- memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T));
+ memmove(cmd + 1, cmd, (size_t)(gap->ga_len - i) * sizeof(ucmd_T));
++gap->ga_len;
- cmd->uc_name = p;
+ cmd->uc_name = (char_u *)p;
}
- cmd->uc_rep = rep_buf;
+ cmd->uc_rep = (char_u *)rep_buf;
cmd->uc_argt = argt;
cmd->uc_def = def;
cmd->uc_compl = compl;
cmd->uc_script_ctx = current_sctx;
cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
- cmd->uc_compl_arg = compl_arg;
+ nlua_set_sctx(&cmd->uc_script_ctx);
+ cmd->uc_compl_arg = (char_u *)compl_arg;
cmd->uc_compl_luaref = compl_luaref;
+ cmd->uc_preview_luaref = preview_luaref;
cmd->uc_addr_type = addr_type;
cmd->uc_luaref = luaref;
@@ -5255,10 +5630,10 @@ fail:
xfree(compl_arg);
NLUA_CLEAR_REF(luaref);
NLUA_CLEAR_REF(compl_luaref);
+ NLUA_CLEAR_REF(preview_luaref);
return FAIL;
}
-
static struct {
cmd_addr_T expand;
char *name;
@@ -5335,7 +5710,7 @@ static char *get_command_complete(int arg)
}
}
-static void uc_list(char_u *name, size_t name_len)
+static void uc_list(char *name, size_t name_len)
{
int i, j;
bool found = false;
@@ -5343,9 +5718,7 @@ static void uc_list(char_u *name, size_t name_len)
uint32_t a;
// In cmdwin, the alternative buffer should be used.
- garray_T *gap = (cmdwin_type != 0 && get_cmdline_type() == NUL)
- ? &prevwin->w_buffer->b_ucmds
- : &curbuf->b_ucmds;
+ const garray_T *gap = &prevwin_curwin()->w_buffer->b_ucmds;
for (;;) {
for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
@@ -5476,7 +5849,7 @@ static void uc_list(char_u *name, size_t name_len)
} while (len < 25 - over);
IObuff[len] = '\0';
- msg_outtrans(IObuff);
+ msg_outtrans((char *)IObuff);
msg_outtrans_special(cmd->uc_rep, false,
name_len == 0 ? Columns - 47 : 0);
@@ -5499,11 +5872,11 @@ static void uc_list(char_u *name, size_t name_len)
}
}
-static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int *flags,
- int *complp, char_u **compl_arg, cmd_addr_T *addr_type_arg)
+static int uc_scan_attr(char *attr, size_t len, uint32_t *argt, long *def, int *flags, int *complp,
+ char_u **compl_arg, cmd_addr_T *addr_type_arg)
FUNC_ATTR_NONNULL_ALL
{
- char_u *p;
+ char *p;
if (len == 0) {
emsg(_("E175: No attribute specified"));
@@ -5517,11 +5890,13 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int
*flags |= UC_BUFFER;
} else if (STRNICMP(attr, "register", len) == 0) {
*argt |= EX_REGSTR;
+ } else if (STRNICMP(attr, "keepscript", len) == 0) {
+ *argt |= EX_KEEPSCRIPT;
} else if (STRNICMP(attr, "bar", len) == 0) {
*argt |= EX_TRLBAR;
} else {
int i;
- char_u *val = NULL;
+ char *val = NULL;
size_t vallen = 0;
size_t attrlen = len;
@@ -5529,8 +5904,8 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int
for (i = 0; i < (int)len; i++) {
if (attr[i] == '=') {
val = &attr[i + 1];
- vallen = len - i - 1;
- attrlen = i;
+ vallen = len - (size_t)i - 1;
+ attrlen = (size_t)i;
break;
}
}
@@ -5567,7 +5942,7 @@ two_count:
return FAIL;
}
- *def = getdigits_long(&p, true, 0);
+ *def = getdigits_long((char_u **)&p, true, 0);
*argt |= EX_ZEROR;
if (p != val + vallen || vallen == 0) {
@@ -5593,7 +5968,7 @@ invalid_count:
goto two_count;
}
- *def = getdigits_long(&p, true, 0);
+ *def = getdigits_long((char_u **)&p, true, 0);
if (p != val + vallen) {
goto invalid_count;
@@ -5609,7 +5984,7 @@ invalid_count:
return FAIL;
}
- if (parse_compl_arg(val, (int)vallen, complp, argt, compl_arg)
+ if (parse_compl_arg(val, (int)vallen, complp, argt, (char **)compl_arg)
== FAIL) {
return FAIL;
}
@@ -5626,7 +6001,7 @@ invalid_count:
*argt |= EX_ZEROR;
}
} else {
- char_u ch = attr[len];
+ char ch = attr[len];
attr[len] = '\0';
semsg(_("E181: Invalid attribute: %s"), attr);
attr[len] = ch;
@@ -5639,30 +6014,28 @@ invalid_count:
static char e_complete_used_without_nargs[] = N_("E1208: -complete used without -nargs");
-/*
- * ":command ..."
- */
+/// ":command ..."
static void ex_command(exarg_T *eap)
{
- char_u *name;
- char_u *end;
- char_u *p;
+ char *name;
+ char *end;
+ char *p;
uint32_t argt = 0;
long def = -1;
int flags = 0;
int compl = EXPAND_NOTHING;
- char_u *compl_arg = NULL;
+ char *compl_arg = NULL;
cmd_addr_T addr_type_arg = ADDR_NONE;
int has_attr = (eap->arg[0] == '-');
- int name_len;
+ size_t name_len;
p = eap->arg;
// Check for attributes
while (*p == '-') {
- ++p;
- end = skiptowhite(p);
- if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, &compl_arg,
+ p++;
+ end = (char *)skiptowhite((char_u *)p);
+ if (uc_scan_attr(p, (size_t)(end - p), &argt, &def, &flags, &compl, (char_u **)&compl_arg,
&addr_type_arg) == FAIL) {
return;
}
@@ -5671,23 +6044,18 @@ static void ex_command(exarg_T *eap)
// Get the name (if any) and skip to the following argument.
name = p;
- if (ASCII_ISALPHA(*p)) {
- while (ASCII_ISALNUM(*p)) {
- p++;
- }
- }
- if (!ends_excmd(*p) && !ascii_iswhite(*p)) {
+ end = uc_validate_name(name);
+ if (!end) {
emsg(_("E182: Invalid command name"));
return;
}
- end = p;
- name_len = (int)(end - name);
+ name_len = (size_t)(end - name);
// If there is nothing after the name, and no attributes were specified,
// we are listing commands
p = skipwhite(end);
if (!has_attr && ends_excmd(*p)) {
- uc_list(name, end - name);
+ uc_list(name, name_len);
} else if (!ASCII_ISUPPER(*name)) {
emsg(_("E183: User defined commands must start with an uppercase letter"));
} else if (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0) {
@@ -5695,15 +6063,13 @@ static void ex_command(exarg_T *eap)
} else if (compl > 0 && (argt & EX_EXTRA) == 0) {
emsg(_(e_complete_used_without_nargs));
} else {
- uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, LUA_NOREF,
+ uc_add_command(name, name_len, p, argt, def, flags, compl, compl_arg, LUA_NOREF, LUA_NOREF,
addr_type_arg, LUA_NOREF, eap->forceit);
}
}
-/*
- * ":comclear"
- * Clear all user commands, global and for current buffer.
- */
+/// ":comclear"
+/// Clear all user commands, global and for current buffer.
void ex_comclear(exarg_T *eap)
{
uc_clear(&ucmds);
@@ -5717,11 +6083,10 @@ void free_ucmd(ucmd_T *cmd)
xfree(cmd->uc_compl_arg);
NLUA_CLEAR_REF(cmd->uc_compl_luaref);
NLUA_CLEAR_REF(cmd->uc_luaref);
+ NLUA_CLEAR_REF(cmd->uc_preview_luaref);
}
-/*
- * Clear all user commands for "gap".
- */
+/// Clear all user commands for "gap".
void uc_clear(garray_T *gap)
{
GA_DEEP_CLEAR(gap, ucmd_T, free_ucmd);
@@ -5731,26 +6096,36 @@ static void ex_delcommand(exarg_T *eap)
{
int i = 0;
ucmd_T *cmd = NULL;
- int cmp = -1;
+ int res = -1;
garray_T *gap;
+ const char *arg = eap->arg;
+ bool buffer_only = false;
+
+ if (STRNCMP(arg, "-buffer", 7) == 0 && ascii_iswhite(arg[7])) {
+ buffer_only = true;
+ arg = skipwhite(arg + 7);
+ }
gap = &curbuf->b_ucmds;
for (;;) {
for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
- cmp = STRCMP(eap->arg, cmd->uc_name);
- if (cmp <= 0) {
+ res = STRCMP(arg, cmd->uc_name);
+ if (res <= 0) {
break;
}
}
- if (gap == &ucmds || cmp == 0) {
+ if (gap == &ucmds || res == 0 || buffer_only) {
break;
}
gap = &ucmds;
}
- if (cmp != 0) {
- semsg(_("E184: No such user-defined command: %s"), eap->arg);
+ if (res != 0) {
+ semsg(_(buffer_only
+ ? e_no_such_user_defined_command_in_current_buffer_str
+ : e_no_such_user_defined_command_str),
+ arg);
return;
}
@@ -5759,80 +6134,167 @@ static void ex_delcommand(exarg_T *eap)
--gap->ga_len;
if (i < gap->ga_len) {
- memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T));
+ memmove(cmd, cmd + 1, (size_t)(gap->ga_len - i) * sizeof(ucmd_T));
}
}
-/*
- * split and quote args for <f-args>
- */
-static char_u *uc_split_args(char_u *arg, size_t *lenp)
+/// Split a string by unescaped whitespace (space & tab), used for f-args on Lua commands callback.
+/// Similar to uc_split_args(), but does not allocate, add quotes, add commas and is an iterator.
+///
+/// @param[in] arg String to split
+/// @param[in] arglen Length of {arg}
+/// @param[inout] end Index of last character of previous iteration
+/// @param[out] buf Buffer to copy string into
+/// @param[out] len Length of string in {buf}
+///
+/// @return true if iteration is complete, else false
+bool uc_split_args_iter(const char *arg, size_t arglen, size_t *end, char *buf, size_t *len)
+{
+ if (!arglen) {
+ return true;
+ }
+
+ size_t pos = *end;
+ while (pos < arglen && ascii_iswhite(arg[pos])) {
+ pos++;
+ }
+
+ size_t l = 0;
+ for (; pos < arglen - 1; pos++) {
+ if (arg[pos] == '\\' && (arg[pos + 1] == '\\' || ascii_iswhite(arg[pos + 1]))) {
+ buf[l++] = arg[++pos];
+ } else {
+ buf[l++] = arg[pos];
+ if (ascii_iswhite(arg[pos + 1])) {
+ *end = pos + 1;
+ *len = l;
+ return false;
+ }
+ }
+ }
+
+ if (pos < arglen && !ascii_iswhite(arg[pos])) {
+ buf[l++] = arg[pos];
+ }
+
+ *len = l;
+ return true;
+}
+
+/// split and quote args for <f-args>
+static char *uc_split_args(char *arg, char **args, size_t *arglens, size_t argc, size_t *lenp)
{
- char_u *buf;
- char_u *p;
- char_u *q;
+ char *buf;
+ char *p;
+ char *q;
int len;
// Precalculate length
- p = arg;
len = 2; // Initial and final quotes
+ if (args == NULL) {
+ p = arg;
- while (*p) {
- if (p[0] == '\\' && p[1] == '\\') {
- len += 2;
- p += 2;
- } else if (p[0] == '\\' && ascii_iswhite(p[1])) {
- len += 1;
- p += 2;
- } else if (*p == '\\' || *p == '"') {
- len += 2;
- p += 1;
- } else if (ascii_iswhite(*p)) {
- p = skipwhite(p);
- if (*p == NUL) {
- break;
+ while (*p) {
+ if (p[0] == '\\' && p[1] == '\\') {
+ len += 2;
+ p += 2;
+ } else if (p[0] == '\\' && ascii_iswhite(p[1])) {
+ len += 1;
+ p += 2;
+ } else if (*p == '\\' || *p == '"') {
+ len += 2;
+ p += 1;
+ } else if (ascii_iswhite(*p)) {
+ p = skipwhite(p);
+ if (*p == NUL) {
+ break;
+ }
+ len += 3; // ","
+ } else {
+ const int charlen = utfc_ptr2len(p);
+
+ len += charlen;
+ p += charlen;
}
- len += 3; // ","
- } else {
- const int charlen = utfc_ptr2len(p);
+ }
+ } else {
+ for (size_t i = 0; i < argc; i++) {
+ p = args[i];
+ const char *arg_end = args[i] + arglens[i];
+
+ while (p < arg_end) {
+ if (*p == '\\' || *p == '"') {
+ len += 2;
+ p += 1;
+ } else {
+ const int charlen = utfc_ptr2len(p);
- len += charlen;
- p += charlen;
+ len += charlen;
+ p += charlen;
+ }
+ }
+
+ if (i != argc - 1) {
+ len += 3; // ","
+ }
}
}
- buf = xmalloc(len + 1);
+ buf = xmalloc((size_t)len + 1);
- p = arg;
q = buf;
*q++ = '"';
- while (*p) {
- if (p[0] == '\\' && p[1] == '\\') {
- *q++ = '\\';
- *q++ = '\\';
- p += 2;
- } else if (p[0] == '\\' && ascii_iswhite(p[1])) {
- *q++ = p[1];
- p += 2;
- } else if (*p == '\\' || *p == '"') {
- *q++ = '\\';
- *q++ = *p++;
- } else if (ascii_iswhite(*p)) {
- p = skipwhite(p);
- if (*p == NUL) {
- break;
+
+ if (args == NULL) {
+ p = arg;
+ while (*p) {
+ if (p[0] == '\\' && p[1] == '\\') {
+ *q++ = '\\';
+ *q++ = '\\';
+ p += 2;
+ } else if (p[0] == '\\' && ascii_iswhite(p[1])) {
+ *q++ = p[1];
+ p += 2;
+ } else if (*p == '\\' || *p == '"') {
+ *q++ = '\\';
+ *q++ = *p++;
+ } else if (ascii_iswhite(*p)) {
+ p = skipwhite(p);
+ if (*p == NUL) {
+ break;
+ }
+ *q++ = '"';
+ *q++ = ',';
+ *q++ = '"';
+ } else {
+ mb_copy_char((const char_u **)&p, (char_u **)&q);
+ }
+ }
+ } else {
+ for (size_t i = 0; i < argc; i++) {
+ p = args[i];
+ const char *arg_end = args[i] + arglens[i];
+
+ while (p < arg_end) {
+ if (*p == '\\' || *p == '"') {
+ *q++ = '\\';
+ *q++ = *p++;
+ } else {
+ mb_copy_char((const char_u **)&p, (char_u **)&q);
+ }
+ }
+ if (i != argc - 1) {
+ *q++ = '"';
+ *q++ = ',';
+ *q++ = '"';
}
- *q++ = '"';
- *q++ = ',';
- *q++ = '"';
- } else {
- mb_copy_char((const char_u **)&p, &q);
}
}
+
*q++ = '"';
*q = 0;
- *lenp = len;
+ *lenp = (size_t)len;
return buf;
}
@@ -5865,11 +6327,11 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods)
///
/// @return the length of the replacement, which has been added to "buf".
/// Return -1 if there was no match, and only the "<" has been copied.
-static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap,
- char_u **split_buf, size_t *split_len)
+static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exarg_T *eap,
+ char **split_buf, size_t *split_len)
{
size_t result = 0;
- char_u *p = code + 1;
+ char *p = code + 1;
size_t l = len - 2;
int quote = 0;
enum {
@@ -5885,7 +6347,7 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
ct_NONE,
} type = ct_NONE;
- if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-') {
+ if ((vim_strchr("qQfF", *p) != NULL) && p[1] == '-') {
quote = (*p == 'q' || *p == 'Q') ? 1 : 2;
p += 2;
l -= 2;
@@ -5965,7 +6427,7 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
case 2: // Quote and split (<f-args>)
// This is hard, so only do it once, and cache the result
if (*split_buf == NULL) {
- *split_buf = uc_split_args(eap->arg, split_len);
+ *split_buf = uc_split_args(eap->arg, eap->args, eap->arglens, eap->argc, split_len);
}
result = *split_len;
@@ -6029,20 +6491,7 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
}
case ct_MODS:
- result = quote ? 2 : 0;
- if (buf != NULL) {
- if (quote) {
- *buf++ = '"';
- }
- *buf = '\0';
- }
-
- result += uc_mods((char *)buf);
-
- if (quote && buf != NULL) {
- buf += result - 2;
- *buf = '"';
- }
+ result = uc_mods(buf, &cmdmod, quote);
break;
case ct_REGISTER:
@@ -6055,7 +6504,7 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
*buf++ = '\'';
}
if (eap->regname) {
- *buf++ = eap->regname;
+ *buf++ = (char)eap->regname;
}
if (quote) {
*buf = '\'';
@@ -6082,91 +6531,124 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
return result;
}
-size_t uc_mods(char *buf)
+/// Add modifiers from "cmod->cmod_split" to "buf". Set "multi_mods" when one
+/// was added.
+///
+/// @return the number of bytes added
+size_t add_win_cmd_modifers(char *buf, const cmdmod_T *cmod, bool *multi_mods)
{
size_t result = 0;
- bool multi_mods = false;
// :aboveleft and :leftabove
- if (cmdmod.split & WSP_ABOVE) {
- result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
+ if (cmod->cmod_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);
+ if (cmod->cmod_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);
+ if (cmod->cmod_split & WSP_BOT) {
+ result += add_cmd_modifier(buf, "botright", multi_mods);
+ }
+
+ // :tab
+ if (cmod->cmod_tab > 0) {
+ result += add_cmd_modifier(buf, "tab", multi_mods);
}
+ // :topleft
+ if (cmod->cmod_split & WSP_TOP) {
+ result += add_cmd_modifier(buf, "topleft", multi_mods);
+ }
+ // :vertical
+ if (cmod->cmod_split & WSP_VERT) {
+ result += add_cmd_modifier(buf, "vertical", multi_mods);
+ }
+ return result;
+}
+
+/// Generate text for the "cmod" command modifiers.
+/// If "buf" is NULL just return the length.
+size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote)
+{
+ size_t result = 0;
+ bool multi_mods = false;
typedef struct {
- bool *set;
+ int flag;
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" }
+ { CMOD_BROWSE, "browse" },
+ { CMOD_CONFIRM, "confirm" },
+ { CMOD_HIDE, "hide" },
+ { CMOD_KEEPALT, "keepalt" },
+ { CMOD_KEEPJUMPS, "keepjumps" },
+ { CMOD_KEEPMARKS, "keepmarks" },
+ { CMOD_KEEPPATTERNS, "keeppatterns" },
+ { CMOD_LOCKMARKS, "lockmarks" },
+ { CMOD_NOSWAPFILE, "noswapfile" },
+ { CMOD_UNSILENT, "unsilent" },
+ { CMOD_NOAUTOCMD, "noautocmd" },
+ { CMOD_SANDBOX, "sandbox" },
};
+
+ result = quote ? 2 : 0;
+ if (buf != NULL) {
+ if (quote) {
+ *buf++ = '"';
+ }
+ *buf = '\0';
+ }
+
// the modifiers that are simple flags
for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) {
- if (*mod_entries[i].set) {
+ if (cmod->cmod_flags & mod_entries[i].flag) {
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);
+ if (cmod->cmod_flags & CMOD_SILENT) {
+ result += add_cmd_modifier(buf,
+ (cmod->cmod_flags & CMOD_ERRSILENT) ? "silent!" : "silent",
+ &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 (cmod->cmod_verbose > 0) {
+ int verbose_value = cmod->cmod_verbose - 1;
+ if (verbose_value == 1) {
+ result += add_cmd_modifier(buf, "verbose", &multi_mods);
+ } else {
+ char verbose_buf[NUMBUFLEN];
+ snprintf(verbose_buf, NUMBUFLEN, "%dverbose", verbose_value);
+ result += add_cmd_modifier(buf, verbose_buf, &multi_mods);
+ }
}
+ // flags from cmod->cmod_split
+ result += add_win_cmd_modifers(buf, cmod, &multi_mods);
+ if (quote && buf != NULL) {
+ buf += result - 2;
+ *buf = '"';
+ }
return result;
}
-static void do_ucmd(exarg_T *eap)
+static int do_ucmd(exarg_T *eap, bool preview)
{
- char_u *buf;
- char_u *p;
- char_u *q;
+ char *buf;
+ char *p;
+ char *q;
- char_u *start;
- char_u *end = NULL;
- char_u *ksp;
+ char *start;
+ char *end = NULL;
+ char *ksp;
size_t len, totlen;
size_t split_len = 0;
- char_u *split_buf = NULL;
+ char *split_buf = NULL;
ucmd_T *cmd;
- const sctx_T save_current_sctx = current_sctx;
if (eap->cmdidx == CMD_USER) {
cmd = USER_CMD(eap->useridx);
@@ -6174,9 +6656,14 @@ static void do_ucmd(exarg_T *eap)
cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx);
}
+ if (preview) {
+ assert(cmd->uc_preview_luaref > 0);
+ return nlua_do_ucmd(cmd, eap, true);
+ }
+
if (cmd->uc_luaref > 0) {
- nlua_do_ucmd(cmd, eap);
- return;
+ nlua_do_ucmd(cmd, eap, false);
+ return 0;
}
/*
@@ -6186,7 +6673,7 @@ static void do_ucmd(exarg_T *eap)
*/
buf = NULL;
for (;;) {
- p = cmd->uc_rep; // source
+ p = (char *)cmd->uc_rep; // source
q = buf; // destination
totlen = 0;
@@ -6196,21 +6683,19 @@ static void do_ucmd(exarg_T *eap)
end = vim_strchr(start + 1, '>');
}
if (buf != NULL) {
- for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ksp++) {
- }
- if (*ksp == K_SPECIAL
+ for (ksp = p; *ksp != NUL && (char_u)(*ksp) != K_SPECIAL; ksp++) {}
+ if ((char_u)(*ksp) == K_SPECIAL
&& (start == NULL || ksp < start || end == NULL)
- && (ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)) {
+ && ((char_u)ksp[1] == KS_SPECIAL && ksp[2] == KE_FILLER)) {
// K_SPECIAL has been put in the buffer as K_SPECIAL
// KS_SPECIAL KE_FILLER, like for mappings, but
// do_cmdline() doesn't handle that, so convert it back.
- // Also change K_SPECIAL KS_EXTRA KE_CSI into CSI.
- len = ksp - p;
+ len = (size_t)(ksp - p);
if (len > 0) {
memmove(q, p, len);
q += len;
}
- *q++ = K_SPECIAL;
+ *q++ = (char)K_SPECIAL;
p = ksp + 3;
continue;
}
@@ -6225,7 +6710,7 @@ static void do_ucmd(exarg_T *eap)
++end;
// Take everything up to the '<'
- len = start - p;
+ len = (size_t)(start - p);
if (buf == NULL) {
totlen += len;
} else {
@@ -6233,8 +6718,7 @@ static void do_ucmd(exarg_T *eap)
q += len;
}
- len = uc_check_code(start, end - start, q, cmd, eap,
- &split_buf, &split_len);
+ len = uc_check_code(start, (size_t)(end - start), q, cmd, eap, &split_buf, &split_len);
if (len == (size_t)-1) {
// no match, continue after '<'
p = start + 1;
@@ -6257,96 +6741,117 @@ static void do_ucmd(exarg_T *eap)
buf = xmalloc(totlen + 1);
}
- current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
+ sctx_T save_current_sctx;
+ bool restore_current_sctx = false;
+ if ((cmd->uc_argt & EX_KEEPSCRIPT) == 0) {
+ restore_current_sctx = true;
+ save_current_sctx = current_sctx;
+ current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
+ }
(void)do_cmdline(buf, eap->getline, eap->cookie,
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
- current_sctx = save_current_sctx;
+
+ // Careful: Do not use "cmd" here, it may have become invalid if a user
+ // command was added.
+ if (restore_current_sctx) {
+ current_sctx = save_current_sctx;
+ }
xfree(buf);
xfree(split_buf);
+
+ return 0;
}
-static char_u *get_user_command_name(int idx)
+static char *expand_user_command_name(int idx)
{
return get_user_commands(NULL, idx - CMD_SIZE);
}
-/*
- * Function given to ExpandGeneric() to obtain the list of user address type names.
- */
-char_u *get_user_cmd_addr_type(expand_T *xp, int idx)
+
+/// Function given to ExpandGeneric() to obtain the list of user address type names.
+char *get_user_cmd_addr_type(expand_T *xp, int idx)
{
- return (char_u *)addr_type_complete[idx].name;
+ return addr_type_complete[idx].name;
}
-/*
- * Function given to ExpandGeneric() to obtain the list of user command names.
- */
-char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx)
+/// Function given to ExpandGeneric() to obtain the list of user command names.
+char *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// In cmdwin, the alternative buffer should be used.
- const buf_T *const buf = (cmdwin_type != 0 && get_cmdline_type() == NUL)
- ? prevwin->w_buffer
- : curbuf;
+ const buf_T *const buf = prevwin_curwin()->w_buffer;
if (idx < buf->b_ucmds.ga_len) {
- return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
+ return (char *)USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
}
idx -= buf->b_ucmds.ga_len;
if (idx < ucmds.ga_len) {
- return USER_CMD(idx)->uc_name;
+ return (char *)USER_CMD(idx)->uc_name;
}
return NULL;
}
-/*
- * Function given to ExpandGeneric() to obtain the list of user command
- * attributes.
- */
-char_u *get_user_cmd_flags(expand_T *xp, int idx)
+/// Get the name of user command "idx". "cmdidx" can be CMD_USER or
+/// CMD_USER_BUF.
+///
+/// @return NULL if the command is not found.
+static char *get_user_command_name(int idx, int cmdidx)
+{
+ if (cmdidx == CMD_USER && idx < ucmds.ga_len) {
+ return (char *)USER_CMD(idx)->uc_name;
+ }
+ if (cmdidx == CMD_USER_BUF) {
+ // In cmdwin, the alternative buffer should be used.
+ const buf_T *const buf = prevwin_curwin()->w_buffer;
+
+ if (idx < buf->b_ucmds.ga_len) {
+ return (char *)USER_CMD_GA(&buf->b_ucmds, idx)->uc_name;
+ }
+ }
+ return NULL;
+}
+
+/// Function given to ExpandGeneric() to obtain the list of user command
+/// attributes.
+char *get_user_cmd_flags(expand_T *xp, int idx)
{
static char *user_cmd_flags[] = { "addr", "bang", "bar",
"buffer", "complete", "count",
- "nargs", "range", "register" };
+ "nargs", "range", "register",
+ "keepscript" };
if (idx >= (int)ARRAY_SIZE(user_cmd_flags)) {
return NULL;
}
- return (char_u *)user_cmd_flags[idx];
+ return user_cmd_flags[idx];
}
-/*
- * Function given to ExpandGeneric() to obtain the list of values for -nargs.
- */
-char_u *get_user_cmd_nargs(expand_T *xp, int idx)
+/// Function given to ExpandGeneric() to obtain the list of values for -nargs.
+char *get_user_cmd_nargs(expand_T *xp, int idx)
{
static char *user_cmd_nargs[] = { "0", "1", "*", "?", "+" };
if (idx >= (int)ARRAY_SIZE(user_cmd_nargs)) {
return NULL;
}
- return (char_u *)user_cmd_nargs[idx];
+ return user_cmd_nargs[idx];
}
-/*
- * Function given to ExpandGeneric() to obtain the list of values for -complete.
- */
-char_u *get_user_cmd_complete(expand_T *xp, int idx)
+/// Function given to ExpandGeneric() to obtain the list of values for -complete.
+char *get_user_cmd_complete(expand_T *xp, int idx)
{
if (idx >= (int)ARRAY_SIZE(command_complete)) {
return NULL;
}
char *cmd_compl = get_command_complete(idx);
if (cmd_compl == NULL) {
- return (char_u *)"";
+ return "";
} else {
- return (char_u *)cmd_compl;
+ return cmd_compl;
}
}
-/*
- * Parse address type argument
- */
-int parse_addr_type_arg(char_u *value, int vallen, cmd_addr_T *addr_type_arg)
+/// Parse address type argument
+int parse_addr_type_arg(char *value, int vallen, cmd_addr_T *addr_type_arg)
FUNC_ATTR_NONNULL_ALL
{
int i, a, b;
@@ -6361,7 +6866,7 @@ int parse_addr_type_arg(char_u *value, int vallen, cmd_addr_T *addr_type_arg)
}
if (addr_type_complete[i].expand == ADDR_NONE) {
- char_u *err = value;
+ char *err = value;
for (i = 0; err[i] != NUL && !ascii_iswhite(err[i]); i++) {}
err[i] = NUL;
@@ -6372,18 +6877,16 @@ int parse_addr_type_arg(char_u *value, int vallen, cmd_addr_T *addr_type_arg)
return OK;
}
-/*
- * Parse a completion argument "value[vallen]".
- * The detected completion goes in "*complp", argument type in "*argt".
- * When there is an argument, for function and user defined completion, it's
- * copied to allocated memory and stored in "*compl_arg".
- * Returns FAIL if something is wrong.
- */
-int parse_compl_arg(const char_u *value, int vallen, int *complp, uint32_t *argt,
- char_u **compl_arg)
+/// Parse a completion argument "value[vallen]".
+/// The detected completion goes in "*complp", argument type in "*argt".
+/// When there is an argument, for function and user defined completion, it's
+/// copied to allocated memory and stored in "*compl_arg".
+///
+/// @return FAIL if something is wrong.
+int parse_compl_arg(const char *value, int vallen, int *complp, uint32_t *argt, char **compl_arg)
FUNC_ATTR_NONNULL_ALL
{
- const char_u *arg = NULL;
+ const char *arg = NULL;
size_t arglen = 0;
int i;
int valend = vallen;
@@ -6391,8 +6894,8 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp, uint32_t *argt
// Look for any argument part - which is the part after any ','
for (i = 0; i < vallen; ++i) {
if (value[i] == ',') {
- arg = &value[i + 1];
- arglen = vallen - i - 1;
+ arg = (char *)&value[i + 1];
+ arglen = (size_t)(vallen - i - 1);
valend = i;
break;
}
@@ -6432,7 +6935,7 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp, uint32_t *argt
}
if (arg != NULL) {
- *compl_arg = vim_strnsave(arg, arglen);
+ *compl_arg = xstrnsave(arg, arglen);
}
return OK;
}
@@ -6455,8 +6958,8 @@ int cmdcomplete_str_to_type(const char *complete_str)
static void ex_colorscheme(exarg_T *eap)
{
if (*eap->arg == NUL) {
- char_u *expr = vim_strsave((char_u *)"g:colors_name");
- char_u *p = NULL;
+ char *expr = xstrdup("g:colors_name");
+ char *p = NULL;
emsg_off++;
p = eval_to_string(expr, NULL, false);
@@ -6464,12 +6967,12 @@ static void ex_colorscheme(exarg_T *eap)
xfree(expr);
if (p != NULL) {
- msg((char *)p);
+ msg(p);
xfree(p);
} else {
msg("default");
}
- } else if (load_colors(eap->arg) == FAIL) {
+ } else if (load_colors((char_u *)eap->arg) == FAIL) {
semsg(_("E185: Cannot find color scheme '%s'"), eap->arg);
}
}
@@ -6482,11 +6985,8 @@ static void ex_highlight(exarg_T *eap)
do_highlight((const char *)eap->arg, eap->forceit, false);
}
-
-/*
- * Call this function if we thought we were going to exit, but we won't
- * (because of an error). May need to restore the terminal mode.
- */
+/// Call this function if we thought we were going to exit, but we won't
+/// (because of an error). May need to restore the terminal mode.
void not_exiting(void)
{
exiting = false;
@@ -6521,8 +7021,8 @@ bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit)
return false;
}
-// ":quit": quit current window, quit Vim if the last window is closed.
-// ":{nr}quit": quit window {nr}
+/// ":quit": quit current window, quit Vim if the last window is closed.
+/// ":{nr}quit": quit window {nr}
static void ex_quit(exarg_T *eap)
{
if (cmdwin_type != 0) {
@@ -6538,7 +7038,7 @@ static void ex_quit(exarg_T *eap)
win_T *wp;
if (eap->addr_count > 0) {
- int wnr = eap->line2;
+ linenr_T wnr = eap->line2;
for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next) {
if (--wnr <= 0) {
@@ -6582,12 +7082,13 @@ static void ex_quit(exarg_T *eap)
}
not_exiting();
// close window; may free buffer
- win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit);
+ win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit, eap->forceit);
}
}
/// ":cquit".
static void ex_cquit(exarg_T *eap)
+ FUNC_ATTR_NORETURN
{
// this does not always pass on the exit code to the Manx compiler. why?
getout(eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE);
@@ -6622,9 +7123,7 @@ static void ex_quit_all(exarg_T *eap)
not_exiting();
}
-/*
- * ":close": close current window, unless it is the last one
- */
+/// ":close": close current window, unless it is the last one
static void ex_close(exarg_T *eap)
{
win_T *win = NULL;
@@ -6650,9 +7149,7 @@ static void ex_close(exarg_T *eap)
}
}
-/*
- * ":pclose": Close any preview window.
- */
+/// ":pclose": Close any preview window.
static void ex_pclose(exarg_T *eap)
{
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
@@ -6680,7 +7177,7 @@ void ex_win_close(int forceit, win_T *win, tabpage_T *tp)
need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
if (need_hide && !buf_hide(buf) && !forceit) {
- if ((p_confirm || cmdmod.confirm) && p_write) {
+ if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) {
bufref_T bufref;
set_bufref(&bufref, buf);
dialog_changed(buf, false);
@@ -6694,19 +7191,16 @@ void ex_win_close(int forceit, win_T *win, tabpage_T *tp)
}
}
-
// free buffer when not hiding it or when it's a scratch buffer
if (tp == NULL) {
- win_close(win, !need_hide && !buf_hide(buf));
+ win_close(win, !need_hide && !buf_hide(buf), forceit);
} else {
win_close_othertab(win, !need_hide && !buf_hide(buf), tp);
}
}
-/*
- * ":tabclose": close current tab page, unless it is the last one.
- * ":tabclose N": close tab page N.
- */
+/// ":tabclose": close current tab page, unless it is the last one.
+/// ":tabclose N": close tab page N.
static void ex_tabclose(exarg_T *eap)
{
tabpage_T *tp;
@@ -6767,9 +7261,7 @@ static void ex_tabonly(exarg_T *eap)
}
}
-/*
- * Close the current tab page.
- */
+/// Close the current tab page.
void tabpage_close(int forceit)
{
// First close all the windows but the current one. If that worked then
@@ -6785,18 +7277,16 @@ void tabpage_close(int forceit)
}
}
-/*
- * Close tab page "tp", which is not the current tab page.
- * Note that autocommands may make "tp" invalid.
- * Also takes care of the tab pages line disappearing when closing the
- * last-but-one tab page.
- */
+/// Close tab page "tp", which is not the current tab page.
+/// Note that autocommands may make "tp" invalid.
+/// Also takes care of the tab pages line disappearing when closing the
+/// last-but-one tab page.
void tabpage_close_other(tabpage_T *tp, int forceit)
{
int done = 0;
win_T *wp;
int h = tabline_height();
- char_u prev_idx[NUMBUFLEN];
+ char prev_idx[NUMBUFLEN];
// Limit to 1000 windows, autocommands may add a window while we close
// one. OK, so I'm paranoid...
@@ -6807,24 +7297,22 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
// Autocommands may delete the tab page under our fingers and we may
// fail to close a window with a modified buffer.
- if (!valid_tabpage(tp) || tp->tp_firstwin == wp) {
+ if (!valid_tabpage(tp) || tp->tp_lastwin == wp) {
break;
}
}
redraw_tabline = true;
if (h != tabline_height()) {
- shell_new_rows();
+ win_new_screen_rows();
}
}
-/*
- * ":only".
- */
+/// ":only".
static void ex_only(exarg_T *eap)
{
win_T *wp;
- int wnr;
+ linenr_T wnr;
if (eap->addr_count > 0) {
wnr = eap->line2;
@@ -6844,10 +7332,8 @@ static void ex_only(exarg_T *eap)
close_others(TRUE, eap->forceit);
}
-/*
- * ":all" and ":sall".
- * Also used for ":tab drop file ..." after setting the argument list.
- */
+/// ":all" and ":sall".
+/// Also used for ":tab drop file ..." after setting the argument list.
void ex_all(exarg_T *eap)
{
if (eap->addr_count == 0) {
@@ -6861,7 +7347,7 @@ static void ex_hide(exarg_T *eap)
// ":hide" or ":hide | cmd": hide current window
if (!eap->skip) {
if (eap->addr_count == 0) {
- win_close(curwin, false); // don't free buffer
+ win_close(curwin, false, eap->forceit); // don't free buffer
} else {
int winnr = 0;
win_T *win = NULL;
@@ -6876,7 +7362,7 @@ static void ex_hide(exarg_T *eap)
if (win == NULL) {
win = lastwin;
}
- win_close(win, false);
+ win_close(win, false, eap->forceit);
}
}
}
@@ -6902,7 +7388,7 @@ static void ex_stop(exarg_T *eap)
apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL);
}
-// ":exit", ":xit" and ":wq": Write file and quit the current window.
+/// ":exit", ":xit" and ":wq": Write file and quit the current window.
static void ex_exit(exarg_T *eap)
{
if (cmdwin_type != 0) {
@@ -6934,13 +7420,11 @@ static void ex_exit(exarg_T *eap)
}
not_exiting();
// Quit current window, may free the buffer.
- win_close(curwin, !buf_hide(curwin->w_buffer));
+ win_close(curwin, !buf_hide(curwin->w_buffer), eap->forceit);
}
}
-/*
- * ":print", ":list", ":number".
- */
+/// ":print", ":list", ":number".
static void ex_print(exarg_T *eap)
{
if (curbuf->b_ml.ml_flags & ML_EMPTY) {
@@ -6970,29 +7454,22 @@ static void ex_goto(exarg_T *eap)
goto_byte(eap->line2);
}
-/*
- * Clear an argument list: free all file names and reset it to zero entries.
- */
+/// Clear an argument list: free all file names and reset it to zero entries.
void alist_clear(alist_T *al)
{
-#define FREE_AENTRY_FNAME(arg) xfree(arg->ae_fname)
+#define FREE_AENTRY_FNAME(arg) xfree((arg)->ae_fname)
GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME);
}
-/*
- * Init an argument list.
- */
+/// Init an argument list.
void alist_init(alist_T *al)
{
ga_init(&al->al_ga, (int)sizeof(aentry_T), 5);
}
-
-/*
- * Remove a reference from an argument list.
- * Ignored when the argument list is the global one.
- * If the argument list is no longer used by any window, free it.
- */
+/// Remove a reference from an argument list.
+/// Ignored when the argument list is the global one.
+/// If the argument list is no longer used by any window, free it.
void alist_unlink(alist_T *al)
{
if (al != &global_alist && --al->al_refcount <= 0) {
@@ -7001,9 +7478,7 @@ void alist_unlink(alist_T *al)
}
}
-/*
- * Create a new argument list and use it for the current window.
- */
+/// Create a new argument list and use it for the current window.
void alist_new(void)
{
curwin->w_alist = xmalloc(sizeof(*curwin->w_alist));
@@ -7013,18 +7488,17 @@ void alist_new(void)
}
#if !defined(UNIX)
-/*
- * Expand the file names in the global argument list.
- * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer
- * numbers to be re-used.
- */
+
+/// Expand the file names in the global argument list.
+/// If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer
+/// numbers to be re-used.
void alist_expand(int *fnum_list, int fnum_len)
{
- char_u **old_arg_files;
+ char **old_arg_files;
int old_arg_count;
- char_u **new_arg_files;
+ char **new_arg_files;
int new_arg_file_count;
- char_u *save_p_su = p_su;
+ char *save_p_su = p_su;
int i;
/* Don't use 'suffixes' here. This should work like the shell did the
@@ -7048,11 +7522,9 @@ void alist_expand(int *fnum_list, int fnum_len)
}
#endif
-/*
- * Set the argument list for the current window.
- * Takes over the allocated files[] and the allocated fnames in it.
- */
-void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum_list, int fnum_len)
+/// Set the argument list for the current window.
+/// Takes over the allocated files[] and the allocated fnames in it.
+void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_list, int fnum_len)
{
int i;
static int recursive = 0;
@@ -7098,7 +7570,7 @@ void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum
/// "fname" must have been allocated and "al" must have been checked for room.
///
/// @param set_fnum 1: set buffer number; 2: re-use curbuf
-void alist_add(alist_T *al, char_u *fname, int set_fnum)
+void alist_add(alist_T *al, char *fname, int set_fnum)
{
if (fname == NULL) { // don't add NULL file names
return;
@@ -7106,7 +7578,7 @@ void alist_add(alist_T *al, char_u *fname, int set_fnum)
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(fname);
#endif
- AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname;
+ AARGLIST(al)[al->al_ga.ga_len].ae_fname = (char_u *)fname;
if (set_fnum > 0) {
AARGLIST(al)[al->al_ga.ga_len].ae_fnum =
buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
@@ -7115,9 +7587,8 @@ void alist_add(alist_T *al, char_u *fname, int set_fnum)
}
#if defined(BACKSLASH_IN_FILENAME)
-/*
- * Adjust slashes in file names. Called after 'shellslash' was set.
- */
+
+/// Adjust slashes in file names. Called after 'shellslash' was set.
void alist_slash_adjust(void)
{
for (int i = 0; i < GARGCOUNT; ++i) {
@@ -7142,7 +7613,6 @@ void alist_slash_adjust(void)
/// ":preserve".
static void ex_preserve(exarg_T *eap)
{
- curbuf->b_flags |= BF_PRESERVED;
ml_preserve(curbuf, true, true);
}
@@ -7163,38 +7633,34 @@ static void ex_recover(exarg_T *eap)
recoverymode = false;
}
-/*
- * Command modifier used in a wrong way.
- */
+/// Command modifier used in a wrong way.
static void ex_wrongmodifier(exarg_T *eap)
{
eap->errmsg = e_invcmd;
}
-/*
- * :sview [+command] file split window with new file, read-only
- * :split [[+command] file] split window with current or new file
- * :vsplit [[+command] file] split window vertically with current or new file
- * :new [[+command] file] split window with no or new file
- * :vnew [[+command] file] split vertically window with no or new file
- * :sfind [+command] file split window with file in 'path'
- *
- * :tabedit open new Tab page with empty window
- * :tabedit [+command] file open new Tab page and edit "file"
- * :tabnew [[+command] file] just like :tabedit
- * :tabfind [+command] file open new Tab page and find "file"
- */
+/// :sview [+command] file split window with new file, read-only
+/// :split [[+command] file] split window with current or new file
+/// :vsplit [[+command] file] split window vertically with current or new file
+/// :new [[+command] file] split window with no or new file
+/// :vnew [[+command] file] split vertically window with no or new file
+/// :sfind [+command] file split window with file in 'path'
+///
+/// :tabedit open new Tab page with empty window
+/// :tabedit [+command] file open new Tab page and edit "file"
+/// :tabnew [[+command] file] just like :tabedit
+/// :tabfind [+command] file open new Tab page and find "file"
void ex_splitview(exarg_T *eap)
{
win_T *old_curwin = curwin;
- char_u *fname = NULL;
+ char *fname = NULL;
const bool use_tab = eap->cmdidx == CMD_tabedit
|| eap->cmdidx == CMD_tabfind
|| eap->cmdidx == CMD_tabnew;
// A ":split" in the quickfix window works like ":new". Don't want two
// quickfix windows. But it's OK when doing ":tab split".
- if (bt_quickfix(curbuf) && cmdmod.tab == 0) {
+ if (bt_quickfix(curbuf) && cmdmod.cmod_tab == 0) {
if (eap->cmdidx == CMD_split) {
eap->cmdidx = CMD_new;
}
@@ -7204,8 +7670,8 @@ void ex_splitview(exarg_T *eap)
}
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
- fname = find_file_in_path(eap->arg, STRLEN(eap->arg),
- FNAME_MESS, TRUE, curbuf->b_ffname);
+ fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg),
+ FNAME_MESS, true, (char_u *)curbuf->b_ffname);
if (fname == NULL) {
goto theend;
}
@@ -7216,8 +7682,8 @@ void ex_splitview(exarg_T *eap)
* Either open new tab page or split the window.
*/
if (use_tab) {
- if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab : eap->addr_count == 0
- ? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) {
+ if (win_new_tabpage(cmdmod.cmod_tab != 0 ? cmdmod.cmod_tab : eap->addr_count == 0
+ ? 0 : (int)eap->line2 + 1, (char_u *)eap->arg) != FAIL) {
do_exedit(eap, old_curwin);
apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf);
@@ -7225,7 +7691,7 @@ void ex_splitview(exarg_T *eap)
if (curwin != old_curwin
&& win_valid(old_curwin)
&& old_curwin->w_buffer != curbuf
- && !cmdmod.keepalt) {
+ && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) {
old_curwin->w_alt_fnum = curbuf->b_fnum;
}
}
@@ -7241,28 +7707,23 @@ void ex_splitview(exarg_T *eap)
do_exedit(eap, old_curwin);
}
-
theend:
xfree(fname);
}
-/*
- * Open a new tab page.
- */
+/// Open a new tab page.
void tabpage_new(void)
{
exarg_T ea;
memset(&ea, 0, sizeof(ea));
ea.cmdidx = CMD_tabnew;
- ea.cmd = (char_u *)"tabn";
- ea.arg = (char_u *)"";
+ ea.cmd = "tabn";
+ ea.arg = "";
ex_splitview(&ea);
}
-/*
- * :tabnext command
- */
+/// :tabnext command
static void ex_tabnext(exarg_T *eap)
{
int tab_number;
@@ -7278,9 +7739,9 @@ static void ex_tabnext(exarg_T *eap)
case CMD_tabprevious:
case CMD_tabNext:
if (eap->arg && *eap->arg != NUL) {
- char_u *p = eap->arg;
- char_u *p_save = p;
- tab_number = getdigits(&p, false, 0);
+ char *p = eap->arg;
+ char *p_save = p;
+ tab_number = (int)getdigits((char_u **)&p, false, 0);
if (p == p_save || *p_save == '-' || *p_save == '+' || *p != NUL
|| tab_number == 0) {
// No numbers as argument.
@@ -7291,7 +7752,7 @@ static void ex_tabnext(exarg_T *eap)
if (eap->addr_count == 0) {
tab_number = 1;
} else {
- tab_number = eap->line2;
+ tab_number = (int)eap->line2;
if (tab_number < 1) {
eap->errmsg = e_invrange;
return;
@@ -7309,9 +7770,7 @@ static void ex_tabnext(exarg_T *eap)
}
}
-/*
- * :tabmove command
- */
+/// :tabmove command
static void ex_tabmove(exarg_T *eap)
{
int tab_number = get_tabpage_arg(eap);
@@ -7320,9 +7779,7 @@ static void ex_tabmove(exarg_T *eap)
}
}
-/*
- * :tabs command: List tabs and their contents.
- */
+/// :tabs command: List tabs and their contents.
static void ex_tabs(exarg_T *eap)
{
int tabcount = 1;
@@ -7358,20 +7815,17 @@ static void ex_tabs(exarg_T *eap)
if (buf_spname(wp->w_buffer) != NULL) {
STRLCPY(IObuff, buf_spname(wp->w_buffer), IOSIZE);
} else {
- home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true);
+ home_replace(wp->w_buffer, wp->w_buffer->b_fname, (char *)IObuff, IOSIZE, true);
}
- msg_outtrans(IObuff);
+ msg_outtrans((char *)IObuff);
ui_flush(); // output one line at a time
os_breakcheck();
}
}
}
-
-/*
- * ":mode":
- * If no argument given, get the screen size and redraw.
- */
+/// ":mode":
+/// If no argument given, get the screen size and redraw.
static void ex_mode(exarg_T *eap)
{
if (*eap->arg == NUL) {
@@ -7382,23 +7836,20 @@ static void ex_mode(exarg_T *eap)
}
}
-/*
- * ":resize".
- * set, increment or decrement current window height
- */
+/// ":resize".
+/// set, increment or decrement current window height
static void ex_resize(exarg_T *eap)
{
int n;
win_T *wp = curwin;
if (eap->addr_count > 0) {
- n = eap->line2;
- for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) {
- }
+ n = (int)eap->line2;
+ for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) {}
}
- n = atol((char *)eap->arg);
- if (cmdmod.split & WSP_VERT) {
+ n = (int)atol(eap->arg);
+ if (cmdmod.cmod_split & WSP_VERT) {
if (*eap->arg == '-' || *eap->arg == '+') {
n += wp->w_width;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
@@ -7409,29 +7860,27 @@ static void ex_resize(exarg_T *eap)
if (*eap->arg == '-' || *eap->arg == '+') {
n += wp->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
- n = Rows-1;
+ n = Rows - 1;
}
win_setheight_win(n, wp);
}
}
-/*
- * ":find [+command] <file>" command.
- */
+/// ":find [+command] <file>" command.
static void ex_find(exarg_T *eap)
{
- char_u *fname;
- int count;
+ char *fname;
+ linenr_T count;
- fname = find_file_in_path(eap->arg, STRLEN(eap->arg),
- FNAME_MESS, TRUE, curbuf->b_ffname);
+ fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg),
+ FNAME_MESS, true, (char_u *)curbuf->b_ffname);
if (eap->addr_count > 0) {
// Repeat finding the file "count" times. This matters when it
// appears several times in the path.
count = eap->line2;
while (fname != NULL && --count > 0) {
xfree(fname);
- fname = find_file_in_path(NULL, 0, FNAME_MESS, FALSE, curbuf->b_ffname);
+ fname = (char *)find_file_in_path(NULL, 0, FNAME_MESS, false, (char_u *)curbuf->b_ffname);
}
}
@@ -7448,7 +7897,7 @@ static void ex_edit(exarg_T *eap)
do_exedit(eap, NULL);
}
-/// ":edit <file>" command and alikes.
+/// ":edit <file>" command and alike.
///
/// @param old_curwin curwin before doing a split or NULL
void do_exedit(exarg_T *eap, win_T *old_curwin)
@@ -7480,9 +7929,11 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
need_wait_return = false;
msg_scroll = 0;
redraw_all_later(NOT_VALID);
+ pending_exmode_active = true;
normal_enter(false, true);
+ pending_exmode_active = false;
RedrawingDisabled = rd;
no_wait_return = nwr;
msg_scroll = ms;
@@ -7517,7 +7968,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
if (eap->cmdidx != CMD_balt && eap->cmdidx != CMD_badd) {
setpcmark();
}
- if (do_ecmd(0, (eap->cmdidx == CMD_enew ? NULL : eap->arg),
+ if (do_ecmd(0, eap->cmdidx == CMD_enew ? NULL : eap->arg,
NULL, eap, eap->do_ecmd_lnum,
(buf_hide(curbuf) ? ECMD_HIDE : 0)
+ (eap->forceit ? ECMD_FORCEIT : 0)
@@ -7535,7 +7986,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
// Reset the error/interrupt/exception state here so that
// aborting() returns FALSE when closing a window.
enter_cleanup(&cs);
- win_close(curwin, !need_hide && !buf_hide(curbuf));
+ win_close(curwin, !need_hide && !buf_hide(curbuf), false);
// Restore the error/interrupt/exception state if not
// discarded by a new aborting error, interrupt, or
@@ -7553,7 +8004,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
readonlymode = n;
} else {
if (eap->do_ecmd_cmd != NULL) {
- do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ do_cmdline_cmd(eap->do_ecmd_cmd);
}
n = curwin->w_arg_idx_invalid;
check_arg_idx(curwin);
@@ -7571,7 +8022,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
&& curwin != old_curwin
&& win_valid(old_curwin)
&& old_curwin->w_buffer != curbuf
- && !cmdmod.keepalt) {
+ && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) {
old_curwin->w_alt_fnum = curbuf->b_fnum;
}
@@ -7584,6 +8035,10 @@ static void ex_nogui(exarg_T *eap)
eap->errmsg = N_("E25: Nvim does not have a built-in GUI");
}
+static void ex_popup(exarg_T *eap)
+{
+ pum_make_popup(eap->arg, eap->forceit);
+}
static void ex_swapname(exarg_T *eap)
{
@@ -7594,11 +8049,9 @@ static void ex_swapname(exarg_T *eap)
}
}
-/*
- * ":syncbind" forces all 'scrollbind' windows to have the same relative
- * offset.
- * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>)
- */
+/// ":syncbind" forces all 'scrollbind' windows to have the same relative
+/// offset.
+/// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>)
static void ex_syncbind(exarg_T *eap)
{
win_T *save_curwin = curwin;
@@ -7629,7 +8082,6 @@ static void ex_syncbind(exarg_T *eap)
topline = 1;
}
-
/*
* Set all scrollbind windows to the same topline.
*/
@@ -7655,7 +8107,7 @@ static void ex_syncbind(exarg_T *eap)
did_syncbind = true;
checkpcmark();
if (old_linenr != curwin->w_cursor.lnum) {
- char_u ctrl_o[2];
+ char ctrl_o[2];
ctrl_o[0] = Ctrl_O;
ctrl_o[1] = 0;
@@ -7664,7 +8116,6 @@ static void ex_syncbind(exarg_T *eap)
}
}
-
static void ex_read(exarg_T *eap)
{
int i;
@@ -7683,13 +8134,13 @@ static void ex_read(exarg_T *eap)
return;
}
i = readfile(curbuf->b_ffname, curbuf->b_fname,
- eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false);
} else {
if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) {
(void)setaltfname(eap->arg, eap->arg, (linenr_T)1);
}
i = readfile(eap->arg, NULL,
- eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false);
}
if (i != OK) {
if (!aborting()) {
@@ -7718,7 +8169,7 @@ static void ex_read(exarg_T *eap)
}
}
-static char_u *prev_dir = NULL;
+static char *prev_dir = NULL;
#if defined(EXITFREE)
void free_cd_dir(void)
@@ -7729,8 +8180,8 @@ void free_cd_dir(void)
#endif
-// Get the previous directory for the given chdir scope.
-static char_u *get_prevdir(CdScope scope)
+/// Get the previous directory for the given chdir scope.
+static char *get_prevdir(CdScope scope)
{
switch (scope) {
case kCdScopeTabpage:
@@ -7747,7 +8198,7 @@ static char_u *get_prevdir(CdScope scope)
/// Deal with the side effects of changing the current directory.
///
/// @param scope Scope of the function call (global, tab or window).
-void post_chdir(CdScope scope, bool trigger_dirchanged)
+static void post_chdir(CdScope scope, bool trigger_dirchanged)
{
// Always overwrite the window-local CWD.
XFREE_CLEAR(curwin->w_localdir);
@@ -7758,10 +8209,10 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
}
if (scope < kCdScopeGlobal) {
- char_u *pdir = get_prevdir(scope);
+ char *pdir = get_prevdir(scope);
// If still in global directory, set CWD as the global directory.
if (globaldir == NULL && pdir != NULL) {
- globaldir = vim_strsave(pdir);
+ globaldir = xstrdup(pdir);
}
}
@@ -7775,10 +8226,10 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
XFREE_CLEAR(globaldir);
break;
case kCdScopeTabpage:
- curtab->tp_localdir = (char_u *)xstrdup(cwd);
+ curtab->tp_localdir = xstrdup(cwd);
break;
case kCdScopeWindow:
- curwin->w_localdir = (char_u *)xstrdup(cwd);
+ curwin->w_localdir = xstrdup(cwd);
break;
case kCdScopeInvalid:
abort();
@@ -7788,7 +8239,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
shorten_fnames(true);
if (trigger_dirchanged) {
- do_autocmd_dirchanged(cwd, scope, kCdCauseManual);
+ do_autocmd_dirchanged(cwd, scope, kCdCauseManual, false);
}
}
@@ -7796,16 +8247,13 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
/// @param new_dir The directory to change to.
/// @param scope Scope of the function call (global, tab or window).
/// @return true if the directory is successfully changed.
-bool changedir_func(char_u *new_dir, CdScope scope)
+bool changedir_func(char *new_dir, CdScope scope)
{
- char_u *tofree;
- char_u *pdir = NULL;
- bool retval = false;
-
if (new_dir == NULL || allbuf_locked()) {
return false;
}
+ char *pdir = NULL;
// ":cd -": Change to previous directory
if (STRCMP(new_dir, "-") == 0) {
pdir = get_prevdir(scope);
@@ -7816,26 +8264,12 @@ bool changedir_func(char_u *new_dir, CdScope scope)
new_dir = pdir;
}
- // Free the previous directory
- tofree = get_prevdir(scope);
-
if (os_dirname(NameBuff, MAXPATHL) == OK) {
- pdir = vim_strsave(NameBuff);
+ pdir = (char *)vim_strsave(NameBuff);
} else {
pdir = NULL;
}
- switch (scope) {
- case kCdScopeTabpage:
- curtab->tp_prevdir = pdir;
- break;
- case kCdScopeWindow:
- curwin->w_prevdir = pdir;
- break;
- default:
- prev_dir = pdir;
- }
-
// For UNIX ":cd" means: go to home directory.
// On other systems too if 'cdhome' is set.
#if defined(UNIX)
@@ -7845,27 +8279,42 @@ bool changedir_func(char_u *new_dir, CdScope scope)
#endif
// Use NameBuff for home directory name.
expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
- new_dir = NameBuff;
+ new_dir = (char *)NameBuff;
}
- bool dir_differs = new_dir == NULL || pdir == NULL
- || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
- if (new_dir != NULL && (!dir_differs || vim_chdir(new_dir) == 0)) {
- post_chdir(scope, dir_differs);
- retval = true;
- } else {
- emsg(_(e_failed));
+ bool dir_differs = pdir == NULL || pathcmp(pdir, new_dir, -1) != 0;
+ if (dir_differs) {
+ do_autocmd_dirchanged(new_dir, scope, kCdCauseManual, true);
+ if (vim_chdir((char_u *)new_dir) != 0) {
+ emsg(_(e_failed));
+ xfree(pdir);
+ return false;
+ }
}
- xfree(tofree);
- return retval;
+ char **pp;
+ switch (scope) {
+ case kCdScopeTabpage:
+ pp = &curtab->tp_prevdir;
+ break;
+ case kCdScopeWindow:
+ pp = &curwin->w_prevdir;
+ break;
+ default:
+ pp = &prev_dir;
+ }
+ xfree(*pp);
+ *pp = pdir;
+
+ post_chdir(scope, dir_differs);
+
+ return true;
}
/// ":cd", ":tcd", ":lcd", ":chdir", "tchdir" and ":lchdir".
void ex_cd(exarg_T *eap)
{
- char_u *new_dir;
- new_dir = eap->arg;
+ char *new_dir = eap->arg;
#if !defined(UNIX)
// for non-UNIX ":cd" means: print current directory unless 'cdhome' is set
if (*new_dir == NUL && !p_cdh) {
@@ -7895,9 +8344,7 @@ void ex_cd(exarg_T *eap)
}
}
-/*
- * ":pwd".
- */
+/// ":pwd".
static void ex_pwd(exarg_T *eap)
{
if (os_dirname(NameBuff, MAXPATHL) == OK) {
@@ -7922,9 +8369,7 @@ static void ex_pwd(exarg_T *eap)
}
}
-/*
- * ":=".
- */
+/// ":=".
static void ex_equal(exarg_T *eap)
{
smsg("%" PRId64, (int64_t)eap->line2);
@@ -7955,9 +8400,7 @@ static void ex_sleep(exarg_T *eap)
do_sleep(len);
}
-/*
- * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second.
- */
+/// Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second.
void do_sleep(long msec)
{
ui_flush(); // flush before waiting
@@ -7974,31 +8417,10 @@ void do_sleep(long msec)
}
}
-static void do_exmap(exarg_T *eap, int isabbrev)
-{
- int mode;
- char_u *cmdp;
-
- cmdp = eap->cmd;
- mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
-
- switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
- eap->arg, mode, isabbrev)) {
- case 1:
- emsg(_(e_invarg));
- break;
- case 2:
- emsg(isabbrev ? _(e_noabbr) : _(e_nomap));
- break;
- }
-}
-
-/*
- * ":winsize" command (obsolete).
- */
+/// ":winsize" command (obsolete).
static void ex_winsize(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char *arg = eap->arg;
if (!ascii_isdigit(*arg)) {
semsg(_(e_invarg2), arg);
@@ -8006,7 +8428,7 @@ static void ex_winsize(exarg_T *eap)
}
int w = getdigits_int(&arg, false, 10);
arg = skipwhite(arg);
- char_u *p = arg;
+ char *p = arg;
int h = getdigits_int(&arg, false, 10);
if (*p != NUL && *arg == NUL) {
screen_resize(w, h);
@@ -8018,7 +8440,7 @@ static void ex_winsize(exarg_T *eap)
static void ex_wincmd(exarg_T *eap)
{
int xchar = NUL;
- char_u *p;
+ char *p;
if (*eap->arg == 'g' || *eap->arg == Ctrl_G) {
// CTRL-W g and CTRL-W CTRL-G have an extra command character
@@ -8026,29 +8448,27 @@ static void ex_wincmd(exarg_T *eap)
emsg(_(e_invarg));
return;
}
- xchar = eap->arg[1];
+ xchar = (uint8_t)eap->arg[1];
p = eap->arg + 2;
} else {
p = eap->arg + 1;
}
- eap->nextcmd = check_nextcmd(p);
+ eap->nextcmd = (char *)check_nextcmd((char_u *)p);
p = skipwhite(p);
if (*p != NUL && *p != '"' && eap->nextcmd == NULL) {
emsg(_(e_invarg));
} else if (!eap->skip) {
// Pass flags on for ":vertical wincmd ]".
- postponed_split_flags = cmdmod.split;
- postponed_split_tab = cmdmod.tab;
+ postponed_split_flags = cmdmod.cmod_split;
+ postponed_split_tab = cmdmod.cmod_tab;
do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar);
postponed_split_flags = 0;
postponed_split_tab = 0;
}
}
-/*
- * Handle command that work like operators: ":delete", ":yank", ":>" and ":<".
- */
+/// Handle command that work like operators: ":delete", ":yank", ":>" and ":<".
static void ex_operators(exarg_T *eap)
{
oparg_T oa;
@@ -8078,7 +8498,7 @@ static void ex_operators(exarg_T *eap)
case CMD_yank:
oa.op_type = OP_YANK;
- (void)op_yank(&oa, true, false);
+ (void)op_yank(&oa, true);
break;
default: // CMD_rshift or CMD_lshift
@@ -8095,9 +8515,7 @@ static void ex_operators(exarg_T *eap)
ex_may_print(eap);
}
-/*
- * ":put".
- */
+/// ":put".
static void ex_put(exarg_T *eap)
{
// ":0put" works like ":1put!".
@@ -8106,13 +8524,12 @@ static void ex_put(exarg_T *eap)
eap->forceit = TRUE;
}
curwin->w_cursor.lnum = eap->line2;
+ check_cursor_col();
do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1,
PUT_LINE|PUT_CURSLINE);
}
-/*
- * Handle ":copy" and ":move".
- */
+/// Handle ":copy" and ":move".
static void ex_copymove(exarg_T *eap)
{
long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1);
@@ -8131,20 +8548,18 @@ static void ex_copymove(exarg_T *eap)
}
if (eap->cmdidx == CMD_move) {
- if (do_move(eap->line1, eap->line2, n) == FAIL) {
+ if (do_move(eap->line1, eap->line2, (linenr_T)n) == FAIL) {
return;
}
} else {
- ex_copy(eap->line1, eap->line2, n);
+ ex_copy(eap->line1, eap->line2, (linenr_T)n);
}
u_clearline();
beginline(BL_SOL | BL_FIX);
ex_may_print(eap);
}
-/*
- * Print the current line if flags were given to the Ex command.
- */
+/// Print the current line if flags were given to the Ex command.
void ex_may_print(exarg_T *eap)
{
if (eap->flags != 0) {
@@ -8164,9 +8579,19 @@ static void ex_submagic(exarg_T *eap)
p_magic = magic_save;
}
-/*
- * ":join".
- */
+/// ":smagic" and ":snomagic" preview callback.
+static int ex_submagic_preview(exarg_T *eap, long cmdpreview_ns, handle_T cmdpreview_bufnr)
+{
+ int magic_save = p_magic;
+
+ p_magic = (eap->cmdidx == CMD_smagic);
+ int retv = ex_substitute_preview(eap, cmdpreview_ns, cmdpreview_bufnr);
+ p_magic = magic_save;
+
+ return retv;
+}
+
+/// ":join".
static void ex_join(exarg_T *eap)
{
curwin->w_cursor.lnum = eap->line1;
@@ -8180,14 +8605,12 @@ static void ex_join(exarg_T *eap)
}
++eap->line2;
}
- do_join(eap->line2 - eap->line1 + 1, !eap->forceit, TRUE, TRUE, true);
+ do_join((size_t)((ssize_t)eap->line2 - eap->line1 + 1), !eap->forceit, true, true, true);
beginline(BL_WHITE | BL_FIX);
ex_may_print(eap);
}
-/*
- * ":[addr]@r": execute register
- */
+/// ":[addr]@r": execute register
static void ex_at(exarg_T *eap)
{
int prev_len = typebuf.tb_len;
@@ -8196,14 +8619,13 @@ static void ex_at(exarg_T *eap)
check_cursor_col();
// Get the register name. No name means use the previous one.
- int c = *eap->arg;
+ int c = (uint8_t)(*eap->arg);
if (c == NUL) {
c = '@';
}
// Put the register in the typeahead buffer with the "silent" flag.
- if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, TRUE)
- == FAIL) {
+ if (do_execreg(c, true, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, true) == FAIL) {
beep_flush();
} else {
bool save_efr = exec_from_reg;
@@ -8223,40 +8645,64 @@ static void ex_at(exarg_T *eap)
}
}
-/*
- * ":!".
- */
+/// ":!".
static void ex_bang(exarg_T *eap)
{
do_bang(eap->addr_count, eap, eap->forceit, true, true);
}
-/*
- * ":undo".
- */
+/// ":undo".
static void ex_undo(exarg_T *eap)
{
- if (eap->addr_count == 1) { // :undo 123
- undo_time(eap->line2, false, false, true);
- } else {
- u_undo(1);
+ if (eap->addr_count != 1) {
+ if (eap->forceit) {
+ u_undo_and_forget(1); // :undo!
+ } else {
+ u_undo(1); // :undo
+ }
+ return;
+ }
+
+ long step = eap->line2;
+
+ if (eap->forceit) { // undo! 123
+ // change number for "undo!" must be lesser than current change number
+ if (step >= curbuf->b_u_seq_cur) {
+ emsg(_(e_undobang_cannot_redo_or_move_branch));
+ return;
+ }
+ // ensure that target change number is in same branch
+ // while also counting the amount of undoes it'd take to reach target
+ u_header_T *uhp;
+ int count = 0;
+
+ for (uhp = curbuf->b_u_curhead ? curbuf->b_u_curhead : curbuf->b_u_newhead;
+ uhp != NULL && uhp->uh_seq > step;
+ uhp = uhp->uh_next.ptr, ++count) {}
+ if (step != 0 && (uhp == NULL || uhp->uh_seq < step)) {
+ emsg(_(e_undobang_cannot_redo_or_move_branch));
+ return;
+ }
+ u_undo_and_forget(count);
+ } else { // :undo 123
+ undo_time(step, false, false, true);
}
}
static void ex_wundo(exarg_T *eap)
{
- char_u hash[UNDO_HASH_SIZE];
+ char hash[UNDO_HASH_SIZE];
- u_compute_hash(curbuf, hash);
- u_write_undo((char *)eap->arg, eap->forceit, curbuf, hash);
+ u_compute_hash(curbuf, (char_u *)hash);
+ u_write_undo(eap->arg, eap->forceit, curbuf, (char_u *)hash);
}
static void ex_rundo(exarg_T *eap)
{
- char_u hash[UNDO_HASH_SIZE];
+ char hash[UNDO_HASH_SIZE];
- u_compute_hash(curbuf, hash);
- u_read_undo((char *)eap->arg, hash, NULL);
+ u_compute_hash(curbuf, (char_u *)hash);
+ u_read_undo(eap->arg, (char_u *)hash, NULL);
}
/// ":redo".
@@ -8271,12 +8717,12 @@ static void ex_later(exarg_T *eap)
long count = 0;
bool sec = false;
bool file = false;
- char_u *p = eap->arg;
+ char *p = eap->arg;
if (*p == NUL) {
count = 1;
} else if (isdigit(*p)) {
- count = getdigits_long(&p, false, 0);
+ count = getdigits_long((char_u **)&p, false, 0);
switch (*p) {
case 's':
++p; sec = true; break;
@@ -8299,14 +8745,12 @@ static void ex_later(exarg_T *eap)
}
}
-/*
- * ":redir": start/stop redirection.
- */
+/// ":redir": start/stop redirection.
static void ex_redir(exarg_T *eap)
{
char *mode;
- char_u *fname;
- char_u *arg = eap->arg;
+ char *fname;
+ char *arg = eap->arg;
if (STRICMP(eap->arg, "END") == 0) {
close_redir();
@@ -8329,14 +8773,14 @@ static void ex_redir(exarg_T *eap)
return;
}
- redir_fd = open_exfile(fname, eap->forceit, mode);
+ redir_fd = open_exfile((char_u *)fname, eap->forceit, mode);
xfree(fname);
} else if (*arg == '@') {
// redirect to a register a-z (resp. A-Z for appending)
close_redir();
++arg;
if (valid_yank_reg(*arg, true) && *arg != '_') {
- redir_reg = *arg++;
+ redir_reg = (char_u)(*arg++);
if (*arg == '>' && arg[1] == '>') { // append
arg += 2;
} else {
@@ -8388,7 +8832,7 @@ static void ex_redir(exarg_T *eap)
/// ":redraw": force redraw
static void ex_redraw(exarg_T *eap)
{
- if (State & CMDPREVIEW) {
+ if (cmdpreview) {
return; // Ignore :redraw during 'inccommand' preview. #9777
}
int r = RedrawingDisabled;
@@ -8419,10 +8863,10 @@ static void ex_redraw(exarg_T *eap)
ui_flush();
}
-/// ":redrawstatus": force redraw of status line(s)
+/// ":redrawstatus": force redraw of status line(s) and window bar(s)
static void ex_redrawstatus(exarg_T *eap)
{
- if (State & CMDPREVIEW) {
+ if (cmdpreview) {
return; // Ignore :redrawstatus during 'inccommand' preview. #9777
}
int r = RedrawingDisabled;
@@ -8435,14 +8879,13 @@ static void ex_redrawstatus(exarg_T *eap)
} else {
status_redraw_curbuf();
}
- update_screen(VIsual_active ? INVERTED :
- 0);
+ update_screen(VIsual_active ? INVERTED : 0);
RedrawingDisabled = r;
p_lz = p;
ui_flush();
}
-// ":redrawtabline": force redraw of the tabline
+/// ":redrawtabline": force redraw of the tabline
static void ex_redrawtabline(exarg_T *eap FUNC_ATTR_UNUSED)
{
const int r = RedrawingDisabled;
@@ -8516,9 +8959,7 @@ FILE *open_exfile(char_u *fname, int forceit, char *mode)
return fd;
}
-/*
- * ":mark" and ":k".
- */
+/// ":mark" and ":k".
static void ex_mark(exarg_T *eap)
{
pos_T pos;
@@ -8538,9 +8979,7 @@ static void ex_mark(exarg_T *eap)
}
}
-/*
- * Update w_topline, w_leftcol and the cursor position.
- */
+/// Update w_topline, w_leftcol and the cursor position.
void update_topline_cursor(void)
{
check_cursor(); // put cursor on valid line
@@ -8551,8 +8990,9 @@ void update_topline_cursor(void)
update_curswant();
}
-// Save the current State and go to Normal mode.
-// Return true if the typeahead could be saved.
+/// Save the current State and go to Normal mode.
+///
+/// @return true if the typeahead could be saved.
bool save_current_state(save_state_T *sst)
FUNC_ATTR_NONNULL_ALL
{
@@ -8560,14 +9000,13 @@ bool save_current_state(save_state_T *sst)
sst->save_restart_edit = restart_edit;
sst->save_msg_didout = msg_didout;
sst->save_State = State;
- sst->save_insertmode = p_im;
sst->save_finish_op = finish_op;
sst->save_opcount = opcount;
sst->save_reg_executing = reg_executing;
+ sst->save_pending_end_reg_executing = pending_end_reg_executing;
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
- p_im = false; // don't use 'insertmode
// Save the current typeahead. This is required to allow using ":normal"
// from an event handler and makes sure we don't hang when the argument
@@ -8590,10 +9029,10 @@ void restore_current_state(save_state_T *sst)
// override the value of restart_edit anyway.
restart_edit = sst->save_restart_edit;
}
- p_im = sst->save_insertmode;
finish_op = sst->save_finish_op;
opcount = sst->save_opcount;
reg_executing = sst->save_reg_executing;
+ pending_end_reg_executing = sst->save_pending_end_reg_executing;
// don't reset msg_didout now
msg_didout |= sst->save_msg_didout;
@@ -8604,19 +9043,17 @@ void restore_current_state(save_state_T *sst)
ui_cursor_shape(); // may show different cursor shape
}
-/*
- * ":normal[!] {commands}": Execute normal mode commands.
- */
+/// ":normal[!] {commands}": Execute normal mode commands.
static void ex_normal(exarg_T *eap)
{
- if (curbuf->terminal && State & TERM_FOCUS) {
+ if (curbuf->terminal && State & MODE_TERMINAL) {
emsg("Can't re-enter normal mode from terminal mode");
return;
}
save_state_T save_state;
- char_u *arg = NULL;
+ char *arg = NULL;
int l;
- char_u *p;
+ char *p;
if (ex_normal_lock > 0) {
emsg(_(e_secure));
@@ -8627,7 +9064,7 @@ static void ex_normal(exarg_T *eap)
return;
}
- // vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do
+ // vgetc() expects K_SPECIAL to have been escaped. Don't do
// this for the K_SPECIAL leading byte, otherwise special keys will not
// work.
{
@@ -8636,21 +9073,20 @@ static void ex_normal(exarg_T *eap)
// Count the number of characters to be escaped.
for (p = eap->arg; *p != NUL; p++) {
for (l = utfc_ptr2len(p) - 1; l > 0; l--) {
- if (*++p == K_SPECIAL // trailbyte K_SPECIAL or CSI
- ) {
+ if (*++p == (char)K_SPECIAL) { // trailbyte K_SPECIAL
len += 2;
}
}
}
if (len > 0) {
- arg = xmalloc(STRLEN(eap->arg) + len + 1);
+ arg = xmalloc(STRLEN(eap->arg) + (size_t)len + 1);
len = 0;
- for (p = eap->arg; *p != NUL; ++p) {
+ for (p = eap->arg; *p != NUL; p++) {
arg[len++] = *p;
for (l = utfc_ptr2len(p) - 1; l > 0; l--) {
arg[len++] = *++p;
- if (*p == K_SPECIAL) {
- arg[len++] = KS_SPECIAL;
+ if (*p == (char)K_SPECIAL) {
+ arg[len++] = (char)KS_SPECIAL;
arg[len++] = KE_FILLER;
}
}
@@ -8671,7 +9107,7 @@ static void ex_normal(exarg_T *eap)
check_cursor_moved(curwin);
}
- exec_normal_cmd(arg != NULL ? arg : eap->arg,
+ exec_normal_cmd((char_u *)(arg != NULL ? arg : eap->arg),
eap->forceit ? REMAP_NONE : REMAP_YES, false);
} while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int);
}
@@ -8688,9 +9124,7 @@ static void ex_normal(exarg_T *eap)
xfree(arg);
}
-/*
- * ":startinsert", ":startreplace" and ":startgreplace"
- */
+/// ":startinsert", ":startreplace" and ":startgreplace"
static void ex_startinsert(exarg_T *eap)
{
if (eap->forceit) {
@@ -8703,7 +9137,7 @@ static void ex_startinsert(exarg_T *eap)
// Ignore the command when already in Insert mode. Inserting an
// expression register that invokes a function can do this.
- if (State & INSERT) {
+ if (State & MODE_INSERT) {
return;
}
@@ -8727,9 +9161,7 @@ static void ex_startinsert(exarg_T *eap)
}
}
-/*
- * ":stopinsert"
- */
+/// ":stopinsert"
static void ex_stopinsert(exarg_T *eap)
{
restart_edit = 0;
@@ -8737,14 +9169,12 @@ static void ex_stopinsert(exarg_T *eap)
clearmode();
}
-/*
- * Execute normal mode command "cmd".
- * "remap" can be REMAP_NONE or REMAP_YES.
- */
+/// Execute normal mode command "cmd".
+/// "remap" can be REMAP_NONE or REMAP_YES.
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);
+ ins_typebuf((char *)cmd, remap, 0, true, silent);
exec_normal(false);
}
@@ -8773,12 +9203,10 @@ static void ex_checkpath(exarg_T *eap)
(linenr_T)1, (linenr_T)MAXLNUM);
}
-/*
- * ":psearch"
- */
+/// ":psearch"
static void ex_psearch(exarg_T *eap)
{
- g_do_tagpreview = p_pvh;
+ g_do_tagpreview = (int)p_pvh;
ex_findpat(eap);
g_do_tagpreview = 0;
}
@@ -8787,7 +9215,7 @@ static void ex_findpat(exarg_T *eap)
{
bool whole = true;
long n;
- char_u *p;
+ char *p;
int action;
switch (cmdnames[eap->cmdidx].cmd_name[2]) {
@@ -8811,13 +9239,13 @@ static void ex_findpat(exarg_T *eap)
n = 1;
if (ascii_isdigit(*eap->arg)) { // get count
- n = getdigits_long(&eap->arg, false, 0);
+ n = getdigits_long((char_u **)&eap->arg, false, 0);
eap->arg = skipwhite(eap->arg);
}
if (*eap->arg == '/') { // Match regexp, not just whole words
whole = false;
eap->arg++;
- p = skip_regexp(eap->arg, '/', p_magic, NULL);
+ p = (char *)skip_regexp((char_u *)eap->arg, '/', p_magic, NULL);
if (*p) {
*p++ = NUL;
p = skipwhite(p);
@@ -8826,36 +9254,31 @@ static void ex_findpat(exarg_T *eap)
if (!ends_excmd(*p)) {
eap->errmsg = e_trailing;
} else {
- eap->nextcmd = check_nextcmd(p);
+ eap->nextcmd = (char *)check_nextcmd((char_u *)p);
}
}
}
if (!eap->skip) {
- find_pattern_in_path(eap->arg, 0, STRLEN(eap->arg), whole, !eap->forceit,
+ find_pattern_in_path((char_u *)eap->arg, 0, STRLEN(eap->arg), whole, !eap->forceit,
*eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
n, action, eap->line1, eap->line2);
}
}
-
-/*
- * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc.
- */
+/// ":ptag", ":ptselect", ":ptjump", ":ptnext", etc.
static void ex_ptag(exarg_T *eap)
{
- g_do_tagpreview = p_pvh; // will be reset to 0 in ex_tag_cmd()
+ g_do_tagpreview = (int)p_pvh; // will be reset to 0 in ex_tag_cmd()
ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
}
-/*
- * ":pedit"
- */
+/// ":pedit"
static void ex_pedit(exarg_T *eap)
{
win_T *curwin_save = curwin;
// Open the preview window or popup and make it the current window.
- g_do_tagpreview = p_pvh;
+ g_do_tagpreview = (int)p_pvh;
prepare_tagpreview(true);
// Edit the file.
@@ -8870,28 +9293,24 @@ static void ex_pedit(exarg_T *eap)
g_do_tagpreview = 0;
}
-/*
- * ":stag", ":stselect" and ":stjump".
- */
+/// ":stag", ":stselect" and ":stjump".
static void ex_stag(exarg_T *eap)
{
postponed_split = -1;
- postponed_split_flags = cmdmod.split;
- postponed_split_tab = cmdmod.tab;
+ postponed_split_flags = cmdmod.cmod_split;
+ postponed_split_tab = cmdmod.cmod_tab;
ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
postponed_split_flags = 0;
postponed_split_tab = 0;
}
-/*
- * ":tag", ":tselect", ":tjump", ":tnext", etc.
- */
+/// ":tag", ":tselect", ":tjump", ":tnext", etc.
static void ex_tag(exarg_T *eap)
{
ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name);
}
-static void ex_tag_cmd(exarg_T *eap, char_u *name)
+static void ex_tag_cmd(exarg_T *eap, char *name)
{
int cmd;
@@ -8932,8 +9351,8 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
cmd = DT_LTAG;
}
- do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
- eap->forceit, TRUE);
+ do_tag((char_u *)eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
+ eap->forceit, true);
}
enum {
@@ -8954,11 +9373,9 @@ enum {
// SPEC_CLIENT,
};
-/*
- * Check "str" for starting with a special cmdline variable.
- * If found return one of the SPEC_ values and set "*usedlen" to the length of
- * the variable. Otherwise return -1 and "*usedlen" is unchanged.
- */
+/// Check "str" for starting with a special cmdline variable.
+/// If found return one of the SPEC_ values and set "*usedlen" to the length of
+/// the variable. Otherwise return -1 and "*usedlen" is unchanged.
ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
FUNC_ATTR_NONNULL_ALL
{
@@ -9023,9 +9440,9 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
int *escaped)
{
int i;
- char_u *s;
- char_u *result;
- char_u *resultbuf = NULL;
+ char *s;
+ char *result;
+ char *resultbuf = NULL;
size_t resultlen;
buf_T *buf;
int valid = VALID_HEAD | VALID_PATH; // Assume valid result.
@@ -9063,7 +9480,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
if (spec_idx == SPEC_CWORD
|| spec_idx == SPEC_CCWORD
|| spec_idx == SPEC_CEXPR) {
- resultlen = find_ident_under_cursor(&result,
+ resultlen = find_ident_under_cursor((char_u **)&result,
spec_idx == SPEC_CWORD
? (FIND_IDENT | FIND_STRING)
: (spec_idx == SPEC_CEXPR
@@ -9084,7 +9501,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
switch (spec_idx) {
case SPEC_PERC: // '%': current file
if (curbuf->b_fname == NULL) {
- result = (char_u *)"";
+ result = "";
valid = 0; // Must have ":p:h" to be valid
} else {
result = curbuf->b_fname;
@@ -9103,16 +9520,16 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
skip_mod = true;
break;
}
- s = src + 1;
+ s = (char *)src + 1;
if (*s == '<') { // "#<99" uses v:oldfiles.
s++;
}
i = getdigits_int(&s, false, 0);
- if (s == src + 2 && src[1] == '-') {
+ if ((char_u *)s == src + 2 && src[1] == '-') {
// just a minus sign, don't skip over it
s--;
}
- *usedlen = (size_t)(s - src); // length of what we expand
+ *usedlen = (size_t)((char_u *)s - src); // length of what we expand
if (src[1] == '<' && i != 0) {
if (*usedlen < 2) {
@@ -9120,8 +9537,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
*usedlen = 1;
return NULL;
}
- result = (char_u *)tv_list_find_str(get_vim_var_list(VV_OLDFILES),
- i - 1);
+ result = (char *)tv_list_find_str(get_vim_var_list(VV_OLDFILES), i - 1);
if (result == NULL) {
*errormsg = "";
return NULL;
@@ -9139,7 +9555,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
*lnump = ECMD_LAST;
}
if (buf->b_fname == NULL) {
- result = (char_u *)"";
+ result = "";
valid = 0; // Must have ":p:h" to be valid
} else {
result = buf->b_fname;
@@ -9149,7 +9565,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
break;
case SPEC_CFILE: // file name under cursor
- result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL);
+ result = (char *)file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL);
if (result == NULL) {
*errormsg = "";
return NULL;
@@ -9159,12 +9575,12 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
case SPEC_AFILE: // file name for autocommand
if (autocmd_fname != NULL
- && !path_is_absolute(autocmd_fname)
+ && !path_is_absolute((char_u *)autocmd_fname)
// For CmdlineEnter and related events, <afile> is not a path! #9348
- && !strequal("/", (char *)autocmd_fname)) {
+ && !strequal("/", autocmd_fname)) {
// Still need to turn the fname into a full path. It was
// postponed to avoid a delay when <afile> is not used.
- result = (char_u *)FullName_save((char *)autocmd_fname, false);
+ result = FullName_save(autocmd_fname, false);
// Copy into `autocmd_fname`, don't reassign it. #8165
STRLCPY(autocmd_fname, result, MAXPATHL);
xfree(result);
@@ -9174,7 +9590,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
*errormsg = _("E495: no autocommand file name to substitute for \"<afile>\"");
return NULL;
}
- result = path_try_shorten_fname(result);
+ result = (char *)path_try_shorten_fname((char_u *)result);
break;
case SPEC_ABUF: // buffer number for autocommand
@@ -9183,7 +9599,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
return NULL;
}
snprintf(strbuf, sizeof(strbuf), "%d", autocmd_bufnr);
- result = (char_u *)strbuf;
+ result = strbuf;
break;
case SPEC_AMATCH: // match name for autocommand
@@ -9208,7 +9624,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
return NULL;
}
snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, sourcing_lnum);
- result = (char_u *)strbuf;
+ result = strbuf;
break;
case SPEC_SFLNUM: // line in script file
@@ -9218,7 +9634,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
}
snprintf((char *)strbuf, sizeof(strbuf), "%" PRIdLINENR,
current_sctx.sc_lnum + sourcing_lnum);
- result = (char_u *)strbuf;
+ result = strbuf;
break;
case SPEC_SID:
@@ -9228,13 +9644,13 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
}
snprintf(strbuf, sizeof(strbuf), "<SNR>%" PRIdSCID "_",
current_sctx.sc_sid);
- result = (char_u *)strbuf;
+ result = strbuf;
break;
default:
// should not happen
*errormsg = "";
- result = (char_u *)""; // avoid gcc warning
+ result = ""; // avoid gcc warning
break;
}
@@ -9243,11 +9659,12 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
// Remove the file name extension.
if (src[*usedlen] == '<') {
(*usedlen)++;
- if ((s = STRRCHR(result, '.')) != NULL && s >= path_tail(result)) {
+ if ((s = (char *)STRRCHR(result, '.')) != NULL
+ && s >= path_tail(result)) {
resultlen = (size_t)(s - result);
}
} else if (!skip_mod) {
- valid |= modify_fname(src, tilde_file, usedlen, &result,
+ valid |= modify_fname((char *)src, tilde_file, usedlen, &result,
&resultbuf, &resultlen);
if (result == NULL) {
*errormsg = "";
@@ -9265,23 +9682,21 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
}
result = NULL;
} else {
- result = vim_strnsave(result, resultlen);
+ result = xstrnsave(result, resultlen);
}
xfree(resultbuf);
- return result;
+ return (char_u *)result;
}
-/*
- * Concatenate all files in the argument list, separated by spaces, and return
- * it in one allocated string.
- * Spaces and backslashes in the file names are escaped with a backslash.
- */
-static char_u *arg_all(void)
+/// Concatenate all files in the argument list, separated by spaces, and return
+/// it in one allocated string.
+/// Spaces and backslashes in the file names are escaped with a backslash.
+static char *arg_all(void)
{
int len;
int idx;
- char_u *retval = NULL;
- char_u *p;
+ char *retval = NULL;
+ char *p;
/*
* Do this loop two times:
@@ -9290,7 +9705,7 @@ static char_u *arg_all(void)
*/
for (;;) {
len = 0;
- for (idx = 0; idx < ARGCOUNT; ++idx) {
+ for (idx = 0; idx < ARGCOUNT; idx++) {
p = alist_name(&ARGLIST[idx]);
if (p == NULL) {
continue;
@@ -9328,35 +9743,33 @@ static char_u *arg_all(void)
}
// allocate memory
- retval = xmalloc(len + 1);
+ retval = xmalloc((size_t)len + 1);
}
return retval;
}
-/*
- * Expand the <sfile> string in "arg".
- *
- * Returns an allocated string, or NULL for any error.
- */
-char_u *expand_sfile(char_u *arg)
+/// Expand the <sfile> string in "arg".
+///
+/// @return an allocated string, or NULL for any error.
+char *expand_sfile(char *arg)
{
char *errormsg;
size_t len;
- char_u *result;
- char_u *newres;
- char_u *repl;
+ char *result;
+ char *newres;
+ char *repl;
size_t srclen;
- char_u *p;
+ char *p;
- result = vim_strsave(arg);
+ result = xstrdup(arg);
for (p = result; *p;) {
if (STRNCMP(p, "<sfile>", 7) != 0) {
++p;
} else {
// replace "<sfile>" with the sourced file name, and do ":" stuff
- repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL);
+ repl = (char *)eval_vars((char_u *)p, (char_u *)result, &srclen, NULL, &errormsg, NULL);
if (errormsg != NULL) {
if (*errormsg) {
emsg(errormsg);
@@ -9384,40 +9797,34 @@ char_u *expand_sfile(char_u *arg)
return result;
}
-/*
- * ":rshada" and ":wshada".
- */
+/// ":rshada" and ":wshada".
static void ex_shada(exarg_T *eap)
{
- char_u *save_shada;
+ char *save_shada;
- save_shada = p_shada;
+ save_shada = (char *)p_shada;
if (*p_shada == NUL) {
p_shada = (char_u *)"'100";
}
if (eap->cmdidx == CMD_rviminfo || eap->cmdidx == CMD_rshada) {
- (void)shada_read_everything((char *)eap->arg, eap->forceit, false);
+ (void)shada_read_everything(eap->arg, eap->forceit, false);
} else {
- shada_write_file((char *)eap->arg, eap->forceit);
+ shada_write_file(eap->arg, eap->forceit);
}
- p_shada = save_shada;
+ p_shada = (char_u *)save_shada;
}
-/*
- * Make a dialog message in "buff[DIALOG_MSG_SIZE]".
- * "format" must contain "%s".
- */
-void dialog_msg(char_u *buff, char *format, char_u *fname)
+/// Make a dialog message in "buff[DIALOG_MSG_SIZE]".
+/// "format" must contain "%s".
+void dialog_msg(char *buff, char *format, char *fname)
{
if (fname == NULL) {
- fname = (char_u *)_("Untitled");
+ fname = _("Untitled");
}
- vim_snprintf((char *)buff, DIALOG_MSG_SIZE, format, fname);
+ vim_snprintf(buff, DIALOG_MSG_SIZE, format, fname);
}
-/*
- * ":behave {mswin,xterm}"
- */
+/// ":behave {mswin,xterm}"
static void ex_behave(exarg_T *eap)
{
if (STRCMP(eap->arg, "mswin") == 0) {
@@ -9435,35 +9842,33 @@ static void ex_behave(exarg_T *eap)
}
}
-/*
- * Function given to ExpandGeneric() to obtain the possible arguments of the
- * ":behave {mswin,xterm}" command.
- */
-char_u *get_behave_arg(expand_T *xp, int idx)
+/// Function given to ExpandGeneric() to obtain the possible arguments of the
+/// ":behave {mswin,xterm}" command.
+char *get_behave_arg(expand_T *xp, int idx)
{
if (idx == 0) {
- return (char_u *)"mswin";
+ return "mswin";
}
if (idx == 1) {
- return (char_u *)"xterm";
+ return "xterm";
}
return NULL;
}
-// Function given to ExpandGeneric() to obtain the possible arguments of the
-// ":messages {clear}" command.
-char_u *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
+/// Function given to ExpandGeneric() to obtain the possible arguments of the
+/// ":messages {clear}" command.
+char *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
{
if (idx == 0) {
- return (char_u *)"clear";
+ return "clear";
}
return NULL;
}
-char_u *get_mapclear_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
+char *get_mapclear_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
{
if (idx == 0) {
- return (char_u *)"<buffer>";
+ return "<buffer>";
}
return NULL;
}
@@ -9472,18 +9877,16 @@ static TriState filetype_detect = kNone;
static TriState filetype_plugin = kNone;
static TriState filetype_indent = kNone;
-/*
- * ":filetype [plugin] [indent] {on,off,detect}"
- * on: Load the filetype.vim file to install autocommands for file types.
- * off: Load the ftoff.vim file to remove all autocommands for file types.
- * plugin on: load filetype.vim and ftplugin.vim
- * plugin off: load ftplugof.vim
- * indent on: load filetype.vim and indent.vim
- * indent off: load indoff.vim
- */
+/// ":filetype [plugin] [indent] {on,off,detect}"
+/// on: Load the filetype.vim file to install autocommands for file types.
+/// off: Load the ftoff.vim file to remove all autocommands for file types.
+/// plugin on: load filetype.vim and ftplugin.vim
+/// plugin off: load ftplugof.vim
+/// indent on: load filetype.vim and indent.vim
+/// indent off: load indoff.vim
static void ex_filetype(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char *arg = eap->arg;
bool plugin = false;
bool indent = false;
@@ -9491,8 +9894,8 @@ static void ex_filetype(exarg_T *eap)
// Print current status.
smsg("filetype detection:%s plugin:%s indent:%s",
filetype_detect == kTrue ? "ON" : "OFF",
- filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", // NOLINT(whitespace/line_length)
- filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF"); // NOLINT(whitespace/line_length)
+ filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF",
+ filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF");
return;
}
@@ -9524,7 +9927,7 @@ static void ex_filetype(exarg_T *eap)
}
}
if (*arg == 'd') {
- (void)do_doautocmd((char_u *)"filetypedetect BufRead", true, NULL);
+ (void)do_doautocmd("filetypedetect BufRead", true, NULL);
do_modelines(0);
}
} else if (STRCMP(arg, "off") == 0) {
@@ -9546,16 +9949,12 @@ static void ex_filetype(exarg_T *eap)
}
}
-/// Set all :filetype options ON if user did not explicitly set any to OFF.
-void filetype_maybe_enable(void)
+/// Source ftplugin.vim and indent.vim to create the necessary FileType
+/// autocommands. We do this separately from filetype.vim so that these
+/// autocommands will always fire first (and thus can be overridden) while still
+/// allowing general filetype detection to be disabled in the user's init file.
+void filetype_plugin_enable(void)
{
- if (filetype_detect == kNone) {
- // Normally .vim files are sourced before .lua files when both are
- // supported, but we reverse the order here because we want the Lua
- // autocommand to be defined first so that it runs first
- source_runtime(FILETYPE_FILE, DIP_ALL);
- filetype_detect = kTrue;
- }
if (filetype_plugin == kNone) {
source_runtime(FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = kTrue;
@@ -9566,17 +9965,29 @@ void filetype_maybe_enable(void)
}
}
+/// Enable filetype detection if the user did not explicitly disable it.
+void filetype_maybe_enable(void)
+{
+ if (filetype_detect == kNone) {
+ // Normally .vim files are sourced before .lua files when both are
+ // supported, but we reverse the order here because we want the Lua
+ // autocommand to be defined first so that it runs first
+ source_runtime(FILETYPE_FILE, DIP_ALL);
+ filetype_detect = kTrue;
+ }
+}
+
/// ":setfiletype [FALLBACK] {name}"
static void ex_setfiletype(exarg_T *eap)
{
if (!did_filetype) {
- char_u *arg = eap->arg;
+ char *arg = eap->arg;
if (STRNCMP(arg, "FALLBACK ", 9) == 0) {
arg += 9;
}
- set_option_value("filetype", 0L, (char *)arg, OPT_LOCAL);
+ set_option_value("filetype", 0L, arg, OPT_LOCAL);
if (arg != eap->arg) {
did_filetype = false;
}
@@ -9586,103 +9997,25 @@ static void ex_setfiletype(exarg_T *eap)
static void ex_digraphs(exarg_T *eap)
{
if (*eap->arg != NUL) {
- putdigraph(eap->arg);
+ putdigraph((char_u *)eap->arg);
} else {
listdigraphs(eap->forceit);
}
}
-static void ex_set(exarg_T *eap)
-{
- int flags = 0;
-
- if (eap->cmdidx == CMD_setlocal) {
- flags = OPT_LOCAL;
- } else if (eap->cmdidx == CMD_setglobal) {
- flags = OPT_GLOBAL;
- }
- (void)do_set(eap->arg, flags);
-}
-
void set_no_hlsearch(bool flag)
{
no_hlsearch = flag;
set_vim_var_nr(VV_HLSEARCH, !no_hlsearch && p_hls);
}
-/*
- * ":nohlsearch"
- */
+/// ":nohlsearch"
static void ex_nohlsearch(exarg_T *eap)
{
set_no_hlsearch(true);
redraw_all_later(SOME_VALID);
}
-// ":[N]match {group} {pattern}"
-// Sets nextcmd to the start of the next command, if any. Also called when
-// skipping commands to find the next command.
-static void ex_match(exarg_T *eap)
-{
- char_u *p;
- char_u *g = NULL;
- char_u *end;
- int c;
- int id;
-
- if (eap->line2 <= 3) {
- id = eap->line2;
- } else {
- emsg(e_invcmd);
- return;
- }
-
- // First clear any old pattern.
- if (!eap->skip) {
- match_delete(curwin, id, false);
- }
-
- if (ends_excmd(*eap->arg)) {
- end = eap->arg;
- } else if ((STRNICMP(eap->arg, "none", 4) == 0
- && (ascii_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) {
- end = eap->arg + 4;
- } else {
- p = skiptowhite(eap->arg);
- if (!eap->skip) {
- g = vim_strnsave(eap->arg, p - eap->arg);
- }
- p = skipwhite(p);
- if (*p == NUL) {
- // There must be two arguments.
- xfree(g);
- semsg(_(e_invarg2), eap->arg);
- return;
- }
- end = skip_regexp(p + 1, *p, true, NULL);
- if (!eap->skip) {
- if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) {
- xfree(g);
- eap->errmsg = e_trailing;
- return;
- }
- if (*end != *p) {
- xfree(g);
- semsg(_(e_invarg2), p);
- return;
- }
-
- c = *end;
- *end = NUL;
- match_add(curwin, (const char *)g, (const char *)p + 1, 10, id,
- NULL, NULL);
- xfree(g);
- *end = c;
- }
- }
- eap->nextcmd = find_nextcmd(end);
-}
-
static void ex_fold(exarg_T *eap)
{
if (foldManualAllowed(true)) {
@@ -9712,8 +10045,8 @@ static void ex_folddo(exarg_T *eap)
ml_clearmarked(); // clear rest of the marks
}
-// Returns true if the supplied Ex cmdidx is for a location list command
-// instead of a quickfix command.
+/// @return true if the supplied Ex cmdidx is for a location list command
+/// instead of a quickfix command.
bool is_loclist_cmd(int cmdidx)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -9739,7 +10072,7 @@ static void ex_terminal(exarg_T *eap)
char ex_cmd[1024];
if (*eap->arg != NUL) { // Run {cmd} in 'shell'.
- char *name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
+ char *name = (char *)vim_strsave_escaped((char_u *)eap->arg, (char_u *)"\"\\");
snprintf(ex_cmd, sizeof(ex_cmd),
":enew%s | call termopen(\"%s\")",
eap->forceit ? "!" : "", name);
@@ -9770,51 +10103,6 @@ static void ex_terminal(exarg_T *eap)
do_cmdline_cmd(ex_cmd);
}
-/// Checks if `cmd` is "previewable" (i.e. supported by 'inccommand').
-///
-/// @param[in] cmd Commandline to check. May start with a range or modifier.
-///
-/// @return true if `cmd` is previewable
-bool cmd_can_preview(char_u *cmd)
-{
- if (cmd == NULL) {
- return false;
- }
-
- // Ignore additional colons at the start...
- cmd = skip_colon_white(cmd, true);
-
- // Ignore any leading modifiers (:keeppatterns, :verbose, etc.)
- for (int len = modifier_len(cmd); len != 0; len = modifier_len(cmd)) {
- cmd += len;
- cmd = skip_colon_white(cmd, true);
- }
-
- exarg_T ea;
- memset(&ea, 0, sizeof(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;
-}
-
/// Gets a map of maps describing user-commands defined for buffer `buf` or
/// defined globally if `buf` is NULL.
///
@@ -9838,6 +10126,8 @@ Dictionary commands_array(buf_T *buf)
PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG)));
PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR)));
PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR)));
+ PUT(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT)));
+ PUT(d, "preview", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_PREVIEW)));
switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
case 0:
@@ -9898,9 +10188,9 @@ Dictionary commands_array(buf_T *buf)
return rv;
}
-void verify_command(char_u *cmd)
+void verify_command(char *cmd)
{
- if (strcmp("smile", (char *)cmd)) {
+ if (strcmp("smile", cmd)) {
return; // acceptable non-existing command
}
msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx"
@@ -10187,3 +10477,9 @@ void verify_command(char_u *cmd)
msg("` `.:.`.,:iii;;;;;;;;iii;;;:` `.`` "
" `nW");
}
+
+/// Get argt of command with id
+uint32_t get_cmd_argt(cmdidx_T cmdidx)
+{
+ return cmdnames[(int)cmdidx].cmd_argt;
+}