aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_docmd.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
commit9be89f131f87608f224f0ee06d199fcd09d32176 (patch)
tree11022dcfa9e08cb4ac5581b16734196128688d48 /src/nvim/ex_docmd.c
parentff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff)
parent88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff)
downloadrneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r--src/nvim/ex_docmd.c181
1 files changed, 102 insertions, 79 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 1fcfc505df..293aaac036 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -29,6 +29,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -80,6 +81,7 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmenu.h"
#include "nvim/pos_defs.h"
#include "nvim/profile.h"
@@ -971,8 +973,13 @@ void handle_did_throw(void)
current_exception->throw_name = NULL;
discard_current_exception(); // uses IObuff if 'verbose'
- suppress_errthrow = true;
- force_abort = true;
+
+ // If "silent!" is active the uncaught exception is not fatal.
+ if (emsg_silent == 0) {
+ suppress_errthrow = true;
+ force_abort = true;
+ }
+
msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993
if (messages != NULL) {
@@ -1073,7 +1080,6 @@ void *getline_cookie(LineGetter fgetline, void *cookie)
/// @return the buffer number.
static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int offset)
{
- buf_T *nextbuf;
int count = offset;
buf_T *buf = firstbuf;
@@ -1082,7 +1088,7 @@ static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int o
}
while (count != 0) {
count += (count < 0) ? 1 : -1;
- nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
+ buf_T *nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
if (nextbuf == NULL) {
break;
}
@@ -1101,7 +1107,7 @@ static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int o
// we might have gone too far, last buffer is not loaded
if (addr_type == ADDR_LOADED_BUFFERS) {
while (buf->b_ml.ml_mfp == NULL) {
- nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next;
+ buf_T *nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next;
if (nextbuf == NULL) {
break;
}
@@ -1405,7 +1411,11 @@ void set_cmd_count(exarg_T *eap, linenr_T count, bool validate)
}
} else {
eap->line1 = eap->line2;
- eap->line2 += count - 1;
+ if (eap->line2 >= INT32_MAX - (count - 1)) {
+ eap->line2 = INT32_MAX;
+ } else {
+ eap->line2 += 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) {
@@ -1423,7 +1433,7 @@ static int parse_count(exarg_T *eap, const char **errormsg, bool validate)
if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg)
&& (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL
|| ascii_iswhite(*p))) {
- linenr_T n = getdigits_int32(&eap->arg, false, -1);
+ linenr_T n = getdigits_int32(&eap->arg, false, INT32_MAX);
eap->arg = skipwhite(eap->arg);
if (eap->args != NULL) {
@@ -1686,9 +1696,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool pre
// ":silent! try" was used, it should only apply to :try itself.
if (eap->cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) {
emsg_silent -= cmdmod.cmod_did_esilent;
- if (emsg_silent < 0) {
- emsg_silent = 0;
- }
+ emsg_silent = MAX(emsg_silent, 0);
cmdmod.cmod_did_esilent = 0;
}
@@ -1728,12 +1736,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
}
const char *errormsg = NULL;
-#undef ERROR
-#define ERROR(msg) \
- do { \
- errormsg = msg; \
- goto end; \
- } while (0)
cmdmod_T save_cmdmod = cmdmod;
cmdmod = cmdinfo->cmdmod;
@@ -1744,16 +1746,19 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY)
// allow :put in terminals
&& !(curbuf->terminal && eap->cmdidx == CMD_put)) {
- ERROR(_(e_modifiable));
+ errormsg = _(e_modifiable);
+ goto end;
}
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));
+ errormsg = _(e_cmdwin);
+ goto end;
}
if (text_locked() && !(eap->argt & EX_LOCK_OK)) {
// Command not allowed when text is locked
- ERROR(_(get_text_locked_msg()));
+ errormsg = _(get_text_locked_msg());
+ goto end;
}
}
// Disallow editing another buffer when "curbuf->b_ro_locked" is set.
@@ -1801,7 +1806,6 @@ end:
do_cmdline_end();
return retv;
-#undef ERROR
}
static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie)
@@ -2073,29 +2077,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
if (ea.skip) { // skip this if inside :if
goto doend;
}
- if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) {
- ea.cmdidx = CMD_print;
- ea.argt = EX_RANGE | EX_COUNT | EX_TRLBAR;
- if ((errormsg = invalid_range(&ea)) == NULL) {
- correct_range(&ea);
- ex_print(&ea);
- }
- } else if (ea.addr_count != 0) {
- if (ea.line2 > curbuf->b_ml.ml_line_count) {
- ea.line2 = curbuf->b_ml.ml_line_count;
- }
-
- if (ea.line2 < 0) {
- errormsg = _(e_invrange);
- } else {
- if (ea.line2 == 0) {
- curwin->w_cursor.lnum = 1;
- } else {
- curwin->w_cursor.lnum = ea.line2;
- }
- beginline(BL_SOL | BL_FIX);
- }
- }
+ assert(errormsg == NULL);
+ errormsg = ex_range_without_command(&ea);
goto doend;
}
@@ -2441,6 +2424,40 @@ char *ex_errmsg(const char *const msg, const char *const arg)
return ex_error_buf;
}
+/// The "+" string used in place of an empty command in Ex mode.
+/// This string is used in pointer comparison.
+static char exmode_plus[] = "+";
+
+/// Handle a range without a command.
+/// Returns an error message on failure.
+static char *ex_range_without_command(exarg_T *eap)
+{
+ char *errormsg = NULL;
+
+ if (*eap->cmd == '|' || (exmode_active && eap->cmd != exmode_plus + 1)) {
+ eap->cmdidx = CMD_print;
+ eap->argt = EX_RANGE | EX_COUNT | EX_TRLBAR;
+ if ((errormsg = invalid_range(eap)) == NULL) {
+ correct_range(eap);
+ ex_print(eap);
+ }
+ } else if (eap->addr_count != 0) {
+ eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count);
+
+ if (eap->line2 < 0) {
+ errormsg = _(e_invrange);
+ } else {
+ if (eap->line2 == 0) {
+ curwin->w_cursor.lnum = 1;
+ } else {
+ curwin->w_cursor.lnum = eap->line2;
+ }
+ beginline(BL_SOL | BL_FIX);
+ }
+ }
+ return errormsg;
+}
+
/// Parse and skip over command modifiers:
/// - update eap->cmd
/// - store flags in "cmod".
@@ -2474,7 +2491,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod,
if (*eap->cmd == NUL && exmode_active
&& getline_equal(eap->ea_getline, eap->cookie, getexline)
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- eap->cmd = "+";
+ eap->cmd = exmode_plus;
if (!skip_only) {
ex_pressedreturn = true;
}
@@ -2482,6 +2499,15 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod,
// ignore comment and empty lines
if (*eap->cmd == '"') {
+ // a comment ends at a NL
+ eap->nextcmd = vim_strchr(eap->cmd, '\n');
+ if (eap->nextcmd != NULL) {
+ eap->nextcmd++;
+ }
+ return FAIL;
+ }
+ if (*eap->cmd == '\n') {
+ eap->nextcmd = eap->cmd + 1;
return FAIL;
}
if (*eap->cmd == NUL) {
@@ -2695,7 +2721,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod,
/// Apply the command modifiers. Saves current state in "cmdmod", call
/// undo_cmdmod() later.
-static void apply_cmdmod(cmdmod_T *cmod)
+void apply_cmdmod(cmdmod_T *cmod)
{
if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) {
sandbox++;
@@ -2764,9 +2790,7 @@ void undo_cmdmod(cmdmod_T *cmod)
msg_silent = cmod->cmod_save_msg_silent - 1;
}
emsg_silent -= cmod->cmod_did_esilent;
- if (emsg_silent < 0) {
- emsg_silent = 0;
- }
+ emsg_silent = MAX(emsg_silent, 0);
// Restore msg_scroll, it's set by file I/O commands, even when no
// message is actually displayed.
msg_scroll = cmod->cmod_save_msg_scroll;
@@ -3499,11 +3523,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool
// This makes sure we never match in the current
// line, and can match anywhere in the
// next/previous line.
- if (c == '/' && curwin->w_cursor.lnum > 0) {
- curwin->w_cursor.col = MAXCOL;
- } else {
- curwin->w_cursor.col = 0;
- }
+ curwin->w_cursor.col = (c == '/' && curwin->w_cursor.lnum > 0) ? MAXCOL : 0;
searchcmdlen = 0;
flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG;
if (!do_search(NULL, c, c, cmd, strlen(cmd), 1, flags, NULL)) {
@@ -3613,6 +3633,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool
n = getdigits_int32(&cmd, false, MAXLNUM);
if (n == MAXLNUM) {
*errormsg = _(e_line_number_out_of_range);
+ cmd = NULL;
goto error;
}
}
@@ -3635,6 +3656,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool
} else {
if (lnum >= 0 && n >= INT32_MAX - lnum) {
*errormsg = _(e_line_number_out_of_range);
+ cmd = NULL;
goto error;
}
lnum += n;
@@ -3829,8 +3851,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep)
// No $* in arg, build "<makeprg> <arg>" instead
new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2);
STRCPY(new_cmdline, program);
- STRCAT(new_cmdline, " ");
- STRCAT(new_cmdline, arg);
+ strcat(new_cmdline, " ");
+ strcat(new_cmdline, arg);
}
msg_make(arg);
@@ -4089,7 +4111,12 @@ 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 == '|'
+ && eap->cmdidx != CMD_append
+ && eap->cmdidx != CMD_change
+ && eap->cmdidx != CMD_insert)
+ || *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
@@ -4117,7 +4144,7 @@ static char *getargcmd(char **argp)
if (*arg == '+') { // +[command]
arg++;
- if (ascii_isspace(*arg) || *arg == '\0') {
+ if (ascii_isspace(*arg) || *arg == NUL) {
command = dollar_command;
} else {
command = arg;
@@ -4626,7 +4653,7 @@ static void ex_colorscheme(exarg_T *eap)
char *expr = xstrdup("g:colors_name");
emsg_off++;
- char *p = eval_to_string(expr, false);
+ char *p = eval_to_string(expr, false, false);
emsg_off--;
xfree(expr);
@@ -4765,11 +4792,9 @@ static void ex_cquit(exarg_T *eap)
int before_quit_all(exarg_T *eap)
{
if (cmdwin_type != 0) {
- if (eap->forceit) {
- cmdwin_result = K_XF1; // open_cmdwin() takes care of this
- } else {
- cmdwin_result = K_XF2;
- }
+ cmdwin_result = eap->forceit
+ ? K_XF1 // open_cmdwin() takes care of this
+ : K_XF2;
return FAIL;
}
@@ -5565,45 +5590,43 @@ static void ex_swapname(exarg_T *eap)
/// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>)
static void ex_syncbind(exarg_T *eap)
{
- linenr_T topline;
- int y;
+ linenr_T vtopline; // Target topline (including fill)
+
linenr_T old_linenr = curwin->w_cursor.lnum;
setpcmark();
- // determine max topline
+ // determine max (virtual) topline
if (curwin->w_p_scb) {
- topline = curwin->w_topline;
+ vtopline = get_vtopline(curwin);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_scb && wp->w_buffer) {
- y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(curwin);
- if (topline > y) {
- topline = y;
- }
+ linenr_T y = plines_m_win_fill(wp, 1, wp->w_buffer->b_ml.ml_line_count)
+ - get_scrolloff_value(curwin);
+ vtopline = MIN(vtopline, y);
}
}
- if (topline < 1) {
- topline = 1;
- }
+ vtopline = MAX(vtopline, 1);
} else {
- topline = 1;
+ vtopline = 1;
}
// Set all scrollbind windows to the same topline.
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_p_scb) {
- y = topline - wp->w_topline;
+ int y = vtopline - get_vtopline(wp);
if (y > 0) {
scrollup(wp, y, true);
} else {
scrolldown(wp, -y, true);
}
- wp->w_scbind_pos = topline;
+ wp->w_scbind_pos = vtopline;
redraw_later(wp, UPD_VALID);
cursor_correct(wp);
wp->w_redr_status = true;
}
}
+
if (curwin->w_p_scb) {
did_syncbind = true;
checkpcmark();
@@ -7239,7 +7262,7 @@ char *expand_sfile(char *arg)
memmove(newres, result, (size_t)(p - result));
STRCPY(newres + (p - result), repl);
len = strlen(newres);
- STRCAT(newres, p + srclen);
+ strcat(newres, p + srclen);
xfree(repl);
xfree(result);
result = newres;
@@ -7316,7 +7339,7 @@ static void ex_filetype(exarg_T *eap)
break;
}
if (strcmp(arg, "on") == 0 || strcmp(arg, "detect") == 0) {
- if (*arg == 'o' || !filetype_detect) {
+ if (*arg == 'o' || filetype_detect != kTrue) {
source_runtime(FILETYPE_FILE, DIP_ALL);
filetype_detect = kTrue;
if (plugin) {