aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_cmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_cmds.c')
-rw-r--r--src/nvim/ex_cmds.c1327
1 files changed, 554 insertions, 773 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 06a372bb93..437a05f61d 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1,25 +1,30 @@
// 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
- */
+// ex_cmds.c: some functions for command line commands
#include <assert.h>
+#include <ctype.h>
#include <float.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
-#include "nvim/api/buffer.h"
-#include "nvim/api/private/defs.h"
+#include "auto/config.h"
+#include "klib/kvec.h"
#include "nvim/arglist.h"
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/buffer_updates.h"
#include "nvim/change.h"
+#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
@@ -29,22 +34,27 @@
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/garray.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.h"
+#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/input.h"
-#include "nvim/log.h"
+#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -57,21 +67,22 @@
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
+#include "nvim/os/fs_defs.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/os/time.h"
-#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/plines.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/strings.h"
-#include "nvim/syntax.h"
-#include "nvim/tag.h"
+#include "nvim/terminal.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
@@ -147,14 +158,14 @@ void do_ascii(const exarg_T *const eap)
char buf2[20];
buf2[0] = NUL;
- dig = (char *)get_digraph_for_char(cval);
+ dig = get_digraph_for_char(cval);
if (dig != NULL) {
- iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len,
+ 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);
} else {
- iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len,
+ 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);
@@ -193,18 +204,18 @@ void do_ascii(const exarg_T *const eap)
if (utf_iscomposing(c)) {
IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space.
}
- iobuff_len += (size_t)utf_char2bytes(c, (char *)IObuff + iobuff_len);
+ iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len);
- dig = (char *)get_digraph_for_char(c);
+ dig = get_digraph_for_char(c);
if (dig != NULL) {
- iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len,
+ 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);
} else {
- iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len,
+ iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len,
sizeof(IObuff) - iobuff_len,
(c < 0x10000
? _("> %d, Hex %04x, Octal %o")
@@ -217,10 +228,10 @@ void do_ascii(const exarg_T *const eap)
c = cc[ci++];
}
if (ci != MAX_MCO && c != 0) {
- xstrlcpy((char *)IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len);
+ xstrlcpy(IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len);
}
- msg((char *)IObuff);
+ msg(IObuff);
}
/// ":left", ":center" and ":right": align text.
@@ -249,11 +260,9 @@ void ex_align(exarg_T *eap)
indent = width;
}
} else {
- /*
- * if 'textwidth' set, use it
- * else if 'wrapmargin' set, use it
- * if invalid value, use 80
- */
+ // if 'textwidth' set, use it
+ // else if 'wrapmargin' set, use it
+ // if invalid value, use 80
if (width <= 0) {
width = (int)curbuf->b_p_tw;
}
@@ -270,13 +279,12 @@ void ex_align(exarg_T *eap)
}
for (curwin->w_cursor.lnum = eap->line1;
- curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum) {
+ curwin->w_cursor.lnum <= eap->line2; curwin->w_cursor.lnum++) {
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();
+ has_tab = false; // avoid uninit warnings
+ len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent();
if (len <= 0) { // skip blank lines
continue;
@@ -287,18 +295,14 @@ void ex_align(exarg_T *eap)
} else {
new_indent = width - len; // right align
- /*
- * Make sure that embedded TABs don't make the text go too far
- * to the right.
- */
+ // Make sure that embedded TABs don't make the text go too far
+ // to the right.
if (has_tab) {
while (new_indent > 0) {
(void)set_indent(new_indent, 0);
if (linelen(NULL) <= width) {
- /*
- * Now try to move the line as much as possible to
- * the right. Stop when it moves too far.
- */
+ // Now try to move the line as much as possible to
+ // the right. Stop when it moves too far.
do {
(void)set_indent(++new_indent, 0);
} while (linelen(NULL) <= width);
@@ -330,7 +334,7 @@ static int linelen(int *has_tab)
// Get the line. If it's empty bail out early (could be the empty string
// for an unloaded buffer).
- line = (char *)get_cursor_line_ptr();
+ line = get_cursor_line_ptr();
if (*line == NUL) {
return 0;
}
@@ -338,12 +342,12 @@ static int linelen(int *has_tab)
first = skipwhite(line);
// find the character after the last non-blank character
- for (last = first + STRLEN(first);
+ for (last = first + strlen(first);
last > first && ascii_iswhite(last[-1]); last--) {}
char save = *last;
*last = NUL;
// Get line length.
- len = linetabsize((char_u *)line);
+ len = linetabsize(line);
// Check for embedded TAB.
if (has_tab != NULL) {
*has_tab = vim_strchr(first, TAB) != NULL;
@@ -387,7 +391,7 @@ static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL
if (sort_lc) {
return strcoll((char *)s1, (char *)s2);
}
- return sort_ic ? STRICMP(s1, s2) : STRCMP(s1, s2);
+ return sort_ic ? STRICMP(s1, s2) : strcmp(s1, s2);
}
static int sort_compare(const void *s1, const void *s2)
@@ -404,7 +408,7 @@ static int sort_compare(const void *s1, const void *s2)
}
fast_breakcheck();
if (got_int) {
- sort_abort = TRUE;
+ sort_abort = true;
}
// When sorting numbers "start_col_nr" is the number, not the column
@@ -509,13 +513,12 @@ void ex_sort(exarg_T *eap)
} else if (*p == '"') {
// comment start
break;
- } else if (check_nextcmd((char_u *)p) != NULL) {
- eap->nextcmd = (char *)check_nextcmd((char_u *)p);
+ } else if (check_nextcmd(p) != NULL) {
+ eap->nextcmd = check_nextcmd(p);
break;
} else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) {
- s = (char *)skip_regexp((char_u *)p + 1, *p, true, NULL);
- if (*s != *p) {
- emsg(_(e_invalpat));
+ s = skip_regexp_err(p + 1, *p, true);
+ if (s == NULL) {
goto sortend;
}
*s = NUL;
@@ -525,7 +528,7 @@ void ex_sort(exarg_T *eap)
emsg(_(e_noprevre));
goto sortend;
}
- regmatch.regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC);
+ regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
} else {
regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
}
@@ -557,8 +560,8 @@ void ex_sort(exarg_T *eap)
// 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 = (char *)ml_get(lnum);
- len = (int)STRLEN(s);
+ s = ml_get(lnum);
+ len = (int)strlen(s);
if (maxlen < len) {
maxlen = len;
}
@@ -567,10 +570,10 @@ void ex_sort(exarg_T *eap)
end_col = len;
if (regmatch.regprog != NULL && vim_regexec(&regmatch, s, 0)) {
if (sort_rx) {
- start_col = (colnr_T)(regmatch.startp[0] - (char_u *)s);
- end_col = (colnr_T)(regmatch.endp[0] - (char_u *)s);
+ start_col = (colnr_T)(regmatch.startp[0] - s);
+ end_col = (colnr_T)(regmatch.endp[0] - s);
} else {
- start_col = (colnr_T)(regmatch.endp[0] - (char_u *)s);
+ start_col = (colnr_T)(regmatch.endp[0] - s);
}
} else if (regmatch.regprog != NULL) {
end_col = 0;
@@ -586,11 +589,11 @@ void ex_sort(exarg_T *eap)
p = s + start_col;
if (sort_nr) {
if (sort_what & STR2NR_HEX) {
- s = (char *)skiptohex((char_u *)p);
+ s = skiptohex(p);
} else if (sort_what & STR2NR_BIN) {
s = (char *)skiptobin(p);
} else {
- s = (char *)skiptodigit((char_u *)p);
+ s = skiptodigit(p);
}
if (s > p && s[-1] == '-') {
s--; // include preceding negative sign
@@ -601,7 +604,7 @@ void ex_sort(exarg_T *eap)
nrs[lnum - eap->line1].st_u.num.value = 0;
} else {
nrs[lnum - eap->line1].st_u.num.is_number = true;
- vim_str2nr((char_u *)s, NULL, NULL, sort_what,
+ vim_str2nr(s, NULL, NULL, sort_what,
&nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false);
}
} else {
@@ -658,8 +661,8 @@ void ex_sort(exarg_T *eap)
change_occurred = true;
}
- s = (char *)ml_get(get_lnum);
- size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen
+ 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
@@ -678,7 +681,7 @@ void ex_sort(exarg_T *eap)
// delete the original lines if appending worked
if (i == count) {
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
ml_delete(eap->line1, false);
}
} else {
@@ -716,187 +719,6 @@ sortend:
}
}
-/// ":retab".
-void ex_retab(exarg_T *eap)
-{
- linenr_T lnum;
- bool got_tab = false;
- long num_spaces = 0;
- long num_tabs;
- long len;
- long col;
- long vcol;
- long start_col = 0; // For start of white-space string
- long start_vcol = 0; // For start of white-space string
- long old_len;
- char *ptr;
- char *new_line = (char *)1; // init to non-NULL
- bool did_undo; // called u_save for current line
- long *new_vts_array = NULL;
- char *new_ts_str; // string value of tab argument
-
- int save_list;
- linenr_T first_line = 0; // first changed line
- linenr_T last_line = 0; // last changed line
-
- save_list = curwin->w_p_list;
- curwin->w_p_list = 0; // don't want list mode here
-
- new_ts_str = eap->arg;
- if (!tabstop_set((char_u *)eap->arg, &new_vts_array)) {
- return;
- }
- while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') {
- (eap->arg)++;
- }
-
- // This ensures that either new_vts_array and new_ts_str are freshly
- // allocated, or new_vts_array points to an existing array and new_ts_str
- // is null.
- if (new_vts_array == NULL) {
- new_vts_array = curbuf->b_p_vts_array;
- new_ts_str = NULL;
- } else {
- new_ts_str = xstrnsave(new_ts_str, (size_t)(eap->arg - new_ts_str));
- }
- for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) {
- ptr = (char *)ml_get(lnum);
- col = 0;
- vcol = 0;
- did_undo = false;
- for (;;) {
- if (ascii_iswhite(ptr[col])) {
- if (!got_tab && num_spaces == 0) {
- // First consecutive white-space
- start_vcol = vcol;
- start_col = col;
- }
- if (ptr[col] == ' ') {
- num_spaces++;
- } else {
- got_tab = true;
- }
- } else {
- if (got_tab || (eap->forceit && num_spaces > 1)) {
- // Retabulate this string of white-space
-
- // len is virtual length of white string
- len = num_spaces = vcol - start_vcol;
- num_tabs = 0;
- if (!curbuf->b_p_et) {
- int t, s;
-
- tabstop_fromto((colnr_T)start_vcol, (colnr_T)vcol,
- curbuf->b_p_ts, new_vts_array, &t, &s);
- num_tabs = t;
- num_spaces = s;
- }
- if (curbuf->b_p_et || got_tab
- || (num_spaces + num_tabs < len)) {
- if (did_undo == false) {
- did_undo = true;
- if (u_save((linenr_T)(lnum - 1),
- (linenr_T)(lnum + 1)) == FAIL) {
- new_line = NULL; // flag out-of-memory
- break;
- }
- }
-
- // len is actual number of white characters used
- len = num_spaces + num_tabs;
- old_len = (long)STRLEN(ptr);
- const long new_len = old_len - col + start_col + len + 1;
- if (new_len <= 0 || new_len >= MAXCOL) {
- emsg(_(e_resulting_text_too_long));
- break;
- }
- new_line = xmalloc((size_t)new_len);
-
- if (start_col > 0) {
- memmove(new_line, ptr, (size_t)start_col);
- }
- memmove(new_line + start_col + len,
- ptr + col, (size_t)(old_len - col + 1));
- ptr = new_line + start_col;
- for (col = 0; col < len; col++) {
- ptr[col] = (col < num_tabs) ? '\t' : ' ';
- }
- if (ml_replace(lnum, new_line, false) == OK) {
- // "new_line" may have been copied
- new_line = (char *)curbuf->b_ml.ml_line_ptr;
- extmark_splice_cols(curbuf, lnum - 1, 0, (colnr_T)old_len,
- (colnr_T)new_len - 1, kExtmarkUndo);
- }
- if (first_line == 0) {
- first_line = lnum;
- }
- last_line = lnum;
- ptr = new_line;
- col = start_col + len;
- }
- }
- got_tab = false;
- num_spaces = 0;
- }
- if (ptr[col] == NUL) {
- break;
- }
- vcol += win_chartabsize(curwin, (char_u *)ptr + col, (colnr_T)vcol);
- if (vcol >= MAXCOL) {
- emsg(_(e_resulting_text_too_long));
- break;
- }
- col += utfc_ptr2len(ptr + col);
- }
- if (new_line == NULL) { // out of memory
- break;
- }
- line_breakcheck();
- }
- if (got_int) {
- emsg(_(e_interr));
- }
-
- // If a single value was given then it can be considered equal to
- // either the value of 'tabstop' or the value of 'vartabstop'.
- if (tabstop_count(curbuf->b_p_vts_array) == 0
- && tabstop_count(new_vts_array) == 1
- && curbuf->b_p_ts == tabstop_first(new_vts_array)) {
- // not changed
- } else if (tabstop_count(curbuf->b_p_vts_array) > 0
- && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) {
- // not changed
- } else {
- redraw_curbuf_later(NOT_VALID);
- }
- if (first_line != 0) {
- changed_lines(first_line, 0, last_line + 1, 0L, true);
- }
-
- curwin->w_p_list = save_list; // restore 'list'
-
- if (new_ts_str != NULL) { // set the new tabstop
- // If 'vartabstop' is in use or if the value given to retab has more
- // than one tabstop then update 'vartabstop'.
- long *old_vts_ary = curbuf->b_p_vts_array;
-
- if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) {
- set_string_option_direct("vts", -1, new_ts_str, OPT_FREE | OPT_LOCAL, 0);
- curbuf->b_p_vts_array = new_vts_array;
- xfree(old_vts_ary);
- } else {
- // 'vartabstop' wasn't in use and a single value was given to
- // retab then update 'tabstop'.
- curbuf->b_p_ts = tabstop_first(new_vts_array);
- xfree(new_vts_array);
- }
- xfree(new_ts_str);
- }
- coladvance(curwin->w_curswant);
-
- u_clearline();
-}
-
/// :move command - move lines line1-line2 to line dest
///
/// @return FAIL for failure, OK otherwise
@@ -933,15 +755,13 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
num_lines = line2 - line1 + 1;
- /*
- * First we copy the old text to its new location -- webb
- * Also copy the flag that ":global" command uses.
- */
+ // First we copy the old text to its new location -- webb
+ // Also copy the flag that ":global" command uses.
if (u_save(dest, dest + 1) == FAIL) {
return FAIL;
}
for (extra = 0, l = line1; l <= line2; l++) {
- str = (char *)vim_strsave(ml_get(l + extra));
+ str = xstrdup(ml_get(l + extra));
ml_append(dest + l - line1, str, (colnr_T)0, false);
xfree(str);
if (dest < line1) {
@@ -949,21 +769,19 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
}
}
- /*
- * Now we must be careful adjusting our marks so that we don't overlap our
- * mark_adjust() calls.
- *
- * We adjust the marks within the old text so that they refer to the
- * last lines of the file (temporarily), because we know no other marks
- * will be set there since these line numbers did not exist until we added
- * our new lines.
- *
- * Then we adjust the marks on lines between the old and new text positions
- * (either forwards or backwards).
- *
- * 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
- */
+ // Now we must be careful adjusting our marks so that we don't overlap our
+ // mark_adjust() calls.
+ //
+ // We adjust the marks within the old text so that they refer to the
+ // last lines of the file (temporarily), because we know no other marks
+ // will be set there since these line numbers did not exist until we added
+ // our new lines.
+ //
+ // Then we adjust the marks on lines between the old and new text positions
+ // (either forwards or backwards).
+ //
+ // 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);
@@ -1011,9 +829,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
// send update regarding the new lines that were added
buf_updates_send_changes(curbuf, dest + 1, num_lines, 0);
- /*
- * Now we delete the original text -- webb
- */
+ // Now we delete the original text -- webb
if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) {
return FAIL;
}
@@ -1022,7 +838,9 @@ 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("1 line moved", "%" PRId64 " lines moved", num_lines), (int64_t)num_lines);
+ smsg(NGETTEXT("%" PRId64 " line moved",
+ "%" PRId64 " lines moved", num_lines),
+ (int64_t)num_lines);
}
extmark_move_region(curbuf, line1 - 1, 0, start_byte,
@@ -1030,9 +848,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
dest + line_off, 0, dest_byte + byte_off,
kExtmarkUndo);
- /*
- * Leave the cursor on the last of the moved lines.
- */
+ // Leave the cursor on the last of the moved lines.
if (dest >= line1) {
curwin->w_cursor.lnum = dest;
} else {
@@ -1069,26 +885,24 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
}
- /*
- * there are three situations:
- * 1. destination is above line1
- * 2. destination is between line1 and line2
- * 3. destination is below line2
- *
- * n = destination (when starting)
- * curwin->w_cursor.lnum = destination (while copying)
- * line1 = start of source (while copying)
- * line2 = end of source (while copying)
- */
+ // there are three situations:
+ // 1. destination is above line1
+ // 2. destination is between line1 and line2
+ // 3. destination is below line2
+ //
+ // n = destination (when starting)
+ // curwin->w_cursor.lnum = destination (while copying)
+ // line1 = start of source (while copying)
+ // line2 = end of source (while copying)
if (u_save(n, n + 1) == FAIL) {
return;
}
curwin->w_cursor.lnum = n;
while (line1 <= line2) {
- // need to use vim_strsave() because the line will be unlocked within
+ // need to use xstrdup() because the line will be unlocked within
// ml_append()
- p = (char *)vim_strsave(ml_get(line1));
+ p = xstrdup(ml_get(line1));
ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, false);
xfree(p);
@@ -1103,7 +917,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
if (curwin->w_cursor.lnum < line2) {
line2++;
}
- ++curwin->w_cursor.lnum;
+ curwin->w_cursor.lnum++;
}
appended_lines_mark(n, count);
@@ -1142,29 +956,28 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
int scroll_save = msg_scroll;
//
- // Disallow shell commands from .exrc and .vimrc in current directory for
- // security reasons.
+ // Disallow shell commands in secure mode
//
if (check_secure()) {
return;
}
if (addr_count == 0) { // :!
- msg_scroll = FALSE; // don't scroll here
+ msg_scroll = false; // don't scroll here
autowrite_all();
msg_scroll = scroll_save;
}
- /*
- * Try to find an embedded bang, like in :!<cmd> ! [args]
- * (:!! is indicated by the 'forceit' variable)
- */
+ // Try to find an embedded bang, like in ":!<cmd> ! [args]"
+ // ":!!" is indicated by the 'forceit' variable.
bool ins_prevcmd = forceit;
- trailarg = arg;
+
+ // Skip leading white space to avoid a strange error with some shells.
+ trailarg = skipwhite(arg);
do {
- len = STRLEN(trailarg) + 1;
+ len = strlen(trailarg) + 1;
if (newcmd != NULL) {
- len += STRLEN(newcmd);
+ len += strlen(newcmd);
}
if (ins_prevcmd) {
if (prevcmd == NULL) {
@@ -1172,7 +985,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
xfree(newcmd);
return;
}
- len += STRLEN(prevcmd);
+ len += strlen(prevcmd);
}
t = xmalloc(len);
*t = NUL;
@@ -1182,15 +995,13 @@ 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);
+ p = t + strlen(t);
STRCAT(t, trailarg);
xfree(newcmd);
newcmd = t;
- /*
- * Scan the rest of the argument for '!', which is replaced by the
- * previous command. "\!" is replaced by "!" (this is vi compatible).
- */
+ // Scan the rest of the argument for '!', which is replaced by the
+ // previous command. "\!" is replaced by "!" (this is vi compatible).
trailarg = NULL;
while (*p) {
if (*p == '!') {
@@ -1214,18 +1025,16 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
// If % or # appears in the command, it must have been escaped.
// Reescape them, so that redoing them does not substitute them by the
// buffername.
- char *cmd = (char *)vim_strsave_escaped((char_u *)prevcmd, (char_u *)"%#");
+ char *cmd = vim_strsave_escaped(prevcmd, "%#");
AppendToRedobuffLit(cmd, -1);
xfree(cmd);
AppendToRedobuff("\n");
bangredo = false;
}
- /*
- * Add quotes around the command, for shells that need them.
- */
+ // Add quotes around the command, for shells that need them.
if (*p_shq != NUL) {
- newcmd = xmalloc(STRLEN(prevcmd) + 2 * STRLEN(p_shq) + 1);
+ newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1);
STRCPY(newcmd, p_shq);
STRCAT(newcmd, prevcmd);
STRCAT(newcmd, p_shq);
@@ -1298,18 +1107,16 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
changed_line_abv_curs();
invalidate_botline();
- /*
- * When using temp files:
- * 1. * Form temp file names
- * 2. * Write the lines to a temp file
- * 3. Run the filter command on the temp file
- * 4. * Read the output of the command into the buffer
- * 5. * Delete the original lines to be filtered
- * 6. * Remove the temp files
- *
- * When writing the input with a pipe or when catching the output with a
- * pipe only need to do 3.
- */
+ // When using temp files:
+ // 1. * Form temp file names
+ // 2. * Write the lines to a temp file
+ // 3. Run the filter command on the temp file
+ // 4. * Read the output of the command into the buffer
+ // 5. * Delete the original lines to be filtered
+ // 6. * Remove the temp files
+ //
+ // When writing the input with a pipe or when catching the output with a
+ // pipe only need to do 3.
if (do_out) {
shell_flags |= kShellOptDoOut;
@@ -1331,23 +1138,22 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
curbuf->b_op_start.lnum = line1;
curbuf->b_op_end.lnum = line2;
curwin->w_cursor.lnum = line2;
- } else if ((do_in && (itmp = (char *)vim_tempname()) == NULL)
- || (do_out && (otmp = (char *)vim_tempname()) == NULL)) {
+ } else if ((do_in && (itmp = vim_tempname()) == NULL)
+ || (do_out && (otmp = vim_tempname()) == NULL)) {
emsg(_(e_notmp));
goto filterend;
}
- /*
- * The writing and reading of temp files will not be shown.
- * Vi also doesn't do this and the messages are not very informative.
- */
+ // The writing and reading of temp files will not be shown.
+ // Vi also doesn't do this and the messages are not very informative.
no_wait_return++; // don't call wait_return() while busy
if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap,
false, false, false, true) == FAIL) {
msg_putchar('\n'); // Keep message from buf_write().
no_wait_return--;
if (!aborting()) {
- semsg(_("E482: Can't create file %s"), itmp); // Will call wait_return.
+ // will call wait_return()
+ semsg(_("E482: Can't create file %s"), itmp);
}
goto filterend;
}
@@ -1368,22 +1174,22 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
xfree(cmd_buf);
goto error;
}
- redraw_curbuf_later(VALID);
+ redraw_curbuf_later(UPD_VALID);
}
read_linecount = curbuf->b_ml.ml_line_count;
// Pass on the kShellOptDoOut flag when the output is being redirected.
- call_shell((char_u *)cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL);
+ call_shell(cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL);
xfree(cmd_buf);
- did_check_timestamps = FALSE;
- need_check_timestamps = TRUE;
+ did_check_timestamps = false;
+ need_check_timestamps = true;
// When interrupting the shell command, it may still have produced some
// useful output. Reset got_int here, so that readfile() won't cancel
// reading.
os_breakcheck();
- got_int = FALSE;
+ got_int = false;
if (do_out) {
if (otmp != NULL) {
@@ -1427,10 +1233,8 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
}
}
- /*
- * Put cursor on first filtered line for ":range!cmd".
- * Adjust '[ and '] (set by buf_write()).
- */
+ // Put cursor on first filtered line for ":range!cmd".
+ // Adjust '[ and '] (set by buf_write()).
curwin->w_cursor.lnum = line1;
del_lines(linecount, true);
curbuf->b_op_start.lnum -= linecount; // adjust '[
@@ -1439,9 +1243,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
// for next write
foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum);
} else {
- /*
- * Put cursor on last new line for ":r !cmd".
- */
+ // Put cursor on last new line for ":r !cmd".
linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
}
@@ -1496,17 +1298,14 @@ filterend:
/// @param flags may be SHELL_DOOUT when output is redirected
void do_shell(char *cmd, int flags)
{
- // Disallow shell commands from .exrc and .vimrc in current directory for
- // security reasons.
+ // Disallow shell commands in secure mode
if (check_secure()) {
msg_end();
return;
}
- /*
- * For autocommands we want to get the output on the current screen, to
- * avoid having to type return below.
- */
+ // For autocommands we want to get the output on the current screen, to
+ // avoid having to type return below.
msg_putchar('\r'); // put cursor at start of line
msg_putchar('\n'); // may shift screen one line up
@@ -1525,7 +1324,7 @@ void do_shell(char *cmd, int flags)
// This ui_cursor_goto is required for when the '\n' resulted in a "delete line
// 1" command to the terminal.
ui_cursor_goto(msg_row, msg_col);
- (void)call_shell((char_u *)cmd, (ShellOpts)flags, NULL);
+ (void)call_shell(cmd, (ShellOpts)flags, NULL);
msg_didout = true;
did_check_timestamps = false;
need_check_timestamps = true;
@@ -1545,11 +1344,11 @@ static char *find_pipe(const char *cmd)
for (const char *p = cmd; *p != NUL; p++) {
if (!inquote && *p == '|') {
- return p;
+ return (char *)p;
}
if (*p == '"') {
inquote = !inquote;
- } else if (rem_backslash((const char_u *)p)) {
+ } else if (rem_backslash(p)) {
p++;
}
}
@@ -1568,95 +1367,84 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
{
bool is_fish_shell =
#if defined(UNIX)
- STRNCMP(invocation_path_tail(p_sh, NULL), "fish", 4) == 0;
+ strncmp((char *)invocation_path_tail(p_sh, NULL), "fish", 4) == 0;
#else
false;
#endif
- bool is_pwsh = STRNCMP(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0
- || STRNCMP(invocation_path_tail(p_sh, NULL), "powershell", 10) == 0;
+ bool is_pwsh = strncmp((char *)invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0
+ || strncmp((char *)invocation_path_tail(p_sh, NULL), "powershell",
+ 10) == 0;
- size_t len = STRLEN(cmd) + 1; // At least enough space for cmd + NULL.
+ size_t len = strlen(cmd) + 1; // At least enough space for cmd + NULL.
- len += is_fish_shell ? sizeof("begin; " "; end") - 1
- : is_pwsh ? sizeof("Start-Process ")
- : sizeof("(" ")") - 1;
+ len += is_fish_shell ? sizeof("begin; " "; end") - 1
+ : !is_pwsh ? sizeof("(" ")") - 1
+ : 0;
if (itmp != NULL) {
- len += is_pwsh ? STRLEN(itmp) + sizeof(" -RedirectStandardInput ")
- : 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 (" "),
+ len += strlen(otmp) + strlen(p_srr) + 2; // two extra spaces (" "),
}
- const char *const cmd_args = strchr(cmd, ' ');
- len += (is_pwsh && cmd_args)
- ? STRLEN(" -ArgumentList ") + 2 // two extra quotes
- : 0;
-
char *const buf = xmalloc(len);
if (is_pwsh) {
- xstrlcpy(buf, "Start-Process ", len);
- if (cmd_args == NULL) {
- xstrlcat(buf, cmd, len);
+ if (itmp != NULL) {
+ xstrlcpy(buf, "& { Get-Content ", len - 1); // FIXME: should we add "-Encoding utf8"?
+ xstrlcat(buf, (const char *)itmp, len - 1);
+ xstrlcat(buf, " | & ", len - 1); // FIXME: add `&` ourself or leave to user?
+ xstrlcat(buf, cmd, len - 1);
+ xstrlcat(buf, " }", len - 1);
} else {
- xstrlcpy(buf + STRLEN(buf), cmd, (size_t)(cmd_args - cmd + 1));
- xstrlcat(buf, " -ArgumentList \"", len);
- xstrlcat(buf, cmd_args + 1, len); // +1 to skip the leading space.
- xstrlcat(buf, "\"", len);
+ xstrlcpy(buf, cmd, len - 1);
}
+ } else {
#if defined(UNIX)
// Put delimiters around the command (for concatenated commands) when
// redirecting input and/or output.
- } else if (itmp != NULL || otmp != NULL) {
- char *fmt = is_fish_shell ? "begin; %s; end"
- : "(%s)";
- vim_snprintf(buf, len, fmt, cmd);
-#endif
- // For shells that don't understand braces around commands, at least allow
- // the use of commands in a pipe.
- } else {
- xstrlcpy(buf, cmd, len);
- }
-
-#if defined(UNIX)
- if (itmp != NULL) {
- if (is_pwsh) {
- xstrlcat(buf, " -RedirectStandardInput ", len - 1);
+ if (itmp != NULL || otmp != NULL) {
+ char *fmt = is_fish_shell ? "begin; %s; end"
+ : "(%s)";
+ vim_snprintf(buf, len, fmt, cmd);
} else {
+ xstrlcpy(buf, cmd, len);
+ }
+
+ if (itmp != NULL) {
xstrlcat(buf, " < ", len - 1);
+ xstrlcat(buf, (const char *)itmp, len - 1);
}
- xstrlcat(buf, itmp, len - 1);
- }
#else
- if (itmp != NULL) {
- // If there is a pipe, we have to put the '<' in front of it.
- // Don't do this when 'shellquote' is not empty, otherwise the
- // redirection would be inside the quotes.
- if (*p_shq == NUL) {
- char *const p = find_pipe(buf);
- if (p != NULL) {
- *p = NUL;
+ // For shells that don't understand braces around commands, at least allow
+ // the use of commands in a pipe.
+ xstrlcpy(buf, cmd, len);
+ if (itmp != NULL) {
+ // If there is a pipe, we have to put the '<' in front of it.
+ // Don't do this when 'shellquote' is not empty, otherwise the
+ // redirection would be inside the quotes.
+ if (*p_shq == NUL) {
+ char *const p = find_pipe(buf);
+ if (p != NULL) {
+ *p = NUL;
+ }
}
- }
- if (is_pwsh) {
- xstrlcat(buf, " -Red