diff options
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r-- | src/nvim/ex_docmd.c | 181 |
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) { |