ex_cmds.c (161731B)
1 // ex_cmds.c: some functions for command line commands 2 3 #include <assert.h> 4 #include <ctype.h> 5 #include <float.h> 6 #include <inttypes.h> 7 #include <limits.h> 8 #include <math.h> 9 #include <stdbool.h> 10 #include <stddef.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <time.h> 15 16 #include "auto/config.h" 17 #include "klib/kvec.h" 18 #include "nvim/api/private/helpers.h" 19 #include "nvim/arglist.h" 20 #include "nvim/ascii_defs.h" 21 #include "nvim/autocmd.h" 22 #include "nvim/autocmd_defs.h" 23 #include "nvim/buffer.h" 24 #include "nvim/buffer_defs.h" 25 #include "nvim/buffer_updates.h" 26 #include "nvim/bufwrite.h" 27 #include "nvim/change.h" 28 #include "nvim/channel.h" 29 #include "nvim/charset.h" 30 #include "nvim/cmdexpand_defs.h" 31 #include "nvim/cmdhist.h" 32 #include "nvim/cursor.h" 33 #include "nvim/decoration.h" 34 #include "nvim/diff.h" 35 #include "nvim/digraph.h" 36 #include "nvim/drawscreen.h" 37 #include "nvim/edit.h" 38 #include "nvim/errors.h" 39 #include "nvim/eval/typval.h" 40 #include "nvim/eval/typval_defs.h" 41 #include "nvim/eval/vars.h" 42 #include "nvim/ex_cmds.h" 43 #include "nvim/ex_cmds2.h" 44 #include "nvim/ex_cmds_defs.h" 45 #include "nvim/ex_docmd.h" 46 #include "nvim/ex_eval.h" 47 #include "nvim/ex_getln.h" 48 #include "nvim/extmark.h" 49 #include "nvim/extmark_defs.h" 50 #include "nvim/fileio.h" 51 #include "nvim/fold.h" 52 #include "nvim/getchar.h" 53 #include "nvim/gettext_defs.h" 54 #include "nvim/globals.h" 55 #include "nvim/help.h" 56 #include "nvim/highlight_defs.h" 57 #include "nvim/highlight_group.h" 58 #include "nvim/indent.h" 59 #include "nvim/input.h" 60 #include "nvim/macros_defs.h" 61 #include "nvim/main.h" 62 #include "nvim/mark.h" 63 #include "nvim/mark_defs.h" 64 #include "nvim/mbyte.h" 65 #include "nvim/memline.h" 66 #include "nvim/memline_defs.h" 67 #include "nvim/memory.h" 68 #include "nvim/message.h" 69 #include "nvim/mouse.h" 70 #include "nvim/move.h" 71 #include "nvim/normal.h" 72 #include "nvim/ops.h" 73 #include "nvim/option.h" 74 #include "nvim/option_defs.h" 75 #include "nvim/option_vars.h" 76 #include "nvim/os/fs.h" 77 #include "nvim/os/fs_defs.h" 78 #include "nvim/os/input.h" 79 #include "nvim/os/os.h" 80 #include "nvim/os/os_defs.h" 81 #include "nvim/os/shell.h" 82 #include "nvim/os/time.h" 83 #include "nvim/path.h" 84 #include "nvim/plines.h" 85 #include "nvim/pos_defs.h" 86 #include "nvim/profile.h" 87 #include "nvim/quickfix.h" 88 #include "nvim/regexp.h" 89 #include "nvim/regexp_defs.h" 90 #include "nvim/search.h" 91 #include "nvim/spell.h" 92 #include "nvim/state_defs.h" 93 #include "nvim/strings.h" 94 #include "nvim/terminal.h" 95 #include "nvim/types_defs.h" 96 #include "nvim/ui.h" 97 #include "nvim/ui_defs.h" 98 #include "nvim/undo.h" 99 #include "nvim/vim_defs.h" 100 #include "nvim/window.h" 101 102 /// Case matching style to use for :substitute 103 typedef enum { 104 kSubHonorOptions = 0, ///< Honor the user's 'ignorecase'/'smartcase' options 105 kSubIgnoreCase, ///< Ignore case of the search 106 kSubMatchCase, ///< Match case of the search 107 } SubIgnoreType; 108 109 /// Flags kept between calls to :substitute. 110 typedef struct { 111 bool do_all; ///< do multiple substitutions per line 112 bool do_ask; ///< ask for confirmation 113 bool do_count; ///< count only 114 bool do_error; ///< if false, ignore errors 115 bool do_print; ///< print last line with subs 116 bool do_list; ///< list last line with subs 117 bool do_number; ///< list last line with line nr 118 SubIgnoreType do_ic; ///< ignore case flag 119 } subflags_T; 120 121 /// Partial result of a substitution during :substitute. 122 /// Numbers refer to the buffer _after_ substitution 123 typedef struct { 124 lpos_T start; // start of the match 125 lpos_T end; // end of the match 126 linenr_T pre_match; // where to begin showing lines before the match 127 } SubResult; 128 129 // Collected results of a substitution for showing them in 130 // the preview window 131 typedef struct { 132 kvec_t(SubResult) subresults; 133 linenr_T lines_needed; // lines needed in the preview window 134 } PreviewLines; 135 136 #include "ex_cmds.c.generated.h" 137 138 static const char e_non_numeric_argument_to_z[] 139 = N_("E144: Non-numeric argument to :z"); 140 141 /// ":ascii" and "ga" implementation 142 void do_ascii(exarg_T *eap) 143 { 144 char *data = get_cursor_pos_ptr(); 145 size_t len = (size_t)utfc_ptr2len(data); 146 147 if (len == 0) { 148 msg("NUL", 0); 149 return; 150 } 151 152 bool need_clear = true; 153 msg_sb_eol(); 154 msg_start(); 155 156 int c = utf_ptr2char(data); 157 size_t off = 0; 158 159 // TODO(bfredl): merge this with the main loop 160 if (c < 0x80) { 161 if (c == NL) { // NUL is stored as NL. 162 c = NUL; 163 } 164 const int cval = (c == CAR && get_fileformat(curbuf) == EOL_MAC 165 ? NL // NL is stored as CR. 166 : c); 167 char buf1[20]; 168 if (vim_isprintc(c) && (c < ' ' || c > '~')) { 169 char buf3[7]; 170 transchar_nonprint(curbuf, buf3, c); 171 vim_snprintf(buf1, sizeof(buf1), " <%s>", buf3); 172 } else { 173 buf1[0] = NUL; 174 } 175 char buf2[20]; 176 buf2[0] = NUL; 177 178 char *dig = get_digraph_for_char(cval); 179 if (dig != NULL) { 180 vim_snprintf(IObuff, sizeof(IObuff), 181 _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"), 182 transchar(c), buf1, buf2, cval, cval, cval, dig); 183 } else { 184 vim_snprintf(IObuff, sizeof(IObuff), 185 _("<%s>%s%s %d, Hex %02x, Octal %03o"), 186 transchar(c), buf1, buf2, cval, cval, cval); 187 } 188 189 msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear); 190 191 off += (size_t)utf_ptr2len(data); // needed for overlong ascii? 192 } 193 194 // Repeat for combining characters, also handle multiby here. 195 while (off < len) { 196 c = utf_ptr2char(data + off); 197 198 size_t iobuff_len = 0; 199 // This assumes every multi-byte char is printable... 200 if (off > 0) { 201 IObuff[iobuff_len++] = ' '; 202 } 203 IObuff[iobuff_len++] = '<'; 204 if (utf_iscomposing_first(c)) { 205 IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space. 206 } 207 iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len); 208 209 char *dig = get_digraph_for_char(c); 210 if (dig != NULL) { 211 vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, 212 (c < 0x10000 213 ? _("> %d, Hex %04x, Oct %o, Digr %s") 214 : _("> %d, Hex %08x, Oct %o, Digr %s")), 215 c, c, c, dig); 216 } else { 217 vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, 218 (c < 0x10000 219 ? _("> %d, Hex %04x, Octal %o") 220 : _("> %d, Hex %08x, Octal %o")), 221 c, c, c); 222 } 223 224 msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear); 225 226 off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii? 227 } 228 229 if (need_clear) { 230 msg_clr_eos(); 231 } 232 msg_end(); 233 } 234 235 /// ":left", ":center" and ":right": align text. 236 void ex_align(exarg_T *eap) 237 { 238 int indent = 0; 239 int new_indent; 240 241 if (curwin->w_p_rl) { 242 // switch left and right aligning 243 if (eap->cmdidx == CMD_right) { 244 eap->cmdidx = CMD_left; 245 } else if (eap->cmdidx == CMD_left) { 246 eap->cmdidx = CMD_right; 247 } 248 } 249 250 int width = atoi(eap->arg); 251 pos_T save_curpos = curwin->w_cursor; 252 if (eap->cmdidx == CMD_left) { // width is used for new indent 253 if (width >= 0) { 254 indent = width; 255 } 256 } else { 257 // if 'textwidth' set, use it 258 // else if 'wrapmargin' set, use it 259 // if invalid value, use 80 260 if (width <= 0) { 261 width = (int)curbuf->b_p_tw; 262 } 263 if (width == 0 && curbuf->b_p_wm > 0) { 264 width = curwin->w_view_width - (int)curbuf->b_p_wm; 265 } 266 if (width <= 0) { 267 width = 80; 268 } 269 } 270 271 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) { 272 return; 273 } 274 275 for (curwin->w_cursor.lnum = eap->line1; 276 curwin->w_cursor.lnum <= eap->line2; curwin->w_cursor.lnum++) { 277 if (eap->cmdidx == CMD_left) { // left align 278 new_indent = indent; 279 } else { 280 int has_tab = false; // avoid uninit warnings 281 int len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent(); 282 283 if (len <= 0) { // skip blank lines 284 continue; 285 } 286 287 if (eap->cmdidx == CMD_center) { 288 new_indent = (width - len) / 2; 289 } else { 290 new_indent = width - len; // right align 291 292 // Make sure that embedded TABs don't make the text go too far 293 // to the right. 294 if (has_tab) { 295 while (new_indent > 0) { 296 set_indent(new_indent, 0); 297 if (linelen(NULL) <= width) { 298 // Now try to move the line as much as possible to 299 // the right. Stop when it moves too far. 300 do { 301 set_indent(++new_indent, 0); 302 } while (linelen(NULL) <= width); 303 new_indent--; 304 break; 305 } 306 new_indent--; 307 } 308 } 309 } 310 } 311 new_indent = MAX(new_indent, 0); 312 set_indent(new_indent, 0); // set indent 313 } 314 changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, 0, true); 315 curwin->w_cursor = save_curpos; 316 beginline(BL_WHITE | BL_FIX); 317 } 318 319 /// @return the length of the current line, excluding trailing white space. 320 static int linelen(int *has_tab) 321 { 322 char *last; 323 324 // Get the line. If it's empty bail out early (could be the empty string 325 // for an unloaded buffer). 326 char *line = get_cursor_line_ptr(); 327 if (*line == NUL) { 328 return 0; 329 } 330 // find the first non-blank character 331 char *first = skipwhite(line); 332 333 // find the character after the last non-blank character 334 for (last = first + strlen(first); 335 last > first && ascii_iswhite(last[-1]); last--) {} 336 char save = *last; 337 *last = NUL; 338 int len = linetabsize_str(line); // Get line length. 339 if (has_tab != NULL) { // Check for embedded TAB. 340 *has_tab = vim_strchr(first, TAB) != NULL; 341 } 342 *last = save; 343 344 return len; 345 } 346 347 // Buffer for two lines used during sorting. They are allocated to 348 // contain the longest line being sorted. 349 static char *sortbuf1; 350 static char *sortbuf2; 351 352 static bool sort_lc; ///< sort using locale 353 static bool sort_ic; ///< ignore case 354 static bool sort_nr; ///< sort on number 355 static bool sort_rx; ///< sort on regex instead of skipping it 356 static bool sort_flt; ///< sort on floating number 357 358 static bool sort_abort; ///< flag to indicate if sorting has been interrupted 359 360 /// Struct to store info to be sorted. 361 typedef struct { 362 linenr_T lnum; ///< line number 363 union { 364 struct { 365 varnumber_T start_col_nr; ///< starting column number 366 varnumber_T end_col_nr; ///< ending column number 367 } line; 368 struct { 369 varnumber_T value; ///< value if sorting by integer 370 bool is_number; ///< true when line contains a number 371 } num; 372 float_T value_flt; ///< value if sorting by float 373 } st_u; 374 } sorti_T; 375 376 static int string_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL 377 { 378 if (sort_lc) { 379 return strcoll((const char *)s1, (const char *)s2); 380 } 381 return sort_ic ? STRICMP(s1, s2) : strcmp(s1, s2); 382 } 383 384 static int sort_compare(const void *s1, const void *s2) 385 { 386 sorti_T l1 = *(sorti_T *)s1; 387 sorti_T l2 = *(sorti_T *)s2; 388 int result = 0; 389 390 // If the user interrupts, there's no way to stop qsort() immediately, but 391 // if we return 0 every time, qsort will assume it's done sorting and 392 // exit. 393 if (sort_abort) { 394 return 0; 395 } 396 fast_breakcheck(); 397 if (got_int) { 398 sort_abort = true; 399 } 400 401 // When sorting numbers "start_col_nr" is the number, not the column 402 // number. 403 if (sort_nr) { 404 if (l1.st_u.num.is_number != l2.st_u.num.is_number) { 405 result = l1.st_u.num.is_number > l2.st_u.num.is_number ? 1 : -1; 406 } else { 407 result = l1.st_u.num.value == l2.st_u.num.value 408 ? 0 409 : l1.st_u.num.value > l2.st_u.num.value ? 1 : -1; 410 } 411 } else if (sort_flt) { 412 result = l1.st_u.value_flt == l2.st_u.value_flt 413 ? 0 414 : l1.st_u.value_flt > l2.st_u.value_flt ? 1 : -1; 415 } else { 416 // We need to copy one line into "sortbuf1", because there is no 417 // guarantee that the first pointer becomes invalid when obtaining the 418 // second one. 419 memcpy(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr, 420 (size_t)(l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1)); 421 sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = NUL; 422 memcpy(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr, 423 (size_t)(l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1)); 424 sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = NUL; 425 426 result = string_compare(sortbuf1, sortbuf2); 427 } 428 429 // If two lines have the same value, preserve the original line order. 430 if (result == 0) { 431 return l1.lnum - l2.lnum; 432 } 433 return result; 434 } 435 436 /// ":sort". 437 void ex_sort(exarg_T *eap) 438 { 439 regmatch_T regmatch; 440 int maxlen = 0; 441 size_t count = (size_t)(eap->line2 - eap->line1) + 1; 442 size_t i; 443 bool unique = false; 444 int sort_what = 0; 445 446 // Sorting one line is really quick! 447 if (count <= 1) { 448 return; 449 } 450 451 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) { 452 return; 453 } 454 sortbuf1 = NULL; 455 sortbuf2 = NULL; 456 regmatch.regprog = NULL; 457 sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); 458 459 sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = sort_flt = false; 460 size_t format_found = 0; 461 bool change_occurred = false; // Buffer contents changed. 462 463 for (char *p = eap->arg; *p != NUL; p++) { 464 if (ascii_iswhite(*p)) { 465 // Skip 466 } else if (*p == 'i') { 467 sort_ic = true; 468 } else if (*p == 'l') { 469 sort_lc = true; 470 } else if (*p == 'r') { 471 sort_rx = true; 472 } else if (*p == 'n') { 473 sort_nr = true; 474 format_found++; 475 } else if (*p == 'f') { 476 sort_flt = true; 477 format_found++; 478 } else if (*p == 'b') { 479 sort_what = STR2NR_BIN + STR2NR_FORCE; 480 format_found++; 481 } else if (*p == 'o') { 482 sort_what = STR2NR_OCT + STR2NR_FORCE; 483 format_found++; 484 } else if (*p == 'x') { 485 sort_what = STR2NR_HEX + STR2NR_FORCE; 486 format_found++; 487 } else if (*p == 'u') { 488 unique = true; 489 } else if (*p == '"') { // comment start 490 break; 491 } else if (check_nextcmd(p) != NULL) { 492 eap->nextcmd = check_nextcmd(p); 493 break; 494 } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { 495 char *s = skip_regexp_err(p + 1, *p, true); 496 if (s == NULL) { 497 goto sortend; 498 } 499 *s = NUL; 500 // Use last search pattern if sort pattern is empty. 501 if (s == p + 1) { 502 if (last_search_pat() == NULL) { 503 emsg(_(e_noprevre)); 504 goto sortend; 505 } 506 regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); 507 } else { 508 regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); 509 } 510 if (regmatch.regprog == NULL) { 511 goto sortend; 512 } 513 p = s; // continue after the regexp 514 regmatch.rm_ic = p_ic; 515 } else { 516 semsg(_(e_invarg2), p); 517 goto sortend; 518 } 519 } 520 521 // Can only have one of 'n', 'b', 'o' and 'x'. 522 if (format_found > 1) { 523 emsg(_(e_invarg)); 524 goto sortend; 525 } 526 527 // From here on "sort_nr" is used as a flag for any integer number 528 // sorting. 529 sort_nr |= sort_what; 530 531 // Make an array with all line numbers. This avoids having to copy all 532 // the lines into allocated memory. 533 // When sorting on strings "start_col_nr" is the offset in the line, for 534 // numbers sorting it's the number to sort on. This means the pattern 535 // matching and number conversion only has to be done once per line. 536 // Also get the longest line length for allocating "sortbuf". 537 for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { 538 char *s = ml_get(lnum); 539 int len = ml_get_len(lnum); 540 maxlen = MAX(maxlen, len); 541 542 colnr_T start_col = 0; 543 colnr_T end_col = len; 544 if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) { 545 if (sort_rx) { 546 start_col = (colnr_T)(regmatch.startp[0] - s); 547 end_col = (colnr_T)(regmatch.endp[0] - s); 548 } else { 549 start_col = (colnr_T)(regmatch.endp[0] - s); 550 } 551 } else if (regmatch.regprog != NULL) { 552 end_col = 0; 553 } 554 555 if (sort_nr || sort_flt) { 556 // Make sure vim_str2nr() doesn't read any digits past the end 557 // of the match, by temporarily terminating the string there 558 char *s2 = s + end_col; 559 char c = *s2; // temporary character storage 560 *s2 = NUL; 561 // Sorting on number: Store the number itself. 562 char *p = s + start_col; 563 if (sort_nr) { 564 if (sort_what & STR2NR_HEX) { 565 s = skiptohex(p); 566 } else if (sort_what & STR2NR_BIN) { 567 s = (char *)skiptobin(p); 568 } else { 569 s = skiptodigit(p); 570 } 571 if (s > p && s[-1] == '-') { 572 s--; // include preceding negative sign 573 } 574 if (*s == NUL) { 575 // line without number should sort before any number 576 nrs[lnum - eap->line1].st_u.num.is_number = false; 577 nrs[lnum - eap->line1].st_u.num.value = 0; 578 } else { 579 nrs[lnum - eap->line1].st_u.num.is_number = true; 580 vim_str2nr(s, NULL, NULL, sort_what, 581 &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false, NULL); 582 } 583 } else { 584 s = skipwhite(p); 585 if (*s == '+') { 586 s = skipwhite(s + 1); 587 } 588 589 if (*s == NUL) { 590 // empty line should sort before any number 591 nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX; 592 } else { 593 nrs[lnum - eap->line1].st_u.value_flt = strtod(s, NULL); 594 } 595 } 596 *s2 = c; 597 } else { 598 // Store the column to sort at. 599 nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col; 600 nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col; 601 } 602 603 nrs[lnum - eap->line1].lnum = lnum; 604 605 if (regmatch.regprog != NULL) { 606 fast_breakcheck(); 607 } 608 if (got_int) { 609 goto sortend; 610 } 611 } 612 613 // Allocate a buffer that can hold the longest line. 614 sortbuf1 = xmalloc((size_t)maxlen + 1); 615 sortbuf2 = xmalloc((size_t)maxlen + 1); 616 617 // Sort the array of line numbers. Note: can't be interrupted! 618 qsort((void *)nrs, count, sizeof(sorti_T), sort_compare); 619 620 if (sort_abort) { 621 goto sortend; 622 } 623 624 bcount_t old_count = 0; 625 bcount_t new_count = 0; 626 627 // Insert the lines in the sorted order below the last one. 628 linenr_T lnum = eap->line2; 629 for (i = 0; i < count; i++) { 630 const linenr_T get_lnum = nrs[eap->forceit ? count - i - 1 : i].lnum; 631 632 // If the original line number of the line being placed is not the same 633 // as "lnum" (accounting for offset), we know that the buffer changed. 634 if (get_lnum + ((linenr_T)count - 1) != lnum) { 635 change_occurred = true; 636 } 637 638 char *s = ml_get(get_lnum); 639 colnr_T bytelen = ml_get_len(get_lnum) + 1; // include EOL in bytelen 640 old_count += bytelen; 641 if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { 642 // Copy the line into a buffer, it may become invalid in 643 // ml_append(). And it's needed for "unique". 644 STRCPY(sortbuf1, s); 645 if (ml_append(lnum++, sortbuf1, 0, false) == FAIL) { 646 break; 647 } 648 new_count += bytelen; 649 } 650 fast_breakcheck(); 651 if (got_int) { 652 goto sortend; 653 } 654 } 655 656 // delete the original lines if appending worked 657 if (i == count) { 658 for (i = 0; i < count; i++) { 659 ml_delete(eap->line1); 660 } 661 } else { 662 count = 0; 663 } 664 665 // Adjust marks for deleted (or added) lines and prepare for displaying. 666 linenr_T deleted = (linenr_T)count - (lnum - eap->line2); 667 if (deleted > 0) { 668 mark_adjust(eap->line2 - deleted, eap->line2, MAXLNUM, -deleted, kExtmarkNOOP); 669 msgmore(-deleted); 670 } else if (deleted < 0) { 671 mark_adjust(eap->line2, MAXLNUM, -deleted, 0, kExtmarkNOOP); 672 } 673 674 if (change_occurred || deleted != 0) { 675 extmark_splice(curbuf, eap->line1 - 1, 0, 676 (int)count, 0, old_count, 677 lnum - eap->line2, 0, new_count, kExtmarkUndo); 678 changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, -deleted, true); 679 } 680 681 curwin->w_cursor.lnum = eap->line1; 682 beginline(BL_WHITE | BL_FIX); 683 684 sortend: 685 xfree(nrs); 686 xfree(sortbuf1); 687 xfree(sortbuf2); 688 vim_regfree(regmatch.regprog); 689 if (got_int) { 690 emsg(_(e_interr)); 691 } 692 } 693 694 /// ":uniq". 695 void ex_uniq(exarg_T *eap) 696 { 697 regmatch_T regmatch; 698 int maxlen = 0; 699 linenr_T count = eap->line2 - eap->line1 + 1; 700 bool keep_only_unique = false; 701 bool keep_only_not_unique = eap->forceit; 702 linenr_T deleted = 0; 703 704 // Uniq one line is really quick! 705 if (count <= 1) { 706 return; 707 } 708 709 if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) { 710 return; 711 } 712 sortbuf1 = NULL; 713 regmatch.regprog = NULL; 714 715 sort_abort = sort_ic = sort_lc = sort_rx = sort_nr = sort_flt = false; 716 bool change_occurred = false; // Buffer contents changed. 717 718 for (char *p = eap->arg; *p != NUL; p++) { 719 if (ascii_iswhite(*p)) { 720 // Skip 721 } else if (*p == 'i') { 722 sort_ic = true; 723 } else if (*p == 'l') { 724 sort_lc = true; 725 } else if (*p == 'r') { 726 sort_rx = true; 727 } else if (*p == 'u') { 728 // 'u' is only valid when '!' is not given. 729 if (!keep_only_not_unique) { 730 keep_only_unique = true; 731 } 732 } else if (*p == '"') { // comment start 733 break; 734 } else if (eap->nextcmd == NULL && check_nextcmd(p) != NULL) { 735 eap->nextcmd = check_nextcmd(p); 736 break; 737 } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { 738 char *s = skip_regexp_err(p + 1, *p, true); 739 if (s == NULL) { 740 goto uniqend; 741 } 742 *s = NUL; 743 // Use last search pattern if uniq pattern is empty. 744 if (s == p + 1) { 745 if (last_search_pat() == NULL) { 746 emsg(_(e_noprevre)); 747 goto uniqend; 748 } 749 regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); 750 } else { 751 regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); 752 } 753 if (regmatch.regprog == NULL) { 754 goto uniqend; 755 } 756 p = s; // continue after the regexp 757 regmatch.rm_ic = p_ic; 758 } else { 759 semsg(_(e_invarg2), p); 760 goto uniqend; 761 } 762 } 763 764 // Find the length of the longest line. 765 for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { 766 int len = ml_get_len(lnum); 767 if (maxlen < len) { 768 maxlen = len; 769 } 770 771 if (got_int) { 772 goto uniqend; 773 } 774 } 775 776 // Allocate a buffer that can hold the longest line. 777 sortbuf1 = xmalloc((size_t)maxlen + 1); 778 779 // Delete lines according to options. 780 bool match_continue = false; 781 bool next_is_unmatch = false; 782 linenr_T done_lnum = eap->line1 - 1; 783 linenr_T delete_lnum = 0; 784 for (linenr_T i = 0; i < count; i++) { 785 linenr_T get_lnum = eap->line1 + i; 786 787 char *s = ml_get(get_lnum); 788 int len = ml_get_len(get_lnum); 789 790 colnr_T start_col = 0; 791 colnr_T end_col = len; 792 if (regmatch.regprog != NULL && vim_regexec(®match, s, 0)) { 793 if (sort_rx) { 794 start_col = (colnr_T)(regmatch.startp[0] - s); 795 end_col = (colnr_T)(regmatch.endp[0] - s); 796 } else { 797 start_col = (colnr_T)(regmatch.endp[0] - s); 798 } 799 } else if (regmatch.regprog != NULL) { 800 end_col = 0; 801 } 802 char save_c = NUL; // temporary character storage 803 if (end_col > 0) { 804 save_c = s[end_col]; 805 s[end_col] = NUL; 806 } 807 808 bool is_match = i > 0 ? !string_compare(&s[start_col], sortbuf1) : false; 809 delete_lnum = 0; 810 if (next_is_unmatch) { 811 is_match = false; 812 next_is_unmatch = false; 813 } 814 815 if (!keep_only_unique && !keep_only_not_unique) { 816 if (is_match) { 817 delete_lnum = get_lnum; 818 } else { 819 STRCPY(sortbuf1, &s[start_col]); 820 } 821 } else if (keep_only_not_unique) { 822 if (is_match) { 823 done_lnum = get_lnum - 1; 824 delete_lnum = get_lnum; 825 match_continue = true; 826 } else { 827 if (i > 0 && !match_continue && get_lnum - 1 > done_lnum) { 828 delete_lnum = get_lnum - 1; 829 next_is_unmatch = true; 830 } else if (i >= count - 1) { 831 delete_lnum = get_lnum; 832 } 833 match_continue = false; 834 STRCPY(sortbuf1, &s[start_col]); 835 } 836 } else { // keep_only_unique 837 if (is_match) { 838 if (!match_continue) { 839 delete_lnum = get_lnum - 1; 840 } else { 841 delete_lnum = get_lnum; 842 } 843 match_continue = true; 844 } else { 845 if (i == 0 && match_continue) { 846 delete_lnum = get_lnum; 847 } 848 match_continue = false; 849 STRCPY(sortbuf1, &s[start_col]); 850 } 851 } 852 853 if (end_col > 0) { 854 s[end_col] = save_c; 855 } 856 857 if (delete_lnum > 0) { 858 ml_delete(delete_lnum); 859 i -= get_lnum - delete_lnum + 1; 860 count--; 861 deleted++; 862 change_occurred = true; 863 } 864 865 fast_breakcheck(); 866 if (got_int) { 867 goto uniqend; 868 } 869 } 870 871 // Adjust marks for deleted lines and prepare for displaying. 872 mark_adjust(eap->line2 - deleted, eap->line2, MAXLNUM, -deleted, 873 change_occurred ? kExtmarkUndo : kExtmarkNOOP); 874 msgmore(-deleted); 875 876 if (change_occurred) { 877 changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, -deleted, true); 878 } 879 880 curwin->w_cursor.lnum = eap->line1; 881 beginline(BL_WHITE | BL_FIX); 882 883 uniqend: 884 xfree(sortbuf1); 885 vim_regfree(regmatch.regprog); 886 if (got_int) { 887 emsg(_(e_interr)); 888 } 889 } 890 891 /// :move command - move lines line1-line2 to line dest 892 /// 893 /// @return FAIL for failure, OK otherwise 894 int do_move(linenr_T line1, linenr_T line2, linenr_T dest) 895 { 896 if (dest >= line1 && dest < line2) { 897 emsg(_("E134: Cannot move a range of lines into itself")); 898 return FAIL; 899 } 900 901 // Do nothing if we are not actually moving any lines. This will prevent 902 // the 'modified' flag from being set without cause. 903 if (dest == line1 - 1 || dest == line2) { 904 // Move the cursor as if lines were moved (see below) to be backwards 905 // compatible. 906 curwin->w_cursor.lnum = dest >= line1 907 ? dest 908 : dest + (line2 - line1) + 1; 909 return OK; 910 } 911 912 bcount_t start_byte = ml_find_line_or_offset(curbuf, line1, NULL, true); 913 bcount_t end_byte = ml_find_line_or_offset(curbuf, line2 + 1, NULL, true); 914 bcount_t extent_byte = end_byte - start_byte; 915 bcount_t dest_byte = ml_find_line_or_offset(curbuf, dest + 1, NULL, true); 916 917 linenr_T num_lines = line2 - line1 + 1; // Num lines moved 918 919 // First we copy the old text to its new location -- webb 920 // Also copy the flag that ":global" command uses. 921 if (u_save(dest, dest + 1) == FAIL) { 922 return FAIL; 923 } 924 925 linenr_T l; 926 linenr_T extra; // Num lines added before line1 927 for (extra = 0, l = line1; l <= line2; l++) { 928 char *str = xstrnsave(ml_get(l + extra), (size_t)ml_get_len(l + extra)); 929 ml_append(dest + l - line1, str, 0, false); 930 xfree(str); 931 if (dest < line1) { 932 extra++; 933 } 934 } 935 936 // Now we must be careful adjusting our marks so that we don't overlap our 937 // mark_adjust() calls. 938 // 939 // We adjust the marks within the old text so that they refer to the 940 // last lines of the file (temporarily), because we know no other marks 941 // will be set there since these line numbers did not exist until we added 942 // our new lines. 943 // 944 // Then we adjust the marks on lines between the old and new text positions 945 // (either forwards or backwards). 946 // 947 // And Finally we adjust the marks we put at the end of the file back to 948 // their final destination at the new text position -- webb 949 linenr_T last_line = curbuf->b_ml.ml_line_count; // Last line in file after adding new text 950 mark_adjust_nofold(line1, line2, last_line - line2, 0, kExtmarkNOOP); 951 952 disable_fold_update++; 953 changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, num_lines, false); 954 disable_fold_update--; 955 956 int line_off = 0; 957 bcount_t byte_off = 0; 958 if (dest >= line2) { 959 mark_adjust_nofold(line2 + 1, dest, -num_lines, 0, kExtmarkNOOP); 960 FOR_ALL_TAB_WINDOWS(tab, win) { 961 if (win->w_buffer == curbuf) { 962 foldMoveRange(win, &win->w_folds, line1, line2, dest); 963 } 964 } 965 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 966 curbuf->b_op_start.lnum = dest - num_lines + 1; 967 curbuf->b_op_end.lnum = dest; 968 } 969 line_off = -num_lines; 970 byte_off = -extent_byte; 971 } else { 972 mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0, kExtmarkNOOP); 973 FOR_ALL_TAB_WINDOWS(tab, win) { 974 if (win->w_buffer == curbuf) { 975 foldMoveRange(win, &win->w_folds, dest + 1, line1 - 1, line2); 976 } 977 } 978 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 979 curbuf->b_op_start.lnum = dest + 1; 980 curbuf->b_op_end.lnum = dest + num_lines; 981 } 982 } 983 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 984 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 985 } 986 mark_adjust_nofold(last_line - num_lines + 1, last_line, 987 -(last_line - dest - extra), 0, kExtmarkNOOP); 988 989 disable_fold_update++; 990 changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, -extra, false); 991 disable_fold_update--; 992 993 // send update regarding the new lines that were added 994 buf_updates_send_changes(curbuf, dest + 1, num_lines, 0); 995 996 // Now we delete the original text -- webb 997 if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) { 998 return FAIL; 999 } 1000 1001 for (l = line1; l <= line2; l++) { 1002 ml_delete_flags(line1 + extra, ML_DEL_MESSAGE); 1003 } 1004 if (!global_busy && num_lines > p_report) { 1005 smsg(0, NGETTEXT("%" PRId64 " line moved", 1006 "%" PRId64 " lines moved", num_lines), 1007 (int64_t)num_lines); 1008 } 1009 1010 extmark_move_region(curbuf, line1 - 1, 0, start_byte, 1011 line2 - line1 + 1, 0, extent_byte, 1012 dest + line_off, 0, dest_byte + byte_off, 1013 kExtmarkUndo); 1014 1015 // Leave the cursor on the last of the moved lines. 1016 if (dest >= line1) { 1017 curwin->w_cursor.lnum = dest; 1018 } else { 1019 curwin->w_cursor.lnum = dest + (line2 - line1) + 1; 1020 } 1021 1022 if (line1 < dest) { 1023 dest += num_lines + 1; 1024 last_line = curbuf->b_ml.ml_line_count; 1025 dest = MIN(dest, last_line + 1); 1026 changed_lines(curbuf, line1, 0, dest, 0, false); 1027 } else { 1028 changed_lines(curbuf, dest + 1, 0, line1 + num_lines, 0, false); 1029 } 1030 1031 // send nvim_buf_lines_event regarding lines that were deleted 1032 buf_updates_send_changes(curbuf, line1 + extra, 0, num_lines); 1033 1034 return OK; 1035 } 1036 1037 /// ":copy" 1038 void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) 1039 { 1040 linenr_T count = line2 - line1 + 1; 1041 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 1042 curbuf->b_op_start.lnum = n + 1; 1043 curbuf->b_op_end.lnum = n + count; 1044 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 1045 } 1046 1047 // there are three situations: 1048 // 1. destination is above line1 1049 // 2. destination is between line1 and line2 1050 // 3. destination is below line2 1051 // 1052 // n = destination (when starting) 1053 // curwin->w_cursor.lnum = destination (while copying) 1054 // line1 = start of source (while copying) 1055 // line2 = end of source (while copying) 1056 if (u_save(n, n + 1) == FAIL) { 1057 return; 1058 } 1059 1060 curwin->w_cursor.lnum = n; 1061 while (line1 <= line2) { 1062 // need to make a copy because the line will be unlocked within ml_append() 1063 char *p = xstrnsave(ml_get(line1), (size_t)ml_get_len(line1)); 1064 ml_append(curwin->w_cursor.lnum, p, 0, false); 1065 xfree(p); 1066 1067 // situation 2: skip already copied lines 1068 if (line1 == n) { 1069 line1 = curwin->w_cursor.lnum; 1070 } 1071 line1++; 1072 if (curwin->w_cursor.lnum < line1) { 1073 line1++; 1074 } 1075 if (curwin->w_cursor.lnum < line2) { 1076 line2++; 1077 } 1078 curwin->w_cursor.lnum++; 1079 } 1080 1081 appended_lines_mark(n, count); 1082 if (VIsual_active) { 1083 check_pos(curbuf, &VIsual); 1084 } 1085 1086 msgmore(count); 1087 } 1088 1089 static char *prevcmd = NULL; // the previous command 1090 1091 #if defined(EXITFREE) 1092 void free_prev_shellcmd(void) 1093 { 1094 xfree(prevcmd); 1095 } 1096 1097 #endif 1098 1099 /// Check that "prevcmd" is not NULL. If it is NULL then give an error message 1100 /// and return false. 1101 static int prevcmd_is_set(void) 1102 { 1103 if (prevcmd == NULL) { 1104 emsg(_(e_noprev)); 1105 return false; 1106 } 1107 return true; 1108 } 1109 1110 /// Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd" 1111 /// Bangs in the argument are replaced with the previously entered command. 1112 /// Remember the argument. 1113 void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out) 1114 FUNC_ATTR_NONNULL_ALL 1115 { 1116 char *arg = eap->arg; // command 1117 linenr_T line1 = eap->line1; // start of range 1118 linenr_T line2 = eap->line2; // end of range 1119 char *newcmd = NULL; // the new command 1120 bool free_newcmd = false; // need to free() newcmd 1121 int scroll_save = msg_scroll; 1122 1123 // Disallow shell commands in secure mode 1124 if (check_secure()) { 1125 return; 1126 } 1127 1128 if (addr_count == 0) { // :! 1129 msg_scroll = false; // don't scroll here 1130 autowrite_all(); 1131 msg_scroll = scroll_save; 1132 } 1133 1134 // Try to find an embedded bang, like in ":!<cmd> ! [args]" 1135 // ":!!" is indicated by the 'forceit' variable. 1136 bool ins_prevcmd = forceit; 1137 1138 // Skip leading white space to avoid a strange error with some shells. 1139 char *trailarg = skipwhite(arg); 1140 do { 1141 size_t len = strlen(trailarg) + 1; 1142 if (newcmd != NULL) { 1143 len += strlen(newcmd); 1144 } 1145 if (ins_prevcmd) { 1146 if (!prevcmd_is_set()) { 1147 xfree(newcmd); 1148 return; 1149 } 1150 len += strlen(prevcmd); 1151 } 1152 char *t = xmalloc(len); 1153 *t = NUL; 1154 if (newcmd != NULL) { 1155 strcat(t, newcmd); 1156 } 1157 if (ins_prevcmd) { 1158 strcat(t, prevcmd); 1159 } 1160 char *p = t + strlen(t); 1161 strcat(t, trailarg); 1162 xfree(newcmd); 1163 newcmd = t; 1164 1165 // Scan the rest of the argument for '!', which is replaced by the 1166 // previous command. "\!" is replaced by "!" (this is vi compatible). 1167 trailarg = NULL; 1168 while (*p) { 1169 if (*p == '!') { 1170 if (p > newcmd && p[-1] == '\\') { 1171 STRMOVE(p - 1, p); 1172 } else { 1173 trailarg = p; 1174 *trailarg++ = NUL; 1175 ins_prevcmd = true; 1176 break; 1177 } 1178 } 1179 p++; 1180 } 1181 } while (trailarg != NULL); 1182 1183 // Only set "prevcmd" if there is a command to run, otherwise keep te one 1184 // we have. 1185 if (strlen(newcmd) > 0) { 1186 xfree(prevcmd); 1187 prevcmd = newcmd; 1188 } else { 1189 free_newcmd = true; 1190 } 1191 1192 if (bangredo) { // put cmd in redo buffer for ! command 1193 if (!prevcmd_is_set()) { 1194 goto theend; 1195 } 1196 1197 // If % or # appears in the command, it must have been escaped. 1198 // Reescape them, so that redoing them does not substitute them by the 1199 // buffername. 1200 char *cmd = vim_strsave_escaped(prevcmd, "%#"); 1201 1202 AppendToRedobuffLit(cmd, -1); 1203 xfree(cmd); 1204 AppendToRedobuff("\n"); 1205 bangredo = false; 1206 } 1207 // Add quotes around the command, for shells that need them. 1208 if (*p_shq != NUL) { 1209 if (free_newcmd) { 1210 xfree(newcmd); 1211 } 1212 newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1); 1213 STRCPY(newcmd, p_shq); 1214 strcat(newcmd, prevcmd); 1215 strcat(newcmd, p_shq); 1216 free_newcmd = true; 1217 } 1218 if (addr_count == 0) { // :! 1219 // echo the command 1220 msg_start(); 1221 msg_ext_set_kind("shell_cmd"); 1222 msg_putchar(':'); 1223 msg_putchar('!'); 1224 msg_outtrans(newcmd, 0, false); 1225 msg_clr_eos(); 1226 ui_cursor_goto(msg_row, msg_col); 1227 1228 do_shell(newcmd, 0); 1229 } else { // :range! 1230 // Careful: This may recursively call do_bang() again! (because of 1231 // autocommands) 1232 do_filter(line1, line2, eap, newcmd, do_in, do_out); 1233 apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, false, curbuf); 1234 } 1235 1236 theend: 1237 if (free_newcmd) { 1238 xfree(newcmd); 1239 } 1240 } 1241 1242 /// do_filter: filter lines through a command given by the user 1243 /// 1244 /// We mostly use temp files and the call_shell() routine here. This would 1245 /// normally be done using pipes on a Unix system, but this is more portable 1246 /// to non-Unix systems. The call_shell() routine needs to be able 1247 /// to deal with redirection somehow, and should handle things like looking 1248 /// at the PATH env. variable, and adding reasonable extensions to the 1249 /// command name given by the user. All reasonable versions of call_shell() 1250 /// do this. 1251 /// Alternatively, if on Unix and redirecting input or output, but not both, 1252 /// and the 'shelltemp' option isn't set, use pipes. 1253 /// We use input redirection if do_in is true. 1254 /// We use output redirection if do_out is true. 1255 /// 1256 /// @param eap for forced 'ff' and 'fenc' 1257 static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, bool do_in, 1258 bool do_out) 1259 { 1260 char *itmp = NULL; 1261 char *otmp = NULL; 1262 buf_T *old_curbuf = curbuf; 1263 int shell_flags = 0; 1264 const pos_T orig_start = curbuf->b_op_start; 1265 const pos_T orig_end = curbuf->b_op_end; 1266 const int stmp = p_stmp; 1267 1268 if (*cmd == NUL) { // no filter command 1269 return; 1270 } 1271 1272 const int save_cmod_flags = cmdmod.cmod_flags; 1273 // Temporarily disable lockmarks since that's needed to propagate changed 1274 // regions of the buffer for foldUpdate(), linecount, etc. 1275 cmdmod.cmod_flags &= ~CMOD_LOCKMARKS; 1276 1277 pos_T cursor_save = curwin->w_cursor; 1278 linenr_T linecount = line2 - line1 + 1; 1279 curwin->w_cursor.lnum = line1; 1280 curwin->w_cursor.col = 0; 1281 changed_line_abv_curs(); 1282 invalidate_botline_win(curwin); 1283 1284 // When using temp files: 1285 // 1. * Form temp file names 1286 // 2. * Write the lines to a temp file 1287 // 3. Run the filter command on the temp file 1288 // 4. * Read the output of the command into the buffer 1289 // 5. * Delete the original lines to be filtered 1290 // 6. * Remove the temp files 1291 // 1292 // When writing the input with a pipe or when catching the output with a 1293 // pipe only need to do 3. 1294 1295 if (do_out) { 1296 shell_flags |= kShellOptDoOut; 1297 } 1298 1299 if (!do_in && do_out && !stmp) { 1300 // Use a pipe to fetch stdout of the command, do not use a temp file. 1301 shell_flags |= kShellOptRead; 1302 curwin->w_cursor.lnum = line2; 1303 } else if (do_in && !do_out && !stmp) { 1304 // Use a pipe to write stdin of the command, do not use a temp file. 1305 shell_flags |= kShellOptWrite; 1306 curbuf->b_op_start.lnum = line1; 1307 curbuf->b_op_end.lnum = line2; 1308 } else if (do_in && do_out && !stmp) { 1309 // Use a pipe to write stdin and fetch stdout of the command, do not 1310 // use a temp file. 1311 shell_flags |= kShellOptRead | kShellOptWrite; 1312 curbuf->b_op_start.lnum = line1; 1313 curbuf->b_op_end.lnum = line2; 1314 curwin->w_cursor.lnum = line2; 1315 } else if ((do_in && (itmp = vim_tempname()) == NULL) 1316 || (do_out && (otmp = vim_tempname()) == NULL)) { 1317 emsg(_(e_notmp)); 1318 goto filterend; 1319 } 1320 1321 // The writing and reading of temp files will not be shown. 1322 // Vi also doesn't do this and the messages are not very informative. 1323 no_wait_return++; // don't call wait_return() while busy 1324 if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap, 1325 false, false, false, true) == FAIL) { 1326 if (!ui_has(kUIMessages)) { 1327 msg_putchar('\n'); // Keep message from buf_write(). 1328 } 1329 no_wait_return--; 1330 if (!aborting()) { 1331 // will call wait_return() 1332 semsg(_("E482: Can't create file %s"), itmp); 1333 } 1334 goto filterend; 1335 } 1336 if (curbuf != old_curbuf) { 1337 goto filterend; 1338 } 1339 1340 if (!do_out) { 1341 msg_putchar('\n'); 1342 } 1343 1344 // Create the shell command in allocated memory. 1345 char *cmd_buf = make_filter_cmd(cmd, itmp, otmp, do_in); 1346 ui_cursor_goto(Rows - 1, 0); 1347 1348 if (do_out) { 1349 if (u_save(line2, (linenr_T)(line2 + 1)) == FAIL) { 1350 xfree(cmd_buf); 1351 goto error; 1352 } 1353 redraw_curbuf_later(UPD_VALID); 1354 } 1355 linenr_T read_linecount = curbuf->b_ml.ml_line_count; 1356 1357 // Pass on the kShellOptDoOut flag when the output is being redirected. 1358 call_shell(cmd_buf, kShellOptFilter | shell_flags, NULL); 1359 xfree(cmd_buf); 1360 1361 did_check_timestamps = false; 1362 need_check_timestamps = true; 1363 1364 // When interrupting the shell command, it may still have produced some 1365 // useful output. Reset got_int here, so that readfile() won't cancel 1366 // reading. 1367 os_breakcheck(); 1368 got_int = false; 1369 1370 if (do_out) { 1371 if (otmp != NULL) { 1372 if (readfile(otmp, NULL, line2, 0, (linenr_T)MAXLNUM, eap, 1373 READ_FILTER, false) != OK) { 1374 if (!aborting()) { 1375 msg_putchar('\n'); 1376 semsg(_(e_cant_read_file_str), otmp); 1377 } 1378 goto error; 1379 } 1380 if (curbuf != old_curbuf) { 1381 goto filterend; 1382 } 1383 } 1384 1385 read_linecount = curbuf->b_ml.ml_line_count - read_linecount; 1386 1387 if (shell_flags & kShellOptRead) { 1388 curbuf->b_op_start.lnum = line2 + 1; 1389 curbuf->b_op_end.lnum = curwin->w_cursor.lnum; 1390 appended_lines_mark(line2, read_linecount); 1391 } 1392 1393 if (do_in) { 1394 if ((cmdmod.cmod_flags & CMOD_KEEPMARKS) 1395 || vim_strchr(p_cpo, CPO_REMMARK) == NULL) { 1396 // TODO(bfredl): Currently not active for extmarks. What would we 1397 // do if columns don't match, assume added/deleted bytes at the 1398 // end of each line? 1399 if (read_linecount >= linecount) { 1400 // move all marks from old lines to new lines 1401 mark_adjust(line1, line2, linecount, 0, kExtmarkNOOP); 1402 } else { 1403 // move marks from old lines to new lines, delete marks 1404 // that are in deleted lines 1405 mark_adjust(line1, line1 + read_linecount - 1, linecount, 0, 1406 kExtmarkNOOP); 1407 mark_adjust(line1 + read_linecount, line2, MAXLNUM, 0, 1408 kExtmarkNOOP); 1409 } 1410 } 1411 1412 // Put cursor on first filtered line for ":range!cmd". 1413 // Adjust '[ and '] (set by buf_write()). 1414 curwin->w_cursor.lnum = line1; 1415 del_lines(linecount, true); 1416 curbuf->b_op_start.lnum -= linecount; // adjust '[ 1417 curbuf->b_op_end.lnum -= linecount; // adjust '] 1418 write_lnum_adjust(-linecount); // adjust last line 1419 // for next write 1420 foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum); 1421 } else { 1422 // Put cursor on last new line for ":r !cmd". 1423 linecount = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1; 1424 curwin->w_cursor.lnum = curbuf->b_op_end.lnum; 1425 } 1426 1427 beginline(BL_WHITE | BL_FIX); // cursor on first non-blank 1428 no_wait_return--; 1429 1430 if (linecount > p_report) { 1431 if (do_in) { 1432 vim_snprintf(msg_buf, sizeof(msg_buf), 1433 _("%" PRId64 " lines filtered"), (int64_t)linecount); 1434 if (msg(msg_buf, 0) && !msg_scroll) { 1435 // save message to display it after redraw 1436 set_keep_msg(msg_buf, 0); 1437 } 1438 } else { 1439 msgmore(linecount); 1440 } 1441 } 1442 } else { 1443 error: 1444 // put cursor back in same position for ":w !cmd" 1445 curwin->w_cursor = cursor_save; 1446 no_wait_return--; 1447 wait_return(false); 1448 } 1449 1450 filterend: 1451 1452 cmdmod.cmod_flags = save_cmod_flags; 1453 if (curbuf != old_curbuf) { 1454 no_wait_return--; 1455 emsg(_("E135: *Filter* Autocommands must not change current buffer")); 1456 } else if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { 1457 curbuf->b_op_start = orig_start; 1458 curbuf->b_op_end = orig_end; 1459 } 1460 1461 if (itmp != NULL) { 1462 os_remove(itmp); 1463 } 1464 if (otmp != NULL) { 1465 os_remove(otmp); 1466 } 1467 xfree(itmp); 1468 xfree(otmp); 1469 } 1470 1471 /// Call a shell to execute a command. 1472 /// When "cmd" is NULL start an interactive shell. 1473 /// 1474 /// @param flags may be SHELL_DOOUT when output is redirected 1475 void do_shell(char *cmd, int flags) 1476 { 1477 // Disallow shell commands in secure mode 1478 if (check_secure()) { 1479 msg_end(); 1480 return; 1481 } 1482 1483 // For autocommands we want to get the output on the current screen, to 1484 // avoid having to type return below. 1485 msg_putchar('\r'); // put cursor at start of line 1486 msg_putchar('\n'); // may shift screen one line up 1487 1488 // warning message before calling the shell 1489 if (p_warn 1490 && !autocmd_busy 1491 && msg_silent == 0) { 1492 FOR_ALL_BUFFERS(buf) { 1493 if (bufIsChanged(buf)) { 1494 msg_puts(_("[No write since last change]\n")); 1495 break; 1496 } 1497 } 1498 } 1499 1500 // This ui_cursor_goto is required for when the '\n' resulted in a "delete line 1501 // 1" command to the terminal. 1502 ui_cursor_goto(msg_row, msg_col); 1503 call_shell(cmd, flags, NULL); 1504 if (msg_silent == 0) { 1505 msg_didout = true; 1506 } 1507 did_check_timestamps = false; 1508 need_check_timestamps = true; 1509 1510 // put the message cursor at the end of the screen, avoids wait_return() 1511 // to overwrite the text that the external command showed 1512 msg_row = Rows - 1; 1513 msg_col = 0; 1514 1515 apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, false, curbuf); 1516 } 1517 1518 #if !defined(UNIX) 1519 static char *find_pipe(const char *cmd) 1520 { 1521 bool inquote = false; 1522 1523 for (const char *p = cmd; *p != NUL; p++) { 1524 if (!inquote && *p == '|') { 1525 return (char *)p; 1526 } 1527 if (*p == '"') { 1528 inquote = !inquote; 1529 } else if (rem_backslash(p)) { 1530 p++; 1531 } 1532 } 1533 return NULL; 1534 } 1535 #endif 1536 1537 /// Create a shell command from a command string, input redirection file and 1538 /// output redirection file. 1539 /// 1540 /// @param cmd Command to execute. 1541 /// @param itmp NULL or the input file. 1542 /// @param otmp NULL or the output file. 1543 /// @param do_in true if stdin is needed. 1544 /// @returns an allocated string with the shell command. 1545 char *make_filter_cmd(char *cmd, char *itmp, char *otmp, bool do_in) 1546 { 1547 bool is_fish_shell = 1548 #if defined(UNIX) 1549 strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; 1550 #else 1551 false; 1552 #endif 1553 bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 1554 || strncmp(invocation_path_tail(p_sh, NULL), "powershell", 1555 10) == 0; 1556 1557 size_t len = strlen(cmd) + 1; // At least enough space for cmd + NULL. 1558 1559 len += is_fish_shell ? sizeof("begin; " "; end") - 1 1560 : !is_pwsh ? sizeof("(" ")") - 1 1561 : 0; 1562 1563 if (itmp != NULL) { 1564 len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + 6 // +6: #20530 1565 : strlen(itmp) + sizeof(" { " " < " " } ") - 1; 1566 } 1567 1568 if (do_in && is_pwsh) { 1569 len += sizeof(" $input | "); 1570 } 1571 1572 if (otmp != NULL) { 1573 len += strlen(otmp) + strlen(p_srr) + 2; // two extra spaces (" "), 1574 } 1575 1576 char *const buf = xmalloc(len); 1577 1578 if (is_pwsh) { 1579 if (itmp != NULL) { 1580 xstrlcpy(buf, "& { Get-Content ", len - 1); // FIXME: should we add "-Encoding utf8"? 1581 xstrlcat(buf, itmp, len - 1); 1582 xstrlcat(buf, " | & ", len - 1); // FIXME: add `&` ourself or leave to user? 1583 xstrlcat(buf, cmd, len - 1); 1584 xstrlcat(buf, " }", len - 1); 1585 } else if (do_in) { 1586 xstrlcpy(buf, " $input | ", len - 1); 1587 xstrlcat(buf, cmd, len); 1588 } else { 1589 xstrlcpy(buf, cmd, len); 1590 } 1591 } else { 1592 #if defined(UNIX) 1593 // Put delimiters around the command (for concatenated commands) when 1594 // redirecting input and/or output. 1595 if (itmp != NULL || otmp != NULL) { 1596 char *fmt = is_fish_shell ? "begin; %s; end" 1597 : "(%s)"; 1598 vim_snprintf(buf, len, fmt, cmd); 1599 } else { 1600 xstrlcpy(buf, cmd, len); 1601 } 1602 1603 if (itmp != NULL) { 1604 xstrlcat(buf, " < ", len - 1); 1605 xstrlcat(buf, itmp, len - 1); 1606 } 1607 #else 1608 // For shells that don't understand braces around commands, at least allow 1609 // the use of commands in a pipe. 1610 xstrlcpy(buf, cmd, len); 1611 if (itmp != NULL) { 1612 // If there is a pipe, we have to put the '<' in front of it. 1613 // Don't do this when 'shellquote' is not empty, otherwise the 1614 // redirection would be inside the quotes. 1615 if (*p_shq == NUL) { 1616 char *const p = find_pipe(buf); 1617 if (p != NULL) { 1618 *p = NUL; 1619 } 1620 } 1621 xstrlcat(buf, " < ", len); 1622 xstrlcat(buf, itmp, len); 1623 if (*p_shq == NUL) { 1624 const char *const p = find_pipe(cmd); 1625 if (p != NULL) { 1626 xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS 1627 xstrlcat(buf, p, len - 1); 1628 } 1629 } 1630 } 1631 #endif 1632 } 1633 if (otmp != NULL) { 1634 append_redir(buf, len, p_srr, otmp); 1635 } 1636 return buf; 1637 } 1638 1639 /// Append output redirection for the given file to the end of the buffer 1640 /// 1641 /// @param[out] buf Buffer to append to. 1642 /// @param[in] buflen Buffer length. 1643 /// @param[in] opt Separator or format string to append: will append 1644 /// `printf(' ' . opt, fname)` if `%s` is found in `opt` or 1645 /// a space, opt, a space and then fname if `%s` is not found 1646 /// there. 1647 /// @param[in] fname File name to append. 1648 void append_redir(char *const buf, const size_t buflen, const char *const opt, 1649 const char *const fname) 1650 { 1651 char *const end = buf + strlen(buf); 1652 // find "%s" 1653 const char *p = opt; 1654 for (; (p = strchr(p, '%')) != NULL; p++) { 1655 if (p[1] == 's') { // found %s 1656 break; 1657 } else if (p[1] == '%') { // skip %% 1658 p++; 1659 } 1660 } 1661 if (p != NULL) { 1662 *end = ' '; // not really needed? Not with sh, ksh or bash 1663 vim_snprintf(end + 1, (size_t)((ptrdiff_t)buflen - (end + 1 - buf)), opt, fname); 1664 } else { 1665 vim_snprintf(end, (size_t)((ptrdiff_t)buflen - (end - buf)), " %s %s", opt, fname); 1666 } 1667 } 1668 1669 void print_line_no_prefix(linenr_T lnum, bool use_number, bool list) 1670 { 1671 char numbuf[30]; 1672 1673 if (curwin->w_p_nu || use_number) { 1674 vim_snprintf(numbuf, sizeof(numbuf), "%*" PRIdLINENR " ", 1675 number_width(curwin), lnum); 1676 msg_puts_hl(numbuf, HLF_N + 1, false); // Highlight line nrs. 1677 } 1678 msg_prt_line(ml_get(lnum), list); 1679 } 1680 1681 static bool global_need_msg_kind = false; // Start new message only once during :global. 1682 1683 /// Print a text line. Also in silent mode ("ex -s"). 1684 void print_line(linenr_T lnum, bool use_number, bool list, bool first) 1685 { 1686 bool save_silent = silent_mode; 1687 1688 // apply :filter /pat/ 1689 if (message_filtered(ml_get(lnum))) { 1690 return; 1691 } 1692 1693 silent_mode = false; 1694 info_message = true; // use stdout, not stderr 1695 if ((!global_busy || global_need_msg_kind) && first) { 1696 msg_start(); 1697 msg_ext_set_kind("list_cmd"); 1698 global_need_msg_kind = false; 1699 } else if (!save_silent) { 1700 msg_putchar('\n'); // don't want trailing newline with regular messaging 1701 } 1702 print_line_no_prefix(lnum, use_number, list); 1703 if (save_silent) { 1704 msg_putchar('\n'); // batch mode message should always end in newline 1705 silent_mode = save_silent; 1706 } 1707 info_message = false; 1708 } 1709 1710 int rename_buffer(char *new_fname) 1711 { 1712 buf_T *buf = curbuf; 1713 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); 1714 // buffer changed, don't change name now 1715 if (buf != curbuf) { 1716 return FAIL; 1717 } 1718 if (aborting()) { // autocmds may abort script processing 1719 return FAIL; 1720 } 1721 // The name of the current buffer will be changed. 1722 // A new (unlisted) buffer entry needs to be made to hold the old file 1723 // name, which will become the alternate file name. 1724 // But don't set the alternate file name if the buffer didn't have a 1725 // name. 1726 char *fname = curbuf->b_ffname; 1727 char *sfname = curbuf->b_sfname; 1728 char *xfname = curbuf->b_fname; 1729 curbuf->b_ffname = NULL; 1730 curbuf->b_sfname = NULL; 1731 if (setfname(curbuf, new_fname, NULL, true) == FAIL) { 1732 curbuf->b_ffname = fname; 1733 curbuf->b_sfname = sfname; 1734 return FAIL; 1735 } 1736 curbuf->b_flags |= BF_NOTEDITED; 1737 if (xfname != NULL && *xfname != NUL) { 1738 buf = buflist_new(fname, xfname, curwin->w_cursor.lnum, 0); 1739 if (buf != NULL && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 1740 curwin->w_alt_fnum = buf->b_fnum; 1741 } 1742 } 1743 xfree(fname); 1744 xfree(sfname); 1745 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); 1746 // Change directories when the 'acd' option is set. 1747 do_autochdir(); 1748 return OK; 1749 } 1750 1751 /// ":file[!] [fname]". 1752 void ex_file(exarg_T *eap) 1753 { 1754 // ":0file" removes the file name. Check for illegal uses ":3file", 1755 // "0file name", etc. 1756 if (eap->addr_count > 0 1757 && (*eap->arg != NUL 1758 || eap->line2 > 0 1759 || eap->addr_count > 1)) { 1760 emsg(_(e_invarg)); 1761 return; 1762 } 1763 1764 if (*eap->arg != NUL || eap->addr_count == 1) { 1765 if (rename_buffer(eap->arg) == FAIL) { 1766 return; 1767 } 1768 redraw_tabline = true; 1769 } 1770 1771 // print file name if no argument or 'F' is not in 'shortmess' 1772 if (*eap->arg == NUL || !shortmess(SHM_FILEINFO)) { 1773 fileinfo(false, false, eap->forceit); 1774 } 1775 } 1776 1777 /// ":update". 1778 void ex_update(exarg_T *eap) 1779 { 1780 if (curbufIsChanged() 1781 || (!bt_nofilename(curbuf) && curbuf->b_ffname != NULL 1782 && !os_path_exists(curbuf->b_ffname))) { 1783 do_write(eap); 1784 } 1785 } 1786 1787 /// ":write" and ":saveas". 1788 void ex_write(exarg_T *eap) 1789 { 1790 if (eap->cmdidx == CMD_saveas) { 1791 // :saveas does not take a range, uses all lines. 1792 eap->line1 = 1; 1793 eap->line2 = curbuf->b_ml.ml_line_count; 1794 } 1795 1796 if (eap->usefilter) { // input lines to shell command 1797 do_bang(1, eap, false, true, false); 1798 } else { 1799 do_write(eap); 1800 } 1801 } 1802 1803 #ifdef UNIX 1804 static int check_writable(const char *fname) 1805 { 1806 if (os_nodetype(fname) == NODE_OTHER) { 1807 semsg(_("E503: \"%s\" is not a file or writable device"), fname); 1808 return FAIL; 1809 } 1810 return OK; 1811 } 1812 #endif 1813 1814 static int handle_mkdir_p_arg(exarg_T *eap, char *fname) 1815 { 1816 if (eap->mkdir_p && os_file_mkdir(fname, 0755) < 0) { 1817 return FAIL; 1818 } 1819 1820 return OK; 1821 } 1822 1823 /// Write current buffer to file "eap->arg". 1824 /// If "eap->append" is true, append to the file. 1825 /// 1826 /// If "*eap->arg == NUL" write to current file. 1827 /// 1828 /// @return FAIL for failure, OK otherwise. 1829 int do_write(exarg_T *eap) 1830 { 1831 bool other; 1832 char *fname = NULL; // init to shut up gcc 1833 int retval = FAIL; 1834 char *free_fname = NULL; 1835 buf_T *alt_buf = NULL; 1836 1837 if (not_writing()) { // check 'write' option 1838 return FAIL; 1839 } 1840 1841 char *ffname = eap->arg; 1842 if (*ffname == NUL) { 1843 if (eap->cmdidx == CMD_saveas) { 1844 emsg(_(e_argreq)); 1845 goto theend; 1846 } 1847 other = false; 1848 } else { 1849 fname = ffname; 1850 free_fname = fix_fname(ffname); 1851 // When out-of-memory, keep unexpanded file name, because we MUST be 1852 // able to write the file in this situation. 1853 if (free_fname != NULL) { 1854 ffname = free_fname; 1855 } 1856 other = otherfile(ffname); 1857 } 1858 1859 // If we have a new file, put its name in the list of alternate file names. 1860 if (other) { 1861 if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL 1862 || eap->cmdidx == CMD_saveas) { 1863 alt_buf = setaltfname(ffname, fname, 1); 1864 } else { 1865 alt_buf = buflist_findname(ffname); 1866 } 1867 if (alt_buf != NULL && alt_buf->b_ml.ml_mfp != NULL) { 1868 // Overwriting a file that is loaded in another buffer is not a 1869 // good idea. 1870 emsg(_(e_bufloaded)); 1871 goto theend; 1872 } 1873 } 1874 1875 // Writing to the current file is not allowed in readonly mode 1876 // and a file name is required. 1877 // "nofile" and "nowrite" buffers cannot be written implicitly either. 1878 if (!other && (bt_dontwrite_msg(curbuf) 1879 || check_fname() == FAIL 1880 #ifdef UNIX 1881 || check_writable(curbuf->b_ffname) == FAIL 1882 #endif 1883 || check_readonly(&eap->forceit, curbuf))) { 1884 goto theend; 1885 } 1886 1887 if (!other) { 1888 ffname = curbuf->b_ffname; 1889 fname = curbuf->b_fname; 1890 // Not writing the whole file is only allowed with '!'. 1891 if ((eap->line1 != 1 1892 || eap->line2 != curbuf->b_ml.ml_line_count) 1893 && !eap->forceit 1894 && !eap->append 1895 && !p_wa) { 1896 if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { 1897 if (vim_dialog_yesno(VIM_QUESTION, NULL, 1898 _("Write partial file?"), 2) != VIM_YES) { 1899 goto theend; 1900 } 1901 eap->forceit = true; 1902 } else { 1903 emsg(_("E140: Use ! to write partial buffer")); 1904 goto theend; 1905 } 1906 } 1907 } 1908 1909 if (check_overwrite(eap, curbuf, fname, ffname, other) == OK) { 1910 if (eap->cmdidx == CMD_saveas && alt_buf != NULL) { 1911 buf_T *was_curbuf = curbuf; 1912 1913 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); 1914 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, alt_buf); 1915 if (curbuf != was_curbuf || aborting()) { 1916 // buffer changed, don't change name now 1917 retval = FAIL; 1918 goto theend; 1919 } 1920 // Exchange the file names for the current and the alternate 1921 // buffer. This makes it look like we are now editing the buffer 1922 // under the new name. Must be done before buf_write(), because 1923 // if there is no file name and 'cpo' contains 'F', it will set 1924 // the file name. 1925 fname = alt_buf->b_fname; 1926 alt_buf->b_fname = curbuf->b_fname; 1927 curbuf->b_fname = fname; 1928 fname = alt_buf->b_ffname; 1929 alt_buf->b_ffname = curbuf->b_ffname; 1930 curbuf->b_ffname = fname; 1931 fname = alt_buf->b_sfname; 1932 alt_buf->b_sfname = curbuf->b_sfname; 1933 curbuf->b_sfname = fname; 1934 buf_name_changed(curbuf); 1935 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); 1936 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, alt_buf); 1937 if (!alt_buf->b_p_bl) { 1938 alt_buf->b_p_bl = true; 1939 apply_autocmds(EVENT_BUFADD, NULL, NULL, false, alt_buf); 1940 } 1941 if (curbuf != was_curbuf || aborting()) { 1942 // buffer changed, don't write the file 1943 retval = FAIL; 1944 goto theend; 1945 } 1946 1947 // If 'filetype' was empty try detecting it now. 1948 if (*curbuf->b_p_ft == NUL) { 1949 if (augroup_exists("filetypedetect")) { 1950 do_doautocmd("filetypedetect BufRead", true, NULL); 1951 } 1952 do_modelines(0); 1953 } 1954 1955 // Autocommands may have changed buffer names, esp. when 1956 // 'autochdir' is set. 1957 fname = curbuf->b_sfname; 1958 } 1959 1960 if (handle_mkdir_p_arg(eap, fname) == FAIL) { 1961 retval = FAIL; 1962 goto theend; 1963 } 1964 1965 int name_was_missing = curbuf->b_ffname == NULL; 1966 retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2, 1967 eap, eap->append, eap->forceit, true, false); 1968 1969 // After ":saveas fname" reset 'readonly'. 1970 if (eap->cmdidx == CMD_saveas) { 1971 if (retval == OK) { 1972 curbuf->b_p_ro = false; 1973 redraw_tabline = true; 1974 } 1975 } 1976 1977 // Change directories when the 'acd' option is set and the file name 1978 // got changed or set. 1979 if (eap->cmdidx == CMD_saveas || name_was_missing) { 1980 do_autochdir(); 1981 } 1982 } 1983 1984 theend: 1985 xfree(free_fname); 1986 return retval; 1987 } 1988 1989 /// Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED, 1990 /// BF_NEW or BF_READERR, check for overwriting current file. 1991 /// May set eap->forceit if a dialog says it's OK to overwrite. 1992 /// 1993 /// @param fname file name to be used (can differ from buf->ffname) 1994 /// @param ffname full path version of fname 1995 /// @param other writing under other name 1996 /// 1997 /// @return OK if it's OK, FAIL if it is not. 1998 int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, bool other) 1999 { 2000 // Write to another file or b_flags set or not writing the whole file: 2001 // overwriting only allowed with '!' 2002 // If "other" is false and bt_nofilename(buf) is true, this must be 2003 // writing an "acwrite" buffer to the same file as its b_ffname, and 2004 // buf_write() will only allow writing with BufWriteCmd autocommands, 2005 // so there is no need for an overwrite check. 2006 if ((other 2007 || (!bt_nofilename(buf) 2008 && ((buf->b_flags & BF_NOTEDITED) 2009 || ((buf->b_flags & BF_NEW) 2010 && vim_strchr(p_cpo, CPO_OVERNEW) == NULL) 2011 || (buf->b_flags & BF_READERR)))) 2012 && !p_wa 2013 && os_path_exists(ffname)) { 2014 if (!eap->forceit && !eap->append) { 2015 #ifdef UNIX 2016 // It is possible to open a directory on Unix. 2017 if (os_isdir(ffname)) { 2018 semsg(_(e_isadir2), ffname); 2019 return FAIL; 2020 } 2021 #endif 2022 if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { 2023 char buff[DIALOG_MSG_SIZE]; 2024 2025 dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname); 2026 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) { 2027 return FAIL; 2028 } 2029 eap->forceit = true; 2030 } else { 2031 emsg(_(e_exists)); 2032 return FAIL; 2033 } 2034 } 2035 2036 // For ":w! filename" check that no swap file exists for "filename". 2037 if (other && !emsg_silent) { 2038 char *dir; 2039 2040 // We only try the first entry in 'directory', without checking if 2041 // it's writable. If the "." directory is not writable the write 2042 // will probably fail anyway. 2043 // Use 'shortname' of the current buffer, since there is no buffer 2044 // for the written file. 2045 if (*p_dir == NUL) { 2046 dir = xmalloc(5); 2047 STRCPY(dir, "."); 2048 } else { 2049 dir = xmalloc(MAXPATHL); 2050 char *p = p_dir; 2051 copy_option_part(&p, dir, MAXPATHL, ","); 2052 } 2053 char *swapname = makeswapname(fname, ffname, curbuf, dir); 2054 xfree(dir); 2055 if (os_path_exists(swapname)) { 2056 if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { 2057 char buff[DIALOG_MSG_SIZE]; 2058 2059 dialog_msg(buff, 2060 _("Swap file \"%s\" exists, overwrite anyway?"), 2061 swapname); 2062 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) 2063 != VIM_YES) { 2064 xfree(swapname); 2065 return FAIL; 2066 } 2067 eap->forceit = true; 2068 } else { 2069 semsg(_("E768: Swap file exists: %s (:silent! overrides)"), 2070 swapname); 2071 xfree(swapname); 2072 return FAIL; 2073 } 2074 } 2075 xfree(swapname); 2076 } 2077 } 2078 return OK; 2079 } 2080 2081 /// Handle ":wnext", ":wNext" and ":wprevious" commands. 2082 void ex_wnext(exarg_T *eap) 2083 { 2084 int i; 2085 2086 if (eap->cmd[1] == 'n') { 2087 i = curwin->w_arg_idx + (int)eap->line2; 2088 } else { 2089 i = curwin->w_arg_idx - (int)eap->line2; 2090 } 2091 eap->line1 = 1; 2092 eap->line2 = curbuf->b_ml.ml_line_count; 2093 if (do_write(eap) != FAIL) { 2094 do_argfile(eap, i); 2095 } 2096 } 2097 2098 /// ":wall", ":wqall" and ":xall": Write all changed files (and exit). 2099 void do_wqall(exarg_T *eap) 2100 { 2101 int error = 0; 2102 int save_forceit = eap->forceit; 2103 bool save_exiting = exiting; 2104 2105 if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall) { 2106 if (before_quit_all(eap) == FAIL) { 2107 return; 2108 } 2109 exiting = true; 2110 } 2111 2112 FOR_ALL_BUFFERS(buf) { 2113 if (exiting && !eap->forceit 2114 && buf->terminal 2115 // TODO(zeertzjq): this always returns false for nvim_open_term() terminals. 2116 // Use terminal_running() instead? 2117 && channel_job_running((uint64_t)buf->b_p_channel)) { 2118 no_write_message_buf(buf); 2119 error++; 2120 } else if (!bufIsChanged(buf) || bt_dontwrite(buf)) { 2121 continue; 2122 } 2123 // Check if there is a reason the buffer cannot be written: 2124 // 1. if the 'write' option is set 2125 // 2. if there is no file name (even after browsing) 2126 // 3. if the 'readonly' is set (even after a dialog) 2127 // 4. if overwriting is allowed (even after a dialog) 2128 if (not_writing()) { 2129 error++; 2130 break; 2131 } 2132 if (buf->b_ffname == NULL) { 2133 semsg(_("E141: No file name for buffer %" PRId64), (int64_t)buf->b_fnum); 2134 error++; 2135 } else if (check_readonly(&eap->forceit, buf) 2136 || check_overwrite(eap, buf, buf->b_fname, buf->b_ffname, false) == FAIL) { 2137 error++; 2138 } else { 2139 bufref_T bufref; 2140 set_bufref(&bufref, buf); 2141 if (handle_mkdir_p_arg(eap, buf->b_fname) == FAIL 2142 || buf_write_all(buf, eap->forceit) == FAIL) { 2143 error++; 2144 } 2145 // An autocommand may have deleted the buffer. 2146 if (!bufref_valid(&bufref)) { 2147 buf = firstbuf; 2148 } 2149 } 2150 eap->forceit = save_forceit; // check_overwrite() may set it 2151 } 2152 if (exiting) { 2153 if (!error) { 2154 getout(0); // exit Vim 2155 } 2156 not_exiting(save_exiting); 2157 } 2158 } 2159 2160 /// Check the 'write' option. 2161 /// 2162 /// @return true and give a message when it's not st. 2163 static bool not_writing(void) 2164 { 2165 if (p_write) { 2166 return false; 2167 } 2168 emsg(_("E142: File not written: Writing is disabled by 'write' option")); 2169 return true; 2170 } 2171 2172 /// Check if a buffer is read-only (either 'readonly' option is set or file is 2173 /// read-only). Ask for overruling in a dialog. Return true and give an error 2174 /// message when the buffer is readonly. 2175 static int check_readonly(int *forceit, buf_T *buf) 2176 { 2177 // Handle a file being readonly when the 'readonly' option is set or when 2178 // the file exists and permissions are read-only. 2179 if (!*forceit && (buf->b_p_ro 2180 || (os_path_exists(buf->b_ffname) 2181 && !os_file_is_writable(buf->b_ffname)))) { 2182 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && buf->b_fname != NULL) { 2183 char buff[DIALOG_MSG_SIZE]; 2184 2185 if (buf->b_p_ro) { 2186 dialog_msg(buff, 2187 _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), 2188 buf->b_fname); 2189 } else { 2190 dialog_msg(buff, 2191 _("File permissions of \"%s\" are read-only.\nIt may still be possible to " 2192 "write it.\nDo you wish to try?"), 2193 buf->b_fname); 2194 } 2195 2196 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES) { 2197 // Set forceit, to force the writing of a readonly file 2198 *forceit = true; 2199 return false; 2200 } 2201 return true; 2202 } else if (buf->b_p_ro) { 2203 emsg(_(e_readonly)); 2204 } else { 2205 semsg(_("E505: \"%s\" is read-only (add ! to override)"), 2206 buf->b_fname); 2207 } 2208 return true; 2209 } 2210 2211 return false; 2212 } 2213 2214 /// Try to abandon the current file and edit a new or existing file. 2215 /// 2216 /// @param fnum the number of the file, if zero use "ffname_arg"/"sfname_arg". 2217 /// @param lnum the line number for the cursor in the new file (if non-zero). 2218 /// 2219 /// @return: 2220 /// GETFILE_ERROR for "normal" error, 2221 /// GETFILE_NOT_WRITTEN for "not written" error, 2222 /// GETFILE_SAME_FILE for success 2223 /// GETFILE_OPEN_OTHER for successfully opening another file. 2224 int getfile(int fnum, char *ffname_arg, char *sfname_arg, bool setpm, linenr_T lnum, bool forceit) 2225 { 2226 if (!check_can_set_curbuf_forceit(forceit)) { 2227 return GETFILE_ERROR; 2228 } 2229 2230 char *ffname = ffname_arg; 2231 char *sfname = sfname_arg; 2232 bool other; 2233 int retval; 2234 char *free_me = NULL; 2235 2236 if (text_locked()) { 2237 return GETFILE_ERROR; 2238 } 2239 if (curbuf_locked()) { 2240 return GETFILE_ERROR; 2241 } 2242 2243 if (fnum == 0) { 2244 // make ffname full path, set sfname 2245 fname_expand(curbuf, &ffname, &sfname); 2246 other = otherfile(ffname); 2247 free_me = ffname; // has been allocated, free() later 2248 } else { 2249 other = (fnum != curbuf->b_fnum); 2250 } 2251 2252 if (other) { 2253 no_wait_return++; // don't wait for autowrite message 2254 } 2255 if (other && !forceit && curbuf->b_nwindows == 1 && !buf_hide(curbuf) 2256 && curbufIsChanged() && autowrite(curbuf, forceit) == FAIL) { 2257 if (p_confirm && p_write) { 2258 dialog_changed(curbuf, false); 2259 } 2260 if (curbufIsChanged()) { 2261 no_wait_return--; 2262 no_write_message(); 2263 retval = GETFILE_NOT_WRITTEN; // File has been changed. 2264 goto theend; 2265 } 2266 } 2267 if (other) { 2268 no_wait_return--; 2269 } 2270 if (setpm) { 2271 setpcmark(); 2272 } 2273 if (!other) { 2274 if (lnum != 0) { 2275 curwin->w_cursor.lnum = lnum; 2276 } 2277 check_cursor_lnum(curwin); 2278 beginline(BL_SOL | BL_FIX); 2279 retval = GETFILE_SAME_FILE; // it's in the same file 2280 } else if (do_ecmd(fnum, ffname, sfname, NULL, lnum, 2281 (buf_hide(curbuf) ? ECMD_HIDE : 0) 2282 + (forceit ? ECMD_FORCEIT : 0), curwin) == OK) { 2283 retval = GETFILE_OPEN_OTHER; // opened another file 2284 } else { 2285 retval = GETFILE_ERROR; // error encountered 2286 } 2287 2288 theend: 2289 xfree(free_me); 2290 return retval; 2291 } 2292 2293 /// set v:swapcommand for the SwapExists autocommands. 2294 /// 2295 /// @param command [+cmd] to be executed (e.g. +10). 2296 /// @param newlnum if > 0: put cursor on this line number (if possible) 2297 // 2298 /// @return 1 if swapcommand was actually set, 0 otherwise 2299 bool set_swapcommand(char *command, linenr_T newlnum) 2300 { 2301 if ((command == NULL && newlnum <= 0) || *get_vim_var_str(VV_SWAPCOMMAND) != NUL) { 2302 return false; 2303 } 2304 const size_t len = (command != NULL) ? strlen(command) + 3 : 30; 2305 char *const p = xmalloc(len); 2306 if (command != NULL) { 2307 vim_snprintf(p, len, ":%s\r", command); 2308 } else { 2309 vim_snprintf(p, len, "%" PRId64 "G", (int64_t)newlnum); 2310 } 2311 set_vim_var_string(VV_SWAPCOMMAND, p, -1); 2312 xfree(p); 2313 return true; 2314 } 2315 2316 /// start editing a new file 2317 /// 2318 /// @param fnum file number; if zero use ffname/sfname 2319 /// @param ffname the file name 2320 /// - full path if sfname used, 2321 /// - any file name if sfname is NULL 2322 /// - empty string to re-edit with the same file name (but may 2323 /// be in a different directory) 2324 /// - NULL to start an empty buffer 2325 /// @param sfname the short file name (or NULL) 2326 /// @param eap contains the command to be executed after loading the file 2327 /// and forced 'ff' and 'fenc'. Can be NULL! 2328 /// @param newlnum if > 0: put cursor on this line number (if possible) 2329 /// ECMD_LASTL: use last position in loaded file 2330 /// ECMD_LAST: use last position in all files 2331 /// ECMD_ONE: use first line 2332 /// @param flags ECMD_HIDE: if true don't free the current buffer 2333 /// ECMD_SET_HELP: set b_help flag of (new) buffer before 2334 /// opening file 2335 /// ECMD_OLDBUF: use existing buffer if it exists 2336 /// ECMD_FORCEIT: ! used for Ex command 2337 /// ECMD_ADDBUF: don't edit, just add to buffer list 2338 /// ECMD_ALTBUF: like ECMD_ADDBUF and also set the alternate 2339 /// file 2340 /// ECMD_NOWINENTER: Do not trigger BufWinEnter 2341 /// @param oldwin Should be "curwin" when editing a new buffer in the current 2342 /// window, NULL when splitting the window first. When not NULL 2343 /// info of the previous buffer for "oldwin" is stored. 2344 /// 2345 /// @return FAIL for failure, OK otherwise 2346 int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum, int flags, 2347 win_T *oldwin) 2348 { 2349 bool other_file; // true if editing another file 2350 int oldbuf; // true if using existing buffer 2351 bool auto_buf = false; // true if autocommands brought us 2352 // into the buffer unexpectedly 2353 char *new_name = NULL; 2354 bool did_set_swapcommand = false; 2355 buf_T *buf; 2356 bufref_T bufref; 2357 bufref_T old_curbuf; 2358 char *free_fname = NULL; 2359 int retval = FAIL; 2360 linenr_T topline = 0; 2361 int newcol = -1; 2362 int solcol = -1; 2363 char *command = NULL; 2364 bool did_get_winopts = false; 2365 int readfile_flags = 0; 2366 bool did_inc_redrawing_disabled = false; 2367 OptInt *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; 2368 2369 if (eap != NULL) { 2370 command = eap->do_ecmd_cmd; 2371 } 2372 2373 set_bufref(&old_curbuf, curbuf); 2374 2375 if (fnum != 0) { 2376 if (fnum == curbuf->b_fnum) { // file is already being edited 2377 return OK; // nothing to do 2378 } 2379 other_file = true; 2380 } else { 2381 // if no short name given, use ffname for short name 2382 if (sfname == NULL) { 2383 sfname = ffname; 2384 } 2385 #ifdef CASE_INSENSITIVE_FILENAME 2386 if (sfname != NULL) { 2387 path_fix_case(sfname); // set correct case for sfname 2388 } 2389 #endif 2390 2391 if ((flags & (ECMD_ADDBUF | ECMD_ALTBUF)) 2392 && (ffname == NULL || *ffname == NUL)) { 2393 goto theend; 2394 } 2395 2396 if (ffname == NULL) { 2397 other_file = true; 2398 } else if (*ffname == NUL && curbuf->b_ffname == NULL) { // there is no file name 2399 other_file = false; 2400 } else { 2401 if (*ffname == NUL) { // re-edit with same file name 2402 ffname = curbuf->b_ffname; 2403 sfname = curbuf->b_fname; 2404 } 2405 free_fname = fix_fname(ffname); // may expand to full path name 2406 if (free_fname != NULL) { 2407 ffname = free_fname; 2408 } 2409 other_file = otherfile(ffname); 2410 } 2411 } 2412 2413 // Re-editing a terminal buffer: skip most buffer re-initialization. 2414 if (!other_file && curbuf->terminal) { 2415 check_arg_idx(curwin); // Needed when called from do_argfile(). 2416 maketitle(); // Title may show the arg index, e.g. "(2 of 5)". 2417 retval = OK; 2418 goto theend; 2419 } 2420 2421 // If the file was changed we may not be allowed to abandon it: 2422 // - if we are going to re-edit the same file 2423 // - or if we are the only window on this file and if ECMD_HIDE is false 2424 if (((!other_file && !(flags & ECMD_OLDBUF)) 2425 || (curbuf->b_nwindows == 1 2426 && !(flags & (ECMD_HIDE | ECMD_ADDBUF | ECMD_ALTBUF)))) 2427 && check_changed(curbuf, (p_awa ? CCGD_AW : 0) 2428 | (other_file ? 0 : CCGD_MULTWIN) 2429 | ((flags & ECMD_FORCEIT) ? CCGD_FORCEIT : 0) 2430 | (eap == NULL ? 0 : CCGD_EXCMD))) { 2431 if (fnum == 0 && other_file && ffname != NULL) { 2432 setaltfname(ffname, sfname, newlnum < 0 ? 0 : newlnum); 2433 } 2434 goto theend; 2435 } 2436 2437 // End Visual mode before switching to another buffer, so the text can be 2438 // copied into the GUI selection buffer. 2439 // Careful: may trigger ModeChanged() autocommand 2440 2441 // Should we block autocommands here? 2442 reset_VIsual(); 2443 2444 // autocommands freed window :( 2445 if (oldwin != NULL && !win_valid(oldwin)) { 2446 oldwin = NULL; 2447 } 2448 2449 did_set_swapcommand = set_swapcommand(command, newlnum); 2450 2451 // If we are starting to edit another file, open a (new) buffer. 2452 // Otherwise we re-use the current buffer. 2453 if (other_file) { 2454 const int prev_alt_fnum = curwin->w_alt_fnum; 2455 2456 if (!(flags & (ECMD_ADDBUF | ECMD_ALTBUF))) { 2457 if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 2458 curwin->w_alt_fnum = curbuf->b_fnum; 2459 } 2460 if (oldwin != NULL) { 2461 buflist_altfpos(oldwin); 2462 } 2463 } 2464 2465 if (fnum) { 2466 buf = buflist_findnr(fnum); 2467 } else { 2468 if (flags & (ECMD_ADDBUF | ECMD_ALTBUF)) { 2469 // Default the line number to zero to avoid that a wininfo item 2470 // is added for the current window. 2471 linenr_T tlnum = 0; 2472 2473 if (command != NULL) { 2474 tlnum = (linenr_T)atol(command); 2475 if (tlnum <= 0) { 2476 tlnum = 1; 2477 } 2478 } 2479 // Add BLN_NOCURWIN to avoid a new wininfo items are associated 2480 // with the current window. 2481 const buf_T *const newbuf 2482 = buflist_new(ffname, sfname, tlnum, BLN_LISTED | BLN_NOCURWIN); 2483 if (newbuf != NULL && (flags & ECMD_ALTBUF)) { 2484 curwin->w_alt_fnum = newbuf->b_fnum; 2485 } 2486 goto theend; 2487 } 2488 buf = buflist_new(ffname, sfname, 0, 2489 BLN_CURBUF | (flags & ECMD_SET_HELP ? 0 : BLN_LISTED)); 2490 // Autocmds may change curwin and curbuf. 2491 if (oldwin != NULL) { 2492 oldwin = curwin; 2493 } 2494 set_bufref(&old_curbuf, curbuf); 2495 } 2496 if (buf == NULL) { 2497 goto theend; 2498 } 2499 // autocommands try to edit a closing buffer, which like splitting, can 2500 // result in more windows displaying it; abort 2501 if (buf->b_locked_split) { 2502 // window was split, but not editing the new buffer, reset b_nwindows again 2503 if (oldwin == NULL 2504 && curwin->w_buffer != NULL 2505 && curwin->w_buffer->b_nwindows > 1) { 2506 curwin->w_buffer->b_nwindows--; 2507 } 2508 emsg(_(e_cannot_switch_to_a_closing_buffer)); 2509 goto theend; 2510 } 2511 if (curwin->w_alt_fnum == buf->b_fnum && prev_alt_fnum != 0) { 2512 // reusing the buffer, keep the old alternate file 2513 curwin->w_alt_fnum = prev_alt_fnum; 2514 } 2515 if (buf->b_ml.ml_mfp == NULL) { 2516 // No memfile yet. 2517 oldbuf = false; 2518 } else { 2519 // Existing memfile. 2520 oldbuf = true; 2521 set_bufref(&bufref, buf); 2522 buf_check_timestamp(buf); 2523 // Check if autocommands made buffer invalid or changed the current 2524 // buffer. 2525 if (!bufref_valid(&bufref) || curbuf != old_curbuf.br_buf) { 2526 goto theend; 2527 } 2528 if (aborting()) { 2529 // Autocmds may abort script processing. 2530 goto theend; 2531 } 2532 } 2533 2534 // May jump to last used line number for a loaded buffer or when asked 2535 // for explicitly 2536 if ((oldbuf && newlnum == ECMD_LASTL) || newlnum == ECMD_LAST) { 2537 pos_T *pos = &buflist_findfmark(buf)->mark; 2538 newlnum = pos->lnum; 2539 solcol = pos->col; 2540 } 2541 2542 // Make the (new) buffer the one used by the current window. 2543 // If the old buffer becomes unused, free it if ECMD_HIDE is false. 2544 // If the current buffer was empty and has no file name, curbuf 2545 // is returned by buflist_new(), nothing to do here. 2546 if (buf != curbuf) { 2547 // Should only be possible to get here if the cmdwin is closed, or 2548 // if it's opening and its buffer hasn't been set yet (the new 2549 // buffer is for it). 2550 assert(cmdwin_buf == NULL); 2551 2552 const int save_cmdwin_type = cmdwin_type; 2553 win_T *const save_cmdwin_win = cmdwin_win; 2554 win_T *const save_cmdwin_old_curwin = cmdwin_old_curwin; 2555 2556 // BufLeave applies to the old buffer. 2557 cmdwin_type = 0; 2558 cmdwin_win = NULL; 2559 cmdwin_old_curwin = NULL; 2560 2561 // Be careful: The autocommands may delete any buffer and change 2562 // the current buffer. 2563 // - If the buffer we are going to edit is deleted, give up. 2564 // - If the current buffer is deleted, prefer to load the new 2565 // buffer when loading a buffer is required. This avoids 2566 // loading another buffer which then must be closed again. 2567 // - If we ended up in the new buffer already, need to skip a few 2568 // things, set auto_buf. 2569 if (buf->b_fname != NULL) { 2570 new_name = xstrdup(buf->b_fname); 2571 } 2572 const bufref_T save_au_new_curbuf = au_new_curbuf; 2573 set_bufref(&au_new_curbuf, buf); 2574 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf); 2575 2576 cmdwin_type = save_cmdwin_type; 2577 cmdwin_win = save_cmdwin_win; 2578 cmdwin_old_curwin = save_cmdwin_old_curwin; 2579 2580 if (!bufref_valid(&au_new_curbuf)) { 2581 // New buffer has been deleted. 2582 delbuf_msg(new_name); // Frees new_name. 2583 au_new_curbuf = save_au_new_curbuf; 2584 goto theend; 2585 } 2586 if (aborting()) { // autocmds may abort script processing 2587 xfree(new_name); 2588 au_new_curbuf = save_au_new_curbuf; 2589 goto theend; 2590 } 2591 if (buf == curbuf) { // already in new buffer 2592 auto_buf = true; 2593 } else { 2594 win_T *the_curwin = curwin; 2595 buf_T *was_curbuf = curbuf; 2596 2597 // Set w_locked to avoid that autocommands close the window. 2598 // Set b_locked for the same reason. 2599 the_curwin->w_locked = true; 2600 buf->b_locked++; 2601 2602 if (curbuf == old_curbuf.br_buf) { 2603 buf_copy_options(buf, BCO_ENTER); 2604 } 2605 2606 // Close the link to the current buffer. This will set 2607 // oldwin->w_buffer to NULL. 2608 u_sync(false); 2609 const bool did_decrement 2610 = close_buffer(oldwin, curbuf, 2611 (flags & ECMD_HIDE) 2612 || (curbuf->terminal && terminal_running(curbuf->terminal)) 2613 ? 0 : DOBUF_UNLOAD, 2614 false, false); 2615 2616 // Autocommands may have closed the window. 2617 if (win_valid(the_curwin)) { 2618 the_curwin->w_locked = false; 2619 } 2620 buf->b_locked--; 2621 2622 // autocmds may abort script processing 2623 if (aborting() && curwin->w_buffer != NULL) { 2624 xfree(new_name); 2625 au_new_curbuf = save_au_new_curbuf; 2626 goto theend; 2627 } 2628 // Be careful again, like above. 2629 if (!bufref_valid(&au_new_curbuf)) { 2630 // New buffer has been deleted. 2631 delbuf_msg(new_name); // Frees new_name. 2632 au_new_curbuf = save_au_new_curbuf; 2633 goto theend; 2634 } 2635 if (buf == curbuf) { // already in new buffer 2636 // close_buffer() has decremented the window count, 2637 // increment it again here and restore w_buffer. 2638 if (did_decrement && buf_valid(was_curbuf)) { 2639 was_curbuf->b_nwindows++; 2640 } 2641 if (win_valid_any_tab(oldwin) && oldwin->w_buffer == NULL) { 2642 oldwin->w_buffer = was_curbuf; 2643 } 2644 auto_buf = true; 2645 } else { 2646 // <VN> We could instead free the synblock 2647 // and re-attach to buffer, perhaps. 2648 if (curwin->w_buffer == NULL 2649 || curwin->w_s == &(curwin->w_buffer->b_s)) { 2650 curwin->w_s = &(buf->b_s); 2651 } 2652 2653 curwin->w_buffer = buf; 2654 curbuf = buf; 2655 curbuf->b_nwindows++; 2656 2657 // Set 'fileformat', 'binary' and 'fenc' when forced. 2658 if (!oldbuf && eap != NULL) { 2659 set_file_options(true, eap); 2660 set_forced_fenc(eap); 2661 } 2662 } 2663 2664 // May get the window options from the last time this buffer 2665 // was in this window (or another window). If not used 2666 // before, reset the local window options to the global 2667 // values. Also restores old folding stuff. 2668 get_winopts(curbuf); 2669 did_get_winopts = true; 2670 } 2671 xfree(new_name); 2672 au_new_curbuf = save_au_new_curbuf; 2673 } 2674 2675 curwin->w_pcmark.lnum = 1; 2676 curwin->w_pcmark.col = 0; 2677 } else { // !other_file 2678 if ((flags & (ECMD_ADDBUF | ECMD_ALTBUF)) || check_fname() == FAIL) { 2679 goto theend; 2680 } 2681 oldbuf = (flags & ECMD_OLDBUF); 2682 } 2683 2684 // Don't redraw until the cursor is in the right line, otherwise 2685 // autocommands may cause ml_get errors. 2686 RedrawingDisabled++; 2687 did_inc_redrawing_disabled = true; 2688 2689 buf = curbuf; 2690 if ((flags & ECMD_SET_HELP) || keep_help_flag) { 2691 prepare_help_buffer(); 2692 } else if (!curbuf->b_help) { 2693 // Don't make a buffer listed if it's a help buffer. Useful when using 2694 // CTRL-O to go back to a help file. 2695 set_buflisted(true); 2696 } 2697 2698 // If autocommands change buffers under our fingers, forget about 2699 // editing the file. 2700 if (buf != curbuf) { 2701 goto theend; 2702 } 2703 if (aborting()) { // autocmds may abort script processing 2704 goto theend; 2705 } 2706 2707 // Since we are starting to edit a file, consider the filetype to be 2708 // unset. Helps for when an autocommand changes files and expects syntax 2709 // highlighting to work in the other file. 2710 curbuf->b_did_filetype = false; 2711 2712 // other_file oldbuf 2713 // false false re-edit same file, buffer is re-used 2714 // false true re-edit same file, nothing changes 2715 // true false start editing new file, new buffer 2716 // true true start editing in existing buffer (nothing to do) 2717 if (!other_file && !oldbuf) { // re-use the buffer 2718 set_last_cursor(curwin); // may set b_last_cursor 2719 if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL) { 2720 newlnum = curwin->w_cursor.lnum; 2721 solcol = curwin->w_cursor.col; 2722 } 2723 buf = curbuf; 2724 if (buf->b_fname != NULL) { 2725 new_name = xstrdup(buf->b_fname); 2726 } else { 2727 new_name = NULL; 2728 } 2729 set_bufref(&bufref, buf); 2730 2731 // If the buffer was used before, store the current contents so that 2732 // the reload can be undone. Do not do this if the (empty) buffer is 2733 // being re-used for another file. 2734 if (!(curbuf->b_flags & BF_NEVERLOADED) 2735 && (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)) { 2736 // Sync first so that this is a separate undo-able action. 2737 u_sync(false); 2738 if (u_savecommon(curbuf, 0, curbuf->b_ml.ml_line_count + 1, 0, true) 2739 == FAIL) { 2740 xfree(new_name); 2741 goto theend; 2742 } 2743 u_unchanged(curbuf); 2744 buf_freeall(curbuf, BFA_KEEP_UNDO); 2745 2746 // Tell readfile() not to clear or reload undo info. 2747 readfile_flags = READ_KEEP_UNDO; 2748 } else { 2749 buf_freeall(curbuf, 0); // Free all things for buffer. 2750 } 2751 // If autocommands deleted the buffer we were going to re-edit, give 2752 // up and jump to the end. 2753 if (!bufref_valid(&bufref)) { 2754 delbuf_msg(new_name); // Frees new_name. 2755 goto theend; 2756 } 2757 xfree(new_name); 2758 2759 // If autocommands change buffers under our fingers, forget about 2760 // re-editing the file. Should do the buf_clear_file(), but perhaps 2761 // the autocommands changed the buffer... 2762 if (buf != curbuf) { 2763 goto theend; 2764 } 2765 if (aborting()) { // autocmds may abort script processing 2766 goto theend; 2767 } 2768 buf_clear_file(curbuf); 2769 curbuf->b_op_start.lnum = 0; // clear '[ and '] marks 2770 curbuf->b_op_end.lnum = 0; 2771 } 2772 2773 // If we get here we are sure to start editing 2774 2775 // Assume success now 2776 retval = OK; 2777 2778 // If the file name was changed, reset the not-edit flag so that ":write" 2779 // works. 2780 if (!other_file) { 2781 curbuf->b_flags &= ~BF_NOTEDITED; 2782 } 2783 2784 // Check if we are editing the w_arg_idx file in the argument list. 2785 check_arg_idx(curwin); 2786 2787 if (!auto_buf) { 2788 // Set cursor and init window before reading the file and executing 2789 // autocommands. This allows for the autocommands to position the 2790 // cursor. 2791 curwin_init(); 2792 2793 // It's possible that all lines in the buffer changed. Need to update 2794 // automatic folding for all windows where it's used. 2795 FOR_ALL_TAB_WINDOWS(tp, win) { 2796 if (win->w_buffer == curbuf) { 2797 foldUpdateAll(win); 2798 } 2799 } 2800 2801 // Change directories when the 'acd' option is set. 2802 do_autochdir(); 2803 2804 // Careful: open_buffer() and apply_autocmds() may change the current 2805 // buffer and window. 2806 pos_T orig_pos = curwin->w_cursor; 2807 topline = curwin->w_topline; 2808 if (!oldbuf) { // need to read the file 2809 swap_exists_action = SEA_DIALOG; 2810 curbuf->b_flags |= BF_CHECK_RO; // set/reset 'ro' flag 2811 2812 // Open the buffer and read the file. 2813 if (flags & ECMD_NOWINENTER) { 2814 readfile_flags |= READ_NOWINENTER; 2815 } 2816 if (should_abort(open_buffer(false, eap, readfile_flags))) { 2817 retval = FAIL; 2818 } 2819 2820 if (swap_exists_action == SEA_QUIT) { 2821 retval = FAIL; 2822 } 2823 handle_swap_exists(&old_curbuf); 2824 } else { 2825 // Read the modelines, but only to set window-local options. Any 2826 // buffer-local options have already been set and may have been 2827 // changed by the user. 2828 do_modelines(OPT_WINONLY); 2829 2830 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, false, curbuf, 2831 &retval); 2832 if ((flags & ECMD_NOWINENTER) == 0) { 2833 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, false, curbuf, 2834 &retval); 2835 } 2836 } 2837 check_arg_idx(curwin); 2838 2839 // If autocommands change the cursor position or topline, we should 2840 // keep it. Also when it moves within a line. But not when it moves 2841 // to the first non-blank. 2842 if (!equalpos(curwin->w_cursor, orig_pos)) { 2843 const char *text = get_cursor_line_ptr(); 2844 2845 if (curwin->w_cursor.lnum != orig_pos.lnum 2846 || curwin->w_cursor.col != (int)(skipwhite(text) - text)) { 2847 newlnum = curwin->w_cursor.lnum; 2848 newcol = curwin->w_cursor.col; 2849 } 2850 } 2851 if (curwin->w_topline == topline) { 2852 topline = 0; 2853 } 2854 2855 // Even when cursor didn't move we need to recompute topline. 2856 changed_line_abv_curs(); 2857 2858 maketitle(); 2859 } 2860 2861 // Tell the diff stuff that this buffer is new and/or needs updating. 2862 // Also needed when re-editing the same buffer, because unloading will 2863 // have removed it as a diff buffer. 2864 if (curwin->w_p_diff) { 2865 diff_buf_add(curbuf); 2866 diff_invalidate(curbuf); 2867 } 2868 2869 // If the window options were changed may need to set the spell language. 2870 // Can only do this after the buffer has been properly setup. 2871 if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { 2872 parse_spelllang(curwin); 2873 } 2874 2875 if (command == NULL) { 2876 if (newcol >= 0) { // position set by autocommands 2877 curwin->w_cursor.lnum = newlnum; 2878 curwin->w_cursor.col = newcol; 2879 check_cursor(curwin); 2880 } else if (newlnum > 0) { // line number from caller or old position 2881 curwin->w_cursor.lnum = newlnum; 2882 check_cursor_lnum(curwin); 2883 if (solcol >= 0 && !p_sol) { 2884 // 'sol' is off: Use last known column. 2885 curwin->w_cursor.col = solcol; 2886 check_cursor_col(curwin); 2887 curwin->w_cursor.coladd = 0; 2888 curwin->w_set_curswant = true; 2889 } else { 2890 beginline(BL_SOL | BL_FIX); 2891 } 2892 } else { // no line number, go to last line in Ex mode 2893 if (exmode_active) { 2894 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2895 } 2896 beginline(BL_WHITE | BL_FIX); 2897 } 2898 } 2899 2900 // Check if cursors in other windows on the same buffer are still valid 2901 check_lnums(false); 2902 2903 // Did not read the file, need to show some info about the file. 2904 // Do this after setting the cursor. 2905 if (oldbuf 2906 && !auto_buf) { 2907 int msg_scroll_save = msg_scroll; 2908 2909 // Obey the 'O' flag in 'cpoptions': overwrite any previous file 2910 // message. 2911 if (shortmess(SHM_OVERALL) && !msg_listdo_overwrite && !exiting && p_verbose == 0) { 2912 msg_scroll = false; 2913 } 2914 if (!msg_scroll) { // wait a bit when overwriting an error msg 2915 msg_check_for_delay(false); 2916 } 2917 msg_start(); 2918 msg_scroll = msg_scroll_save; 2919 msg_scrolled_ign = true; 2920 2921 if (!shortmess(SHM_FILEINFO)) { 2922 fileinfo(false, true, false); 2923 } 2924 2925 msg_scrolled_ign = false; 2926 } 2927 2928 curbuf->b_last_used = time(NULL); 2929 2930 if (command != NULL) { 2931 do_cmdline(command, NULL, NULL, DOCMD_VERBOSE); 2932 } 2933 2934 if (curbuf->b_kmap_state & KEYMAP_INIT) { 2935 keymap_init(); 2936 } 2937 2938 RedrawingDisabled--; 2939 did_inc_redrawing_disabled = false; 2940 if (!skip_redraw) { 2941 OptInt n = *so_ptr; 2942 if (topline == 0 && command == NULL) { 2943 *so_ptr = 999; // force cursor to be vertically centered in the window 2944 } 2945 update_topline(curwin); 2946 curwin->w_scbind_pos = plines_m_win_fill(curwin, 1, curwin->w_topline); 2947 *so_ptr = n; 2948 redraw_curbuf_later(UPD_NOT_VALID); // redraw this buffer later 2949 } 2950 2951 // Change directories when the 'acd' option is set. 2952 do_autochdir(); 2953 2954 theend: 2955 if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->terminal != NULL) { 2956 terminal_check_size(old_curbuf.br_buf->terminal); 2957 } 2958 if ((!bufref_valid(&old_curbuf) || curbuf != old_curbuf.br_buf) && curbuf->terminal != NULL) { 2959 terminal_check_size(curbuf->terminal); 2960 } 2961 2962 if (did_inc_redrawing_disabled) { 2963 RedrawingDisabled--; 2964 } 2965 if (did_set_swapcommand) { 2966 set_vim_var_string(VV_SWAPCOMMAND, NULL, -1); 2967 } 2968 xfree(free_fname); 2969 return retval; 2970 } 2971 2972 static void delbuf_msg(char *name) 2973 { 2974 semsg(_("E143: Autocommands unexpectedly deleted new buffer %s"), 2975 name == NULL ? "" : name); 2976 xfree(name); 2977 au_new_curbuf.br_buf = NULL; 2978 au_new_curbuf.br_buf_free_count = 0; 2979 } 2980 2981 static int append_indent = 0; // autoindent for first line 2982 2983 /// ":insert" and ":append", also used by ":change" 2984 void ex_append(exarg_T *eap) 2985 { 2986 char *theline; 2987 bool did_undo = false; 2988 linenr_T lnum = eap->line2; 2989 int indent = 0; 2990 char *p; 2991 bool empty = (curbuf->b_ml.ml_flags & ML_EMPTY); 2992 2993 // the ! flag toggles autoindent 2994 if (eap->forceit) { 2995 curbuf->b_p_ai = !curbuf->b_p_ai; 2996 } 2997 2998 // First autoindent comes from the line we start on 2999 if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0) { 3000 append_indent = get_indent_lnum(lnum); 3001 } 3002 3003 if (eap->cmdidx != CMD_append) { 3004 lnum--; 3005 } 3006 3007 // when the buffer is empty need to delete the dummy line 3008 if (empty && lnum == 1) { 3009 lnum = 0; 3010 } 3011 3012 State = MODE_INSERT; // behave like in Insert mode 3013 if (curbuf->b_p_iminsert == B_IMODE_LMAP) { 3014 State |= MODE_LANGMAP; 3015 } 3016 3017 while (true) { 3018 msg_scroll = true; 3019 need_wait_return = false; 3020 if (curbuf->b_p_ai) { 3021 if (append_indent >= 0) { 3022 indent = append_indent; 3023 append_indent = -1; 3024 } else if (lnum > 0) { 3025 indent = get_indent_lnum(lnum); 3026 } 3027 } 3028 if (*eap->arg == '|') { 3029 // Get the text after the trailing bar. 3030 theline = xstrdup(eap->arg + 1); 3031 *eap->arg = NUL; 3032 } else if (eap->ea_getline == NULL) { 3033 // No getline() function, use the lines that follow. This ends 3034 // when there is no more. 3035 if (eap->nextcmd == NULL) { 3036 break; 3037 } 3038 p = vim_strchr(eap->nextcmd, NL); 3039 if (p == NULL) { 3040 p = eap->nextcmd + strlen(eap->nextcmd); 3041 } 3042 theline = xmemdupz(eap->nextcmd, (size_t)(p - eap->nextcmd)); 3043 if (*p != NUL) { 3044 p++; 3045 } else { 3046 p = NULL; 3047 } 3048 eap->nextcmd = p; 3049 } else { 3050 int save_State = State; 3051 // Set State to avoid the cursor shape to be set to MODE_INSERT 3052 // state when getline() returns. 3053 State = MODE_CMDLINE; 3054 theline = eap->ea_getline(eap->cstack->cs_looplevel > 0 ? -1 : NUL, 3055 eap->cookie, indent, true); 3056 State = save_State; 3057 } 3058 lines_left = Rows - 1; 3059 if (theline == NULL) { 3060 break; 3061 } 3062 3063 // Look for the "." after automatic indent. 3064 int vcol = 0; 3065 for (p = theline; indent > vcol; p++) { 3066 if (*p == ' ') { 3067 vcol++; 3068 } else if (*p == TAB) { 3069 vcol += 8 - vcol % 8; 3070 } else { 3071 break; 3072 } 3073 } 3074 if ((p[0] == '.' && p[1] == NUL) 3075 || (!did_undo && u_save(lnum, lnum + 1 + (empty ? 1 : 0)) 3076 == FAIL)) { 3077 xfree(theline); 3078 break; 3079 } 3080 3081 // don't use autoindent if nothing was typed. 3082 if (p[0] == NUL) { 3083 theline[0] = NUL; 3084 } 3085 3086 did_undo = true; 3087 ml_append(lnum, theline, 0, false); 3088 if (empty) { 3089 // there are no marks below the inserted lines 3090 appended_lines(lnum, 1); 3091 } else { 3092 appended_lines_mark(lnum, 1); 3093 } 3094 3095 xfree(theline); 3096 lnum++; 3097 3098 if (empty) { 3099 ml_delete(2); 3100 empty = false; 3101 } 3102 } 3103 State = MODE_NORMAL; 3104 ui_cursor_shape(); 3105 3106 if (eap->forceit) { 3107 curbuf->b_p_ai = !curbuf->b_p_ai; 3108 } 3109 3110 // "start" is set to eap->line2+1 unless that position is invalid (when 3111 // eap->line2 pointed to the end of the buffer and nothing was appended) 3112 // "end" is set to lnum when something has been appended, otherwise 3113 // it is the same as "start" -- Acevedo 3114 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 3115 curbuf->b_op_start.lnum 3116 = (eap->line2 < curbuf->b_ml.ml_line_count) ? eap->line2 + 1 : curbuf->b_ml.ml_line_count; 3117 if (eap->cmdidx != CMD_append) { 3118 curbuf->b_op_start.lnum--; 3119 } 3120 curbuf->b_op_end.lnum = (eap->line2 < lnum) ? lnum : curbuf->b_op_start.lnum; 3121 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 3122 } 3123 curwin->w_cursor.lnum = lnum; 3124 check_cursor_lnum(curwin); 3125 beginline(BL_SOL | BL_FIX); 3126 3127 need_wait_return = false; // don't use wait_return() now 3128 ex_no_reprint = true; 3129 } 3130 3131 /// ":change" 3132 void ex_change(exarg_T *eap) 3133 { 3134 linenr_T lnum; 3135 3136 if (eap->line2 >= eap->line1 3137 && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) { 3138 return; 3139 } 3140 3141 // the ! flag toggles autoindent 3142 if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai) { 3143 append_indent = get_indent_lnum(eap->line1); 3144 } 3145 3146 for (lnum = eap->line2; lnum >= eap->line1; lnum--) { 3147 if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete 3148 break; 3149 } 3150 ml_delete(eap->line1); 3151 } 3152 3153 // make sure the cursor is not beyond the end of the file now 3154 check_cursor_lnum(curwin); 3155 deleted_lines_mark(eap->line1, (eap->line2 - lnum)); 3156 3157 // ":append" on the line above the deleted lines. 3158 eap->line2 = eap->line1; 3159 ex_append(eap); 3160 } 3161 3162 void ex_z(exarg_T *eap) 3163 { 3164 int64_t bigness; 3165 int minus = 0; 3166 linenr_T start, end, curs; 3167 linenr_T lnum = eap->line2; 3168 3169 // Vi compatible: ":z!" uses display height, without a count uses 3170 // 'scroll' 3171 if (eap->forceit) { 3172 bigness = Rows - 1; 3173 } else if (ONE_WINDOW) { 3174 bigness = curwin->w_p_scr * 2; 3175 } else { 3176 bigness = curwin->w_view_height - 3; 3177 } 3178 bigness = MAX(bigness, 1); 3179 3180 char *x = eap->arg; 3181 char *kind = x; 3182 if (*kind == '-' || *kind == '+' || *kind == '=' 3183 || *kind == '^' || *kind == '.') { 3184 x++; 3185 } 3186 while (*x == '-' || *x == '+') { 3187 x++; 3188 } 3189 3190 if (*x != 0) { 3191 if (!ascii_isdigit(*x)) { 3192 emsg(_(e_non_numeric_argument_to_z)); 3193 return; 3194 } 3195 bigness = atol(x); 3196 3197 // bigness could be < 0 if atol(x) overflows. 3198 if (bigness > 2 * curbuf->b_ml.ml_line_count || bigness < 0) { 3199 bigness = 2 * curbuf->b_ml.ml_line_count; 3200 } 3201 3202 p_window = (int)bigness; 3203 if (*kind == '=') { 3204 bigness += 2; 3205 } 3206 } 3207 3208 // the number of '-' and '+' multiplies the distance 3209 if (*kind == '-' || *kind == '+') { 3210 for (x = kind + 1; *x == *kind; x++) {} 3211 } 3212 3213 switch (*kind) { 3214 case '-': 3215 start = lnum - (linenr_T)bigness * (linenr_T)(x - kind) + 1; 3216 end = start + (linenr_T)bigness - 1; 3217 curs = end; 3218 break; 3219 3220 case '=': 3221 start = lnum - ((linenr_T)bigness + 1) / 2 + 1; 3222 end = lnum + ((linenr_T)bigness + 1) / 2 - 1; 3223 curs = lnum; 3224 minus = 1; 3225 break; 3226 3227 case '^': 3228 start = lnum - (linenr_T)bigness * 2; 3229 end = lnum - (linenr_T)bigness; 3230 curs = lnum - (linenr_T)bigness; 3231 break; 3232 3233 case '.': 3234 start = lnum - ((linenr_T)bigness + 1) / 2 + 1; 3235 end = lnum + ((linenr_T)bigness + 1) / 2 - 1; 3236 curs = end; 3237 break; 3238 3239 default: // '+' 3240 start = lnum; 3241 if (*kind == '+') { 3242 start += (linenr_T)bigness * (linenr_T)(x - kind - 1) + 1; 3243 } else if (eap->addr_count == 0) { 3244 start++; 3245 } 3246 end = start + (linenr_T)bigness - 1; 3247 curs = end; 3248 break; 3249 } 3250 3251 start = MAX(start, 1); 3252 end = MIN(end, curbuf->b_ml.ml_line_count); 3253 curs = MIN(MAX(curs, 1), curbuf->b_ml.ml_line_count); 3254 3255 for (linenr_T i = start; i <= end; i++) { 3256 if (minus && i == lnum) { 3257 msg_putchar('\n'); 3258 3259 for (int j = 1; j < Columns; j++) { 3260 msg_putchar('-'); 3261 } 3262 } 3263 3264 print_line(i, eap->flags & EXFLAG_NR, eap->flags & EXFLAG_LIST, i == start); 3265 3266 if (minus && i == lnum) { 3267 msg_putchar('\n'); 3268 3269 for (int j = 1; j < Columns; j++) { 3270 msg_putchar('-'); 3271 } 3272 } 3273 } 3274 3275 if (curwin->w_cursor.lnum != curs) { 3276 curwin->w_cursor.lnum = curs; 3277 curwin->w_cursor.col = 0; 3278 } 3279 ex_no_reprint = true; 3280 } 3281 3282 /// @return true if the secure flag is set and also give an error message. 3283 /// Otherwise, return false. 3284 bool check_secure(void) 3285 { 3286 if (secure) { 3287 secure = 2; 3288 emsg(_(e_curdir)); 3289 return true; 3290 } 3291 3292 // In the sandbox more things are not allowed, including the things 3293 // disallowed in secure mode. 3294 if (sandbox != 0) { 3295 emsg(_(e_sandbox)); 3296 return true; 3297 } 3298 return false; 3299 } 3300 3301 /// Previous substitute replacement string 3302 static SubReplacementString old_sub = { NULL, 0, NULL }; 3303 3304 static int global_need_beginline; // call beginline() after ":g" 3305 3306 /// Get old substitute replacement string 3307 /// 3308 /// @param[out] ret_sub Location where old string will be saved. 3309 void sub_get_replacement(SubReplacementString *const ret_sub) 3310 FUNC_ATTR_NONNULL_ALL 3311 { 3312 *ret_sub = old_sub; 3313 } 3314 3315 /// Set substitute string and timestamp 3316 /// 3317 /// @warning `sub` must be in allocated memory. It is not copied. 3318 /// 3319 /// @param[in] sub New replacement string. 3320 void sub_set_replacement(SubReplacementString sub) 3321 { 3322 xfree(old_sub.sub); 3323 if (sub.additional_data != old_sub.additional_data) { 3324 xfree(old_sub.additional_data); 3325 } 3326 old_sub = sub; 3327 } 3328 3329 /// Recognize ":%s/\n//" and turn it into a join command, which is much 3330 /// more efficient. 3331 /// 3332 /// @param[in] eap Ex arguments 3333 /// @param[in] pat Search pattern 3334 /// @param[in] sub Replacement string 3335 /// @param[in] cmd Command from :s_flags 3336 /// @param[in] save Save pattern to options, history 3337 /// 3338 /// @returns true if :substitute can be replaced with a join command 3339 static bool sub_joining_lines(exarg_T *eap, char *pat, size_t patlen, const char *sub, 3340 const char *cmd, bool save, bool keeppatterns) 3341 FUNC_ATTR_NONNULL_ARG(1, 4, 5) 3342 { 3343 // TODO(vim): find a generic solution to make line-joining operations more 3344 // efficient, avoid allocating a string that grows in size. 3345 if (pat != NULL 3346 && strcmp(pat, "\\n") == 0 3347 && *sub == NUL 3348 && (*cmd == NUL || (cmd[1] == NUL 3349 && (*cmd == 'g' 3350 || *cmd == 'l' 3351 || *cmd == 'p' 3352 || *cmd == '#')))) { 3353 if (eap->skip) { 3354 return true; 3355 } 3356 curwin->w_cursor.lnum = eap->line1; 3357 if (*cmd == 'l') { 3358 eap->flags = EXFLAG_LIST; 3359 } else if (*cmd == '#') { 3360 eap->flags = EXFLAG_NR; 3361 } else if (*cmd == 'p') { 3362 eap->flags = EXFLAG_PRINT; 3363 } 3364 3365 // The number of lines joined is the number of lines in the range 3366 linenr_T joined_lines_count = eap->line2 - eap->line1 + 1 3367 // plus one extra line if not at the end of file. 3368 + (eap->line2 < curbuf->b_ml.ml_line_count ? 1 : 0); 3369 if (joined_lines_count > 1) { 3370 do_join((size_t)joined_lines_count, false, true, false, true); 3371 sub_nsubs = joined_lines_count - 1; 3372 sub_nlines = 1; 3373 do_sub_msg(false); 3374 ex_may_print(eap); 3375 } 3376 3377 if (save) { 3378 if (!keeppatterns) { 3379 save_re_pat(RE_SUBST, pat, patlen, magic_isset()); 3380 } 3381 // put pattern in history 3382 add_to_history(HIST_SEARCH, pat, patlen, true, NUL); 3383 } 3384 3385 return true; 3386 } 3387 3388 return false; 3389 } 3390 3391 /// Allocate memory to store the replacement text for :substitute. 3392 /// 3393 /// Slightly more memory that is strictly necessary is allocated to reduce the 3394 /// frequency of memory (re)allocation. 3395 /// 3396 /// @param[in,out] new_start pointer to the memory for the replacement text 3397 /// @param[in,out] new_start_len pointer to length of new_start 3398 /// @param[in] needed_len amount of memory needed 3399 /// 3400 /// @returns pointer to the end of the allocated memory 3401 static char *sub_grow_buf(char **new_start, int *new_start_len, int needed_len) 3402 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 3403 { 3404 char *new_end; 3405 if (*new_start == NULL) { 3406 // Get some space for a temporary buffer to do the 3407 // substitution into (and some extra space to avoid 3408 // too many calls to xmalloc()/free()). 3409 *new_start_len = needed_len + 50; 3410 *new_start = xcalloc(1, (size_t)(*new_start_len)); 3411 **new_start = NUL; 3412 new_end = *new_start; 3413 } else { 3414 // Check if the temporary buffer is long enough to do the 3415 // substitution into. If not, make it larger (with a bit 3416 // extra to avoid too many calls to xmalloc()/free()). 3417 size_t len = strlen(*new_start); 3418 needed_len += (int)len; 3419 if (needed_len > *new_start_len) { 3420 size_t prev_new_start_len = (size_t)(*new_start_len); 3421 *new_start_len = needed_len + 50; 3422 size_t added_len = (size_t)(*new_start_len) - prev_new_start_len; 3423 *new_start = xrealloc(*new_start, (size_t)(*new_start_len)); 3424 memset(*new_start + prev_new_start_len, 0, added_len); 3425 } 3426 new_end = *new_start + len; 3427 } 3428 3429 return new_end; 3430 } 3431 3432 /// Parse cmd string for :substitute's {flags} and update subflags accordingly 3433 /// 3434 /// @param[in] cmd command string 3435 /// @param[in,out] subflags current flags defined for the :substitute command 3436 /// @param[in,out] which_pat pattern type from which to get default search 3437 /// 3438 /// @returns pointer to the end of the flags, which may be the end of the string 3439 static char *sub_parse_flags(char *cmd, subflags_T *subflags, int *which_pat) 3440 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 3441 { 3442 // Find trailing options. When '&' is used, keep old options. 3443 if (*cmd == '&') { 3444 cmd++; 3445 } else { 3446 subflags->do_all = p_gd; 3447 subflags->do_ask = false; 3448 subflags->do_error = true; 3449 subflags->do_print = false; 3450 subflags->do_list = false; 3451 subflags->do_count = false; 3452 subflags->do_number = false; 3453 subflags->do_ic = kSubHonorOptions; 3454 } 3455 while (*cmd) { 3456 // Note that 'g' and 'c' are always inverted. 3457 // 'r' is never inverted. 3458 if (*cmd == 'g') { 3459 subflags->do_all = !subflags->do_all; 3460 } else if (*cmd == 'c') { 3461 subflags->do_ask = !subflags->do_ask; 3462 } else if (*cmd == 'n') { 3463 subflags->do_count = true; 3464 } else if (*cmd == 'e') { 3465 subflags->do_error = !subflags->do_error; 3466 } else if (*cmd == 'r') { // use last used regexp 3467 *which_pat = RE_LAST; 3468 } else if (*cmd == 'p') { 3469 subflags->do_print = true; 3470 } else if (*cmd == '#') { 3471 subflags->do_print = true; 3472 subflags->do_number = true; 3473 } else if (*cmd == 'l') { 3474 subflags->do_print = true; 3475 subflags->do_list = true; 3476 } else if (*cmd == 'i') { // ignore case 3477 subflags->do_ic = kSubIgnoreCase; 3478 } else if (*cmd == 'I') { // don't ignore case 3479 subflags->do_ic = kSubMatchCase; 3480 } else { 3481 break; 3482 } 3483 cmd++; 3484 } 3485 if (subflags->do_count) { 3486 subflags->do_ask = false; 3487 } 3488 3489 return cmd; 3490 } 3491 3492 /// Skip over the "sub" part in :s/pat/sub/ where "delimiter" is the separating 3493 /// character. 3494 static char *skip_substitute(char *start, int delimiter) 3495 { 3496 char *p = start; 3497 3498 while (p[0]) { 3499 if (p[0] == delimiter) { // end delimiter found 3500 *p++ = NUL; // replace it with a NUL 3501 break; 3502 } 3503 if (p[0] == '\\' && p[1] != 0) { // skip escaped characters 3504 p++; 3505 } 3506 MB_PTR_ADV(p); 3507 } 3508 return p; 3509 } 3510 3511 static int check_regexp_delim(int c) 3512 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3513 { 3514 if (isalpha(c)) { 3515 emsg(_("E146: Regular expressions can't be delimited by letters")); 3516 return FAIL; 3517 } 3518 return OK; 3519 } 3520 3521 /// Perform a substitution from line eap->line1 to line eap->line2 using the 3522 /// command pointed to by eap->arg which should be of the form: 3523 /// 3524 /// /pattern/substitution/{flags} 3525 /// 3526 /// The usual escapes are supported as described in the regexp docs. 3527 /// 3528 /// @param cmdpreview_ns The namespace to show 'inccommand' preview highlights. 3529 /// If <= 0, preview shouldn't be shown. 3530 /// @return 0, 1 or 2. See cmdpreview_may_show() for more information on the meaning. 3531 static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_ns, 3532 const handle_T cmdpreview_bufnr) 3533 { 3534 #define ADJUST_SUB_FIRSTLNUM() \ 3535 do { \ 3536 /* For a multi-line match, make a copy of the last matched */ \ 3537 /* line and continue in that one. */ \ 3538 if (nmatch > 1) { \ 3539 sub_firstlnum += (linenr_T)nmatch - 1; \ 3540 xfree(sub_firstline); \ 3541 sub_firstline = xstrnsave(ml_get(sub_firstlnum), \ 3542 (size_t)ml_get_len(sub_firstlnum)); \ 3543 /* When going beyond the last line, stop substituting. */ \ 3544 if (sub_firstlnum <= line2) { \ 3545 do_again = true; \ 3546 } else { \ 3547 subflags.do_all = false; \ 3548 } \ 3549 } \ 3550 if (skip_match) { \ 3551 /* Already hit end of the buffer, sub_firstlnum is one */ \ 3552 /* less than what it ought to be. */ \ 3553 xfree(sub_firstline); \ 3554 sub_firstline = xstrdup(""); \ 3555 copycol = 0; \ 3556 } \ 3557 } while (0) 3558 3559 int i = 0; 3560 regmmatch_T regmatch; 3561 static subflags_T subflags = { 3562 .do_all = false, 3563 .do_ask = false, 3564 .do_count = false, 3565 .do_error = true, 3566 .do_print = false, 3567 .do_list = false, 3568 .do_number = false, 3569 .do_ic = kSubHonorOptions 3570 }; 3571 char *pat = NULL; 3572 char *sub = NULL; // init for GCC 3573 size_t patlen = 0; 3574 int delimiter; 3575 bool has_second_delim = false; 3576 int sublen; 3577 bool got_quit = false; 3578 bool got_match = false; 3579 int which_pat; 3580 char *cmd = eap->arg; 3581 linenr_T first_line = 0; // first changed line 3582 linenr_T last_line = 0; // below last changed line AFTER the change 3583 linenr_T old_line_count = curbuf->b_ml.ml_line_count; 3584 char *sub_firstline; // allocated copy of first sub line 3585 bool endcolumn = false; // cursor in last column when done 3586 const bool keeppatterns = cmdmod.cmod_flags & CMOD_KEEPPATTERNS; 3587 PreviewLines preview_lines = { KV_INITIAL_VALUE, 0 }; 3588 static int pre_hl_id = 0; 3589 pos_T old_cursor = curwin->w_cursor; 3590 int start_nsubs; 3591 3592 bool did_save = false; 3593 3594 if (!global_busy) { 3595 sub_nsubs = 0; 3596 sub_nlines = 0; 3597 } 3598 start_nsubs = sub_nsubs; 3599 3600 if (eap->cmdidx == CMD_tilde) { 3601 which_pat = RE_LAST; // use last used regexp 3602 } else { 3603 which_pat = RE_SUBST; // use last substitute regexp 3604 } 3605 // new pattern and substitution 3606 if (eap->cmd[0] == 's' && *cmd != NUL && !ascii_iswhite(*cmd) 3607 && vim_strchr("0123456789cegriIp|\"", (uint8_t)(*cmd)) == NULL) { 3608 // don't accept alphanumeric for separator 3609 if (check_regexp_delim(*cmd) == FAIL) { 3610 return 0; 3611 } 3612 3613 // undocumented vi feature: 3614 // "\/sub/" and "\?sub?" use last used search pattern (almost like 3615 // //sub/r). "\&sub&" use last substitute pattern (like //sub/). 3616 if (*cmd == '\\') { 3617 cmd++; 3618 if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { 3619 emsg(_(e_backslash)); 3620 return 0; 3621 } 3622 if (*cmd != '&') { 3623 which_pat = RE_SEARCH; // use last '/' pattern 3624 } 3625 pat = ""; // empty search pattern 3626 patlen = 0; 3627 delimiter = (uint8_t)(*cmd++); // remember delimiter character 3628 has_second_delim = true; 3629 } else { // find the end of the regexp 3630 which_pat = RE_LAST; // use last used regexp 3631 delimiter = (uint8_t)(*cmd++); // remember delimiter character 3632 pat = cmd; // remember start of search pat 3633 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL); 3634 if (cmd[0] == delimiter) { // end delimiter found 3635 *cmd++ = NUL; // replace it with a NUL 3636 has_second_delim = true; 3637 } 3638 patlen = strlen(pat); 3639 } 3640 3641 // Small incompatibility: vi sees '\n' as end of the command, but in 3642 // Vim we want to use '\n' to find/substitute a NUL. 3643 char *p = cmd; // remember the start of the substitution 3644 cmd = skip_substitute(cmd, delimiter); 3645 sub = xstrdup(p); 3646 3647 if (!eap->skip && !keeppatterns && cmdpreview_ns <= 0) { 3648 sub_set_replacement((SubReplacementString) { 3649 .sub = xstrdup(sub), 3650 .timestamp = os_time(), 3651 .additional_data = NULL, 3652 }); 3653 } 3654 } else if (!eap->skip) { // use previous pattern and substitution 3655 if (old_sub.sub == NULL) { // there is no previous command 3656 emsg(_(e_nopresub)); 3657 return 0; 3658 } 3659 pat = NULL; // search_regcomp() will use previous pattern 3660 patlen = 0; 3661 sub = xstrdup(old_sub.sub); 3662 3663 // Vi compatibility quirk: repeating with ":s" keeps the cursor in the 3664 // last column after using "$". 3665 endcolumn = (curwin->w_curswant == MAXCOL); 3666 } 3667 3668 if (sub != NULL && sub_joining_lines(eap, pat, patlen, sub, cmd, cmdpreview_ns <= 0, 3669 keeppatterns)) { 3670 xfree(sub); 3671 return 0; 3672 } 3673 3674 cmd = sub_parse_flags(cmd, &subflags, &which_pat); 3675 3676 bool save_do_all = subflags.do_all; // remember user specified 'g' flag 3677 bool save_do_ask = subflags.do_ask; // remember user specified 'c' flag 3678 3679 // check for a trailing count 3680 cmd = skipwhite(cmd); 3681 if (ascii_isdigit(*cmd)) { 3682 i = getdigits_int(&cmd, true, INT_MAX); 3683 if (i <= 0 && !eap->skip && subflags.do_error) { 3684 emsg(_(e_zerocount)); 3685 xfree(sub); 3686 return 0; 3687 } else if (i >= INT_MAX) { 3688 char buf[20]; 3689 vim_snprintf(buf, sizeof(buf), "%d", i); 3690 semsg(_(e_val_too_large), buf); 3691 xfree(sub); 3692 return 0; 3693 } 3694 eap->line1 = eap->line2; 3695 eap->line2 += (linenr_T)i - 1; 3696 eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count); 3697 } 3698 3699 // check for trailing command or garbage 3700 cmd = skipwhite(cmd); 3701 if (*cmd && *cmd != '"') { // if not end-of-line or comment 3702 eap->nextcmd = check_nextcmd(cmd); 3703 if (eap->nextcmd == NULL) { 3704 semsg(_(e_trailing_arg), cmd); 3705 xfree(sub); 3706 return 0; 3707 } 3708 } 3709 3710 if (eap->skip) { // not executing commands, only parsing 3711 xfree(sub); 3712 return 0; 3713 } 3714 3715 if (!subflags.do_count && !MODIFIABLE(curbuf)) { 3716 // Substitution is not allowed in non-'modifiable' buffer 3717 emsg(_(e_modifiable)); 3718 xfree(sub); 3719 return 0; 3720 } 3721 3722 if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat, 3723 (cmdpreview_ns > 0 ? 0 : SEARCH_HIS), ®match) == FAIL) { 3724 if (subflags.do_error) { 3725 emsg(_(e_invcmd)); 3726 } 3727 xfree(sub); 3728 return 0; 3729 } 3730 3731 // the 'i' or 'I' flag overrules 'ignorecase' and 'smartcase' 3732 if (subflags.do_ic == kSubIgnoreCase) { 3733 regmatch.rmm_ic = true; 3734 } else if (subflags.do_ic == kSubMatchCase) { 3735 regmatch.rmm_ic = false; 3736 } 3737 3738 sub_firstline = NULL; 3739 3740 assert(sub != NULL); 3741 3742 // If the substitute pattern starts with "\=" then it's an expression. 3743 // Make a copy, a recursive function may free it. 3744 // Otherwise, '~' in the substitute pattern is replaced with the old 3745 // pattern. We do it here once to avoid it to be replaced over and over 3746 // again. 3747 if (sub[0] == '\\' && sub[1] == '=') { 3748 char *p = xstrdup(sub); 3749 xfree(sub); 3750 sub = p; 3751 } else { 3752 char *p = regtilde(sub, magic_isset(), cmdpreview_ns > 0); 3753 if (p != sub) { 3754 xfree(sub); 3755 sub = p; 3756 } 3757 } 3758 3759 // Check for a match on each line. 3760 // If preview: limit to max('cmdwinheight', viewport). 3761 linenr_T line2 = eap->line2; 3762 3763 for (linenr_T lnum = eap->line1; 3764 lnum <= line2 && !got_quit && !aborting() 3765 && (cmdpreview_ns <= 0 || preview_lines.lines_needed <= (linenr_T)p_cwh 3766 || lnum <= curwin->w_botline); 3767 lnum++) { 3768 int nmatch = vim_regexec_multi(®match, curwin, curbuf, lnum, 3769 0, NULL, NULL); 3770 if (nmatch) { 3771 colnr_T copycol; 3772 colnr_T matchcol; 3773 colnr_T prev_matchcol = MAXCOL; 3774 char *new_end; 3775 char *new_start = NULL; 3776 int new_start_len = 0; 3777 char *p1; 3778 bool did_sub = false; 3779 int lastone; 3780 linenr_T nmatch_tl = 0; // nr of lines matched below lnum 3781 int do_again; // do it again after joining lines 3782 bool skip_match = false; 3783 linenr_T sub_firstlnum; // nr of first sub line 3784 3785 // Track where substitutions started (set once per line). 3786 linenr_T lnum_start = 0; 3787 3788 // Track per-line data for each match. 3789 // Will be sent as a batch to `extmark_splice` after the substitution is done. 3790 typedef struct { 3791 int start_col; // Position in new text where replacement goes 3792 lpos_T start; // Match start position in original text 3793 lpos_T end; // Match end position in original text 3794 int matchcols; // Columns deleted from original text 3795 bcount_t matchbytes; // Bytes deleted from original text 3796 int subcols; // Columns in replacement text 3797 bcount_t subbytes; // Bytes in replacement text 3798 linenr_T lnum_before; // Line number before this substitution 3799 linenr_T lnum_after; // Line number after this substitution 3800 } LineData; 3801 3802 kvec_t(LineData) line_matches = KV_INITIAL_VALUE; 3803 3804 // The new text is build up step by step, to avoid too much 3805 // copying. There are these pieces: 3806 // sub_firstline The old text, unmodified. 3807 // copycol Column in the old text where we started 3808 // looking for a match; from here old text still 3809 // needs to be copied to the new text. 3810 // matchcol Column number of the old text where to look 3811 // for the next match. It's just after the 3812 // previous match or one further. 3813 // prev_matchcol Column just after the previous match (if any). 3814 // Mostly equal to matchcol, except for the first 3815 // match and after skipping an empty match. 3816 // regmatch.*pos Where the pattern matched in the old text. 3817 // new_start The new text, all that has been produced so 3818 // far. 3819 // new_end The new text, where to append new text. 3820 // 3821 // lnum The line number where we found the start of 3822 // the match. Can be below the line we searched 3823 // when there is a \n before a \zs in the 3824 // pattern. 3825 // sub_firstlnum The line number in the buffer where to look 3826 // for a match. Can be different from "lnum" 3827 // when the pattern or substitute string contains 3828 // line breaks. 3829 // 3830 // Special situations: 3831 // - When the substitute string contains a line break, the part up 3832 // to the line break is inserted in the text, but the copy of 3833 // the original line is kept. "sub_firstlnum" is adjusted for 3834 // the inserted lines. 3835 // - When the matched pattern contains a line break, the old line 3836 // is taken from the line at the end of the pattern. The lines 3837 // in the match are deleted later, "sub_firstlnum" is adjusted 3838 // accordingly. 3839 // 3840 // The new text is built up in new_start[]. It has some extra 3841 // room to avoid using xmalloc()/free() too often. new_start_len is 3842 // the length of the allocated memory at new_start. 3843 // 3844 // Make a copy of the old line, so it won't be taken away when 3845 // updating the screen or handling a multi-line match. The "old_" 3846 // pointers point into this copy. 3847 sub_firstlnum = lnum; 3848 copycol = 0; 3849 matchcol = 0; 3850 3851 // At first match, remember current cursor position. 3852 if (!got_match) { 3853 setpcmark(); 3854 got_match = true; 3855 } 3856 3857 // Loop until nothing more to replace in this line. 3858 // 1. Handle match with empty string. 3859 // 2. If subflags.do_ask is set, ask for confirmation. 3860 // 3. substitute the string. 3861 // 4. if subflags.do_all is set, find next match 3862 // 5. break if there isn't another match in this line 3863 while (true) { 3864 SubResult current_match = { 3865 .start = { 0, 0 }, 3866 .end = { 0, 0 }, 3867 .pre_match = 0, 3868 }; 3869 // lnum is where the match start, but maybe not the pattern match, 3870 // since we can have \n before \zs in the pattern 3871 3872 // Advance "lnum" to the line where the match starts. The 3873 // match does not start in the first line when there is a line 3874 // break before \zs. 3875 if (regmatch.startpos[0].lnum > 0) { 3876 current_match.pre_match = lnum; 3877 lnum += regmatch.startpos[0].lnum; 3878 sub_firstlnum += regmatch.startpos[0].lnum; 3879 nmatch -= regmatch.startpos[0].lnum; 3880 XFREE_CLEAR(sub_firstline); 3881 } 3882 3883 // Now we're at the line where the pattern match starts 3884 // Note: If not first match on a line, column can't be known here 3885 current_match.start.lnum = sub_firstlnum; 3886 3887 // Match might be after the last line for "\n\zs" matching at 3888 // the end of the last line. 3889 if (lnum > curbuf->b_ml.ml_line_count) { 3890 break; 3891 } 3892 if (sub_firstline == NULL) { 3893 sub_firstline = xstrnsave(ml_get(sub_firstlnum), 3894 (size_t)ml_get_len(sub_firstlnum)); 3895 } 3896 3897 // Save the line number of the last change for the final 3898 // cursor position (just like Vi). 3899 curwin->w_cursor.lnum = lnum; 3900 do_again = false; 3901 3902 // 1. Match empty string does not count, except for first 3903 // match. This reproduces the strange vi behaviour. 3904 // This also catches endless loops. 3905 if (matchcol == prev_matchcol 3906 && regmatch.endpos[0].lnum == 0 3907 && matchcol == regmatch.endpos[0].col) { 3908 if (sub_firstline[matchcol] == NUL) { 3909 // We already were at the end of the line. Don't look 3910 // for a match in this line again. 3911 skip_match = true; 3912 } else { 3913 // search for a match at next column 3914 matchcol += utfc_ptr2len(sub_firstline + matchcol); 3915 } 3916 // match will be pushed to preview_lines, bring it into a proper state 3917 current_match.start.col = matchcol; 3918 current_match.end.lnum = sub_firstlnum; 3919 current_match.end.col = matchcol; 3920 goto skip; 3921 } 3922 3923 // Normally we continue searching for a match just after the 3924 // previous match. 3925 matchcol = regmatch.endpos[0].col; 3926 prev_matchcol = matchcol; 3927 3928 // 2. If subflags.do_count is set only increase the counter. 3929 // If do_ask is set, ask for confirmation. 3930 if (subflags.do_count) { 3931 // For a multi-line match, put matchcol at the NUL at 3932 // the end of the line and set nmatch to one, so that 3933 // we continue looking for a match on the next line. 3934 // Avoids that ":s/\nB\@=//gc" get stuck. 3935 if (nmatch > 1) { 3936 matchcol = (colnr_T)strlen(sub_firstline); 3937 nmatch = 1; 3938 skip_match = true; 3939 } 3940 sub_nsubs++; 3941 did_sub = true; 3942 // Skip the substitution, unless an expression is used, 3943 // then it is evaluated in the sandbox. 3944 if (!(sub[0] == '\\' && sub[1] == '=')) { 3945 goto skip; 3946 } 3947 } 3948 3949 if (subflags.do_ask && cmdpreview_ns <= 0) { 3950 int typed = 0; 3951 int save_State = State; 3952 curwin->w_cursor.col = regmatch.startpos[0].col; 3953 3954 if (curwin->w_p_crb) { 3955 do_check_cursorbind(); 3956 } 3957 3958 // When 'cpoptions' contains "u" don't sync undo when 3959 // asking for confirmation. 3960 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) { 3961 no_u_sync++; 3962 } 3963 3964 // Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed. 3965 while (subflags.do_ask) { 3966 if (exmode_active) { 3967 print_line_no_prefix(lnum, subflags.do_number, subflags.do_list); 3968 3969 colnr_T sc, ec; 3970 getvcol(curwin, &curwin->w_cursor, &sc, NULL, NULL); 3971 curwin->w_cursor.col = MAX(regmatch.endpos[0].col - 1, 0); 3972 3973 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec); 3974 curwin->w_cursor.col = regmatch.startpos[0].col; 3975 if (subflags.do_number || curwin->w_p_nu) { 3976 int numw = number_width(curwin) + 1; 3977 sc += numw; 3978 ec += numw; 3979 } 3980 3981 char *prompt = xmallocz((size_t)ec + 1); 3982 memset(prompt, ' ', (size_t)sc); 3983 memset(prompt + sc, '^', (size_t)(ec - sc) + 1); 3984 char *resp = getcmdline_prompt(-1, prompt, 0, EXPAND_NOTHING, NULL, 3985 CALLBACK_NONE, false, NULL); 3986 if (!ui_has(kUIMessages)) { 3987 msg_putchar('\n'); 3988 } 3989 xfree(prompt); 3990 if (resp != NULL) { 3991 typed = (uint8_t)(*resp); 3992 xfree(resp); 3993 } else { 3994 // getcmdline_prompt() returns NULL if there is no command line to return. 3995 typed = NUL; 3996 } 3997 // When ":normal" runs out of characters we get 3998 // an empty line. Use "q" to get out of the 3999 // loop. 4000 if (ex_normal_busy && typed == NUL) { 4001 typed = 'q'; 4002 } 4003 } else { 4004 char *orig_line = NULL; 4005 int len_change = 0; 4006 const bool save_p_lz = p_lz; 4007 int save_p_fen = curwin->w_p_fen; 4008 4009 curwin->w_p_fen = false; 4010 // Invert the matched string. 4011 // Remove the inversion afterwards. 4012 int temp = RedrawingDisabled; 4013 RedrawingDisabled = 0; 4014 4015 // avoid calling update_screen() in vgetorpeek() 4016 p_lz = false; 4017 4018 if (new_start != NULL) { 4019 // There already was a substitution, we would 4020 // like to show this to the user. We cannot 4021 // really update the line, it would change 4022 // what matches. Temporarily replace the line 4023 // and change it back afterwards. 4024 orig_line = xstrnsave(ml_get(lnum), (size_t)ml_get_len(lnum)); 4025 char *new_line = concat_str(new_start, sub_firstline + copycol); 4026 4027 // Position the cursor relative to the end of the line, the 4028 // previous substitute may have inserted or deleted characters 4029 // before the cursor. 4030 len_change = (int)strlen(new_line) - (int)strlen(orig_line); 4031 curwin->w_cursor.col += len_change; 4032 ml_replace(lnum, new_line, false); 4033 } 4034 4035 search_match_lines = regmatch.endpos[0].lnum 4036 - regmatch.startpos[0].lnum; 4037 search_match_endcol = regmatch.endpos[0].col 4038 + len_change; 4039 if (search_match_lines == 0 && search_match_endcol == 0) { 4040 // highlight at least one character for /^/ 4041 search_match_endcol = 1; 4042 } 4043 highlight_match = true; 4044 4045 update_topline(curwin); 4046 validate_cursor(curwin); 4047 redraw_later(curwin, UPD_SOME_VALID); 4048 show_cursor_info_later(true); 4049 update_screen(); 4050 redraw_later(curwin, UPD_SOME_VALID); 4051 4052 curwin->w_p_fen = save_p_fen; 4053 4054 char *p = _("replace with %s? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll up(^E)/down(^Y)"); 4055 snprintf(IObuff, IOSIZE, p, sub); 4056 p = xstrdup(IObuff); 4057 typed = prompt_for_input(p, HLF_R, true, NULL); 4058 highlight_match = false; 4059 xfree(p); 4060 4061 msg_didout = false; // don't scroll up 4062 gotocmdline(true); 4063 p_lz = save_p_lz; 4064 RedrawingDisabled = temp; 4065 4066 // restore the line 4067 if (orig_line != NULL) { 4068 ml_replace(lnum, orig_line, false); 4069 } 4070 } 4071 4072 need_wait_return = false; // no hit-return prompt 4073 if (typed == 'q' || typed == ESC || typed == Ctrl_C) { 4074 got_quit = true; 4075 break; 4076 } 4077 if (typed == 'n') { 4078 break; 4079 } 4080 if (typed == 'y') { 4081 break; 4082 } 4083 if (typed == 'l') { 4084 // last: replace and then stop 4085 subflags.do_all = false; 4086 line2 = lnum; 4087 break; 4088 } 4089 if (typed == 'a') { 4090 subflags.do_ask = false; 4091 break; 4092 } 4093 if (typed == Ctrl_E) { 4094 scrollup_clamp(); 4095 } else if (typed == Ctrl_Y) { 4096 scrolldown_clamp(); 4097 } 4098 } 4099 State = save_State; 4100 setmouse(); 4101 if (vim_strchr(p_cpo, CPO_UNDO) != NULL) { 4102 no_u_sync--; 4103 } 4104 4105 if (typed == 'n') { 4106 // For a multi-line match, put matchcol at the NUL at 4107 // the end of the line and set nmatch to one, so that 4108 // we continue looking for a match on the next line. 4109 // Avoids that ":%s/\nB\@=//gc" and ":%s/\n/,\r/gc" 4110 // get stuck when pressing 'n'. 4111 if (nmatch > 1) { 4112 matchcol = (colnr_T)strlen(sub_firstline); 4113 skip_match = true; 4114 } 4115 goto skip; 4116 } 4117 if (got_quit) { 4118 goto skip; 4119 } 4120 } 4121 4122 // Move the cursor to the start of the match, so that we can 4123 // use "\=col("."). 4124 curwin->w_cursor.col = regmatch.startpos[0].col; 4125 4126 // When the match included the "$" of the last line it may 4127 // go beyond the last line of the buffer. 4128 if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) { 4129 nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1; 4130 current_match.end.lnum = sub_firstlnum + (linenr_T)nmatch; 4131 skip_match = true; 4132 // safety check 4133 if (nmatch < 0) { 4134 goto skip; 4135 } 4136 } 4137 4138 // Save the line numbers for the preview buffer 4139 // NOTE: If the pattern matches a final newline, the next line will 4140 // be shown also, but should not be highlighted. Intentional for now. 4141 if (cmdpreview_ns > 0 && !has_second_delim) { 4142 current_match.start.col = regmatch.startpos[0].col; 4143 if (current_match.end.lnum == 0) { 4144 current_match.end.lnum = sub_firstlnum + (linenr_T)nmatch - 1; 4145 } 4146 current_match.end.col = regmatch.endpos[0].col; 4147 4148 ADJUST_SUB_FIRSTLNUM(); 4149 lnum += (linenr_T)nmatch - 1; 4150 4151 goto skip; 4152 } 4153 4154 // 3. Substitute the string. During 'inccommand' preview only do this if 4155 // there is a replace pattern. 4156 if (cmdpreview_ns <= 0 || has_second_delim) { 4157 lnum_start = lnum; // save the start lnum 4158 int save_ma = curbuf->b_p_ma; 4159 int save_sandbox = sandbox; 4160 if (subflags.do_count) { 4161 // prevent accidentally changing the buffer by a function 4162 curbuf->b_p_ma = false; 4163 sandbox++; 4164 } 4165 // Save flags for recursion. They can change for e.g. 4166 // :s/^/\=execute("s#^##gn") 4167 subflags_T subflags_save = subflags; 4168 4169 // Disallow changing text or switching window in an expression. 4170 textlock++; 4171 // Get length of substitution part, including the NUL. 4172 // When it fails sublen is zero. 4173 sublen = vim_regsub_multi(®match, 4174 sub_firstlnum - regmatch.startpos[0].lnum, 4175 sub, sub_firstline, 0, 4176 REGSUB_BACKSLASH 4177 | (magic_isset() ? REGSUB_MAGIC : 0)); 4178 textlock--; 4179 4180 // If getting the substitute string caused an error, don't do 4181 // the replacement. 4182 // Don't keep flags set by a recursive call 4183 subflags = subflags_save; 4184 if (sublen == 0 || aborting() || subflags.do_count) { 4185 curbuf->b_p_ma = save_ma; 4186 sandbox = save_sandbox; 4187 goto skip; 4188 } 4189 4190 // Need room for: 4191 // - result so far in new_start (not for first sub in line) 4192 // - original text up to match 4193 // - length of substituted part 4194 // - original text after match 4195 if (nmatch == 1) { 4196 p1 = sub_firstline; 4197 } else { 4198 linenr_T lastlnum = sub_firstlnum + (linenr_T)nmatch - 1; 4199 p1 = ml_get(lastlnum); 4200 nmatch_tl += nmatch - 1; 4201 } 4202 int copy_len = regmatch.startpos[0].col - copycol; 4203 new_end = sub_grow_buf(&new_start, &new_start_len, 4204 (colnr_T)strlen(p1) - regmatch.endpos[0].col 4205 + copy_len + sublen + 1); 4206 4207 // copy the text up to the part that matched 4208 memmove(new_end, sub_firstline + copycol, (size_t)copy_len); 4209 new_end += copy_len; 4210 4211 if (new_start_len - copy_len < sublen) { 4212 sublen = new_start_len - copy_len - 1; 4213 } 4214 4215 // Finally, at this point we can know where the match actually will 4216 // start in the new text 4217 int start_col = (int)(new_end - new_start); 4218 current_match.start.col = start_col; 4219 4220 textlock++; 4221 vim_regsub_multi(®match, 4222 sub_firstlnum - regmatch.startpos[0].lnum, 4223 sub, new_end, sublen, 4224 REGSUB_COPY | REGSUB_BACKSLASH 4225 | (magic_isset() ? REGSUB_MAGIC : 0)); 4226 textlock--; 4227 sub_nsubs++; 4228 did_sub = true; 4229 4230 // Move the cursor to the start of the line, to avoid that it 4231 // is beyond the end of the line after the substitution. 4232 curwin->w_cursor.col = 0; 4233 4234 // Remember next character to be copied. 4235 copycol = regmatch.endpos[0].col; 4236 4237 ADJUST_SUB_FIRSTLNUM(); 4238 4239 // TODO(bfredl): this has some robustness issues, look into later. 4240 bcount_t replaced_bytes = 0; 4241 lpos_T start = regmatch.startpos[0]; 4242 lpos_T end = regmatch.endpos[0]; 4243 for (i = 0; i < nmatch - 1; i++) { 4244 replaced_bytes += (bcount_t)strlen(ml_get((linenr_T)(lnum_start + i))) + 1; 4245 } 4246 replaced_bytes += end.col - start.col; 4247 4248 // Save the line number before processing newlines. 4249 linenr_T lnum_before_newlines = lnum; 4250 4251 // Now the trick is to replace CTRL-M chars with a real line 4252 // break. This would make it impossible to insert a CTRL-M in 4253 // the text. The line break can be avoided by preceding the 4254 // CTRL-M with a backslash. To be able to insert a backslash, 4255 // they must be doubled in the string and are halved here. 4256 // That is Vi compatible. 4257 for (p1 = new_end; *p1; p1++) { 4258 if (p1[0] == '\\' && p1[1] != NUL) { // remove backslash 4259 sublen--; // correct the byte counts for extmark_splice() 4260 STRMOVE(p1, p1 + 1); 4261 } else if (*p1 == CAR) { 4262 if (u_inssub(lnum) == OK) { // prepare for undo 4263 *p1 = NUL; // truncate up to the CR 4264 ml_append(lnum - 1, new_start, 4265 (colnr_T)(p1 - new_start + 1), false); 4266 mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1, 0, kExtmarkNOOP); 4267 4268 if (subflags.do_ask) { 4269 appended_lines(lnum - 1, 1); 4270 } else { 4271 if (first_line == 0) { 4272 first_line = lnum; 4273 } 4274 last_line = lnum + 1; 4275 } 4276 // All line numbers increase. 4277 sub_firstlnum++; 4278 lnum++; 4279 line2++; 4280 // move the cursor to the new line, like Vi 4281 curwin->w_cursor.lnum++; 4282 // copy the rest 4283 STRMOVE(new_start, p1 + 1); 4284 p1 = new_start - 1; 4285 } 4286 } else { 4287 p1 += utfc_ptr2len(p1) - 1; 4288 } 4289 } 4290 colnr_T new_endcol = (colnr_T)strlen(new_start); 4291 current_match.end.col = new_endcol; 4292 current_match.end.lnum = lnum; 4293 4294 int matchcols = end.col - ((end.lnum == start.lnum) 4295 ? start.col : 0); 4296 int subcols = new_endcol - ((lnum == lnum_start) ? start_col : 0); 4297 if (!did_save) { 4298 // Required for Undo to work for extmarks. 4299 u_save_cursor(); 4300 did_save = true; 4301 } 4302 4303 // Store extmark data for this match. 4304 LineData *data = kv_pushp(line_matches); 4305 data->start_col = start_col; 4306 data->start = start; 4307 data->end = end; 4308 data->matchcols = matchcols; 4309 data->matchbytes = replaced_bytes; 4310 data->subcols = subcols; 4311 data->subbytes = sublen - 1; 4312 data->lnum_before = lnum_before_newlines; 4313 data->lnum_after = lnum; 4314 } 4315 4316 // 4. If subflags.do_all is set, find next match. 4317 // Prevent endless loop with patterns that match empty 4318 // strings, e.g. :s/$/pat/g or :s/[a-z]* /(&)/g. 4319 // But ":s/\n/#/" is OK. 4320 skip: 4321 // We already know that we did the last subst when we are at 4322 // the end of the line, except that a pattern like 4323 // "bar\|\nfoo" may match at the NUL. "lnum" can be below 4324 // "line2" when there is a \zs in the pattern after a line 4325 // break. 4326 lastone = (skip_match 4327 || got_int 4328 || got_quit 4329 || lnum > line2 4330 || !(subflags.do_all || do_again) 4331 || (sub_firstline[matchcol] == NUL && nmatch <= 1 4332 && !re_multiline(regmatch.regprog))); 4333 nmatch = -1; 4334 4335 // Replace the line in the buffer when needed. This is 4336 // skipped when there are more matches. 4337 // The check for nmatch_tl is needed for when multi-line 4338 // matching must replace the lines before trying to do another 4339 // match, otherwise "\@<=" won't work. 4340 // When the match starts below where we start searching also 4341 // need to replace the line first (using \zs after \n). 4342 if (lastone 4343 || nmatch_tl > 0 4344 || (nmatch = vim_regexec_multi(®match, curwin, 4345 curbuf, sub_firstlnum, 4346 matchcol, NULL, NULL)) == 0 4347 || regmatch.startpos[0].lnum > 0) { 4348 if (new_start != NULL) { 4349 // Copy the rest of the line, that didn't match. 4350 // "matchcol" has to be adjusted, we use the end of 4351 // the line as reference, because the substitute may 4352 // have changed the number of characters. Same for 4353 // "prev_matchcol". 4354 strcat(new_start, sub_firstline + copycol); 4355 matchcol = (colnr_T)strlen(sub_firstline) - matchcol; 4356 prev_matchcol = (colnr_T)strlen(sub_firstline) 4357 - prev_matchcol; 4358 4359 if (u_savesub(lnum) != OK) { 4360 break; 4361 } 4362 ml_replace(lnum, new_start, true); 4363 4364 // Call extmark_splice for each match on this line. 4365 for (size_t match_idx = 0; match_idx < kv_size(line_matches); match_idx++) { 4366 LineData *match = &kv_A(line_matches, match_idx); 4367 4368 extmark_splice(curbuf, (int)match->lnum_before - 1, match->start_col, 4369 match->end.lnum - match->start.lnum, match->matchcols, 4370 match->matchbytes, 4371 match->lnum_after - match->lnum_before, 4372 match->subcols, 4373 match->subbytes, kExtmarkUndo); 4374 } 4375 4376 // Reset the match data for the next line. 4377 kv_size(line_matches) = 0; 4378 4379 if (nmatch_tl > 0) { 4380 // Matched lines have now been substituted and are 4381 // useless, delete them. The part after the match 4382 // has been appended to new_start, we don't need 4383 // it in the buffer. 4384 lnum++; 4385 if (u_savedel(lnum, nmatch_tl) != OK) { 4386 break; 4387 } 4388 for (i = 0; i < nmatch_tl; i++) { 4389 ml_delete(lnum); 4390 } 4391 mark_adjust(lnum, lnum + nmatch_tl - 1, MAXLNUM, -nmatch_tl, kExtmarkNOOP); 4392 if (subflags.do_ask) { 4393 deleted_lines(lnum, nmatch_tl); 4394 } 4395 lnum--; 4396 line2 -= nmatch_tl; // nr of lines decreases 4397 nmatch_tl = 0; 4398 } 4399 4400 // When asking, undo is saved each time, must also set 4401 // changed flag each time. 4402 if (subflags.do_ask) { 4403 changed_bytes(lnum, 0); 4404 } else { 4405 if (first_line == 0) { 4406 first_line = lnum; 4407 } 4408 last_line = lnum + 1; 4409 } 4410 4411 sub_firstlnum = lnum; 4412 xfree(sub_firstline); // free the temp buffer 4413 sub_firstline = new_start; 4414 new_start = NULL; 4415 matchcol = (colnr_T)strlen(sub_firstline) - matchcol; 4416 prev_matchcol = (colnr_T)strlen(sub_firstline) 4417 - prev_matchcol; 4418 copycol = 0; 4419 } 4420 if (nmatch == -1 && !lastone) { 4421 nmatch = vim_regexec_multi(®match, curwin, curbuf, 4422 sub_firstlnum, matchcol, NULL, NULL); 4423 } 4424 4425 // 5. break if there isn't another match in this line 4426 if (nmatch <= 0) { 4427 // If the match found didn't start where we were 4428 // searching, do the next search in the line where we 4429 // found the match. 4430 if (nmatch == -1) { 4431 lnum -= regmatch.startpos[0].lnum; 4432 } 4433 4434 // uncrustify:off 4435 4436 #define PUSH_PREVIEW_LINES() \ 4437 do { \ 4438 if (cmdpreview_ns > 0) { \ 4439 linenr_T match_lines = current_match.end.lnum \ 4440 - current_match.start.lnum +1; \ 4441 if (preview_lines.subresults.size > 0) { \ 4442 linenr_T last = kv_last(preview_lines.subresults).end.lnum; \ 4443 if (last == current_match.start.lnum) { \ 4444 preview_lines.lines_needed += match_lines - 1; \ 4445 } else { \ 4446 preview_lines.lines_needed += match_lines; \ 4447 } \ 4448 } else { \ 4449 preview_lines.lines_needed += match_lines; \ 4450 } \ 4451 kv_push(preview_lines.subresults, current_match); \ 4452 } \ 4453 } while (0) 4454 4455 // uncrustify:on 4456 4457 // Push the match to preview_lines. 4458 PUSH_PREVIEW_LINES(); 4459 4460 break; 4461 } 4462 } 4463 // Push the match to preview_lines. 4464 PUSH_PREVIEW_LINES(); 4465 4466 line_breakcheck(); 4467 } 4468 4469 if (did_sub) { 4470 sub_nlines++; 4471 } 4472 xfree(new_start); // for when substitute was cancelled 4473 XFREE_CLEAR(sub_firstline); // free the copy of the original line 4474 kv_destroy(line_matches); // clean up match data 4475 } 4476 4477 line_breakcheck(); 4478 4479 if (profile_passed_limit(timeout)) { 4480 got_quit = true; 4481 } 4482 } 4483 4484 curbuf->deleted_bytes2 = 0; 4485 4486 if (first_line != 0) { 4487 // Need to subtract the number of added lines from "last_line" to get 4488 // the line number before the change (same as adding the number of 4489 // deleted lines). 4490 i = curbuf->b_ml.ml_line_count - old_line_count; 4491 changed_lines(curbuf, first_line, 0, last_line - (linenr_T)i, (linenr_T)i, false); 4492 4493 int64_t num_added = last_line - first_line; 4494 int64_t num_removed = num_added - i; 4495 buf_updates_send_changes(curbuf, first_line, num_added, num_removed); 4496 } 4497 4498 xfree(sub_firstline); // may have to free allocated copy of the line 4499 4500 // ":s/pat//n" doesn't move the cursor 4501 if (subflags.do_count) { 4502 curwin->w_cursor = old_cursor; 4503 } 4504 4505 if (sub_nsubs > start_nsubs) { 4506 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 4507 // Set the '[ and '] marks. 4508 curbuf->b_op_start.lnum = eap->line1; 4509 curbuf->b_op_end.lnum = line2; 4510 curbuf->b_op_start.col = curbuf->b_op_end.col = 0; 4511 } 4512 4513 if (!global_busy) { 4514 // when interactive leave cursor on the match 4515 if (!subflags.do_ask) { 4516 if (endcolumn) { 4517 coladvance(curwin, MAXCOL); 4518 } else { 4519 beginline(BL_WHITE | BL_FIX); 4520 } 4521 } 4522 if (cmdpreview_ns <= 0 && !do_sub_msg(subflags.do_count) && subflags.do_ask && p_ch > 0) { 4523 msg("", 0); 4524 } 4525 } else { 4526 global_need_beginline = true; 4527 } 4528 if (subflags.do_print) { 4529 print_line(curwin->w_cursor.lnum, subflags.do_number, subflags.do_list, true); 4530 } 4531 } else if (!global_busy) { 4532 if (got_int) { 4533 // interrupted 4534 emsg(_(e_interr)); 4535 } else if (got_match) { 4536 // did find something but nothing substituted 4537 if (p_ch > 0 && !ui_has(kUIMessages)) { 4538 msg("", 0); 4539 } 4540 } else if (subflags.do_error) { 4541 // nothing found 4542 semsg(_(e_patnotf2), get_search_pat()); 4543 } 4544 } 4545 4546 if (subflags.do_ask && hasAnyFolding(curwin)) { 4547 // Cursor position may require updating 4548 changed_window_setting(curwin); 4549 } 4550 4551 vim_regfree(regmatch.regprog); 4552 xfree(sub); 4553 4554 // Restore the flag values, they can be used for ":&&". 4555 subflags.do_all = save_do_all; 4556 subflags.do_ask = save_do_ask; 4557 4558 int retv = 0; 4559 4560 // Show 'inccommand' preview if there are matched lines. 4561 if (cmdpreview_ns > 0 && !aborting()) { 4562 if (got_quit || profile_passed_limit(timeout)) { // Too slow, disable. 4563 set_option_direct(kOptInccommand, STATIC_CSTR_AS_OPTVAL(""), 0, SID_NONE); 4564 } else if (*p_icm != NUL && pat != NULL) { 4565 if (pre_hl_id == 0) { 4566 pre_hl_id = syn_check_group(S_LEN("Substitute")); 4567 } 4568 retv = show_sub(eap, old_cursor, &preview_lines, pre_hl_id, cmdpreview_ns, cmdpreview_bufnr); 4569 } 4570 } 4571 4572 kv_destroy(preview_lines.subresults); 4573 return retv; 4574 #undef ADJUST_SUB_FIRSTLNUM 4575 #undef PUSH_PREVIEW_LINES 4576 } 4577 4578 /// Give message for number of substitutions. 4579 /// Can also be used after a ":global" command. 4580 /// 4581 /// @param count_only used 'n' flag for ":s" 4582 /// 4583 /// @return true if a message was given. 4584 bool do_sub_msg(bool count_only) 4585 { 4586 // Only report substitutions when: 4587 // - more than 'report' substitutions 4588 // - command was typed by user, or number of changed lines > 'report' 4589 // - giving messages is not disabled by 'lazyredraw' 4590 if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1)) 4591 || count_only) 4592 && messaging()) { 4593 if (got_int) { 4594 STRCPY(msg_buf, _("(Interrupted) ")); 4595 } else { 4596 *msg_buf = NUL; 4597 } 4598 4599 char *msg_single = count_only 4600 ? NGETTEXT("%" PRId64 " match on %" PRId64 " line", 4601 "%" PRId64 " matches on %" PRId64 " line", sub_nsubs) 4602 : NGETTEXT("%" PRId64 " substitution on %" PRId64 " line", 4603 "%" PRId64 " substitutions on %" PRId64 " line", sub_nsubs); 4604 char *msg_plural = count_only 4605 ? NGETTEXT("%" PRId64 " match on %" PRId64 " lines", 4606 "%" PRId64 " matches on %" PRId64 " lines", sub_nsubs) 4607 : NGETTEXT("%" PRId64 " substitution on %" PRId64 " lines", 4608 "%" PRId64 " substitutions on %" PRId64 " lines", sub_nsubs); 4609 vim_snprintf_add(msg_buf, sizeof(msg_buf), 4610 NGETTEXT(msg_single, msg_plural, sub_nlines), 4611 (int64_t)sub_nsubs, (int64_t)sub_nlines); 4612 if (msg(msg_buf, 0)) { 4613 // save message to display it after redraw 4614 set_keep_msg(msg_buf, 0); 4615 } 4616 return true; 4617 } 4618 if (got_int) { 4619 emsg(_(e_interr)); 4620 return true; 4621 } 4622 return false; 4623 } 4624 4625 static void global_exe_one(char *const cmd, const linenr_T lnum) 4626 { 4627 curwin->w_cursor.lnum = lnum; 4628 curwin->w_cursor.col = 0; 4629 if (*cmd == NUL || *cmd == '\n') { 4630 do_cmdline("p", NULL, NULL, DOCMD_NOWAIT); 4631 } else { 4632 do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT); 4633 } 4634 } 4635 4636 /// Execute a global command of the form: 4637 /// 4638 /// g/pattern/X : execute X on all lines where pattern matches 4639 /// v/pattern/X : execute X on all lines where pattern does not match 4640 /// 4641 /// where 'X' is an EX command 4642 /// 4643 /// The command character (as well as the trailing slash) is optional, and 4644 /// is assumed to be 'p' if missing. 4645 /// 4646 /// This is implemented in two passes: first we scan the file for the pattern and 4647 /// set a mark for each line that (not) matches. Secondly we execute the command 4648 /// for each line that has a mark. This is required because after deleting 4649 /// lines we do not know where to search for the next match. 4650 void ex_global(exarg_T *eap) 4651 { 4652 linenr_T lnum; // line number according to old situation 4653 int type; // first char of cmd: 'v' or 'g' 4654 char *cmd; // command argument 4655 4656 char delim; // delimiter, normally '/' 4657 char *pat; 4658 size_t patlen; 4659 regmmatch_T regmatch; 4660 4661 // When nesting the command works on one line. This allows for 4662 // ":g/found/v/notfound/command". 4663 if (global_busy && (eap->line1 != 1 4664 || eap->line2 != curbuf->b_ml.ml_line_count)) { 4665 // will increment global_busy to break out of the loop 4666 emsg(_("E147: Cannot do :global recursive with a range")); 4667 return; 4668 } 4669 4670 if (eap->forceit) { // ":global!" is like ":vglobal" 4671 type = 'v'; 4672 } else { 4673 type = (uint8_t)(*eap->cmd); 4674 } 4675 cmd = eap->arg; 4676 int which_pat = RE_LAST; // default: use last used regexp 4677 4678 // undocumented vi feature: 4679 // "\/" and "\?": use previous search pattern. 4680 // "\&": use previous substitute pattern. 4681 if (*cmd == '\\') { 4682 cmd++; 4683 if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { 4684 emsg(_(e_backslash)); 4685 return; 4686 } 4687 if (*cmd == '&') { 4688 which_pat = RE_SUBST; // use previous substitute pattern 4689 } else { 4690 which_pat = RE_SEARCH; // use previous search pattern 4691 } 4692 cmd++; 4693 pat = ""; 4694 patlen = 0; 4695 } else if (*cmd == NUL) { 4696 emsg(_("E148: Regular expression missing from global")); 4697 return; 4698 } else if (check_regexp_delim(*cmd) == FAIL) { 4699 return; 4700 } else { 4701 delim = *cmd; // get the delimiter 4702 cmd++; // skip delimiter if there is one 4703 pat = cmd; // remember start of pattern 4704 cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL); 4705 if (cmd[0] == delim) { // end delimiter found 4706 *cmd++ = NUL; // replace it with a NUL 4707 } 4708 patlen = strlen(pat); 4709 } 4710 4711 char *used_pat; 4712 if (search_regcomp(pat, patlen, &used_pat, RE_BOTH, which_pat, 4713 SEARCH_HIS, ®match) == FAIL) { 4714 emsg(_(e_invcmd)); 4715 return; 4716 } 4717 4718 if (global_busy) { 4719 lnum = curwin->w_cursor.lnum; 4720 int match = vim_regexec_multi(®match, curwin, curbuf, lnum, 0, NULL, NULL); 4721 if ((type == 'g' && match) || (type == 'v' && !match)) { 4722 global_exe_one(cmd, lnum); 4723 } 4724 } else { 4725 int ndone = 0; 4726 // pass 1: set marks for each (not) matching line 4727 for (lnum = eap->line1; lnum <= eap->line2 && !got_int; lnum++) { 4728 // a match on this line? 4729 int match = vim_regexec_multi(®match, curwin, curbuf, lnum, 0, NULL, NULL); 4730 if (regmatch.regprog == NULL) { 4731 break; // re-compiling regprog failed 4732 } 4733 if ((type == 'g' && match) || (type == 'v' && !match)) { 4734 ml_setmarked(lnum); 4735 ndone++; 4736 } 4737 line_breakcheck(); 4738 } 4739 4740 // pass 2: execute the command for each line that has been marked 4741 if (got_int) { 4742 msg(_(e_interr), 0); 4743 } else if (ndone == 0) { 4744 if (type == 'v') { 4745 smsg(0, _("Pattern found in every line: %s"), used_pat); 4746 } else { 4747 smsg(0, _("Pattern not found: %s"), used_pat); 4748 } 4749 } else { 4750 global_exe(cmd); 4751 } 4752 ml_clearmarked(); // clear rest of the marks 4753 } 4754 vim_regfree(regmatch.regprog); 4755 } 4756 4757 /// Execute `cmd` on lines marked with ml_setmarked(). 4758 void global_exe(char *cmd) 4759 { 4760 linenr_T old_lcount; // b_ml.ml_line_count before the command 4761 buf_T *old_buf = curbuf; // remember what buffer we started in 4762 linenr_T lnum; // line number according to old situation 4763 4764 // Set current position only once for a global command. 4765 // If global_busy is set, setpcmark() will not do anything. 4766 // If there is an error, global_busy will be incremented. 4767 setpcmark(); 4768 4769 // When the command writes a message, don't overwrite the command. 4770 msg_didout = true; 4771 4772 sub_nsubs = 0; 4773 sub_nlines = 0; 4774 global_need_msg_kind = true; 4775 global_need_beginline = false; 4776 global_busy = 1; 4777 old_lcount = curbuf->b_ml.ml_line_count; 4778 4779 while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) { 4780 global_exe_one(cmd, lnum); 4781 os_breakcheck(); 4782 } 4783 4784 global_busy = 0; 4785 if (global_need_beginline) { 4786 beginline(BL_WHITE | BL_FIX); 4787 } else { 4788 check_cursor(curwin); // cursor may be beyond the end of the line 4789 } 4790 4791 // the cursor may not have moved in the text but a change in a previous 4792 // line may move it on the screen 4793 changed_line_abv_curs(); 4794 4795 // If it looks like no message was written, allow overwriting the 4796 // command with the report for number of changes. 4797 if (msg_col == 0 && msg_scrolled == 0) { 4798 msg_didout = false; 4799 } 4800 4801 // If substitutes done, report number of substitutes, otherwise report 4802 // number of extra or deleted lines. 4803 // Don't report extra or deleted lines in the edge case where the buffer 4804 // we are in after execution is different from the buffer we started in. 4805 if (!do_sub_msg(false) && curbuf == old_buf) { 4806 msgmore(curbuf->b_ml.ml_line_count - old_lcount); 4807 } 4808 } 4809 4810 #if defined(EXITFREE) 4811 void free_old_sub(void) 4812 { 4813 sub_set_replacement((SubReplacementString) { NULL, 0, NULL }); 4814 } 4815 4816 #endif 4817 4818 /// Set up for a tagpreview. 4819 /// 4820 /// @param undo_sync sync undo when leaving the window 4821 /// 4822 /// @return true when it was created. 4823 bool prepare_tagpreview(bool undo_sync) 4824 { 4825 if (curwin->w_p_pvw) { 4826 return false; 4827 } 4828 4829 // If there is already a preview window open, use that one. 4830 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 4831 if (wp->w_p_pvw) { 4832 win_enter(wp, undo_sync); 4833 return false; 4834 } 4835 } 4836 4837 // There is no preview window open yet. Create one. 4838 if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) 4839 == FAIL) { 4840 return false; 4841 } 4842 curwin->w_p_pvw = true; 4843 curwin->w_p_wfh = true; 4844 RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind' 4845 curwin->w_p_diff = false; // no 'diff' 4846 4847 set_option_direct(kOptFoldcolumn, STATIC_CSTR_AS_OPTVAL("0"), 0, SID_NONE); // no 'foldcolumn' 4848 return true; 4849 } 4850 4851 /// Shows the effects of the :substitute command being typed ('inccommand'). 4852 /// If inccommand=split, shows a preview window and later restores the layout. 4853 /// 4854 /// @return 1 if preview window isn't needed, 2 if preview window is needed. 4855 static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, int hl_id, 4856 int cmdpreview_ns, handle_T cmdpreview_bufnr) 4857 FUNC_ATTR_NONNULL_ALL 4858 { 4859 char *save_shm_p = xstrdup(p_shm); 4860 PreviewLines lines = *preview_lines; 4861 buf_T *orig_buf = curbuf; 4862 // We keep a special-purpose buffer around, but don't assume it exists. 4863 buf_T *cmdpreview_buf = NULL; 4864 4865 // disable file info message 4866 set_option_direct(kOptShortmess, STATIC_CSTR_AS_OPTVAL("F"), 0, SID_NONE); 4867 4868 // Place cursor on nearest matching line, to undo do_sub() cursor placement. 4869 for (size_t i = 0; i < lines.subresults.size; i++) { 4870 SubResult curres = lines.subresults.items[i]; 4871 if (curres.start.lnum >= old_cusr.lnum) { 4872 curwin->w_cursor.lnum = curres.start.lnum; 4873 curwin->w_cursor.col = curres.start.col; 4874 break; 4875 } // Else: All matches are above, do_sub() already placed cursor. 4876 } 4877 4878 // Update the topline to ensure that main window is on the correct line 4879 update_topline(curwin); 4880 4881 // Width of the "| lnum|..." column which displays the line numbers. 4882 int col_width = 0; 4883 // Use preview window only when inccommand=split and range is not just the current line 4884 bool preview = (*p_icm == 's') && (eap->line1 != old_cusr.lnum || eap->line2 != old_cusr.lnum); 4885 4886 if (preview) { 4887 cmdpreview_buf = buflist_findnr(cmdpreview_bufnr); 4888 assert(cmdpreview_buf != NULL); 4889 4890 if (lines.subresults.size > 0) { 4891 SubResult last_match = kv_last(lines.subresults); 4892 // `last_match.end.lnum` may be 0 when using 'n' flag. 4893 linenr_T highest_lnum = MAX(last_match.start.lnum, last_match.end.lnum); 4894 assert(highest_lnum > 0); 4895 col_width = (int)log10(highest_lnum) + 1 + 3; 4896 } 4897 } 4898 4899 char *str = NULL; // construct the line to show in here 4900 colnr_T old_line_size = 0; 4901 colnr_T line_size = 0; 4902 linenr_T linenr_preview = 0; // last line added to preview buffer 4903 linenr_T linenr_origbuf = 0; // last line added to original buffer 4904 linenr_T next_linenr = 0; // next line to show for the match 4905 4906 for (size_t matchidx = 0; matchidx < lines.subresults.size; matchidx++) { 4907 SubResult match = lines.subresults.items[matchidx]; 4908 4909 if (cmdpreview_buf) { 4910 lpos_T p_start = { 0, match.start.col }; // match starts here in preview 4911 lpos_T p_end = { 0, match.end.col }; // ... and ends here 4912 4913 // You Might Gonna Need It 4914 buf_ensure_loaded(cmdpreview_buf); 4915 4916 if (match.pre_match == 0) { 4917 next_linenr = match.start.lnum; 4918 } else { 4919 next_linenr = match.pre_match; 4920 } 4921 // Don't add a line twice 4922 if (next_linenr == linenr_origbuf) { 4923 next_linenr++; 4924 p_start.lnum = linenr_preview; // might be redefined below 4925 p_end.lnum = linenr_preview; // might be redefined below 4926 } 4927 4928 for (; next_linenr <= match.end.lnum; next_linenr++) { 4929 if (next_linenr == match.start.lnum) { 4930 p_start.lnum = linenr_preview + 1; 4931 } 4932 if (next_linenr == match.end.lnum) { 4933 p_end.lnum = linenr_preview + 1; 4934 } 4935 char *line; 4936 if (next_linenr == orig_buf->b_ml.ml_line_count + 1) { 4937 line = ""; 4938 } else { 4939 line = ml_get_buf(orig_buf, next_linenr); 4940 line_size = ml_get_buf_len(orig_buf, next_linenr) + col_width + 1; 4941 4942 // Reallocate if line not long enough 4943 if (line_size > old_line_size) { 4944 str = xrealloc(str, (size_t)line_size * sizeof(char)); 4945 old_line_size = line_size; 4946 } 4947 } 4948 // Put "|lnum| line" into `str` and append it to the preview buffer. 4949 snprintf(str, (size_t)line_size, "|%*" PRIdLINENR "| %s", col_width - 3, 4950 next_linenr, line); 4951 if (linenr_preview == 0) { 4952 ml_replace_buf(cmdpreview_buf, 1, str, true, false); 4953 } else { 4954 ml_append_buf(cmdpreview_buf, linenr_preview, str, line_size, false); 4955 } 4956 linenr_preview += 1; 4957 } 4958 linenr_origbuf = match.end.lnum; 4959 4960 bufhl_add_hl_pos_offset(cmdpreview_buf, cmdpreview_ns, hl_id, p_start, p_end, col_width); 4961 } 4962 bufhl_add_hl_pos_offset(orig_buf, cmdpreview_ns, hl_id, match.start, match.end, 0); 4963 } 4964 4965 xfree(str); 4966 4967 set_option_direct(kOptShortmess, CSTR_AS_OPTVAL(save_shm_p), 0, SID_NONE); 4968 xfree(save_shm_p); 4969 4970 return preview ? 2 : 1; 4971 } 4972 4973 /// :substitute command. 4974 void ex_substitute(exarg_T *eap) 4975 { 4976 do_sub(eap, profile_zero(), 0, 0); 4977 } 4978 4979 /// :substitute command preview callback. 4980 int ex_substitute_preview(exarg_T *eap, int cmdpreview_ns, handle_T cmdpreview_bufnr) 4981 { 4982 // Only preview once the pattern delimiter has been typed 4983 if (*eap->arg && !ASCII_ISALNUM(*eap->arg)) { 4984 char *save_eap = eap->arg; 4985 int retv = do_sub(eap, profile_setlimit(p_rdt), cmdpreview_ns, cmdpreview_bufnr); 4986 eap->arg = save_eap; 4987 return retv; 4988 } 4989 4990 return 0; 4991 } 4992 4993 /// Skip over the pattern argument of ":vimgrep /pat/[g][j]". 4994 /// Put the start of the pattern in "*s", unless "s" is NULL. 4995 /// 4996 /// @param flags if not NULL, put the flags in it: VGR_GLOBAL, VGR_NOJUMP. 4997 /// @param s if not NULL, terminate the pattern with a NUL. 4998 /// 4999 /// @return a pointer to the char just past the pattern plus flags. 5000 char *skip_vimgrep_pat(char *p, char **s, int *flags) 5001 { 5002 if (vim_isIDc((uint8_t)(*p))) { 5003 // ":vimgrep pattern fname" 5004 if (s != NULL) { 5005 *s = p; 5006 } 5007 p = skiptowhite(p); 5008 if (s != NULL && *p != NUL) { 5009 *p++ = NUL; 5010 } 5011 } else { 5012 // ":vimgrep /pattern/[g][j] fname" 5013 if (s != NULL) { 5014 *s = p + 1; 5015 } 5016 int c = (uint8_t)(*p); 5017 p = skip_regexp(p + 1, c, true); 5018 if (*p != c) { 5019 return NULL; 5020 } 5021 5022 // Truncate the pattern. 5023 if (s != NULL) { 5024 *p = NUL; 5025 } 5026 p++; 5027 5028 // Find the flags 5029 while (*p == 'g' || *p == 'j' || *p == 'f') { 5030 if (flags != NULL) { 5031 if (*p == 'g') { 5032 *flags |= VGR_GLOBAL; 5033 } else if (*p == 'j') { 5034 *flags |= VGR_NOJUMP; 5035 } else { 5036 *flags |= VGR_FUZZY; 5037 } 5038 } 5039 p++; 5040 } 5041 } 5042 return p; 5043 } 5044 5045 /// List v:oldfiles in a nice way. 5046 void ex_oldfiles(exarg_T *eap) 5047 { 5048 list_T *l = get_vim_var_list(VV_OLDFILES); 5049 int nr = 0; 5050 5051 if (l == NULL) { 5052 msg(_("No old files"), 0); 5053 return; 5054 } 5055 5056 msg_start(); 5057 msg_scroll = true; 5058 TV_LIST_ITER(l, li, { 5059 if (got_int) { 5060 break; 5061 } 5062 nr++; 5063 const char *fname = tv_get_string(TV_LIST_ITEM_TV(li)); 5064 if (!message_filtered(fname)) { 5065 msg_outnum(nr); 5066 msg_puts(": "); 5067 msg_outtrans(tv_get_string(TV_LIST_ITEM_TV(li)), 0, false); 5068 msg_clr_eos(); 5069 msg_putchar('\n'); 5070 os_breakcheck(); 5071 } 5072 }); 5073 5074 // Assume "got_int" was set to truncate the listing. 5075 got_int = false; 5076 5077 // File selection prompt on ":browse oldfiles" 5078 if (cmdmod.cmod_flags & CMOD_BROWSE) { 5079 quit_more = false; 5080 nr = prompt_for_input(NULL, 0, false, NULL); 5081 msg_starthere(); 5082 if (nr > 0 && nr <= tv_list_len(l)) { 5083 const char *const p = tv_list_find_str(l, nr - 1); 5084 if (p == NULL) { 5085 return; 5086 } 5087 char *const s = expand_env_save((char *)p); 5088 eap->arg = s; 5089 eap->cmdidx = CMD_edit; 5090 cmdmod.cmod_flags &= ~CMOD_BROWSE; 5091 do_exedit(eap, NULL); 5092 xfree(s); 5093 } 5094 } 5095 }