indent.c (57911B)
1 #include <assert.h> 2 #include <stdbool.h> 3 #include <stdint.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "nvim/ascii_defs.h" 8 #include "nvim/assert_defs.h" 9 #include "nvim/buffer.h" 10 #include "nvim/buffer_defs.h" 11 #include "nvim/change.h" 12 #include "nvim/charset.h" 13 #include "nvim/cursor.h" 14 #include "nvim/drawscreen.h" 15 #include "nvim/edit.h" 16 #include "nvim/errors.h" 17 #include "nvim/eval.h" 18 #include "nvim/eval/typval.h" 19 #include "nvim/eval/typval_defs.h" 20 #include "nvim/eval/vars.h" 21 #include "nvim/ex_cmds_defs.h" 22 #include "nvim/ex_docmd.h" 23 #include "nvim/extmark.h" 24 #include "nvim/extmark_defs.h" 25 #include "nvim/gettext_defs.h" 26 #include "nvim/globals.h" 27 #include "nvim/indent.h" 28 #include "nvim/indent_c.h" 29 #include "nvim/mark_defs.h" 30 #include "nvim/mbyte.h" 31 #include "nvim/mbyte_defs.h" 32 #include "nvim/memline.h" 33 #include "nvim/memory.h" 34 #include "nvim/message.h" 35 #include "nvim/move.h" 36 #include "nvim/ops.h" 37 #include "nvim/option.h" 38 #include "nvim/option_defs.h" 39 #include "nvim/option_vars.h" 40 #include "nvim/os/input.h" 41 #include "nvim/plines.h" 42 #include "nvim/pos_defs.h" 43 #include "nvim/regexp.h" 44 #include "nvim/regexp_defs.h" 45 #include "nvim/search.h" 46 #include "nvim/state_defs.h" 47 #include "nvim/strings.h" 48 #include "nvim/textformat.h" 49 #include "nvim/types_defs.h" 50 #include "nvim/undo.h" 51 #include "nvim/vim_defs.h" 52 53 #include "indent.c.generated.h" 54 55 /// Set the integer values corresponding to the string setting of 'vartabstop'. 56 /// "array" will be set, caller must free it if needed. 57 /// 58 /// @return false for an error. 59 bool tabstop_set(char *var, colnr_T **array) 60 { 61 int valcount = 1; 62 63 if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) { 64 *array = NULL; 65 return true; 66 } 67 68 for (char *cp = var; *cp != NUL; cp++) { 69 if (cp == var || cp[-1] == ',') { 70 char *end; 71 72 if (strtol(cp, &end, 10) <= 0) { 73 if (cp != end) { 74 emsg(_(e_positive)); 75 } else { 76 semsg(_(e_invarg2), cp); 77 } 78 return false; 79 } 80 } 81 82 if (ascii_isdigit(*cp)) { 83 continue; 84 } 85 if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) { 86 valcount++; 87 continue; 88 } 89 semsg(_(e_invarg2), var); 90 return false; 91 } 92 93 *array = (colnr_T *)xmalloc((unsigned)(valcount + 1) * sizeof(int)); 94 (*array)[0] = (colnr_T)valcount; 95 96 int t = 1; 97 for (char *cp = var; *cp != NUL;) { 98 int n = atoi(cp); 99 100 // Catch negative values, overflow and ridiculous big values. 101 if (n <= 0 || n > TABSTOP_MAX) { 102 semsg(_(e_invarg2), cp); 103 XFREE_CLEAR(*array); 104 return false; 105 } 106 (*array)[t++] = n; 107 while (*cp != NUL && *cp != ',') { 108 cp++; 109 } 110 if (*cp != NUL) { 111 cp++; 112 } 113 } 114 115 return true; 116 } 117 118 /// Calculate the number of screen spaces a tab will occupy. 119 /// If "vts" is set then the tab widths are taken from that array, 120 /// otherwise the value of ts is used. 121 int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts) 122 FUNC_ATTR_PURE 123 { 124 OptInt ts = ts_arg == 0 ? 8 : ts_arg; 125 colnr_T tabcol = 0; 126 int t; 127 int padding = 0; 128 129 if (vts == NULL || vts[0] == 0) { 130 return (int)(ts - (col % ts)); 131 } 132 133 const int tabcount = vts[0]; 134 135 for (t = 1; t <= tabcount; t++) { 136 tabcol += vts[t]; 137 if (tabcol > col) { 138 padding = tabcol - col; 139 break; 140 } 141 } 142 if (t > tabcount) { 143 padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]); 144 } 145 146 return padding; 147 } 148 149 /// Find the size of the tab that covers a particular column. 150 /// 151 /// If this is being called as part of a shift operation, col is not the cursor 152 /// column but is the column number to the left of the first non-whitespace 153 /// character in the line. If the shift is to the left (left == true), then 154 /// return the size of the tab interval to the left of the column. 155 int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left) 156 { 157 if (vts == NULL || vts[0] == 0) { 158 return (int)ts; 159 } 160 161 colnr_T tabcol = 0; // Column of the tab stop under consideration. 162 int t; // Tabstop index in the list of variable tab stops. 163 int tab_size = 0; // Size of the tab stop interval to the right or left of the col. 164 const int tabcount // Number of tab stops in the list of variable tab stops. 165 = vts[0]; 166 for (t = 1; t <= tabcount; t++) { 167 tabcol += vts[t]; 168 if (tabcol > col) { 169 // If shifting left (left == true), and if the column to the left of 170 // the first first non-blank character (col) in the line is 171 // already to the left of the first tabstop, set the shift amount 172 // (tab_size) to just enough to shift the line to the left margin. 173 // The value doesn't seem to matter as long as it is at least that 174 // distance. 175 if (left && (t == 1)) { 176 tab_size = col; 177 } else { 178 tab_size = vts[t - (left ? 1 : 0)]; 179 } 180 break; 181 } 182 } 183 if (t > tabcount) { // If the value of the index t is beyond the 184 // end of the list, use the tab stop value at 185 // the end of the list. 186 tab_size = vts[tabcount]; 187 } 188 189 return tab_size; 190 } 191 192 /// Find the column on which a tab starts. 193 colnr_T tabstop_start(colnr_T col, int ts, colnr_T *vts) 194 { 195 colnr_T tabcol = 0; 196 197 if (vts == NULL || vts[0] == 0) { 198 return col - col % ts; 199 } 200 201 const int tabcount = vts[0]; 202 for (int t = 1; t <= tabcount; t++) { 203 tabcol += vts[t]; 204 if (tabcol > col) { 205 return (tabcol - vts[t]); 206 } 207 } 208 209 const int excess = (tabcol % vts[tabcount]); 210 return col - (col - excess) % vts[tabcount]; 211 } 212 213 /// Find the number of tabs and spaces necessary to get from one column 214 /// to another. 215 void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, const colnr_T *vts, int *ntabs, 216 int *nspcs) 217 { 218 int spaces = end_col - start_col; 219 colnr_T tabcol = 0; 220 int padding = 0; 221 int t; 222 int ts = ts_arg == 0 ? (int)curbuf->b_p_ts : ts_arg; 223 assert(ts != 0); // suppress clang "Division by zero" 224 225 if (vts == NULL || vts[0] == 0) { 226 int tabs = 0; 227 228 const int initspc = (ts - (start_col % ts)); 229 if (spaces >= initspc) { 230 spaces -= initspc; 231 tabs++; 232 } 233 tabs += (spaces / ts); 234 spaces -= ((spaces / ts) * ts); 235 236 *ntabs = tabs; 237 *nspcs = spaces; 238 return; 239 } 240 241 // Find the padding needed to reach the next tabstop. 242 const int tabcount = vts[0]; 243 for (t = 1; t <= tabcount; t++) { 244 tabcol += vts[t]; 245 if (tabcol > start_col) { 246 padding = tabcol - start_col; 247 break; 248 } 249 } 250 if (t > tabcount) { 251 padding = vts[tabcount] - ((start_col - tabcol) % vts[tabcount]); 252 } 253 254 // If the space needed is less than the padding no tabs can be used. 255 if (spaces < padding) { 256 *ntabs = 0; 257 *nspcs = spaces; 258 return; 259 } 260 261 *ntabs = 1; 262 spaces -= padding; 263 264 // At least one tab has been used. See if any more will fit. 265 while (spaces != 0 && ++t <= tabcount) { 266 padding = vts[t]; 267 if (spaces < padding) { 268 *nspcs = spaces; 269 return; 270 } 271 *ntabs += 1; 272 spaces -= padding; 273 } 274 275 *ntabs += spaces / (int)vts[tabcount]; 276 *nspcs = spaces % (int)vts[tabcount]; 277 } 278 279 /// See if two tabstop arrays contain the same values. 280 static bool tabstop_eq(const colnr_T *ts1, const colnr_T *ts2) 281 { 282 if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) { 283 return false; 284 } 285 if (ts1 == ts2) { 286 return true; 287 } 288 if (ts1[0] != ts2[0]) { 289 return false; 290 } 291 292 for (int t = 1; t <= ts1[0]; t++) { 293 if (ts1[t] != ts2[t]) { 294 return false; 295 } 296 } 297 298 return true; 299 } 300 301 /// Copy a tabstop array, allocating space for the new array. 302 int *tabstop_copy(const int *oldts) 303 { 304 if (oldts == 0) { 305 return 0; 306 } 307 308 int *newts = xmalloc((unsigned)(oldts[0] + 1) * sizeof(int)); 309 for (int t = 0; t <= oldts[0]; t++) { 310 newts[t] = oldts[t]; 311 } 312 313 return newts; 314 } 315 316 /// Return a count of the number of tabstops. 317 int tabstop_count(colnr_T *ts) 318 { 319 return ts != NULL ? (int)ts[0] : 0; 320 } 321 322 /// Return the first tabstop, or 8 if there are no tabstops defined. 323 int tabstop_first(colnr_T *ts) 324 { 325 return ts != NULL ? (int)ts[1] : 8; 326 } 327 328 /// Return the effective shiftwidth value for current buffer, using the 329 /// 'tabstop' value when 'shiftwidth' is zero. 330 int get_sw_value(buf_T *buf) 331 { 332 int result = get_sw_value_col(buf, 0, false); 333 return result; 334 } 335 336 /// Idem, using "pos". 337 static int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left) 338 { 339 pos_T save_cursor = curwin->w_cursor; 340 341 curwin->w_cursor = *pos; 342 int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left); 343 curwin->w_cursor = save_cursor; 344 return sw_value; 345 } 346 347 /// Idem, using the first non-black in the current line. 348 int get_sw_value_indent(buf_T *buf, bool left) 349 { 350 pos_T pos = curwin->w_cursor; 351 352 pos.col = (colnr_T)getwhitecols_curline(); 353 return get_sw_value_pos(buf, &pos, left); 354 } 355 356 /// Idem, using virtual column "col". 357 int get_sw_value_col(buf_T *buf, colnr_T col, bool left) 358 { 359 return buf->b_p_sw ? (int)buf->b_p_sw 360 : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left); 361 } 362 363 /// Return the effective softtabstop value for the current buffer, 364 /// using the shiftwidth value when 'softtabstop' is negative. 365 int get_sts_value(void) 366 { 367 int result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : (int)curbuf->b_p_sts; 368 return result; 369 } 370 371 /// Count the size (in window cells) of the indent in the current line. 372 int get_indent(void) 373 { 374 return indent_size_ts(get_cursor_line_ptr(), curbuf->b_p_ts, curbuf->b_p_vts_array); 375 } 376 377 /// Count the size (in window cells) of the indent in line "lnum". 378 int get_indent_lnum(linenr_T lnum) 379 { 380 return indent_size_ts(ml_get(lnum), curbuf->b_p_ts, curbuf->b_p_vts_array); 381 } 382 383 /// Count the size (in window cells) of the indent in line "lnum" of buffer "buf". 384 int get_indent_buf(buf_T *buf, linenr_T lnum) 385 { 386 return indent_size_ts(ml_get_buf(buf, lnum), buf->b_p_ts, buf->b_p_vts_array); 387 } 388 389 /// Compute the size of the indent (in window cells) in line "ptr", 390 /// without tabstops (count tab as ^I or <09>). 391 int indent_size_no_ts(char const *ptr) 392 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE 393 { 394 int tab_size = byte2cells(TAB); 395 396 int vcol = 0; 397 while (true) { 398 char const c = *ptr++; 399 if (c == ' ') { 400 vcol++; 401 } else if (c == TAB) { 402 vcol += tab_size; 403 } else { 404 return vcol; 405 } 406 } 407 } 408 409 /// Compute the size of the indent (in window cells) in line "ptr", 410 /// using tabstops 411 int indent_size_ts(char const *ptr, OptInt ts, colnr_T *vts) 412 FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_PURE 413 { 414 assert(char2cells(' ') == 1); 415 416 int vcol = 0; 417 int tabstop_width, next_tab_vcol; 418 419 if (vts == NULL || vts[0] < 1) { // tab has fixed width 420 // can ts be 0 ? This is from tabstop_padding(). 421 tabstop_width = (int)(ts == 0 ? 8 : ts); 422 next_tab_vcol = tabstop_width; 423 } else { // tab has variable width 424 colnr_T *cur_tabstop = vts + 1; 425 colnr_T *const last_tabstop = vts + vts[0]; 426 427 while (cur_tabstop != last_tabstop) { 428 int cur_vcol = vcol; 429 vcol += *cur_tabstop++; 430 assert(cur_vcol < vcol); 431 432 do { 433 char const c = *ptr++; 434 if (c == ' ') { 435 cur_vcol++; 436 } else if (c == TAB) { 437 break; 438 } else { 439 return cur_vcol; 440 } 441 } while (cur_vcol != vcol); 442 } 443 444 tabstop_width = *last_tabstop; 445 next_tab_vcol = vcol + tabstop_width; 446 } 447 448 assert(tabstop_width != 0); 449 while (true) { 450 char const c = *ptr++; 451 if (c == ' ') { 452 vcol++; 453 next_tab_vcol += (vcol == next_tab_vcol) ? tabstop_width : 0; 454 } else if (c == TAB) { 455 vcol = next_tab_vcol; 456 next_tab_vcol += tabstop_width; 457 } else { 458 return vcol; 459 } 460 } 461 } 462 463 /// Set the indent of the current line. 464 /// Leaves the cursor on the first non-blank in the line. 465 /// Caller must take care of undo. 466 /// "flags": 467 /// SIN_CHANGED: call changed_bytes() if the line was changed. 468 /// SIN_INSERT: insert the indent in front of the line. 469 /// SIN_UNDO: save line for undo before changing it. 470 /// SIN_NOMARK: don't move extmarks (because just after ml_append or something) 471 /// @param size measured in spaces 472 /// 473 /// @return true if the line was changed. 474 bool set_indent(int size, int flags) 475 { 476 char *newline; 477 char *oldline; 478 char *s; 479 int doit = false; 480 int ind_done = 0; // Measured in spaces. 481 int tab_pad; 482 bool retval = false; 483 484 // Number of initial whitespace chars when 'et' and 'pi' are both set. 485 int orig_char_len = -1; 486 487 // First check if there is anything to do and compute the number of 488 // characters needed for the indent. 489 int todo = size; 490 int ind_len = 0; // Measured in characters. 491 char *p = oldline = get_cursor_line_ptr(); 492 int line_len = get_cursor_line_len() + 1; // size of the line (including the NUL) 493 494 // Calculate the buffer size for the new indent, and check to see if it 495 // isn't already set. 496 // If 'expandtab' isn't set: use TABs; if both 'expandtab' and 497 // 'preserveindent' are set count the number of characters at the 498 // beginning of the line to be copied. 499 if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) { 500 int ind_col = 0; 501 // If 'preserveindent' is set then reuse as much as possible of 502 // the existing indent structure for the new indent. 503 if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { 504 ind_done = 0; 505 506 // Count as many characters as we can use. 507 while (todo > 0 && ascii_iswhite(*p)) { 508 if (*p == TAB) { 509 tab_pad = tabstop_padding(ind_done, 510 curbuf->b_p_ts, 511 curbuf->b_p_vts_array); 512 513 // Stop if this tab will overshoot the target. 514 if (todo < tab_pad) { 515 break; 516 } 517 todo -= tab_pad; 518 ind_len++; 519 ind_done += tab_pad; 520 } else { 521 todo--; 522 ind_len++; 523 ind_done++; 524 } 525 p++; 526 } 527 528 // These diverge from this point. 529 ind_col = ind_done; 530 // Set initial number of whitespace chars to copy if we are 531 // preserving indent but expandtab is set. 532 if (curbuf->b_p_et) { 533 orig_char_len = ind_len; 534 } 535 // Fill to next tabstop with a tab, if possible. 536 tab_pad = tabstop_padding(ind_done, 537 curbuf->b_p_ts, 538 curbuf->b_p_vts_array); 539 if ((todo >= tab_pad) && (orig_char_len == -1)) { 540 doit = true; 541 todo -= tab_pad; 542 ind_len++; 543 544 // ind_done += tab_pad; 545 ind_col += tab_pad; 546 } 547 } 548 549 // Count tabs required for indent. 550 while (true) { 551 tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts, curbuf->b_p_vts_array); 552 if (todo < tab_pad) { 553 break; 554 } 555 if (*p != TAB) { 556 doit = true; 557 } else { 558 p++; 559 } 560 todo -= tab_pad; 561 ind_len++; 562 ind_col += tab_pad; 563 } 564 } 565 566 // Count spaces required for indent. 567 while (todo > 0) { 568 if (*p != ' ') { 569 doit = true; 570 } else { 571 p++; 572 } 573 todo--; 574 ind_len++; 575 576 // ind_done++; 577 } 578 579 // Return if the indent is OK already. 580 if (!doit && !ascii_iswhite(*p) && !(flags & SIN_INSERT)) { 581 return false; 582 } 583 584 // Allocate memory for the new line. 585 if (flags & SIN_INSERT) { 586 p = oldline; 587 } else { 588 p = skipwhite(p); 589 line_len -= (int)(p - oldline); 590 } 591 592 // If 'preserveindent' and 'expandtab' are both set keep the original 593 // characters and allocate accordingly. We will fill the rest with spaces 594 // after the if (!curbuf->b_p_et) below. 595 int skipcols = 0; // number of columns (in bytes) that were presved 596 if (orig_char_len != -1) { 597 int newline_size; // = orig_char_len + size - ind_done + line_len 598 STRICT_ADD(orig_char_len, size, &newline_size, int); 599 STRICT_SUB(newline_size, ind_done, &newline_size, int); 600 STRICT_ADD(newline_size, line_len, &newline_size, int); 601 assert(newline_size >= 0); 602 newline = xmalloc((size_t)newline_size); 603 todo = size - ind_done; 604 605 // Set total length of indent in characters, which may have been 606 // undercounted until now. 607 ind_len = orig_char_len + todo; 608 p = oldline; 609 s = newline; 610 skipcols = orig_char_len; 611 612 while (orig_char_len > 0) { 613 *s++ = *p++; 614 orig_char_len--; 615 } 616 617 // Skip over any additional white space (useful when newindent is less 618 // than old). 619 while (ascii_iswhite(*p)) { 620 p++; 621 } 622 } else { 623 todo = size; 624 assert(ind_len + line_len >= 0); 625 size_t newline_size; 626 STRICT_ADD(ind_len, line_len, &newline_size, size_t); 627 newline = xmalloc(newline_size); 628 s = newline; 629 } 630 631 // Put the characters in the new line. 632 // if 'expandtab' isn't set: use TABs 633 if (!curbuf->b_p_et) { 634 // If 'preserveindent' is set then reuse as much as possible of 635 // the existing indent structure for the new indent. 636 if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { 637 p = oldline; 638 ind_done = 0; 639 640 while (todo > 0 && ascii_iswhite(*p)) { 641 if (*p == TAB) { 642 tab_pad = tabstop_padding(ind_done, 643 curbuf->b_p_ts, 644 curbuf->b_p_vts_array); 645 646 // Stop if this tab will overshoot the target. 647 if (todo < tab_pad) { 648 break; 649 } 650 todo -= tab_pad; 651 ind_done += tab_pad; 652 } else { 653 todo--; 654 ind_done++; 655 } 656 *s++ = *p++; 657 skipcols++; 658 } 659 660 // Fill to next tabstop with a tab, if possible. 661 tab_pad = tabstop_padding(ind_done, 662 curbuf->b_p_ts, 663 curbuf->b_p_vts_array); 664 665 if (todo >= tab_pad) { 666 *s++ = TAB; 667 todo -= tab_pad; 668 ind_done += tab_pad; 669 } 670 p = skipwhite(p); 671 } 672 673 while (true) { 674 tab_pad = tabstop_padding(ind_done, 675 curbuf->b_p_ts, 676 curbuf->b_p_vts_array); 677 if (todo < tab_pad) { 678 break; 679 } 680 *s++ = TAB; 681 todo -= tab_pad; 682 ind_done += tab_pad; 683 } 684 } 685 686 while (todo > 0) { 687 *s++ = ' '; 688 todo--; 689 } 690 memmove(s, p, (size_t)line_len); 691 692 // Replace the line (unless undo fails). 693 if (!(flags & SIN_UNDO) || (u_savesub(curwin->w_cursor.lnum) == OK)) { 694 const colnr_T old_offset = (colnr_T)(p - oldline); 695 const colnr_T new_offset = (colnr_T)(s - newline); 696 697 // this may free "newline" 698 ml_replace(curwin->w_cursor.lnum, newline, false); 699 if (!(flags & SIN_NOMARK)) { 700 extmark_splice_cols(curbuf, 701 (int)curwin->w_cursor.lnum - 1, 702 skipcols, 703 old_offset - skipcols, 704 new_offset - skipcols, 705 kExtmarkUndo); 706 } 707 708 if (flags & SIN_CHANGED) { 709 changed_bytes(curwin->w_cursor.lnum, 0); 710 } 711 712 // Correct saved cursor position if it is in this line. 713 if (saved_cursor.lnum == curwin->w_cursor.lnum) { 714 if (saved_cursor.col >= old_offset) { 715 // Cursor was after the indent, adjust for the number of 716 // bytes added/removed. 717 saved_cursor.col += ind_len - old_offset; 718 } else if (saved_cursor.col >= new_offset) { 719 // Cursor was in the indent, and is now after it, put it back 720 // at the start of the indent (replacing spaces with TAB). 721 saved_cursor.col = new_offset; 722 } 723 } 724 retval = true; 725 } else { 726 xfree(newline); 727 } 728 curwin->w_cursor.col = ind_len; 729 return retval; 730 } 731 732 // Return the indent of the current line after a number. Return -1 if no 733 // number was found. Used for 'n' in 'formatoptions': numbered list. 734 // Since a pattern is used it can actually handle more than numbers. 735 int get_number_indent(linenr_T lnum) 736 { 737 colnr_T col; 738 pos_T pos; 739 regmatch_T regmatch; 740 int lead_len = 0; // Length of comment leader. 741 742 if (lnum > curbuf->b_ml.ml_line_count) { 743 return -1; 744 } 745 pos.lnum = 0; 746 747 // In format_lines() (i.e. not insert mode), fo+=q is needed too... 748 if ((State & MODE_INSERT) || has_format_option(FO_Q_COMS)) { 749 lead_len = get_leader_len(ml_get(lnum), NULL, false, true); 750 } 751 regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC); 752 753 if (regmatch.regprog != NULL) { 754 regmatch.rm_ic = false; 755 756 // vim_regexec() expects a pointer to a line. This lets us 757 // start matching for the flp beyond any comment leader... 758 if (vim_regexec(®match, ml_get(lnum) + lead_len, 0)) { 759 pos.lnum = lnum; 760 pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum)); 761 pos.coladd = 0; 762 } 763 vim_regfree(regmatch.regprog); 764 } 765 766 if ((pos.lnum == 0) || (*ml_get_pos(&pos) == NUL)) { 767 return -1; 768 } 769 getvcol(curwin, &pos, &col, NULL, NULL); 770 return (int)col; 771 } 772 773 /// Check "briopt" as 'breakindentopt' and update the members of "wp". 774 /// This is called when 'breakindentopt' is changed and when a window is 775 /// initialized 776 /// 777 /// @param briopt when NULL: use "wp->w_p_briopt" 778 /// @param wp when NULL: only check "briopt" 779 /// 780 /// @return FAIL for failure, OK otherwise. 781 bool briopt_check(char *briopt, win_T *wp) 782 { 783 int bri_shift = 0; 784 int bri_min = 20; 785 bool bri_sbr = false; 786 int bri_list = 0; 787 int bri_vcol = 0; 788 789 char *p = empty_string_option; 790 if (briopt != NULL) { 791 p = briopt; 792 } else if (wp != NULL) { 793 p = wp->w_p_briopt; 794 } 795 796 while (*p != NUL) { 797 // Note: Keep this in sync with opt_briopt_values. 798 if (strncmp(p, "shift:", 6) == 0 799 && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) { 800 p += 6; 801 bri_shift = getdigits_int(&p, true, 0); 802 } else if (strncmp(p, "min:", 4) == 0 && ascii_isdigit(p[4])) { 803 p += 4; 804 bri_min = getdigits_int(&p, true, 0); 805 } else if (strncmp(p, "sbr", 3) == 0) { 806 p += 3; 807 bri_sbr = true; 808 } else if (strncmp(p, "list:", 5) == 0) { 809 p += 5; 810 bri_list = (int)getdigits(&p, false, 0); 811 } else if (strncmp(p, "column:", 7) == 0) { 812 p += 7; 813 bri_vcol = (int)getdigits(&p, false, 0); 814 } 815 if (*p != ',' && *p != NUL) { 816 return false; 817 } 818 if (*p == ',') { 819 p++; 820 } 821 } 822 823 if (wp == NULL) { 824 return OK; 825 } 826 827 wp->w_briopt_shift = bri_shift; 828 wp->w_briopt_min = bri_min; 829 wp->w_briopt_sbr = bri_sbr; 830 wp->w_briopt_list = bri_list; 831 wp->w_briopt_vcol = bri_vcol; 832 833 return true; 834 } 835 836 // Return appropriate space number for breakindent, taking influencing 837 // parameters into account. Window must be specified, since it is not 838 // necessarily always the current one. 839 int get_breakindent_win(win_T *wp, char *line) 840 FUNC_ATTR_NONNULL_ALL 841 { 842 static int prev_indent = 0; // cached indent value 843 static OptInt prev_ts = 0; // cached tabstop value 844 static colnr_T *prev_vts = NULL; // cached vartabs values 845 static int prev_fnum = 0; // cached buffer number 846 static char *prev_line = NULL; // cached copy of "line" 847 static varnumber_T prev_tick = 0; // changedtick of cached value 848 static int prev_list = 0; // cached list indent 849 static int prev_listopt = 0; // cached w_p_briopt_list value 850 static bool prev_no_ts = false; // cached no_ts value 851 static unsigned prev_dy_uhex = 0; // cached 'display' "uhex" value 852 static char *prev_flp = NULL; // cached formatlistpat value 853 int bri = 0; 854 // window width minus window margin space, i.e. what rests for text 855 const int eff_wwidth = wp->w_view_width - win_col_off(wp) + win_col_off2(wp); 856 857 // In list mode, if 'listchars' "tab" isn't set, a TAB is displayed as ^I. 858 const bool no_ts = wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL; 859 860 // Used cached indent, unless 861 // - buffer changed, or 862 // - 'tabstop' changed, or 863 // - 'vartabstop' changed, or 864 // - buffer was changed, or 865 // - 'breakindentopt' "list" changed, or 866 // - 'list' or 'listchars' "tab" changed, or 867 // - 'display' "uhex" flag changed, or 868 // - 'formatlistpat' changed, or 869 // - line changed. 870 if (prev_fnum != wp->w_buffer->b_fnum 871 || prev_ts != wp->w_buffer->b_p_ts 872 || prev_vts != wp->w_buffer->b_p_vts_array 873 || prev_tick != buf_get_changedtick(wp->w_buffer) 874 || prev_listopt != wp->w_briopt_list 875 || prev_no_ts != no_ts 876 || prev_dy_uhex != (dy_flags & kOptDyFlagUhex) 877 || prev_flp == NULL 878 || strcmp(prev_flp, get_flp_value(wp->w_buffer)) != 0 879 || prev_line == NULL || strcmp(prev_line, line) != 0) { 880 prev_fnum = wp->w_buffer->b_fnum; 881 xfree(prev_line); 882 prev_line = xstrdup(line); 883 prev_ts = wp->w_buffer->b_p_ts; 884 prev_vts = wp->w_buffer->b_p_vts_array; 885 if (wp->w_briopt_vcol == 0) { 886 if (no_ts) { 887 prev_indent = indent_size_no_ts(line); 888 } else { 889 prev_indent = indent_size_ts(line, wp->w_buffer->b_p_ts, 890 wp->w_buffer->b_p_vts_array); 891 } 892 } 893 prev_tick = buf_get_changedtick(wp->w_buffer); 894 prev_listopt = wp->w_briopt_list; 895 prev_list = 0; 896 prev_no_ts = no_ts; 897 prev_dy_uhex = (dy_flags & kOptDyFlagUhex); 898 xfree(prev_flp); 899 prev_flp = xstrdup(get_flp_value(wp->w_buffer)); 900 // add additional indent for numbered lists 901 if (wp->w_briopt_list != 0 && wp->w_briopt_vcol == 0) { 902 regmatch_T regmatch = { 903 .regprog = vim_regcomp(prev_flp, RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT), 904 }; 905 if (regmatch.regprog != NULL) { 906 regmatch.rm_ic = false; 907 if (vim_regexec(®match, line, 0)) { 908 if (wp->w_briopt_list > 0) { 909 prev_list += wp->w_briopt_list; 910 } else { 911 char *ptr = *regmatch.startp; 912 char *end_ptr = *regmatch.endp; 913 int indent = 0; 914 // Compute the width of the matched text. 915 // Use win_chartabsize() so that TAB size is correct, 916 // while wrapping is ignored. 917 while (ptr < end_ptr) { 918 indent += win_chartabsize(wp, ptr, indent); 919 MB_PTR_ADV(ptr); 920 } 921 prev_indent = indent; 922 } 923 } 924 vim_regfree(regmatch.regprog); 925 } 926 } 927 } 928 if (wp->w_briopt_vcol != 0) { 929 // column value has priority 930 bri = wp->w_briopt_vcol; 931 prev_list = 0; 932 } else { 933 bri = prev_indent + wp->w_briopt_shift; 934 } 935 936 // Add offset for number column, if 'n' is in 'cpoptions' 937 bri += win_col_off2(wp); 938 939 // add additional indent for numbered lists 940 if (wp->w_briopt_list > 0) { 941 bri += prev_list; 942 } 943 944 // indent minus the length of the showbreak string 945 if (wp->w_briopt_sbr) { 946 bri -= vim_strsize(get_showbreak_value(wp)); 947 } 948 949 // never indent past left window margin 950 if (bri < 0) { 951 bri = 0; 952 } else if (bri > eff_wwidth - wp->w_briopt_min) { 953 // always leave at least bri_min characters on the left, 954 // if text width is sufficient 955 bri = (eff_wwidth - wp->w_briopt_min < 0) 956 ? 0 : eff_wwidth - wp->w_briopt_min; 957 } 958 959 return bri; 960 } 961 962 // When extra == 0: Return true if the cursor is before or on the first 963 // non-blank in the line. 964 // When extra == 1: Return true if the cursor is before the first non-blank in 965 // the line. 966 bool inindent(int extra) 967 { 968 char *ptr; 969 colnr_T col; 970 971 for (col = 0, ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr); col++) { 972 ptr++; 973 } 974 975 if (col >= curwin->w_cursor.col + extra) { 976 return true; 977 } 978 return false; 979 } 980 981 /// Handle reindenting a block of lines. 982 void op_reindent(oparg_T *oap, Indenter how) 983 { 984 int i = 0; 985 linenr_T first_changed = 0; 986 linenr_T last_changed = 0; 987 linenr_T start_lnum = curwin->w_cursor.lnum; 988 989 // Don't even try when 'modifiable' is off. 990 if (!MODIFIABLE(curbuf)) { 991 emsg(_(e_modifiable)); 992 return; 993 } 994 995 // Save for undo. Do this once for all lines, much faster than doing this 996 // for each line separately, especially when undoing. 997 if (u_savecommon(curbuf, start_lnum - 1, start_lnum + oap->line_count, 998 start_lnum + oap->line_count, false) == OK) { 999 int amount; 1000 for (i = oap->line_count - 1; i >= 0 && !got_int; i--) { 1001 // it's a slow thing to do, so give feedback so there's no worry 1002 // that the computer's just hung. 1003 1004 if (i > 1 1005 && (i % 50 == 0 || i == oap->line_count - 1) 1006 && oap->line_count > p_report) { 1007 smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i); 1008 } 1009 1010 // Be vi-compatible: For lisp indenting the first line is not 1011 // indented, unless there is only one line. 1012 if (i != oap->line_count - 1 || oap->line_count == 1 1013 || how != get_lisp_indent) { 1014 char *l = skipwhite(get_cursor_line_ptr()); 1015 if (*l == NUL) { // empty or blank line 1016 amount = 0; 1017 } else { 1018 amount = how(); // get the indent for this line 1019 } 1020 if (amount >= 0 && set_indent(amount, 0)) { 1021 // did change the indent, call changed_lines() later 1022 if (first_changed == 0) { 1023 first_changed = curwin->w_cursor.lnum; 1024 } 1025 last_changed = curwin->w_cursor.lnum; 1026 } 1027 } 1028 curwin->w_cursor.lnum++; 1029 curwin->w_cursor.col = 0; // make sure it's valid 1030 } 1031 } 1032 1033 // put cursor on first non-blank of indented line 1034 curwin->w_cursor.lnum = start_lnum; 1035 beginline(BL_SOL | BL_FIX); 1036 1037 // Mark changed lines so that they will be redrawn. When Visual 1038 // highlighting was present, need to continue until the last line. When 1039 // there is no change still need to remove the Visual highlighting. 1040 if (last_changed != 0) { 1041 changed_lines(curbuf, first_changed, 0, 1042 oap->is_VIsual ? start_lnum + oap->line_count 1043 : last_changed + 1, 0, true); 1044 } else if (oap->is_VIsual) { 1045 redraw_curbuf_later(UPD_INVERTED); 1046 } 1047 1048 if (oap->line_count > p_report) { 1049 i = oap->line_count - (i + 1); 1050 smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i); 1051 } 1052 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 1053 // set '[ and '] marks 1054 curbuf->b_op_start = oap->start; 1055 curbuf->b_op_end = oap->end; 1056 } 1057 } 1058 1059 /// @return true if lines starting with '#' should be left aligned. 1060 bool preprocs_left(void) 1061 { 1062 return ((curbuf->b_p_si && !curbuf->b_p_cin) 1063 || (curbuf->b_p_cin && in_cinkeys('#', ' ', true) 1064 && curbuf->b_ind_hash_comment == 0)); 1065 } 1066 1067 /// @return true if the conditions are OK for smart indenting. 1068 bool may_do_si(void) 1069 { 1070 return curbuf->b_p_si && !curbuf->b_p_cin && *curbuf->b_p_inde == NUL && !p_paste; 1071 } 1072 1073 // Try to do some very smart auto-indenting. 1074 // Used when inserting a "normal" character. 1075 void ins_try_si(int c) 1076 { 1077 pos_T *pos; 1078 1079 // do some very smart indenting when entering '{' or '}' 1080 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}' && inindent(0))) { 1081 pos_T old_pos; 1082 char *ptr; 1083 int i; 1084 bool temp; 1085 // for '}' set indent equal to indent of line containing matching '{' 1086 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) { 1087 old_pos = curwin->w_cursor; 1088 // If the matching '{' has a ')' immediately before it (ignoring 1089 // white-space), then line up with the start of the line 1090 // containing the matching '(' if there is one. This handles the 1091 // case where an "if (..\n..) {" statement continues over multiple 1092 // lines -- webb 1093 ptr = ml_get(pos->lnum); 1094 i = pos->col; 1095 if (i > 0) { // skip blanks before '{' 1096 while (--i > 0 && ascii_iswhite(ptr[i])) {} 1097 } 1098 curwin->w_cursor.lnum = pos->lnum; 1099 curwin->w_cursor.col = i; 1100 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) { 1101 curwin->w_cursor = *pos; 1102 } 1103 i = get_indent(); 1104 curwin->w_cursor = old_pos; 1105 if (State & VREPLACE_FLAG) { 1106 change_indent(INDENT_SET, i, false, true); 1107 } else { 1108 set_indent(i, SIN_CHANGED); 1109 } 1110 } else if (curwin->w_cursor.col > 0) { 1111 // when inserting '{' after "O" reduce indent, but not 1112 // more than indent of previous line 1113 temp = true; 1114 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) { 1115 old_pos = curwin->w_cursor; 1116 i = get_indent(); 1117 while (curwin->w_cursor.lnum > 1) { 1118 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum))); 1119 1120 // ignore empty lines and lines starting with '#'. 1121 if (*ptr != '#' && *ptr != NUL) { 1122 break; 1123 } 1124 } 1125 if (get_indent() >= i) { 1126 temp = false; 1127 } 1128 curwin->w_cursor = old_pos; 1129 } 1130 if (temp) { 1131 shift_line(true, false, 1, true); 1132 } 1133 } 1134 } 1135 1136 // set indent of '#' always to 0 1137 if (curwin->w_cursor.col > 0 && can_si && c == '#' && inindent(0)) { 1138 // remember current indent for next line 1139 old_indent = get_indent(); 1140 set_indent(0, SIN_CHANGED); 1141 } 1142 1143 // Adjust ai_col, the char at this position can be deleted. 1144 ai_col = MIN(ai_col, curwin->w_cursor.col); 1145 } 1146 1147 /// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D). 1148 /// Keep the cursor on the same character. 1149 /// type == INDENT_INC increase indent (for CTRL-T or <Tab>) 1150 /// type == INDENT_DEC decrease indent (for CTRL-D) 1151 /// type == INDENT_SET set indent to "amount" 1152 /// 1153 /// @param round if true, round the indent to 'shiftwidth' (only with _INC and _Dec). 1154 /// @param call_changed_bytes call changed_bytes() 1155 void change_indent(int type, int amount, int round, bool call_changed_bytes) 1156 { 1157 int insstart_less; // reduction for Insstart.col 1158 colnr_T orig_col = 0; // init for GCC 1159 char *orig_line = NULL; // init for GCC 1160 1161 // MODE_VREPLACE state needs to know what the line was like before changing 1162 if (State & VREPLACE_FLAG) { 1163 orig_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); 1164 orig_col = curwin->w_cursor.col; 1165 } 1166 1167 // for the following tricks we don't want list mode 1168 int save_p_list = curwin->w_p_list; 1169 curwin->w_p_list = false; 1170 colnr_T vc = getvcol_nolist(&curwin->w_cursor); 1171 int vcol = vc; 1172 1173 // For Replace mode we need to fix the replace stack later, which is only 1174 // possible when the cursor is in the indent. Remember the number of 1175 // characters before the cursor if it's possible. 1176 int start_col = curwin->w_cursor.col; 1177 1178 // determine offset from first non-blank 1179 int new_cursor_col = curwin->w_cursor.col; 1180 beginline(BL_WHITE); 1181 new_cursor_col -= curwin->w_cursor.col; 1182 1183 insstart_less = curwin->w_cursor.col; 1184 1185 // If the cursor is in the indent, compute how many screen columns the 1186 // cursor is to the left of the first non-blank. 1187 if (new_cursor_col < 0) { 1188 vcol = get_indent() - vcol; 1189 } 1190 1191 if (new_cursor_col > 0) { // can't fix replace stack 1192 start_col = -1; 1193 } 1194 1195 // Set the new indent. The cursor will be put on the first non-blank. 1196 if (type == INDENT_SET) { 1197 set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0); 1198 } else { 1199 int save_State = State; 1200 1201 // Avoid being called recursively. 1202 if (State & VREPLACE_FLAG) { 1203 State = MODE_INSERT; 1204 } 1205 shift_line(type == INDENT_DEC, round, 1, call_changed_bytes); 1206 State = save_State; 1207 } 1208 insstart_less -= curwin->w_cursor.col; 1209 1210 // Try to put cursor on same character. 1211 // If the cursor is at or after the first non-blank in the line, 1212 // compute the cursor column relative to the column of the first 1213 // non-blank character. 1214 // If we are not in insert mode, leave the cursor on the first non-blank. 1215 // If the cursor is before the first non-blank, position it relative 1216 // to the first non-blank, counted in screen columns. 1217 if (new_cursor_col >= 0) { 1218 // When changing the indent while the cursor is touching it, reset 1219 // Insstart_col to 0. 1220 if (new_cursor_col == 0) { 1221 insstart_less = MAXCOL; 1222 } 1223 new_cursor_col += curwin->w_cursor.col; 1224 } else if (!(State & MODE_INSERT)) { 1225 new_cursor_col = curwin->w_cursor.col; 1226 } else { 1227 // Compute the screen column where the cursor should be. 1228 vcol = get_indent() - vcol; 1229 int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol); 1230 curwin->w_virtcol = end_vcol; 1231 1232 // Advance the cursor until we reach the right screen column. 1233 new_cursor_col = 0; 1234 char *const line = get_cursor_line_ptr(); 1235 vcol = 0; 1236 if (*line != NUL) { 1237 CharsizeArg csarg; 1238 CSType cstype = init_charsize_arg(&csarg, curwin, 0, line); 1239 StrCharInfo ci = utf_ptr2StrCharInfo(line); 1240 while (true) { 1241 int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width; 1242 if (next_vcol > end_vcol) { 1243 break; 1244 } 1245 vcol = next_vcol; 1246 ci = utfc_next(ci); 1247 if (*ci.ptr == NUL) { 1248 break; 1249 } 1250 } 1251 new_cursor_col = (int)(ci.ptr - line); 1252 } 1253 1254 // May need to insert spaces to be able to position the cursor on 1255 // the right screen column. 1256 if (vcol != (int)curwin->w_virtcol) { 1257 curwin->w_cursor.col = (colnr_T)new_cursor_col; 1258 const size_t ptrlen = (size_t)(curwin->w_virtcol - vcol); 1259 char *ptr = xmallocz(ptrlen); 1260 memset(ptr, ' ', ptrlen); 1261 new_cursor_col += (int)ptrlen; 1262 ins_str(ptr, ptrlen); 1263 xfree(ptr); 1264 } 1265 1266 // When changing the indent while the cursor is in it, reset 1267 // Insstart_col to 0. 1268 insstart_less = MAXCOL; 1269 } 1270 1271 curwin->w_p_list = save_p_list; 1272 curwin->w_cursor.col = MAX(0, (colnr_T)new_cursor_col); 1273 curwin->w_set_curswant = true; 1274 changed_cline_bef_curs(curwin); 1275 1276 // May have to adjust the start of the insert. 1277 if (State & MODE_INSERT) { 1278 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) { 1279 if ((int)Insstart.col <= insstart_less) { 1280 Insstart.col = 0; 1281 } else { 1282 Insstart.col -= insstart_less; 1283 } 1284 } 1285 if ((int)ai_col <= insstart_less) { 1286 ai_col = 0; 1287 } else { 1288 ai_col -= insstart_less; 1289 } 1290 } 1291 1292 // For MODE_REPLACE state, may have to fix the replace stack, if it's 1293 // possible. If the number of characters before the cursor decreased, need 1294 // to pop a few characters from the replace stack. 1295 // If the number of characters before the cursor increased, need to push a 1296 // few NULs onto the replace stack. 1297 if (REPLACE_NORMAL(State) && start_col >= 0) { 1298 while (start_col > (int)curwin->w_cursor.col) { 1299 replace_join(0); // remove a NUL from the replace stack 1300 start_col--; 1301 } 1302 while (start_col < (int)curwin->w_cursor.col) { 1303 replace_push_nul(); 1304 start_col++; 1305 } 1306 } 1307 1308 // For MODE_VREPLACE state, we also have to fix the replace stack. In this 1309 // case it is always possible because we backspace over the whole line and 1310 // then put it back again the way we wanted it. 1311 if (State & VREPLACE_FLAG) { 1312 // Save new line 1313 char *new_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); 1314 1315 // We only put back the new line up to the cursor 1316 new_line[curwin->w_cursor.col] = NUL; 1317 int new_col = curwin->w_cursor.col; 1318 1319 // Put back original line 1320 ml_replace(curwin->w_cursor.lnum, orig_line, false); 1321 curwin->w_cursor.col = orig_col; 1322 1323 curbuf_splice_pending++; 1324 1325 // Backspace from cursor to start of line 1326 backspace_until_column(0); 1327 1328 // Insert new stuff into line again 1329 ins_bytes(new_line); 1330 1331 xfree(new_line); 1332 1333 curbuf_splice_pending--; 1334 1335 // TODO(bfredl): test for crazy edge cases, like we stand on a TAB or 1336 // something? does this even do the right text change then? 1337 int delta = orig_col - new_col; 1338 extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, new_col, 1339 delta < 0 ? -delta : 0, 1340 delta > 0 ? delta : 0, 1341 kExtmarkUndo); 1342 } 1343 } 1344 1345 /// Copy the indent from ptr to the current line (and fill to size). 1346 /// Leaves the cursor on the first non-blank in the line. 1347 /// 1348 /// @return true if the line was changed. 1349 bool copy_indent(int size, char *src) 1350 { 1351 char *p = NULL; 1352 char *line = NULL; 1353 int ind_len; 1354 int line_len = 0; 1355 int tab_pad; 1356 1357 // Round 1: compute the number of characters needed for the indent 1358 // Round 2: copy the characters. 1359 for (int round = 1; round <= 2; round++) { 1360 int todo = size; 1361 ind_len = 0; 1362 int ind_done = 0; 1363 int ind_col = 0; 1364 char *s = src; 1365 1366 // Count/copy the usable portion of the source line. 1367 while (todo > 0 && ascii_iswhite(*s)) { 1368 if (*s == TAB) { 1369 tab_pad = tabstop_padding(ind_done, 1370 curbuf->b_p_ts, 1371 curbuf->b_p_vts_array); 1372 1373 // Stop if this tab will overshoot the target. 1374 if (todo < tab_pad) { 1375 break; 1376 } 1377 todo -= tab_pad; 1378 ind_done += tab_pad; 1379 ind_col += tab_pad; 1380 } else { 1381 todo--; 1382 ind_done++; 1383 ind_col++; 1384 } 1385 ind_len++; 1386 1387 if (p != NULL) { 1388 *p++ = *s; 1389 } 1390 s++; 1391 } 1392 1393 // Fill to next tabstop with a tab, if possible. 1394 tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array); 1395 1396 if ((todo >= tab_pad) && !curbuf->b_p_et) { 1397 todo -= tab_pad; 1398 ind_len++; 1399 ind_col += tab_pad; 1400 1401 if (p != NULL) { 1402 *p++ = TAB; 1403 } 1404 } 1405 1406 // Add tabs required for indent. 1407 if (!curbuf->b_p_et) { 1408 while (true) { 1409 tab_pad = tabstop_padding(ind_col, 1410 curbuf->b_p_ts, 1411 curbuf->b_p_vts_array); 1412 if (todo < tab_pad) { 1413 break; 1414 } 1415 todo -= tab_pad; 1416 ind_len++; 1417 ind_col += tab_pad; 1418 if (p != NULL) { 1419 *p++ = TAB; 1420 } 1421 } 1422 } 1423 1424 // Count/add spaces required for indent. 1425 while (todo > 0) { 1426 todo--; 1427 ind_len++; 1428 1429 if (p != NULL) { 1430 *p++ = ' '; 1431 } 1432 } 1433 1434 if (p == NULL) { 1435 // Allocate memory for the result: the copied indent, new indent 1436 // and the rest of the line. 1437 line_len = get_cursor_line_len() + 1; 1438 assert(ind_len + line_len >= 0); 1439 size_t line_size; 1440 STRICT_ADD(ind_len, line_len, &line_size, size_t); 1441 line = xmalloc(line_size); 1442 p = line; 1443 } 1444 } 1445 1446 // Append the original line 1447 memmove(p, get_cursor_line_ptr(), (size_t)line_len); 1448 1449 // Replace the line 1450 ml_replace(curwin->w_cursor.lnum, line, false); 1451 1452 // Put the cursor after the indent. 1453 curwin->w_cursor.col = ind_len; 1454 return true; 1455 } 1456 1457 /// Give a "resulting text too long" error and maybe set got_int. 1458 static void emsg_text_too_long(void) 1459 { 1460 emsg(_(e_resulting_text_too_long)); 1461 // when not inside a try/catch set got_int to break out of any loop 1462 if (trylevel == 0) { 1463 got_int = true; 1464 } 1465 } 1466 1467 /// ":retab". 1468 void ex_retab(exarg_T *eap) 1469 { 1470 bool got_tab = false; 1471 int num_spaces = 0; 1472 int start_col = 0; // For start of white-space string 1473 int64_t start_vcol = 0; // For start of white-space string 1474 char *new_line = (char *)1; // init to non-NULL 1475 colnr_T *new_vts_array = NULL; 1476 char *new_ts_str; // string value of tab argument 1477 1478 linenr_T first_line = 0; // first changed line 1479 linenr_T last_line = 0; // last changed line 1480 bool is_indent_only = false; 1481 1482 int save_list = curwin->w_p_list; 1483 curwin->w_p_list = 0; // don't want list mode here 1484 1485 char *ptr = eap->arg; 1486 if (strncmp(ptr, "-indentonly", 11) == 0 && ascii_iswhite_or_nul(ptr[11])) { 1487 is_indent_only = true; 1488 ptr = skipwhite(ptr + 11); 1489 } 1490 1491 new_ts_str = ptr; 1492 if (!tabstop_set(ptr, &new_vts_array)) { 1493 return; 1494 } 1495 while (ascii_isdigit(*ptr) || *ptr == ',') { 1496 ptr++; 1497 } 1498 1499 // This ensures that either new_vts_array and new_ts_str are freshly 1500 // allocated, or new_vts_array points to an existing array and new_ts_str 1501 // is null. 1502 if (new_vts_array == NULL) { 1503 new_vts_array = curbuf->b_p_vts_array; 1504 new_ts_str = NULL; 1505 } else { 1506 new_ts_str = xmemdupz(new_ts_str, (size_t)(ptr - new_ts_str)); 1507 } 1508 for (linenr_T lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) { 1509 ptr = ml_get(lnum); 1510 int old_len = ml_get_len(lnum); 1511 int col = 0; 1512 int64_t vcol = 0; 1513 bool did_undo = false; // called u_save for current line 1514 while (true) { 1515 if (ascii_iswhite(ptr[col])) { 1516 if (!got_tab && num_spaces == 0) { 1517 // First consecutive white-space 1518 start_vcol = vcol; 1519 start_col = col; 1520 } 1521 if (ptr[col] == ' ') { 1522 num_spaces++; 1523 } else { 1524 got_tab = true; 1525 } 1526 } else { 1527 if (got_tab || (eap->forceit && num_spaces > 1)) { 1528 // Retabulate this string of white-space 1529 1530 // len is virtual length of white string 1531 int len = num_spaces = (int)(vcol - start_vcol); 1532 int num_tabs = 0; 1533 if (!curbuf->b_p_et) { 1534 int t, s; 1535 1536 tabstop_fromto((colnr_T)start_vcol, (colnr_T)vcol, 1537 (int)curbuf->b_p_ts, new_vts_array, &t, &s); 1538 num_tabs = t; 1539 num_spaces = s; 1540 } 1541 if (curbuf->b_p_et || got_tab 1542 || (num_spaces + num_tabs < len)) { 1543 if (did_undo == false) { 1544 did_undo = true; 1545 if (u_save((linenr_T)(lnum - 1), 1546 (linenr_T)(lnum + 1)) == FAIL) { 1547 new_line = NULL; // flag out-of-memory 1548 break; 1549 } 1550 } 1551 1552 // len is actual number of white characters used 1553 len = num_spaces + num_tabs; 1554 const int new_len = old_len - col + start_col + len + 1; 1555 if (new_len <= 0 || new_len >= MAXCOL) { 1556 emsg_text_too_long(); 1557 break; 1558 } 1559 new_line = xmalloc((size_t)new_len); 1560 1561 if (start_col > 0) { 1562 memmove(new_line, ptr, (size_t)start_col); 1563 } 1564 memmove(new_line + start_col + len, 1565 ptr + col, (size_t)old_len - (size_t)col + 1); 1566 ptr = new_line + start_col; 1567 for (col = 0; col < len; col++) { 1568 ptr[col] = (col < num_tabs) ? '\t' : ' '; 1569 } 1570 if (ml_replace(lnum, new_line, false) == OK) { 1571 // "new_line" may have been copied 1572 new_line = curbuf->b_ml.ml_line_ptr; 1573 extmark_splice_cols(curbuf, lnum - 1, 0, (colnr_T)old_len, 1574 (colnr_T)new_len - 1, kExtmarkUndo); 1575 } 1576 if (first_line == 0) { 1577 first_line = lnum; 1578 } 1579 last_line = lnum; 1580 ptr = new_line; 1581 old_len = new_len - 1; 1582 col = start_col + len; 1583 } 1584 } 1585 got_tab = false; 1586 num_spaces = 0; 1587 1588 if (is_indent_only) { 1589 break; 1590 } 1591 } 1592 if (ptr[col] == NUL) { 1593 break; 1594 } 1595 vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); 1596 if (vcol >= MAXCOL) { 1597 emsg_text_too_long(); 1598 break; 1599 } 1600 col += utfc_ptr2len(ptr + col); 1601 } 1602 if (new_line == NULL) { // out of memory 1603 break; 1604 } 1605 line_breakcheck(); 1606 } 1607 if (got_int) { 1608 emsg(_(e_interr)); 1609 } 1610 1611 // If a single value was given then it can be considered equal to 1612 // either the value of 'tabstop' or the value of 'vartabstop'. 1613 if (tabstop_count(curbuf->b_p_vts_array) == 0 1614 && tabstop_count(new_vts_array) == 1 1615 && curbuf->b_p_ts == tabstop_first(new_vts_array)) { 1616 // not changed 1617 } else if (tabstop_count(curbuf->b_p_vts_array) > 0 1618 && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) { 1619 // not changed 1620 } else { 1621 redraw_curbuf_later(UPD_NOT_VALID); 1622 } 1623 if (first_line != 0) { 1624 changed_lines(curbuf, first_line, 0, last_line + 1, 0, true); 1625 } 1626 1627 curwin->w_p_list = save_list; // restore 'list' 1628 1629 if (new_ts_str != NULL) { // set the new tabstop 1630 // If 'vartabstop' is in use or if the value given to retab has more 1631 // than one tabstop then update 'vartabstop'. 1632 colnr_T *old_vts_ary = curbuf->b_p_vts_array; 1633 1634 if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) { 1635 set_option_direct(kOptVartabstop, CSTR_AS_OPTVAL(new_ts_str), OPT_LOCAL, 0); 1636 curbuf->b_p_vts_array = new_vts_array; 1637 xfree(old_vts_ary); 1638 } else { 1639 // 'vartabstop' wasn't in use and a single value was given to 1640 // retab then update 'tabstop'. 1641 curbuf->b_p_ts = tabstop_first(new_vts_array); 1642 xfree(new_vts_array); 1643 } 1644 xfree(new_ts_str); 1645 } 1646 coladvance(curwin, curwin->w_curswant); 1647 1648 u_clearline(curbuf); 1649 } 1650 1651 /// Get indent level from 'indentexpr'. 1652 int get_expr_indent(void) 1653 { 1654 bool use_sandbox = was_set_insecurely(curwin, kOptIndentexpr, OPT_LOCAL); 1655 const sctx_T save_sctx = current_sctx; 1656 1657 // Save and restore cursor position and curswant, in case it was changed 1658 // * via :normal commands. 1659 pos_T save_pos = curwin->w_cursor; 1660 colnr_T save_curswant = curwin->w_curswant; 1661 bool save_set_curswant = curwin->w_set_curswant; 1662 set_vim_var_nr(VV_LNUM, (varnumber_T)curwin->w_cursor.lnum); 1663 1664 if (use_sandbox) { 1665 sandbox++; 1666 } 1667 textlock++; 1668 current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr]; 1669 1670 // Need to make a copy, the 'indentexpr' option could be changed while 1671 // evaluating it. 1672 char *inde_copy = xstrdup(curbuf->b_p_inde); 1673 int indent = (int)eval_to_number(inde_copy, true); 1674 xfree(inde_copy); 1675 1676 if (use_sandbox) { 1677 sandbox--; 1678 } 1679 textlock--; 1680 current_sctx = save_sctx; 1681 1682 // Restore the cursor position so that 'indentexpr' doesn't need to. 1683 // Pretend to be in Insert mode, allow cursor past end of line for "o" 1684 // command. 1685 int save_State = State; 1686 State = MODE_INSERT; 1687 curwin->w_cursor = save_pos; 1688 curwin->w_curswant = save_curswant; 1689 curwin->w_set_curswant = save_set_curswant; 1690 check_cursor(curwin); 1691 State = save_State; 1692 1693 // Reset did_throw, unless 'debug' has "throw" and inside a try/catch. 1694 if (did_throw && (vim_strchr(p_debug, 't') == NULL || trylevel == 0)) { 1695 handle_did_throw(); 1696 did_throw = false; 1697 } 1698 1699 // If there is an error, just keep the current indent. 1700 if (indent < 0) { 1701 indent = get_indent(); 1702 } 1703 1704 return indent; 1705 } 1706 1707 // When 'p' is present in 'cpoptions, a Vi compatible method is used. 1708 // The incompatible newer method is quite a bit better at indenting 1709 // code in lisp-like languages than the traditional one; it's still 1710 // mostly heuristics however -- Dirk van Deun, dirk@rave.org 1711 1712 // TODO(unknown): 1713 // Findmatch() should be adapted for lisp, also to make showmatch 1714 // work correctly: now (v5.3) it seems all C/C++ oriented: 1715 // - it does not recognize the #\( and #\) notations as character literals 1716 // - it doesn't know about comments starting with a semicolon 1717 // - it incorrectly interprets '(' as a character literal 1718 // All this messes up get_lisp_indent in some rare cases. 1719 // Update from Sergey Khorev: 1720 // I tried to fix the first two issues. 1721 int get_lisp_indent(void) 1722 { 1723 pos_T *pos; 1724 pos_T paren; 1725 int amount; 1726 1727 pos_T realpos = curwin->w_cursor; 1728 curwin->w_cursor.col = 0; 1729 1730 if ((pos = findmatch(NULL, '(')) == NULL) { 1731 pos = findmatch(NULL, '['); 1732 } else { 1733 paren = *pos; 1734 pos = findmatch(NULL, '['); 1735 1736 if ((pos == NULL) || lt(*pos, paren)) { 1737 pos = &paren; 1738 } 1739 } 1740 1741 if (pos != NULL) { 1742 // Extra trick: Take the indent of the first previous non-white 1743 // line that is at the same () level. 1744 amount = -1; 1745 int parencount = 0; 1746 1747 while (--curwin->w_cursor.lnum >= pos->lnum) { 1748 if (linewhite(curwin->w_cursor.lnum)) { 1749 continue; 1750 } 1751 1752 for (char *that = get_cursor_line_ptr(); *that != NUL; that++) { 1753 if (*that == ';') { 1754 while (*(that + 1) != NUL) { 1755 that++; 1756 } 1757 continue; 1758 } 1759 1760 if (*that == '\\') { 1761 if (*(that + 1) != NUL) { 1762 that++; 1763 } 1764 continue; 1765 } 1766 1767 if ((*that == '"') && (*(that + 1) != NUL)) { 1768 while (*++that && *that != '"') { 1769 // Skipping escaped characters in the string 1770 if (*that == '\\') { 1771 if (*++that == NUL) { 1772 break; 1773 } 1774 if (that[1] == NUL) { 1775 that++; 1776 break; 1777 } 1778 } 1779 } 1780 if (*that == NUL) { 1781 break; 1782 } 1783 } 1784 if ((*that == '(') || (*that == '[')) { 1785 parencount++; 1786 } else if ((*that == ')') || (*that == ']')) { 1787 parencount--; 1788 } 1789 } 1790 1791 if (parencount == 0) { 1792 amount = get_indent(); 1793 break; 1794 } 1795 } 1796 1797 if (amount == -1) { 1798 curwin->w_cursor.lnum = pos->lnum; 1799 curwin->w_cursor.col = pos->col; 1800 colnr_T col = pos->col; 1801 1802 char *line = get_cursor_line_ptr(); 1803 1804 CharsizeArg csarg; 1805 CSType cstype = init_charsize_arg(&csarg, curwin, pos->lnum, line); 1806 1807 StrCharInfo sci = utf_ptr2StrCharInfo(line); 1808 amount = 0; 1809 while (*sci.ptr != NUL && col > 0) { 1810 amount += win_charsize(cstype, amount, sci.ptr, sci.chr.value, &csarg).width; 1811 sci = utfc_next(sci); 1812 col--; 1813 } 1814 char *that = sci.ptr; 1815 1816 // Some keywords require "body" indenting rules (the 1817 // non-standard-lisp ones are Scheme special forms): 1818 // (let ((a 1)) instead (let ((a 1)) 1819 // (...)) of (...)) 1820 if (((*that == '(') || (*that == '[')) && lisp_match(that + 1)) { 1821 amount += 2; 1822 } else { 1823 if (*that != NUL) { 1824 that++; 1825 amount++; 1826 } 1827 colnr_T firsttry = amount; 1828 1829 while (ascii_iswhite(*that)) { 1830 amount += win_charsize(cstype, amount, that, (uint8_t)(*that), &csarg).width; 1831 that++; 1832 } 1833 1834 if (*that && (*that != ';')) { 1835 // Not a comment line. 1836 // Test *that != '(' to accommodate first let/do 1837 // argument if it is more than one line. 1838 if ((*that != '(') && (*that != '[')) { 1839 firsttry++; 1840 } 1841 1842 parencount = 0; 1843 1844 CharInfo ci = utf_ptr2CharInfo(that); 1845 if (((ci.value != '"') && (ci.value != '\'') && (ci.value != '#') 1846 && ((ci.value < '0') || (ci.value > '9')))) { 1847 int quotecount = 0; 1848 while (*that && (!ascii_iswhite(ci.value) || quotecount || parencount)) { 1849 if (ci.value == '"') { 1850 quotecount = !quotecount; 1851 } 1852 if (((ci.value == '(') || (ci.value == '[')) && !quotecount) { 1853 parencount++; 1854 } 1855 if (((ci.value == ')') || (ci.value == ']')) && !quotecount) { 1856 parencount--; 1857 } 1858 if ((ci.value == '\\') && (*(that + 1) != NUL)) { 1859 amount += win_charsize(cstype, amount, that, ci.value, &csarg).width; 1860 StrCharInfo next_sci = utfc_next((StrCharInfo){ that, ci }); 1861 that = next_sci.ptr; 1862 ci = next_sci.chr; 1863 } 1864 1865 amount += win_charsize(cstype, amount, that, ci.value, &csarg).width; 1866 StrCharInfo next_sci = utfc_next((StrCharInfo){ that, ci }); 1867 that = next_sci.ptr; 1868 ci = next_sci.chr; 1869 } 1870 } 1871 1872 while (ascii_iswhite(*that)) { 1873 amount += win_charsize(cstype, amount, that, (uint8_t)(*that), &csarg).width; 1874 that++; 1875 } 1876 1877 if (!*that || (*that == ';')) { 1878 amount = firsttry; 1879 } 1880 } 1881 } 1882 } 1883 } else { 1884 amount = 0; // No matching '(' or '[' found, use zero indent. 1885 } 1886 curwin->w_cursor = realpos; 1887 1888 return amount; 1889 } 1890 1891 static int lisp_match(char *p) 1892 { 1893 char buf[512]; 1894 char *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; 1895 1896 while (*word != NUL) { 1897 size_t len = copy_option_part(&word, buf, sizeof(buf), ","); 1898 if ((strncmp(buf, p, len) == 0) && ascii_iswhite_or_nul(p[len])) { 1899 return true; 1900 } 1901 } 1902 return false; 1903 } 1904 1905 /// Re-indent the current line, based on the current contents of it and the 1906 /// surrounding lines. Fixing the cursor position seems really easy -- I'm very 1907 /// confused what all the part that handles Control-T is doing that I'm not. 1908 /// "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent. 1909 void fixthisline(IndentGetter get_the_indent) 1910 { 1911 int amount = get_the_indent(); 1912 1913 if (amount < 0) { 1914 return; 1915 } 1916 1917 change_indent(INDENT_SET, amount, false, true); 1918 if (linewhite(curwin->w_cursor.lnum)) { 1919 did_ai = true; // delete the indent if the line stays empty 1920 } 1921 } 1922 1923 /// Return true if 'indentexpr' should be used for Lisp indenting. 1924 /// Caller may want to check 'autoindent'. 1925 bool use_indentexpr_for_lisp(void) 1926 { 1927 return curbuf->b_p_lisp 1928 && *curbuf->b_p_inde != NUL 1929 && strcmp(curbuf->b_p_lop, "expr:1") == 0; 1930 } 1931 1932 /// Fix indent for 'lisp' and 'cindent'. 1933 void fix_indent(void) 1934 { 1935 if (p_paste) { 1936 return; // no auto-indenting when 'paste' is set 1937 } 1938 if (curbuf->b_p_lisp && curbuf->b_p_ai) { 1939 if (use_indentexpr_for_lisp()) { 1940 do_c_expr_indent(); 1941 } else { 1942 fixthisline(get_lisp_indent); 1943 } 1944 } else if (cindent_on()) { 1945 do_c_expr_indent(); 1946 } 1947 } 1948 1949 /// "indent()" function 1950 void f_indent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1951 { 1952 const linenr_T lnum = tv_get_lnum(argvars); 1953 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) { 1954 rettv->vval.v_number = get_indent_lnum(lnum); 1955 } else { 1956 rettv->vval.v_number = -1; 1957 } 1958 } 1959 1960 /// "lispindent(lnum)" function 1961 void f_lispindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1962 { 1963 const pos_T pos = curwin->w_cursor; 1964 const linenr_T lnum = tv_get_lnum(argvars); 1965 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) { 1966 curwin->w_cursor.lnum = lnum; 1967 rettv->vval.v_number = get_lisp_indent(); 1968 curwin->w_cursor = pos; 1969 } else { 1970 rettv->vval.v_number = -1; 1971 } 1972 }