From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/ex_docmd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1fcfc505df..028ee8f6ae 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" -- cgit From a18982cb839d7f05e32b1026bbd99b8aa34ad189 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:00:20 +0700 Subject: refactor: replace '\0' with NUL --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 028ee8f6ae..2f54aa511b 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4118,7 +4118,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; -- cgit From 9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 19:04:28 +0200 Subject: feat(lua): add `vim._with` It's a function to perform operations in their own sealed context, similar to pythons `with`. This helps ease operations where you need to perform an operation in a specific context, and then restore the context. Marked as private for now as it's not ready for public use. The current plan is to start using this internally so we can discover and fix any problems. Once this is ready to be exposed it will be renamed to `vim.with`. Usage: ```lua local ret = vim._with({context = val}, function() return "hello" end) ``` , where `context` is any combination of: - `buf` - `emsg_silent` - `hide` - `horizontal` - `keepalt` - `keepjumps` - `keepmarks` - `keeppatterns` - `lockmarks` - `noautocmd` - `options` - `sandbox` - `silent` - `unsilent` - `win` (except for `win` and `buf` which can't be used at the same time). This list will most likely be expanded in the future. Work on https://github.com/neovim/neovim/issues/19832. Co-authored-by: Lewis Russell --- src/nvim/ex_docmd.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2f54aa511b..1e2c515195 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1729,12 +1729,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; @@ -1745,16 +1739,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. @@ -1802,7 +1799,6 @@ end: do_cmdline_end(); return retv; -#undef ERROR } static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie) @@ -2696,7 +2692,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++; -- cgit From bbd2f340a2895ed59785f952b2585e6590602cad Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 11 Jun 2024 10:25:32 +0200 Subject: refactor(memory): use builtin strcat() instead of STRCAT() The latter was mostly relevant with the past char_u madness. NOTE: STRCAT also functioned as a counterfeit "NOLINT" for clint apparently. But NOLINT-ing every usecase is just the same as disabling the check entirely. --- src/nvim/ex_docmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1e2c515195..a6246afb41 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3826,8 +3826,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // No $* in arg, build " " 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); @@ -7236,7 +7236,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; -- cgit From c37695a5d5f2e8914fff86f3581bed70b4c85d3c Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:40:24 +0700 Subject: refactor: use S_LEN(s) instead of s, n (#29219) --- src/nvim/ex_docmd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1e2c515195..a38ff6333a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4191,7 +4191,7 @@ static int getargopt(exarg_T *eap) // Note: Keep this in sync with get_argopt_name. // ":edit ++[no]bin[ary] file" - if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { + if (strncmp(arg, S_LEN("bin")) == 0 || strncmp(arg, S_LEN("nobin")) == 0) { if (*arg == 'n') { arg += 2; eap->force_bin = FORCE_NOBIN; @@ -4206,33 +4206,33 @@ static int getargopt(exarg_T *eap) } // ":read ++edit file" - if (strncmp(arg, "edit", 4) == 0) { + if (strncmp(arg, S_LEN("edit")) == 0) { eap->read_edit = true; eap->arg = skipwhite(arg + 4); return OK; } // ":write ++p foo/bar/file - if (strncmp(arg, "p", 1) == 0) { + if (strncmp(arg, S_LEN("p")) == 0) { eap->mkdir_p = true; eap->arg = skipwhite(arg + 1); return OK; } - if (strncmp(arg, "ff", 2) == 0) { + if (strncmp(arg, S_LEN("ff")) == 0) { arg += 2; pp = &eap->force_ff; - } else if (strncmp(arg, "fileformat", 10) == 0) { + } else if (strncmp(arg, S_LEN("fileformat")) == 0) { arg += 10; pp = &eap->force_ff; - } else if (strncmp(arg, "enc", 3) == 0) { - if (strncmp(arg, "encoding", 8) == 0) { + } else if (strncmp(arg, S_LEN("enc")) == 0) { + if (strncmp(arg, S_LEN("encoding")) == 0) { arg += 8; } else { arg += 3; } pp = &eap->force_enc; - } else if (strncmp(arg, "bad", 3) == 0) { + } else if (strncmp(arg, S_LEN("bad")) == 0) { arg += 3; pp = &bad_char_idx; } @@ -4296,19 +4296,19 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int char *name_end = xp->xp_pattern - 1; if (name_end - xp->xp_line >= 2 - && strncmp(name_end - 2, "ff", 2) == 0) { + && strncmp(name_end - 2, S_LEN("ff")) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 10 - && strncmp(name_end - 10, "fileformat", 10) == 0) { + && strncmp(name_end - 10, S_LEN("fileformat")) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, "enc", 3) == 0) { + && strncmp(name_end - 3, S_LEN("enc")) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 8 - && strncmp(name_end - 8, "encoding", 8) == 0) { + && strncmp(name_end - 8, S_LEN("encoding")) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, "bad", 3) == 0) { + && strncmp(name_end - 3, S_LEN("bad")) == 0) { cb = get_bad_name; } @@ -7213,7 +7213,7 @@ char *expand_sfile(char *arg) char *result = xstrdup(arg); for (char *p = result; *p;) { - if (strncmp(p, "", 7) != 0) { + if (strncmp(p, S_LEN("")) != 0) { p++; } else { // replace "" with the sourced file name, and do ":" stuff @@ -7300,12 +7300,12 @@ static void ex_filetype(exarg_T *eap) // Accept "plugin" and "indent" in any order. while (true) { - if (strncmp(arg, "plugin", 6) == 0) { + if (strncmp(arg, S_LEN("plugin")) == 0) { plugin = true; arg = skipwhite(arg + 6); continue; } - if (strncmp(arg, "indent", 6) == 0) { + if (strncmp(arg, S_LEN("indent")) == 0) { indent = true; arg = skipwhite(arg + 6); continue; @@ -7384,7 +7384,7 @@ static void ex_setfiletype(exarg_T *eap) } char *arg = eap->arg; - if (strncmp(arg, "FALLBACK ", 9) == 0) { + if (strncmp(arg, S_LEN("FALLBACK ")) == 0) { arg += 9; } -- cgit From 43d8435cf84468e776e0a6a98d05ae7bd62583b7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jun 2024 22:20:06 +0100 Subject: revert: "refactor: use S_LEN macro" (#29319) revert: "refactor: use S_LEN(s) instead of s, n (#29219)" This reverts commit c37695a5d5f2e8914fff86f3581bed70b4c85d3c. --- src/nvim/ex_docmd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 9a6a845958..a6246afb41 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4191,7 +4191,7 @@ static int getargopt(exarg_T *eap) // Note: Keep this in sync with get_argopt_name. // ":edit ++[no]bin[ary] file" - if (strncmp(arg, S_LEN("bin")) == 0 || strncmp(arg, S_LEN("nobin")) == 0) { + if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { if (*arg == 'n') { arg += 2; eap->force_bin = FORCE_NOBIN; @@ -4206,33 +4206,33 @@ static int getargopt(exarg_T *eap) } // ":read ++edit file" - if (strncmp(arg, S_LEN("edit")) == 0) { + if (strncmp(arg, "edit", 4) == 0) { eap->read_edit = true; eap->arg = skipwhite(arg + 4); return OK; } // ":write ++p foo/bar/file - if (strncmp(arg, S_LEN("p")) == 0) { + if (strncmp(arg, "p", 1) == 0) { eap->mkdir_p = true; eap->arg = skipwhite(arg + 1); return OK; } - if (strncmp(arg, S_LEN("ff")) == 0) { + if (strncmp(arg, "ff", 2) == 0) { arg += 2; pp = &eap->force_ff; - } else if (strncmp(arg, S_LEN("fileformat")) == 0) { + } else if (strncmp(arg, "fileformat", 10) == 0) { arg += 10; pp = &eap->force_ff; - } else if (strncmp(arg, S_LEN("enc")) == 0) { - if (strncmp(arg, S_LEN("encoding")) == 0) { + } else if (strncmp(arg, "enc", 3) == 0) { + if (strncmp(arg, "encoding", 8) == 0) { arg += 8; } else { arg += 3; } pp = &eap->force_enc; - } else if (strncmp(arg, S_LEN("bad")) == 0) { + } else if (strncmp(arg, "bad", 3) == 0) { arg += 3; pp = &bad_char_idx; } @@ -4296,19 +4296,19 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int char *name_end = xp->xp_pattern - 1; if (name_end - xp->xp_line >= 2 - && strncmp(name_end - 2, S_LEN("ff")) == 0) { + && strncmp(name_end - 2, "ff", 2) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 10 - && strncmp(name_end - 10, S_LEN("fileformat")) == 0) { + && strncmp(name_end - 10, "fileformat", 10) == 0) { cb = get_fileformat_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, S_LEN("enc")) == 0) { + && strncmp(name_end - 3, "enc", 3) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 8 - && strncmp(name_end - 8, S_LEN("encoding")) == 0) { + && strncmp(name_end - 8, "encoding", 8) == 0) { cb = get_encoding_name; } else if (name_end - xp->xp_line >= 3 - && strncmp(name_end - 3, S_LEN("bad")) == 0) { + && strncmp(name_end - 3, "bad", 3) == 0) { cb = get_bad_name; } @@ -7213,7 +7213,7 @@ char *expand_sfile(char *arg) char *result = xstrdup(arg); for (char *p = result; *p;) { - if (strncmp(p, S_LEN("")) != 0) { + if (strncmp(p, "", 7) != 0) { p++; } else { // replace "" with the sourced file name, and do ":" stuff @@ -7300,12 +7300,12 @@ static void ex_filetype(exarg_T *eap) // Accept "plugin" and "indent" in any order. while (true) { - if (strncmp(arg, S_LEN("plugin")) == 0) { + if (strncmp(arg, "plugin", 6) == 0) { plugin = true; arg = skipwhite(arg + 6); continue; } - if (strncmp(arg, S_LEN("indent")) == 0) { + if (strncmp(arg, "indent", 6) == 0) { indent = true; arg = skipwhite(arg + 6); continue; @@ -7384,7 +7384,7 @@ static void ex_setfiletype(exarg_T *eap) } char *arg = eap->arg; - if (strncmp(arg, S_LEN("FALLBACK ")) == 0) { + if (strncmp(arg, "FALLBACK ", 9) == 0) { arg += 9; } -- cgit From 6cbba2b48d604b5fdbd874d75c30c6c55449f33e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 Jul 2024 07:10:30 +0800 Subject: vim-patch:9.1.0529: silent! causes following try/catch to not work (#29567) Problem: silent! causes following try/catch to not work (Malcolm Rowe) Solution: consider emsg_silent in handle_did_throw() and do not abort evaluation flow for :silent! (LemonBoy) The silent! flag causes the evaluation not to be aborted in case of uncaught exceptions, adjust handle_did_throw to take this detail into account. Fixes the long-standing todo.txt item: ``` Problem that a previous silent ":throw" causes a following try/catch not to work. (ZyX, 2013 Sep 28) With examples: (Malcolm Rowe, 2015 Dec 24) Also see vim/vim#8487 for an example. ``` fixes: vim/vim#538 closes: vim/vim#15128 https://github.com/vim/vim/commit/749ba0f6d922b3f6b54a66543c214479492b5a0e Cherry-pick Test_deeply_nested_source() from patch 8.2.5169. Co-authored-by: LemonBoy --- src/nvim/ex_docmd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a6246afb41..f66464fa3a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -972,8 +972,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) { -- cgit From 5531c95101b7656416c97acdd4acb3173d09f64c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 05:58:32 +0800 Subject: vim-patch:8.2.4065: computation overflow with large cound for :yank Problem: Computation overflow with large cound for :yank. Solution: Avoid an overflow. https://github.com/vim/vim/commit/3cf21b305104e91a28e4ce3a473672b2e88a9469 Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index f66464fa3a..63e7a80e53 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1411,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) { @@ -1429,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) { -- cgit From 3700d94c6fa3c6e2a58fc02414e4ca32b823214f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 06:09:53 +0800 Subject: vim-patch:9.1.0579: Ex command is still executed after giving E1247 Problem: Ex command is still executed after giving E1247. Solution: Indicate the error properly and set cmd to NULL. (zeertzjq) closes: vim/vim#15241 https://github.com/vim/vim/commit/d1b5ea984d41102d253ecdd9a76124cd4c58b97d --- src/nvim/ex_docmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 63e7a80e53..44a9c07ec8 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3619,6 +3619,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; } } @@ -3641,6 +3642,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; -- cgit From 88c698083aa0819fb19c3129b81c6f291a5bf568 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 13 Jul 2024 09:15:16 +0800 Subject: vim-patch:8.2.3716: Vim9: range without a command is not compiled Problem: Vim9: range without a command is not compiled. Solution: Add the ISN_EXECRANGE byte code. https://github.com/vim/vim/commit/e4eed8c6db693a9183b776032570ce2f89dcffb6 Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 56 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 23 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 44a9c07ec8..2495b673e4 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2079,29 +2079,7 @@ 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); - } - } + errormsg = ex_range_without_command(&ea); goto doend; } @@ -2447,6 +2425,38 @@ char *ex_errmsg(const char *const msg, const char *const arg) return ex_error_buf; } +/// 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->line1 != eap->line2)) { + 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) { + if (eap->line2 > curbuf->b_ml.ml_line_count) { + 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". -- cgit From 9093fbdd026f088d923fea374a96a8b01ca0df3a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 06:38:26 +0800 Subject: vim-patch:9.1.0573: ex: no implicit print for single addresses Problem: ex: no implicit print for single addresses Solution: explicitly print even during single addresses, as requested by POSIX (Mohamed Akram) See the POSIX behaviour here: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html#tag_20_40_13_03 Section 6b closes: vim/vim#15230 https://github.com/vim/vim/commit/c25a7084e9ae1f78c28ddcbe1fa23374cfdf1e03 Co-authored-by: Mohamed Akram --- src/nvim/ex_docmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2495b673e4..6fae8f091e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2079,6 +2079,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter if (ea.skip) { // skip this if inside :if goto doend; } + assert(errormsg == NULL); errormsg = ex_range_without_command(&ea); goto doend; } @@ -2431,7 +2432,7 @@ static char *ex_range_without_command(exarg_T *eap) { char *errormsg = NULL; - if (*eap->cmd == '|' || (exmode_active && eap->line1 != eap->line2)) { + if (*eap->cmd == '|' || exmode_active) { eap->cmdidx = CMD_print; eap->argt = EX_RANGE | EX_COUNT | EX_TRLBAR; if ((errormsg = invalid_range(eap)) == NULL) { -- cgit From ba36742211eea55bed2ffbca129a45023967f204 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 08:17:49 +0800 Subject: vim-patch:9.1.0574: ex: wrong handling of commands after bar Problem: ex: wrong handling of commands after bar Solution: for :append, :insert and :change use the text after the bar as input for those commands. This is what POSIX requests. (Mohamed Akram) See the POSIX Spec: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html#tag_20_40_13_03 Section 12.c closes: vim/vim#15229 https://github.com/vim/vim/commit/8c446da34998f6350911e07fbfd7932412c83185 Co-authored-by: Mohamed Akram --- src/nvim/ex_docmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6fae8f091e..1d20829d3c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4108,7 +4108,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 -- cgit From c8401515cdaad20220e30f5a0c39ddb7bae77f5e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 14 Jul 2024 16:28:05 +0800 Subject: vim-patch:9.1.0582: Printed line doesn't overwrite colon when pressing Enter in Ex mode Problem: Printed line no longer overwrites colon when pressing Enter in Ex mode (after 9.1.0573). Solution: Restore the behavior of pressing Enter in Ex mode. (zeertzjq) closes: vim/vim#15258 https://github.com/vim/vim/commit/7d664bf0eb2cb25cb77933c8b7f11ca09929e7b8 --- src/nvim/ex_docmd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1d20829d3c..b252ba2b20 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2426,13 +2426,17 @@ 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) { + 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) { @@ -2491,7 +2495,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; } -- cgit From d1bd3d643e5846eee7343ba1a12bdcbbc8cee7b0 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 19 Jul 2024 11:00:13 +0100 Subject: refactor: collapse statements in single assignments Problem: Variables are often assigned multiple places in common patterns. Solution: Replace these common patterns with different patterns that reduce the number of assignments. Use `MAX` and `MIN`: ```c if (x < y) { x = y; } // --> x = MAX(x, y); ``` ```c if (x > y) { x = y; } // --> x = MIN(x, y); ``` Use ternary: ```c int a; if (cond) { a = b; } els { a = c; } // --> int a = cond ? b : c; ``` --- src/nvim/ex_docmd.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b252ba2b20..2defd580fc 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1079,7 +1079,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; @@ -1088,7 +1087,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; } @@ -1107,7 +1106,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; } @@ -1696,9 +1695,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; } @@ -2444,9 +2441,7 @@ static char *ex_range_without_command(exarg_T *eap) ex_print(eap); } } else if (eap->addr_count != 0) { - if (eap->line2 > curbuf->b_ml.ml_line_count) { - eap->line2 = curbuf->b_ml.ml_line_count; - } + eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count); if (eap->line2 < 0) { errormsg = _(e_invrange); @@ -2785,9 +2780,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; @@ -3520,11 +3513,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)) { @@ -4793,11 +4782,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; } @@ -5594,7 +5581,6 @@ static void ex_swapname(exarg_T *eap) static void ex_syncbind(exarg_T *eap) { linenr_T topline; - int y; linenr_T old_linenr = curwin->w_cursor.lnum; setpcmark(); @@ -5604,15 +5590,10 @@ static void ex_syncbind(exarg_T *eap) topline = curwin->w_topline; 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; - } + topline = MIN(topline, wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(curwin)); } } - if (topline < 1) { - topline = 1; - } + topline = MAX(topline, 1); } else { topline = 1; } @@ -5620,7 +5601,7 @@ static void ex_syncbind(exarg_T *eap) // 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 = topline - wp->w_topline; if (y > 0) { scrollup(wp, y, true); } else { -- cgit From 573a71469d37cc35f72bfc929f4ce1156833df9f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 17 Jul 2024 12:23:15 +0100 Subject: fix(scrollbind): properly take filler/virtual lines into account Problem: `'scrollbind'` does not work properly if the window being scrolled automatically contains any filler/virtual lines (except for diff filler lines). This is because when the scrollbind check is done, the logic only considers changes to topline which are represented as line numbers. Solution: Write the logic for determine the scroll amount to take into account filler/virtual lines. Fixes #29751 --- src/nvim/ex_docmd.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2defd580fc..e384627fec 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -81,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" @@ -5580,39 +5581,43 @@ static void ex_swapname(exarg_T *eap) /// (1998-11-02 16:21:01 R. Edward Ralston ) static void ex_syncbind(exarg_T *eap) { - linenr_T topline; + 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) { - topline = MIN(topline, wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(curwin)); + 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); } } - topline = MAX(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) { - int 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(); -- cgit From 582bf4f1e15988565da53a91395e2d0131628fbb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Aug 2024 10:41:08 +0800 Subject: vim-patch:9.0.0634: evaluating "expr" options has more overhead than needed Problem: Evaluating "expr" options has more overhead than needed. Solution: Use call_simple_func() for 'foldtext', 'includeexpr', 'printexpr', "expr" of 'spellsuggest', 'diffexpr', 'patchexpr', 'balloonexpr', 'formatexpr', 'indentexpr' and 'charconvert'. https://github.com/vim/vim/commit/a4e0b9785e409e9e660171cea76dfcc5fdafad9b vim-patch:9.0.0635: build error and compiler warnings Problem: Build error and compiler warnings. Solution: Add missing change. Add type casts. https://github.com/vim/vim/commit/3292a229402c9892f5ab90645fbfe2b1db342f5b Co-authored-by: Bram Moolenaar --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e384627fec..2142199c8a 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4644,7 +4644,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); -- cgit From 93347a67bf913c72ab2c1ba0aa4b26cc4ba6d1a8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 6 Aug 2024 22:20:26 +0800 Subject: fix(filetype): fix :filetype detect error with -u NONE (#29991) :filetype detect should enable filetype detection when it hasn't been enabled before. --- src/nvim/ex_docmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2142199c8a..b5a5a0f466 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7330,7 +7330,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) { -- cgit From 7b7c95dac97d6ea4f10855cc198dce650a796c20 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 4 Sep 2024 06:35:26 +0800 Subject: vim-patch:9.1.0713: Newline causes E749 in Ex mode (#30254) Problem: Newline causes E749 in Ex mode (after 9.1.0573). Solution: Don't execute empty command followed by a newline. closes: vim/vim#15614 https://github.com/vim/vim/commit/2432b4a75321a1a9ac0f9b326c7e46d38bdb71bb Cherry-pick code change from patch 8.2.3405. --- src/nvim/ex_docmd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b5a5a0f466..80bc31a1d2 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2499,6 +2499,17 @@ 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 + if (eap->nextcmd == NULL) { + eap->nextcmd = vim_strchr(eap->cmd, '\n'); + if (eap->nextcmd != NULL) { + eap->nextcmd++; + } + } + return FAIL; + } + if (eap->nextcmd == NULL && *eap->cmd == '\n') { + eap->nextcmd = eap->cmd + 1; return FAIL; } if (*eap->cmd == NUL) { -- cgit From 9570ad24f52442d75d677412cfe2fa83a7ff7a88 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 6 Sep 2024 07:23:31 +0800 Subject: vim-patch:9.1.0717: Unnecessary nextcmd NULL checks in parse_command_modifiers() (#30275) Problem: Unnecessary nextcmd NULL checks in parse_command_modifiers(). Solution: Remove them (zeertzjq) Every place parse_command_modifiers() is called, nextcmd is NULL, and after it's set to non-NULL the function returns very soon. Even if one day nextcmd may be non-NULL, the NULL checks may still be wrong as the correct behavior may be overriding nextcmd. closes: vim/vim#15620 https://github.com/vim/vim/commit/f7b8609446f171a6a287f61564e39a8dac5ff47d --- src/nvim/ex_docmd.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 80bc31a1d2..293aaac036 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2500,15 +2500,13 @@ 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 - if (eap->nextcmd == NULL) { - eap->nextcmd = vim_strchr(eap->cmd, '\n'); - if (eap->nextcmd != NULL) { - eap->nextcmd++; - } + eap->nextcmd = vim_strchr(eap->cmd, '\n'); + if (eap->nextcmd != NULL) { + eap->nextcmd++; } return FAIL; } - if (eap->nextcmd == NULL && *eap->cmd == '\n') { + if (*eap->cmd == '\n') { eap->nextcmd = eap->cmd + 1; return FAIL; } -- cgit