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