diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
| commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
| tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/ex_cmds.c | |
| parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
| parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
| download | rneovim-aucmd_textputpost.tar.gz rneovim-aucmd_textputpost.tar.bz2 rneovim-aucmd_textputpost.zip | |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/ex_cmds.c')
| -rw-r--r-- | src/nvim/ex_cmds.c | 757 |
1 files changed, 368 insertions, 389 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 437a05f61d..e369397047 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1,12 +1,10 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // ex_cmds.c: some functions for command line commands #include <assert.h> #include <ctype.h> #include <float.h> #include <inttypes.h> +#include <limits.h> #include <math.h> #include <stdbool.h> #include <stddef.h> @@ -18,11 +16,12 @@ #include "auto/config.h" #include "klib/kvec.h" #include "nvim/arglist.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/buffer_updates.h" +#include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/channel.h" #include "nvim/charset.h" @@ -44,17 +43,16 @@ #include "nvim/extmark.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/func_attr.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/grid_defs.h" #include "nvim/help.h" -#include "nvim/highlight_defs.h" +#include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/input.h" -#include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -66,26 +64,28 @@ #include "nvim/normal.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" -#include "nvim/os/fs_defs.h" +#include "nvim/os/fs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/shell.h" #include "nvim/os/time.h" #include "nvim/path.h" #include "nvim/plines.h" +#include "nvim/pos_defs.h" #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" -#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/spell.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/terminal.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" /// Case matching style to use for :substitute @@ -126,20 +126,28 @@ typedef struct { # include "ex_cmds.c.generated.h" #endif +static const char e_non_numeric_argument_to_z[] + = N_("E144: Non-numeric argument to :z"); + /// ":ascii" and "ga" implementation -void do_ascii(const exarg_T *const eap) +void do_ascii(exarg_T *eap) { - char *dig; - int cc[MAX_MCO]; - int c = utfc_ptr2char(get_cursor_pos_ptr(), cc); - if (c == NUL) { - msg("NUL"); + char *data = get_cursor_pos_ptr(); + size_t len = (size_t)utfc_ptr2len(data); + + if (len == 0) { + msg("NUL", 0); return; } - size_t iobuff_len = 0; + bool need_clear = true; + msg_sb_eol(); + msg_start(); + + int c = utf_ptr2char(data); + size_t off = 0; - int ci = 0; + // TODO(bfredl): merge this with the main loop if (c < 0x80) { if (c == NL) { // NUL is stored as NL. c = NUL; @@ -148,56 +156,39 @@ void do_ascii(const exarg_T *const eap) ? NL // NL is stored as CR. : c); char buf1[20]; - if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) { + if (vim_isprintc(c) && (c < ' ' || c > '~')) { char buf3[7]; - transchar_nonprint(curbuf, (char_u *)buf3, c); - vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3); + transchar_nonprint(curbuf, buf3, c); + vim_snprintf(buf1, sizeof(buf1), " <%s>", buf3); } else { buf1[0] = NUL; } char buf2[20]; buf2[0] = NUL; - dig = get_digraph_for_char(cval); + char *dig = get_digraph_for_char(cval); if (dig != NULL) { - iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, - sizeof(IObuff) - iobuff_len, - _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"), - transchar(c), buf1, buf2, cval, cval, cval, dig); + vim_snprintf(IObuff, sizeof(IObuff), + _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"), + transchar(c), buf1, buf2, cval, cval, cval, dig); } else { - iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, - sizeof(IObuff) - iobuff_len, - _("<%s>%s%s %d, Hex %02x, Octal %03o"), - transchar(c), buf1, buf2, cval, cval, cval); - } - - c = cc[ci++]; - } - -#define SPACE_FOR_DESC (1 + 1 + 1 + MB_MAXBYTES + 16 + 4 + 3 + 3 + 1) - // Space for description: - // - 1 byte for separator (starting from second entry) - // - 1 byte for "<" - // - 1 byte for space to draw composing character on (optional, but really - // mostly required) - // - up to MB_MAXBYTES bytes for character itself - // - 16 bytes for raw text ("> , Hex , Octal "). - // - at least 4 bytes for hexadecimal representation - // - at least 3 bytes for decimal representation - // - at least 3 bytes for octal representation - // - 1 byte for NUL - // - // Taking into account MAX_MCO and characters which need 8 bytes for - // hexadecimal representation, but not taking translation into account: - // resulting string will occupy less then 400 bytes (conservative estimate). - // - // Less then 1000 bytes if translation multiplies number of bytes needed for - // raw text by 6, so it should always fit into 1025 bytes reserved for IObuff. + vim_snprintf(IObuff, sizeof(IObuff), + _("<%s>%s%s %d, Hex %02x, Octal %03o"), + transchar(c), buf1, buf2, cval, cval, cval); + } + + msg_multiline(IObuff, 0, true, &need_clear); + + off += (size_t)utf_ptr2len(data); // needed for overlong ascii? + } // Repeat for combining characters, also handle multiby here. - while (c >= 0x80 && iobuff_len < sizeof(IObuff) - SPACE_FOR_DESC) { + while (off < len) { + c = utf_ptr2char(data + off); + + size_t iobuff_len = 0; // This assumes every multi-byte char is printable... - if (iobuff_len > 0) { + if (off > 0) { IObuff[iobuff_len++] = ' '; } IObuff[iobuff_len++] = '<'; @@ -206,43 +197,37 @@ void do_ascii(const exarg_T *const eap) } iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len); - dig = get_digraph_for_char(c); + char *dig = get_digraph_for_char(c); if (dig != NULL) { - iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, - sizeof(IObuff) - iobuff_len, - (c < 0x10000 - ? _("> %d, Hex %04x, Oct %o, Digr %s") - : _("> %d, Hex %08x, Oct %o, Digr %s")), - c, c, c, dig); + vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, + (c < 0x10000 + ? _("> %d, Hex %04x, Oct %o, Digr %s") + : _("> %d, Hex %08x, Oct %o, Digr %s")), + c, c, c, dig); } else { - iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, - sizeof(IObuff) - iobuff_len, - (c < 0x10000 - ? _("> %d, Hex %04x, Octal %o") - : _("> %d, Hex %08x, Octal %o")), - c, c, c); - } - if (ci == MAX_MCO) { - break; + vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, + (c < 0x10000 + ? _("> %d, Hex %04x, Octal %o") + : _("> %d, Hex %08x, Octal %o")), + c, c, c); } - c = cc[ci++]; - } - if (ci != MAX_MCO && c != 0) { - xstrlcpy(IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len); + + msg_multiline(IObuff, 0, true, &need_clear); + + off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii? } - msg(IObuff); + if (need_clear) { + msg_clr_eos(); + } + msg_end(); } /// ":left", ":center" and ":right": align text. void ex_align(exarg_T *eap) { - pos_T save_curpos; - int len; int indent = 0; int new_indent; - int has_tab; - int width; if (curwin->w_p_rl) { // switch left and right aligning @@ -253,8 +238,8 @@ void ex_align(exarg_T *eap) } } - width = atoi(eap->arg); - save_curpos = curwin->w_cursor; + int width = atoi(eap->arg); + pos_T save_curpos = curwin->w_cursor; if (eap->cmdidx == CMD_left) { // width is used for new indent if (width >= 0) { indent = width; @@ -283,8 +268,8 @@ void ex_align(exarg_T *eap) if (eap->cmdidx == CMD_left) { // left align new_indent = indent; } else { - has_tab = false; // avoid uninit warnings - len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent(); + int has_tab = false; // avoid uninit warnings + int len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent(); if (len <= 0) { // skip blank lines continue; @@ -319,7 +304,7 @@ void ex_align(exarg_T *eap) } (void)set_indent(new_indent, 0); // set indent } - changed_lines(eap->line1, 0, eap->line2 + 1, 0L, true); + changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, 0, true); curwin->w_cursor = save_curpos; beginline(BL_WHITE | BL_FIX); } @@ -327,29 +312,24 @@ void ex_align(exarg_T *eap) /// @return the length of the current line, excluding trailing white space. static int linelen(int *has_tab) { - char *line; - char *first; char *last; - int len; // Get the line. If it's empty bail out early (could be the empty string // for an unloaded buffer). - line = get_cursor_line_ptr(); + char *line = get_cursor_line_ptr(); if (*line == NUL) { return 0; } // find the first non-blank character - first = skipwhite(line); + char *first = skipwhite(line); // find the character after the last non-blank character for (last = first + strlen(first); last > first && ascii_iswhite(last[-1]); last--) {} char save = *last; *last = NUL; - // Get line length. - len = linetabsize(line); - // Check for embedded TAB. - if (has_tab != NULL) { + int len = linetabsize_str(line); // Get line length. + if (has_tab != NULL) { // Check for embedded TAB. *has_tab = vim_strchr(first, TAB) != NULL; } *last = save; @@ -389,7 +369,7 @@ typedef struct { static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL { if (sort_lc) { - return strcoll((char *)s1, (char *)s2); + return strcoll((const char *)s1, (const char *)s2); } return sort_ic ? STRICMP(s1, s2) : strcmp(s1, s2); } @@ -418,10 +398,10 @@ static int sort_compare(const void *s1, const void *s2) result = l1.st_u.num.is_number - l2.st_u.num.is_number; } else { result = l1.st_u.num.value == l2.st_u.num.value - ? 0 - : l1.st_u.num.value > l2.st_u.num.value - ? 1 - : -1; + ? 0 + : l1.st_u.num.value > l2.st_u.num.value + ? 1 + : -1; } } else if (sort_flt) { result = l1.st_u.value_flt == l2.st_u.value_flt @@ -452,19 +432,10 @@ static int sort_compare(const void *s1, const void *s2) void ex_sort(exarg_T *eap) { regmatch_T regmatch; - int len; - linenr_T lnum; - long maxlen = 0; + int maxlen = 0; size_t count = (size_t)(eap->line2 - eap->line1) + 1; size_t i; - char *p; - char *s; - char *s2; - char c; // temporary character storage bool unique = false; - long deleted; - colnr_T start_col; - colnr_T end_col; int sort_what = 0; // Sorting one line is really quick! @@ -484,7 +455,7 @@ void ex_sort(exarg_T *eap) size_t format_found = 0; bool change_occurred = false; // Buffer contents changed. - for (p = eap->arg; *p != NUL; p++) { + for (char *p = eap->arg; *p != NUL; p++) { if (ascii_iswhite(*p)) { // Skip } else if (*p == 'i') { @@ -517,7 +488,7 @@ void ex_sort(exarg_T *eap) eap->nextcmd = check_nextcmd(p); break; } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = skip_regexp_err(p + 1, *p, true); + char *s = skip_regexp_err(p + 1, *p, true); if (s == NULL) { goto sortend; } @@ -559,15 +530,15 @@ void ex_sort(exarg_T *eap) // numbers sorting it's the number to sort on. This means the pattern // matching and number conversion only has to be done once per line. // Also get the longest line length for allocating "sortbuf". - for (lnum = eap->line1; lnum <= eap->line2; lnum++) { - s = ml_get(lnum); - len = (int)strlen(s); + for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { + char *s = ml_get(lnum); + int len = (int)strlen(s); if (maxlen < len) { maxlen = len; } - start_col = 0; - end_col = len; + colnr_T start_col = 0; + colnr_T end_col = len; if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) { if (sort_rx) { start_col = (colnr_T)(regmatch.startp[0] - s); @@ -580,13 +551,13 @@ void ex_sort(exarg_T *eap) } if (sort_nr || sort_flt) { - // Make sure vim_str2nr doesn't read any digits past the end + // Make sure vim_str2nr() doesn't read any digits past the end // of the match, by temporarily terminating the string there - s2 = s + end_col; - c = *s2; + char *s2 = s + end_col; + char c = *s2; // temporary character storage *s2 = NUL; // Sorting on number: Store the number itself. - p = s + start_col; + char *p = s + start_col; if (sort_nr) { if (sort_what & STR2NR_HEX) { s = skiptohex(p); @@ -605,7 +576,7 @@ void ex_sort(exarg_T *eap) } else { nrs[lnum - eap->line1].st_u.num.is_number = true; vim_str2nr(s, NULL, NULL, sort_what, - &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false); + &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false, NULL); } } else { s = skipwhite(p); @@ -651,7 +622,7 @@ void ex_sort(exarg_T *eap) bcount_t old_count = 0, new_count = 0; // Insert the lines in the sorted order below the last one. - lnum = eap->line2; + linenr_T lnum = eap->line2; for (i = 0; i < count; i++) { const linenr_T get_lnum = nrs[eap->forceit ? count - i - 1 : i].lnum; @@ -661,14 +632,14 @@ void ex_sort(exarg_T *eap) change_occurred = true; } - s = ml_get(get_lnum); + char *s = ml_get(get_lnum); size_t bytelen = strlen(s) + 1; // include EOL in bytelen old_count += (bcount_t)bytelen; if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in // ml_append(). And it's needed for "unique". STRCPY(sortbuf1, s); - if (ml_append(lnum++, sortbuf1, (colnr_T)0, false) == FAIL) { + if (ml_append(lnum++, sortbuf1, 0, false) == FAIL) { break; } new_count += (bcount_t)bytelen; @@ -689,13 +660,12 @@ void ex_sort(exarg_T *eap) } // Adjust marks for deleted (or added) lines and prepare for displaying. - deleted = (long)count - (lnum - eap->line2); + linenr_T deleted = (linenr_T)count - (lnum - eap->line2); if (deleted > 0) { - mark_adjust(eap->line2 - (linenr_T)deleted, eap->line2, (long)MAXLNUM, (linenr_T)(-deleted), - kExtmarkNOOP); + mark_adjust(eap->line2 - deleted, eap->line2, MAXLNUM, -deleted, kExtmarkNOOP); msgmore(-deleted); } else if (deleted < 0) { - mark_adjust(eap->line2, MAXLNUM, (linenr_T)(-deleted), 0L, kExtmarkNOOP); + mark_adjust(eap->line2, MAXLNUM, -deleted, 0, kExtmarkNOOP); } if (change_occurred || deleted != 0) { @@ -703,7 +673,7 @@ void ex_sort(exarg_T *eap) (int)count, 0, old_count, lnum - eap->line2, 0, new_count, kExtmarkUndo); - changed_lines(eap->line1, 0, eap->line2 + 1, (linenr_T)(-deleted), true); + changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, -deleted, true); } curwin->w_cursor.lnum = eap->line1; @@ -724,7 +694,6 @@ sortend: /// @return FAIL for failure, OK otherwise int do_move(linenr_T line1, linenr_T line2, linenr_T dest) { - char *str; linenr_T l; linenr_T extra; // Num lines added before line1 linenr_T num_lines; // Num lines moved @@ -761,8 +730,8 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) return FAIL; } for (extra = 0, l = line1; l <= line2; l++) { - str = xstrdup(ml_get(l + extra)); - ml_append(dest + l - line1, str, (colnr_T)0, false); + char *str = xstrdup(ml_get(l + extra)); + ml_append(dest + l - line1, str, 0, false); xfree(str); if (dest < line1) { extra++; @@ -783,16 +752,16 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) // And Finally we adjust the marks we put at the end of the file back to // their final destination at the new text position -- webb last_line = curbuf->b_ml.ml_line_count; - mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP); + mark_adjust_nofold(line1, line2, last_line - line2, 0, kExtmarkNOOP); disable_fold_update++; - changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false); + changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, num_lines, false); disable_fold_update--; int line_off = 0; bcount_t byte_off = 0; if (dest >= line2) { - mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, kExtmarkNOOP); + mark_adjust_nofold(line2 + 1, dest, -num_lines, 0, kExtmarkNOOP); FOR_ALL_TAB_WINDOWS(tab, win) { if (win->w_buffer == curbuf) { foldMoveRange(win, &win->w_folds, line1, line2, dest); @@ -805,7 +774,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) line_off = -num_lines; byte_off = -extent_byte; } else { - mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, kExtmarkNOOP); + mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0, kExtmarkNOOP); FOR_ALL_TAB_WINDOWS(tab, win) { if (win->w_buffer == curbuf) { foldMoveRange(win, &win->w_folds, dest + 1, line1 - 1, line2); @@ -820,10 +789,10 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) curbuf->b_op_start.col = curbuf->b_op_end.col = 0; } mark_adjust_nofold(last_line - num_lines + 1, last_line, - -(last_line - dest - extra), 0L, kExtmarkNOOP); + -(last_line - dest - extra), 0, kExtmarkNOOP); disable_fold_update++; - changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false); + changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, -extra, false); disable_fold_update--; // send update regarding the new lines that were added @@ -838,8 +807,8 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) ml_delete(line1 + extra, true); } if (!global_busy && num_lines > p_report) { - smsg(NGETTEXT("%" PRId64 " line moved", - "%" PRId64 " lines moved", num_lines), + smsg(0, NGETTEXT("%" PRId64 " line moved", + "%" PRId64 " lines moved", num_lines), (int64_t)num_lines); } @@ -861,9 +830,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) if (dest > last_line + 1) { dest = last_line + 1; } - changed_lines(line1, 0, dest, 0L, false); + changed_lines(curbuf, line1, 0, dest, 0, false); } else { - changed_lines(dest + 1, 0, line1 + num_lines, 0L, false); + changed_lines(curbuf, dest + 1, 0, line1 + num_lines, 0, false); } // send nvim_buf_lines_event regarding lines that were deleted @@ -875,10 +844,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) /// ":copy" void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) { - linenr_T count; - char *p; - - count = line2 - line1 + 1; + linenr_T count = line2 - line1 + 1; if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { curbuf->b_op_start.lnum = n + 1; curbuf->b_op_end.lnum = n + count; @@ -902,8 +868,8 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) while (line1 <= line2) { // need to use xstrdup() because the line will be unlocked within // ml_append() - p = xstrdup(ml_get(line1)); - ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, false); + char *p = xstrdup(ml_get(line1)); + ml_append(curwin->w_cursor.lnum, p, 0, false); xfree(p); // situation 2: skip already copied lines @@ -925,7 +891,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) check_pos(curbuf, &VIsual); } - msgmore((long)count); + msgmore(count); } static char *prevcmd = NULL; // the previous command @@ -938,6 +904,17 @@ void free_prev_shellcmd(void) #endif +/// Check that "prevcmd" is not NULL. If it is NULL then give an error message +/// and return false. +static int prevcmd_is_set(void) +{ + if (prevcmd == NULL) { + emsg(_(e_noprev)); + return false; + } + return true; +} + /// Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd" /// Bangs in the argument are replaced with the previously entered command. /// Remember the argument. @@ -949,15 +926,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out linenr_T line2 = eap->line2; // end of range char *newcmd = NULL; // the new command bool free_newcmd = false; // need to free() newcmd - char *t; - char *p; - char *trailarg; - size_t len; int scroll_save = msg_scroll; - // // Disallow shell commands in secure mode - // if (check_secure()) { return; } @@ -973,21 +944,20 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out bool ins_prevcmd = forceit; // Skip leading white space to avoid a strange error with some shells. - trailarg = skipwhite(arg); + char *trailarg = skipwhite(arg); do { - len = strlen(trailarg) + 1; + size_t len = strlen(trailarg) + 1; if (newcmd != NULL) { len += strlen(newcmd); } if (ins_prevcmd) { - if (prevcmd == NULL) { - emsg(_(e_noprev)); + if (!prevcmd_is_set()) { xfree(newcmd); return; } len += strlen(prevcmd); } - t = xmalloc(len); + char *t = xmalloc(len); *t = NUL; if (newcmd != NULL) { STRCAT(t, newcmd); @@ -995,7 +965,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out if (ins_prevcmd) { STRCAT(t, prevcmd); } - p = t + strlen(t); + char *p = t + strlen(t); STRCAT(t, trailarg); xfree(newcmd); newcmd = t; @@ -1018,10 +988,20 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } } while (trailarg != NULL); - xfree(prevcmd); - prevcmd = newcmd; + // Only set "prevcmd" if there is a command to run, otherwise keep te one + // we have. + if (strlen(newcmd) > 0) { + xfree(prevcmd); + prevcmd = newcmd; + } else { + free_newcmd = true; + } if (bangredo) { // put cmd in redo buffer for ! command + if (!prevcmd_is_set()) { + goto theend; + } + // If % or # appears in the command, it must have been escaped. // Reescape them, so that redoing them does not substitute them by the // buffername. @@ -1034,6 +1014,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } // Add quotes around the command, for shells that need them. if (*p_shq != NUL) { + if (free_newcmd) { + xfree(newcmd); + } newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1); STRCPY(newcmd, p_shq); STRCAT(newcmd, prevcmd); @@ -1045,7 +1028,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out msg_start(); msg_putchar(':'); msg_putchar('!'); - msg_outtrans(newcmd); + msg_outtrans(newcmd, 0); msg_clr_eos(); ui_cursor_goto(msg_row, msg_col); @@ -1056,6 +1039,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out do_filter(line1, line2, eap, newcmd, do_in, do_out); apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, false, curbuf); } + +theend: if (free_newcmd) { xfree(newcmd); } @@ -1081,10 +1066,6 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b { char *itmp = NULL; char *otmp = NULL; - linenr_T linecount; - linenr_T read_linecount; - pos_T cursor_save; - char *cmd_buf; buf_T *old_curbuf = curbuf; int shell_flags = 0; const pos_T orig_start = curbuf->b_op_start; @@ -1100,12 +1081,12 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b // regions of the buffer for foldUpdate(), linecount, etc. cmdmod.cmod_flags &= ~CMOD_LOCKMARKS; - cursor_save = curwin->w_cursor; - linecount = line2 - line1 + 1; + pos_T cursor_save = curwin->w_cursor; + linenr_T linecount = line2 - line1 + 1; curwin->w_cursor.lnum = line1; curwin->w_cursor.col = 0; changed_line_abv_curs(); - invalidate_botline(); + invalidate_botline(curwin); // When using temp files: // 1. * Form temp file names @@ -1166,7 +1147,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b } // Create the shell command in allocated memory. - cmd_buf = make_filter_cmd(cmd, itmp, otmp); + char *cmd_buf = make_filter_cmd(cmd, itmp, otmp); ui_cursor_goto(Rows - 1, 0); if (do_out) { @@ -1176,7 +1157,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b } redraw_curbuf_later(UPD_VALID); } - read_linecount = curbuf->b_ml.ml_line_count; + linenr_T read_linecount = curbuf->b_ml.ml_line_count; // Pass on the kShellOptDoOut flag when the output is being redirected. call_shell(cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL); @@ -1193,7 +1174,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b if (do_out) { if (otmp != NULL) { - if (readfile(otmp, NULL, line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, + if (readfile(otmp, NULL, line2, 0, (linenr_T)MAXLNUM, eap, READ_FILTER, false) != OK) { if (!aborting()) { msg_putchar('\n'); @@ -1222,13 +1203,13 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b // end of each line? if (read_linecount >= linecount) { // move all marks from old lines to new lines - mark_adjust(line1, line2, linecount, 0L, kExtmarkNOOP); + mark_adjust(line1, line2, linecount, 0, kExtmarkNOOP); } else { // move marks from old lines to new lines, delete marks // that are in deleted lines - mark_adjust(line1, line1 + read_linecount - 1, linecount, 0L, + mark_adjust(line1, line1 + read_linecount - 1, linecount, 0, kExtmarkNOOP); - mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0L, + mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0, kExtmarkNOOP); } } @@ -1255,12 +1236,12 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b if (do_in) { vim_snprintf(msg_buf, sizeof(msg_buf), _("%" PRId64 " lines filtered"), (int64_t)linecount); - if (msg(msg_buf) && !msg_scroll) { + if (msg(msg_buf, 0) && !msg_scroll) { // save message to display it after redraw set_keep_msg(msg_buf, 0); } } else { - msgmore((long)linecount); + msgmore(linecount); } } } else { @@ -1325,7 +1306,9 @@ void do_shell(char *cmd, int flags) // 1" command to the terminal. ui_cursor_goto(msg_row, msg_col); (void)call_shell(cmd, (ShellOpts)flags, NULL); - msg_didout = true; + if (msg_silent == 0) { + msg_didout = true; + } did_check_timestamps = false; need_check_timestamps = true; @@ -1367,12 +1350,12 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) { bool is_fish_shell = #if defined(UNIX) - strncmp((char *)invocation_path_tail(p_sh, NULL), "fish", 4) == 0; + strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; #else false; #endif - bool is_pwsh = strncmp((char *)invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 - || strncmp((char *)invocation_path_tail(p_sh, NULL), "powershell", + bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 + || strncmp(invocation_path_tail(p_sh, NULL), "powershell", 10) == 0; size_t len = strlen(cmd) + 1; // At least enough space for cmd + NULL. @@ -1382,8 +1365,8 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) : 0; if (itmp != NULL) { - len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + 6 // +6: #20530 - : strlen(itmp) + sizeof(" { " " < " " } ") - 1; + len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + 6 // +6: #20530 + : strlen(itmp) + sizeof(" { " " < " " } ") - 1; } if (otmp != NULL) { len += strlen(otmp) + strlen(p_srr) + 2; // two extra spaces (" "), @@ -1394,7 +1377,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) if (is_pwsh) { if (itmp != NULL) { xstrlcpy(buf, "& { Get-Content ", len - 1); // FIXME: should we add "-Encoding utf8"? - xstrlcat(buf, (const char *)itmp, len - 1); + xstrlcat(buf, itmp, len - 1); xstrlcat(buf, " | & ", len - 1); // FIXME: add `&` ourself or leave to user? xstrlcat(buf, cmd, len - 1); xstrlcat(buf, " }", len - 1); @@ -1407,7 +1390,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) // redirecting input and/or output. if (itmp != NULL || otmp != NULL) { char *fmt = is_fish_shell ? "begin; %s; end" - : "(%s)"; + : "(%s)"; vim_snprintf(buf, len, fmt, cmd); } else { xstrlcpy(buf, cmd, len); @@ -1415,7 +1398,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) if (itmp != NULL) { xstrlcat(buf, " < ", len - 1); - xstrlcat(buf, (const char *)itmp, len - 1); + xstrlcat(buf, itmp, len - 1); } #else // For shells that don't understand braces around commands, at least allow @@ -1432,9 +1415,9 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) } } xstrlcat(buf, " < ", len); - xstrlcat(buf, (const char *)itmp, len); + xstrlcat(buf, itmp, len); if (*p_shq == NUL) { - const char *const p = find_pipe((const char *)cmd); + const char *const p = find_pipe(cmd); if (p != NULL) { xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS xstrlcat(buf, p, len - 1); @@ -1507,7 +1490,6 @@ void print_line(linenr_T lnum, int use_number, int list) print_line_no_prefix(lnum, use_number, list); if (save_silent) { msg_putchar('\n'); - ui_flush(); silent_mode = save_silent; } info_message = false; @@ -1515,10 +1497,7 @@ void print_line(linenr_T lnum, int use_number, int list) int rename_buffer(char *new_fname) { - char *fname, *sfname, *xfname; - buf_T *buf; - - buf = curbuf; + buf_T *buf = curbuf; apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); // buffer changed, don't change name now if (buf != curbuf) { @@ -1532,9 +1511,9 @@ int rename_buffer(char *new_fname) // name, which will become the alternate file name. // But don't set the alternate file name if the buffer didn't have a // name. - fname = curbuf->b_ffname; - sfname = curbuf->b_sfname; - xfname = curbuf->b_fname; + char *fname = curbuf->b_ffname; + char *sfname = curbuf->b_sfname; + char *xfname = curbuf->b_fname; curbuf->b_ffname = NULL; curbuf->b_sfname = NULL; if (setfname(curbuf, new_fname, NULL, true) == FAIL) { @@ -1628,17 +1607,15 @@ int do_write(exarg_T *eap) { int other; char *fname = NULL; // init to shut up gcc - char *ffname; int retval = FAIL; char *free_fname = NULL; buf_T *alt_buf = NULL; - int name_was_missing; if (not_writing()) { // check 'write' option return FAIL; } - ffname = eap->arg; + char *ffname = eap->arg; if (*ffname == NUL) { if (eap->cmdidx == CMD_saveas) { emsg(_(e_argreq)); @@ -1660,7 +1637,7 @@ int do_write(exarg_T *eap) if (other) { if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL || eap->cmdidx == CMD_saveas) { - alt_buf = setaltfname(ffname, fname, (linenr_T)1); + alt_buf = setaltfname(ffname, fname, 1); } else { alt_buf = buflist_findname(ffname); } @@ -1764,7 +1741,7 @@ int do_write(exarg_T *eap) } } - name_was_missing = curbuf->b_ffname == NULL; + int name_was_missing = curbuf->b_ffname == NULL; retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2, eap, eap->append, eap->forceit, true, false); @@ -1824,7 +1801,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { char buff[DIALOG_MSG_SIZE]; - dialog_msg((char *)buff, _("Overwrite existing file \"%s\"?"), fname); + dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) { return FAIL; } @@ -1860,7 +1837,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { char buff[DIALOG_MSG_SIZE]; - dialog_msg((char *)buff, + dialog_msg(buff, _("Swap file \"%s\" exists, overwrite anyway?"), swapname); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) @@ -1906,6 +1883,9 @@ void do_wqall(exarg_T *eap) int save_forceit = eap->forceit; if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall) { + if (before_quit_all(eap) == FAIL) { + return; + } exiting = t |