textformat.c (36271B)
1 // textformat.c: text formatting functions 2 3 #include <stdbool.h> 4 #include <stdint.h> 5 #include <string.h> 6 7 #include "nvim/ascii_defs.h" 8 #include "nvim/buffer_defs.h" 9 #include "nvim/change.h" 10 #include "nvim/charset.h" 11 #include "nvim/cursor.h" 12 #include "nvim/drawscreen.h" 13 #include "nvim/edit.h" 14 #include "nvim/eval.h" 15 #include "nvim/eval/typval_defs.h" 16 #include "nvim/eval/vars.h" 17 #include "nvim/ex_cmds_defs.h" 18 #include "nvim/getchar.h" 19 #include "nvim/globals.h" 20 #include "nvim/indent.h" 21 #include "nvim/indent_c.h" 22 #include "nvim/macros_defs.h" 23 #include "nvim/mark.h" 24 #include "nvim/mbyte.h" 25 #include "nvim/memline.h" 26 #include "nvim/memory.h" 27 #include "nvim/message.h" 28 #include "nvim/move.h" 29 #include "nvim/ops.h" 30 #include "nvim/option.h" 31 #include "nvim/option_defs.h" 32 #include "nvim/option_vars.h" 33 #include "nvim/os/input.h" 34 #include "nvim/pos_defs.h" 35 #include "nvim/search.h" 36 #include "nvim/state_defs.h" 37 #include "nvim/strings.h" 38 #include "nvim/textformat.h" 39 #include "nvim/textobject.h" 40 #include "nvim/ui.h" 41 #include "nvim/undo.h" 42 #include "nvim/vim_defs.h" 43 #include "nvim/window.h" 44 45 #include "textformat.c.generated.h" 46 47 static bool did_add_space = false; ///< auto_format() added an extra space 48 ///< under the cursor 49 50 #define WHITECHAR(cc) (ascii_iswhite(cc) \ 51 && !utf_iscomposing_first(utf_ptr2char((char *)get_cursor_pos_ptr() + 1))) 52 53 /// Return true if format option 'x' is in effect. 54 /// Take care of no formatting when 'paste' is set. 55 bool has_format_option(int x) 56 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 57 { 58 if (p_paste) { 59 return false; 60 } 61 return vim_strchr(curbuf->b_p_fo, x) != NULL; 62 } 63 64 /// Format text at the current insert position. 65 /// 66 /// If the INSCHAR_COM_LIST flag is present, then the value of second_indent 67 /// will be the comment leader length sent to open_line(). 68 /// 69 /// @param c character to be inserted (can be NUL) 70 void internal_format(int textwidth, int second_indent, int flags, bool format_only, int c) 71 { 72 int cc; 73 char save_char = NUL; 74 bool haveto_redraw = false; 75 const bool fo_ins_blank = has_format_option(FO_INS_BLANK); 76 const bool fo_multibyte = has_format_option(FO_MBYTE_BREAK); 77 const bool fo_rigor_tw = has_format_option(FO_RIGOROUS_TW); 78 const bool fo_white_par = has_format_option(FO_WHITE_PAR); 79 bool first_line = true; 80 colnr_T leader_len; 81 bool no_leader = false; 82 bool do_comments = (flags & INSCHAR_DO_COM); 83 int has_lbr = curwin->w_p_lbr; 84 85 // make sure win_charsize() counts correctly 86 curwin->w_p_lbr = false; 87 88 // When 'ai' is off we don't want a space under the cursor to be 89 // deleted. Replace it with an 'x' temporarily. 90 if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) { 91 cc = gchar_cursor(); 92 if (ascii_iswhite(cc)) { 93 save_char = (char)cc; 94 pchar_cursor('x'); 95 } 96 } 97 98 // Repeat breaking lines, until the current line is not too long. 99 while (!got_int) { 100 int startcol; // Cursor column at entry 101 int wantcol; // column at textwidth border 102 int foundcol; // column for start of spaces 103 int end_foundcol = 0; // column for start of word 104 int orig_col = 0; 105 char *saved_text = NULL; 106 colnr_T col; 107 bool did_do_comment = false; 108 109 colnr_T virtcol = get_nolist_virtcol() + char2cells(c != NUL ? c : gchar_cursor()); 110 if (virtcol <= (colnr_T)textwidth) { 111 break; 112 } 113 114 if (no_leader) { 115 do_comments = false; 116 } else if (!(flags & INSCHAR_FORMAT) 117 && has_format_option(FO_WRAP_COMS)) { 118 do_comments = true; 119 } 120 121 // Don't break until after the comment leader 122 if (do_comments) { 123 char *line = get_cursor_line_ptr(); 124 leader_len = get_leader_len(line, NULL, false, true); 125 if (leader_len == 0 && curbuf->b_p_cin) { 126 // Check for a line comment after code. 127 int comment_start = check_linecomment(line); 128 if (comment_start != MAXCOL) { 129 leader_len = get_leader_len(line + comment_start, NULL, false, true); 130 if (leader_len != 0) { 131 leader_len += comment_start; 132 } 133 } 134 } 135 } else { 136 leader_len = 0; 137 } 138 139 // If the line doesn't start with a comment leader, then don't 140 // start one in a following broken line. Avoids that a %word 141 // moved to the start of the next line causes all following lines 142 // to start with %. 143 if (leader_len == 0) { 144 no_leader = true; 145 } 146 if (!(flags & INSCHAR_FORMAT) 147 && leader_len == 0 148 && !has_format_option(FO_WRAP)) { 149 break; 150 } 151 if ((startcol = curwin->w_cursor.col) == 0) { 152 break; 153 } 154 155 // find column of textwidth border 156 coladvance(curwin, (colnr_T)textwidth); 157 wantcol = curwin->w_cursor.col; 158 159 curwin->w_cursor.col = startcol; 160 foundcol = 0; 161 int skip_pos = 0; 162 163 // Find position to break at. 164 // Stop at first entered white when 'formatoptions' has 'v' 165 while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) 166 || (flags & INSCHAR_FORMAT) 167 || curwin->w_cursor.lnum != Insstart.lnum 168 || curwin->w_cursor.col >= Insstart.col) { 169 if (curwin->w_cursor.col == startcol && c != NUL) { 170 cc = c; 171 } else { 172 cc = gchar_cursor(); 173 } 174 if (WHITECHAR(cc)) { 175 // remember position of blank just before text 176 colnr_T end_col = curwin->w_cursor.col; 177 178 // find start of sequence of blanks 179 int wcc = 0; // counter for whitespace chars 180 while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) { 181 dec_cursor(); 182 cc = gchar_cursor(); 183 184 // Increment count of how many whitespace chars in this 185 // group; we only need to know if it's more than one. 186 if (wcc < 2) { 187 wcc++; 188 } 189 } 190 if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) { 191 break; // only spaces in front of text 192 } 193 194 // Don't break after a period when 'formatoptions' has 'p' and 195 // there are less than two spaces. 196 if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) { 197 continue; 198 } 199 200 // Don't break until after the comment leader 201 if (curwin->w_cursor.col < leader_len) { 202 break; 203 } 204 205 if (has_format_option(FO_ONE_LETTER)) { 206 // do not break after one-letter words 207 if (curwin->w_cursor.col == 0) { 208 break; // one-letter word at begin 209 } 210 // do not break "#a b" when 'tw' is 2 211 if (curwin->w_cursor.col <= leader_len) { 212 break; 213 } 214 col = curwin->w_cursor.col; 215 dec_cursor(); 216 cc = gchar_cursor(); 217 218 if (WHITECHAR(cc)) { 219 continue; // one-letter, continue 220 } 221 curwin->w_cursor.col = col; 222 } 223 224 inc_cursor(); 225 226 end_foundcol = end_col + 1; 227 foundcol = curwin->w_cursor.col; 228 if (curwin->w_cursor.col <= (colnr_T)wantcol) { 229 break; 230 } 231 } else if ((cc >= 0x100 || !utf_allow_break_before(cc)) && fo_multibyte) { 232 int ncc; 233 bool allow_break; 234 235 // Break after or before a multi-byte character. 236 if (curwin->w_cursor.col != startcol) { 237 // Don't break until after the comment leader 238 if (curwin->w_cursor.col < leader_len) { 239 break; 240 } 241 col = curwin->w_cursor.col; 242 inc_cursor(); 243 ncc = gchar_cursor(); 244 allow_break = utf_allow_break(cc, ncc); 245 246 // If we have already checked this position, skip! 247 if (curwin->w_cursor.col != skip_pos && allow_break) { 248 foundcol = curwin->w_cursor.col; 249 end_foundcol = foundcol; 250 if (curwin->w_cursor.col <= (colnr_T)wantcol) { 251 break; 252 } 253 } 254 curwin->w_cursor.col = col; 255 } 256 257 if (curwin->w_cursor.col == 0) { 258 break; 259 } 260 261 ncc = cc; 262 col = curwin->w_cursor.col; 263 264 dec_cursor(); 265 cc = gchar_cursor(); 266 267 if (WHITECHAR(cc)) { 268 continue; // break with space 269 } 270 // Don't break until after the comment leader. 271 if (curwin->w_cursor.col < leader_len) { 272 break; 273 } 274 275 curwin->w_cursor.col = col; 276 skip_pos = curwin->w_cursor.col; 277 278 allow_break = utf_allow_break(cc, ncc); 279 280 // Must handle this to respect line break prohibition. 281 if (allow_break) { 282 foundcol = curwin->w_cursor.col; 283 end_foundcol = foundcol; 284 } 285 if (curwin->w_cursor.col <= (colnr_T)wantcol) { 286 const bool ncc_allow_break = utf_allow_break_before(ncc); 287 288 if (allow_break) { 289 break; 290 } 291 if (!ncc_allow_break && !fo_rigor_tw) { 292 // Enable at most 1 punct hang outside of textwidth. 293 if (curwin->w_cursor.col == startcol) { 294 // We are inserting a non-breakable char, postpone 295 // line break check to next insert. 296 end_foundcol = foundcol = 0; 297 break; 298 } 299 300 // Neither cc nor ncc is NUL if we are here, so 301 // it's safe to inc_cursor. 302 col = curwin->w_cursor.col; 303 304 inc_cursor(); 305 cc = ncc; 306 ncc = gchar_cursor(); 307 // handle insert 308 ncc = (ncc != NUL) ? ncc : c; 309 310 allow_break = utf_allow_break(cc, ncc); 311 312 if (allow_break) { 313 // Break only when we are not at end of line. 314 end_foundcol = foundcol = ncc == NUL ? 0 : curwin->w_cursor.col; 315 break; 316 } 317 curwin->w_cursor.col = col; 318 } 319 } 320 } 321 if (curwin->w_cursor.col == 0) { 322 break; 323 } 324 dec_cursor(); 325 } 326 327 if (foundcol == 0) { // no spaces, cannot break line 328 curwin->w_cursor.col = startcol; 329 break; 330 } 331 332 // Going to break the line, remove any "$" now. 333 undisplay_dollar(); 334 335 // Offset between cursor position and line break is used by replace 336 // stack functions. MODE_VREPLACE does not use this, and backspaces 337 // over the text instead. 338 if (State & VREPLACE_FLAG) { 339 orig_col = startcol; // Will start backspacing from here 340 } else { 341 replace_offset = startcol - end_foundcol; 342 } 343 344 // adjust startcol for spaces that will be deleted and 345 // characters that will remain on top line 346 curwin->w_cursor.col = foundcol; 347 while ((cc = gchar_cursor(), WHITECHAR(cc)) 348 && (!fo_white_par || curwin->w_cursor.col < startcol)) { 349 inc_cursor(); 350 } 351 startcol -= curwin->w_cursor.col; 352 startcol = MAX(startcol, 0); 353 354 if (State & VREPLACE_FLAG) { 355 // In MODE_VREPLACE state, we will backspace over the text to be 356 // wrapped, so save a copy now to put on the next line. 357 saved_text = xstrnsave(get_cursor_pos_ptr(), (size_t)get_cursor_pos_len()); 358 curwin->w_cursor.col = orig_col; 359 saved_text[startcol] = NUL; 360 361 // Backspace over characters that will move to the next line 362 if (!fo_white_par) { 363 backspace_until_column(foundcol); 364 } 365 } else { 366 // put cursor after pos. to break line 367 if (!fo_white_par) { 368 curwin->w_cursor.col = foundcol; 369 } 370 } 371 372 // Split the line just before the margin. 373 // Only insert/delete lines, but don't really redraw the window. 374 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX 375 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) 376 + (do_comments ? OPENLINE_DO_COM : 0) 377 + OPENLINE_FORMAT 378 + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0), 379 ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent), 380 &did_do_comment); 381 if (!(flags & INSCHAR_COM_LIST)) { 382 old_indent = 0; 383 } 384 385 // If a comment leader was inserted, may also do this on a following 386 // line. 387 if (did_do_comment) { 388 no_leader = false; 389 } 390 391 replace_offset = 0; 392 if (first_line) { 393 if (!(flags & INSCHAR_COM_LIST)) { 394 // This section is for auto-wrap of numeric lists. When not 395 // in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST 396 // flag will be set and open_line() will handle it (as seen 397 // above). The code here (and in get_number_indent()) will 398 // recognize comments if needed... 399 if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) { 400 second_indent = get_number_indent(curwin->w_cursor.lnum - 1); 401 } 402 if (second_indent >= 0) { 403 if (State & VREPLACE_FLAG) { 404 change_indent(INDENT_SET, second_indent, false, true); 405 } else if (leader_len > 0 && second_indent - leader_len > 0) { 406 int padding = second_indent - leader_len; 407 408 // We started at the first_line of a numbered list 409 // that has a comment. the open_line() function has 410 // inserted the proper comment leader and positioned 411 // the cursor at the end of the split line. Now we 412 // add the additional whitespace needed after the 413 // comment leader for the numbered list. 414 for (int i = 0; i < padding; i++) { 415 ins_str(S_LEN(" ")); 416 } 417 } else { 418 set_indent(second_indent, SIN_CHANGED); 419 } 420 } 421 } 422 first_line = false; 423 } 424 425 if (State & VREPLACE_FLAG) { 426 // In MODE_VREPLACE state we have backspaced over the text to be 427 // moved, now we re-insert it into the new line. 428 ins_bytes(saved_text); 429 xfree(saved_text); 430 } else { 431 // Check if cursor is not past the NUL off the line, cindent 432 // may have added or removed indent. 433 curwin->w_cursor.col += startcol; 434 colnr_T len = get_cursor_line_len(); 435 curwin->w_cursor.col = MIN(curwin->w_cursor.col, len); 436 } 437 438 haveto_redraw = true; 439 set_can_cindent(true); 440 // moved the cursor, don't autoindent or cindent now 441 did_ai = false; 442 did_si = false; 443 can_si = false; 444 can_si_back = false; 445 line_breakcheck(); 446 } 447 448 if (save_char != NUL) { // put back space after cursor 449 pchar_cursor(save_char); 450 } 451 452 curwin->w_p_lbr = has_lbr; 453 454 if (!format_only && haveto_redraw) { 455 update_topline(curwin); 456 redraw_curbuf_later(UPD_VALID); 457 } 458 } 459 460 /// Blank lines, and lines containing only the comment leader, are left 461 /// untouched by the formatting. The function returns true in this 462 /// case. It also returns true when a line starts with the end of a comment 463 /// ('e' in comment flags), so that this line is skipped, and not joined to the 464 /// previous line. A new paragraph starts after a blank line, or when the 465 /// comment leader changes. 466 static int fmt_check_par(linenr_T lnum, int *leader_len, char **leader_flags, bool do_comments) 467 { 468 char *flags = NULL; // init for GCC 469 char *ptr = ml_get(lnum); 470 if (do_comments) { 471 *leader_len = get_leader_len(ptr, leader_flags, false, true); 472 } else { 473 *leader_len = 0; 474 } 475 476 if (*leader_len > 0) { 477 // Search for 'e' flag in comment leader flags. 478 flags = *leader_flags; 479 while (*flags && *flags != ':' && *flags != COM_END) { 480 flags++; 481 } 482 } 483 484 return *skipwhite(ptr + *leader_len) == NUL 485 || (*leader_len > 0 && *flags == COM_END) 486 || startPS(lnum, NUL, false); 487 } 488 489 /// @return true if line "lnum" ends in a white character. 490 static bool ends_in_white(linenr_T lnum) 491 { 492 char *s = ml_get(lnum); 493 494 if (*s == NUL) { 495 return false; 496 } 497 colnr_T l = ml_get_len(lnum) - 1; 498 return ascii_iswhite((uint8_t)s[l]); 499 } 500 501 /// @return true if the two comment leaders given are the same. 502 /// 503 /// @param lnum The first line. White-space is ignored. 504 /// 505 /// @note the whole of 'leader1' must match 'leader2_len' characters from 'leader2'. 506 static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int leader2_len, 507 char *leader2_flags) 508 { 509 int idx1 = 0; 510 int idx2 = 0; 511 512 if (leader1_len == 0) { 513 return leader2_len == 0; 514 } 515 516 // If first leader has 'f' flag, the lines can be joined only if the 517 // second line does not have a leader. 518 // If first leader has 'e' flag, the lines can never be joined. 519 // If first leader has 's' flag, the lines can only be joined if there is 520 // some text after it and the second line has the 'm' flag. 521 if (leader1_flags != NULL) { 522 for (char *p = leader1_flags; *p && *p != ':'; p++) { 523 if (*p == COM_FIRST) { 524 return leader2_len == 0; 525 } 526 if (*p == COM_END) { 527 return false; 528 } 529 if (*p == COM_START) { 530 int line_len = ml_get_len(lnum); 531 if (line_len <= leader1_len) { 532 return false; 533 } 534 if (leader2_flags == NULL || leader2_len == 0) { 535 return false; 536 } 537 for (p = leader2_flags; *p && *p != ':'; p++) { 538 if (*p == COM_MIDDLE) { 539 return true; 540 } 541 } 542 return false; 543 } 544 } 545 } 546 547 // Get current line and next line, compare the leaders. 548 // The first line has to be saved, only one line can be locked at a time. 549 char *line1 = xstrnsave(ml_get(lnum), (size_t)ml_get_len(lnum)); 550 for (idx1 = 0; ascii_iswhite(line1[idx1]); idx1++) {} 551 char *line2 = ml_get(lnum + 1); 552 for (idx2 = 0; idx2 < leader2_len; idx2++) { 553 if (!ascii_iswhite(line2[idx2])) { 554 if (line1[idx1++] != line2[idx2]) { 555 break; 556 } 557 } else { 558 while (ascii_iswhite(line1[idx1])) { 559 idx1++; 560 } 561 } 562 } 563 xfree(line1); 564 565 return idx2 == leader2_len && idx1 == leader1_len; 566 } 567 568 /// Used for auto-formatting. 569 /// 570 /// @return true when a paragraph starts in line "lnum". 571 /// false when the previous line is in the same paragraph. 572 static bool paragraph_start(linenr_T lnum) 573 { 574 int leader_len = 0; // leader len of current line 575 char *leader_flags = NULL; // flags for leader of current line 576 int next_leader_len = 0; // leader len of next line 577 char *next_leader_flags = NULL; // flags for leader of next line 578 579 if (lnum <= 1) { 580 return true; // start of the file 581 } 582 char *p = ml_get(lnum - 1); 583 if (*p == NUL) { 584 return true; // after empty line 585 } 586 const bool do_comments = has_format_option(FO_Q_COMS); // format comments 587 if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) { 588 return true; // after non-paragraph line 589 } 590 591 if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) { 592 return true; // "lnum" is not a paragraph line 593 } 594 595 if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) { 596 return true; // missing trailing space in previous line. 597 } 598 if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) { 599 return true; // numbered item starts in "lnum". 600 } 601 if (!same_leader(lnum - 1, leader_len, leader_flags, 602 next_leader_len, next_leader_flags)) { 603 return true; // change of comment leader. 604 } 605 return false; 606 } 607 608 /// Called after inserting or deleting text: When 'formatoptions' includes the 609 /// 'a' flag format from the current line until the end of the paragraph. 610 /// Keep the cursor at the same position relative to the text. 611 /// The caller must have saved the cursor line for undo, following ones will be 612 /// saved here. 613 /// 614 /// @param trailblank when true also format with trailing blank 615 /// @param prev_line may start in previous line 616 void auto_format(bool trailblank, bool prev_line) 617 { 618 if (!has_format_option(FO_AUTO)) { 619 return; 620 } 621 622 pos_T pos = curwin->w_cursor; 623 char *old = get_cursor_line_ptr(); 624 625 // may remove added space 626 check_auto_format(false); 627 628 // Don't format in Insert mode when the cursor is on a trailing blank, the 629 // user might insert normal text next. Also skip formatting when "1" is 630 // in 'formatoptions' and there is a single character before the cursor. 631 // Otherwise the line would be broken and when typing another non-white 632 // next they are not joined back together. 633 bool wasatend = (pos.col == get_cursor_line_len()); 634 if (*old != NUL && !trailblank && wasatend) { 635 dec_cursor(); 636 int cc = gchar_cursor(); 637 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 638 && has_format_option(FO_ONE_LETTER)) { 639 dec_cursor(); 640 } 641 cc = gchar_cursor(); 642 if (WHITECHAR(cc)) { 643 curwin->w_cursor = pos; 644 return; 645 } 646 curwin->w_cursor = pos; 647 } 648 649 // With the 'c' flag in 'formatoptions' and 't' missing: only format 650 // comments. 651 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) 652 && get_leader_len(old, NULL, false, true) == 0) { 653 return; 654 } 655 656 // May start formatting in a previous line, so that after "x" a word is 657 // moved to the previous line if it fits there now. Only when this is not 658 // the start of a paragraph. 659 if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) { 660 curwin->w_cursor.lnum--; 661 if (u_save_cursor() == FAIL) { 662 return; 663 } 664 } 665 666 // Do the formatting and restore the cursor position. "saved_cursor" will 667 // be adjusted for the text formatting. 668 saved_cursor = pos; 669 format_lines(-1, false); 670 curwin->w_cursor = saved_cursor; 671 saved_cursor.lnum = 0; 672 673 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { 674 // "cannot happen" 675 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 676 coladvance(curwin, MAXCOL); 677 } else { 678 check_cursor_col(curwin); 679 } 680 681 // Insert mode: If the cursor is now after the end of the line while it 682 // previously wasn't, the line was broken. Because of the rule above we 683 // need to add a space when 'w' is in 'formatoptions' to keep a paragraph 684 // formatted. 685 if (!wasatend && has_format_option(FO_WHITE_PAR)) { 686 char *linep = get_cursor_line_ptr(); 687 colnr_T len = get_cursor_line_len(); 688 if (curwin->w_cursor.col == len) { 689 char *plinep = xstrnsave(linep, (size_t)len + 2); 690 plinep[len] = ' '; 691 plinep[len + 1] = NUL; 692 ml_replace(curwin->w_cursor.lnum, plinep, false); 693 // remove the space later 694 did_add_space = true; 695 } else { 696 // may remove added space 697 check_auto_format(false); 698 } 699 } 700 701 check_cursor(curwin); 702 } 703 704 /// When an extra space was added to continue a paragraph for auto-formatting, 705 /// delete it now. The space must be under the cursor, just after the insert 706 /// position. 707 /// 708 /// @param end_insert true when ending Insert mode 709 void check_auto_format(bool end_insert) 710 { 711 if (!did_add_space) { 712 return; 713 } 714 715 int cc = gchar_cursor(); 716 if (!WHITECHAR(cc)) { 717 // Somehow the space was removed already. 718 did_add_space = false; 719 } else { 720 int c = ' '; 721 if (!end_insert) { 722 inc_cursor(); 723 c = gchar_cursor(); 724 dec_cursor(); 725 } 726 if (c != NUL) { 727 // The space is no longer at the end of the line, delete it. 728 del_char(false); 729 did_add_space = false; 730 } 731 } 732 } 733 734 /// Find out textwidth to be used for formatting: 735 /// if 'textwidth' option is set, use it 736 /// else if 'wrapmargin' option is set, use curwin->w_view_width-'wrapmargin' 737 /// if invalid value, use 0. 738 /// Set default to window width (maximum 79) for "gq" operator. 739 /// 740 /// @param ff force formatting (for "gq" command) 741 int comp_textwidth(bool ff) 742 { 743 int textwidth = (int)curbuf->b_p_tw; 744 if (textwidth == 0 && curbuf->b_p_wm) { 745 // The width is the window width minus 'wrapmargin' minus all the 746 // things that add to the margin. 747 textwidth = curwin->w_view_width - (int)curbuf->b_p_wm; 748 if (curbuf == cmdwin_buf) { 749 textwidth -= 1; 750 } 751 textwidth -= win_fdccol_count(curwin); 752 textwidth -= curwin->w_scwidth; 753 754 if (curwin->w_p_nu || curwin->w_p_rnu) { 755 textwidth -= 8; 756 } 757 } 758 textwidth = MAX(textwidth, 0); 759 if (ff && textwidth == 0) { 760 textwidth = MIN(curwin->w_view_width - 1, 79); 761 } 762 return textwidth; 763 } 764 765 /// Implementation of the format operator 'gq'. 766 /// 767 /// @param keep_cursor keep cursor on same text char 768 void op_format(oparg_T *oap, bool keep_cursor) 769 { 770 linenr_T old_line_count = curbuf->b_ml.ml_line_count; 771 772 // Place the cursor where the "gq" or "gw" command was given, so that "u" 773 // can put it back there. 774 curwin->w_cursor = oap->cursor_start; 775 776 if (u_save((linenr_T)(oap->start.lnum - 1), 777 (linenr_T)(oap->end.lnum + 1)) == FAIL) { 778 return; 779 } 780 curwin->w_cursor = oap->start; 781 782 if (oap->is_VIsual) { 783 // When there is no change: need to remove the Visual selection 784 redraw_curbuf_later(UPD_INVERTED); 785 } 786 787 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 788 // Set '[ mark at the start of the formatted area 789 curbuf->b_op_start = oap->start; 790 } 791 792 // For "gw" remember the cursor position and put it back below (adjusted 793 // for joined and split lines). 794 if (keep_cursor) { 795 saved_cursor = oap->cursor_start; 796 } 797 798 format_lines(oap->line_count, keep_cursor); 799 800 // Leave the cursor at the first non-blank of the last formatted line. 801 // If the cursor was moved one line back (e.g. with "Q}") go to the next 802 // line, so "." will do the next lines. 803 if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { 804 curwin->w_cursor.lnum++; 805 } 806 beginline(BL_WHITE | BL_FIX); 807 old_line_count = curbuf->b_ml.ml_line_count - old_line_count; 808 msgmore(old_line_count); 809 810 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { 811 // put '] mark on the end of the formatted area 812 curbuf->b_op_end = curwin->w_cursor; 813 } 814 815 if (keep_cursor) { 816 curwin->w_cursor = saved_cursor; 817 saved_cursor.lnum = 0; 818 819 // formatting may have made the cursor position invalid 820 check_cursor(curwin); 821 } 822 823 if (oap->is_VIsual) { 824 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 825 if (wp->w_old_cursor_lnum != 0) { 826 // When lines have been inserted or deleted, adjust the end of 827 // the Visual area to be redrawn. 828 if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) { 829 wp->w_old_cursor_lnum += old_line_count; 830 } else { 831 wp->w_old_visual_lnum += old_line_count; 832 } 833 } 834 } 835 } 836 } 837 838 /// Implementation of the format operator 'gq' for when using 'formatexpr'. 839 void op_formatexpr(oparg_T *oap) 840 { 841 if (oap->is_VIsual) { 842 // When there is no change: need to remove the Visual selection 843 redraw_curbuf_later(UPD_INVERTED); 844 } 845 846 if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) { 847 // As documented: when 'formatexpr' returns non-zero fall back to 848 // internal formatting. 849 op_format(oap, false); 850 } 851 } 852 853 /// @param c character to be inserted 854 int fex_format(linenr_T lnum, long count, int c) 855 { 856 bool use_sandbox = was_set_insecurely(curwin, kOptFormatexpr, OPT_LOCAL); 857 const sctx_T save_sctx = current_sctx; 858 859 // Set v:lnum to the first line number and v:count to the number of lines. 860 // Set v:char to the character to be inserted (can be NUL). 861 set_vim_var_nr(VV_LNUM, (varnumber_T)lnum); 862 set_vim_var_nr(VV_COUNT, (varnumber_T)count); 863 set_vim_var_char(c); 864 865 // Make a copy, the option could be changed while calling it. 866 char *fex = xstrdup(curbuf->b_p_fex); 867 current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr]; 868 869 // Evaluate the function. 870 if (use_sandbox) { 871 sandbox++; 872 } 873 int r = (int)eval_to_number(fex, true); 874 if (use_sandbox) { 875 sandbox--; 876 } 877 878 set_vim_var_string(VV_CHAR, NULL, -1); 879 xfree(fex); 880 current_sctx = save_sctx; 881 882 return r; 883 } 884 885 /// @param line_count number of lines to format, starting at the cursor position. 886 /// when negative, format until the end of the paragraph. 887 /// 888 /// Lines after the cursor line are saved for undo, caller must have saved the 889 /// first line. 890 /// 891 /// @param avoid_fex don't use 'formatexpr' 892 void format_lines(linenr_T line_count, bool avoid_fex) 893 { 894 bool is_not_par; // current line not part of parag. 895 bool next_is_not_par; // next line not part of paragraph 896 bool is_end_par; // at end of paragraph 897 bool prev_is_end_par = false; // prev. line not part of parag. 898 bool next_is_start_par = false; 899 int leader_len = 0; // leader len of current line 900 int next_leader_len; // leader len of next line 901 char *leader_flags = NULL; // flags for leader of current line 902 char *next_leader_flags = NULL; // flags for leader of next line 903 bool advance = true; 904 int second_indent = -1; // indent for second line (comment aware) 905 bool first_par_line = true; 906 int smd_save; 907 long count; 908 bool need_set_indent = true; // set indent of next paragraph 909 linenr_T first_line = curwin->w_cursor.lnum; 910 bool force_format = false; 911 const int old_State = State; 912 913 // length of a line to force formatting: 3 * 'tw' 914 const int max_len = comp_textwidth(true) * 3; 915 916 // check for 'q', '2', 'n' and 'w' in 'formatoptions' 917 const bool do_comments = has_format_option(FO_Q_COMS); // format comments 918 int do_comments_list = 0; // format comments with 'n' or '2' 919 const bool do_second_indent = has_format_option(FO_Q_SECOND); 920 const bool do_number_indent = has_format_option(FO_Q_NUMBER); 921 const bool do_trail_white = has_format_option(FO_WHITE_PAR); 922 923 // Get info about the previous and current line. 924 if (curwin->w_cursor.lnum > 1) { 925 is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1, 926 &leader_len, &leader_flags, do_comments); 927 } else { 928 is_not_par = true; 929 } 930 next_is_not_par = fmt_check_par(curwin->w_cursor.lnum, 931 &next_leader_len, &next_leader_flags, do_comments); 932 is_end_par = (is_not_par || next_is_not_par); 933 if (!is_end_par && do_trail_white) { 934 is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); 935 } 936 937 curwin->w_cursor.lnum--; 938 for (count = line_count; count != 0 && !got_int; count--) { 939 // Advance to next paragraph. 940 if (advance) { 941 curwin->w_cursor.lnum++; 942 prev_is_end_par = is_end_par; 943 is_not_par = next_is_not_par; 944 leader_len = next_leader_len; 945 leader_flags = next_leader_flags; 946 } 947 948 // The last line to be formatted. 949 if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) { 950 next_is_not_par = true; 951 next_leader_len = 0; 952 next_leader_flags = NULL; 953 } else { 954 next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1, 955 &next_leader_len, &next_leader_flags, do_comments); 956 if (do_number_indent) { 957 next_is_start_par = 958 (get_number_indent(curwin->w_cursor.lnum + 1) > 0); 959 } 960 } 961 advance = true; 962 is_end_par = (is_not_par || next_is_not_par || next_is_start_par); 963 if (!is_end_par && do_trail_white) { 964 is_end_par = !ends_in_white(curwin->w_cursor.lnum); 965 } 966 967 // Skip lines that are not in a paragraph. 968 if (is_not_par) { 969 if (line_count < 0) { 970 break; 971 } 972 } else { 973 // For the first line of a paragraph, check indent of second line. 974 // Don't do this for comments and empty lines. 975 if (first_par_line 976 && (do_second_indent || do_number_indent) 977 && prev_is_end_par 978 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { 979 if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) { 980 if (leader_len == 0 && next_leader_len == 0) { 981 // no comment found 982 second_indent = 983 get_indent_lnum(curwin->w_cursor.lnum + 1); 984 } else { 985 second_indent = next_leader_len; 986 do_comments_list = 1; 987 } 988 } else if (do_number_indent) { 989 if (leader_len == 0 && next_leader_len == 0) { 990 // no comment found 991 second_indent = 992 get_number_indent(curwin->w_cursor.lnum); 993 } else { 994 // get_number_indent() is now "comment aware"... 995 second_indent = 996 get_number_indent(curwin->w_cursor.lnum); 997 do_comments_list = 1; 998 } 999 } 1000 } 1001 1002 // When the comment leader changes, it's the end of the paragraph. 1003 if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count 1004 || !same_leader(curwin->w_cursor.lnum, 1005 leader_len, leader_flags, 1006 next_leader_len, 1007 next_leader_flags)) { 1008 // Special case: If the next line starts with a line comment 1009 // and this line has a line comment after some text, the 1010 // paragraph doesn't really end. 1011 if (next_leader_flags == NULL 1012 || strncmp(next_leader_flags, "://", 3) != 0 1013 || check_linecomment(get_cursor_line_ptr()) == MAXCOL) { 1014 is_end_par = true; 1015 } 1016 } 1017 1018 // If we have got to the end of a paragraph, or the line is 1019 // getting long, format it. 1020 if (is_end_par || force_format) { 1021 if (need_set_indent) { 1022 int indent = 0; // amount of indent needed 1023 1024 // Replace indent in first line of a paragraph with minimal 1025 // number of tabs and spaces, according to current options. 1026 // For the very first formatted line keep the current 1027 // indent. 1028 if (curwin->w_cursor.lnum == first_line) { 1029 indent = get_indent(); 1030 } else if (curbuf->b_p_lisp) { 1031 indent = get_lisp_indent(); 1032 } else { 1033 if (cindent_on()) { 1034 indent = *curbuf->b_p_inde != NUL ? get_expr_indent() : get_c_indent(); 1035 } else { 1036 indent = get_indent(); 1037 } 1038 } 1039 set_indent(indent, SIN_CHANGED); 1040 } 1041 1042 // put cursor on last non-space 1043 State = MODE_NORMAL; // don't go past end-of-line 1044 coladvance(curwin, MAXCOL); 1045 while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) { 1046 dec_cursor(); 1047 } 1048 1049 // do the formatting, without 'showmode' 1050 State = MODE_INSERT; // for open_line() 1051 smd_save = p_smd; 1052 p_smd = false; 1053 1054 insertchar(NUL, INSCHAR_FORMAT 1055 + (do_comments ? INSCHAR_DO_COM : 0) 1056 + (do_comments && do_comments_list ? INSCHAR_COM_LIST : 0) 1057 + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); 1058 1059 State = old_State; 1060 p_smd = smd_save; 1061 // Cursor shape may have been updated (e.g. by :normal) in insertchar(), 1062 // so it needs to be updated here. 1063 ui_cursor_shape(); 1064 1065 second_indent = -1; 1066 // at end of par.: need to set indent of next par. 1067 need_set_indent = is_end_par; 1068 if (is_end_par) { 1069 // When called with a negative line count, break at the 1070 // end of the paragraph. 1071 if (line_count < 0) { 1072 break; 1073 } 1074 first_par_line = true; 1075 } 1076 force_format = false; 1077 } 1078 1079 // When still in same paragraph, join the lines together. But 1080 // first delete the leader from the second line. 1081 if (!is_end_par) { 1082 advance = false; 1083 curwin->w_cursor.lnum++; 1084 curwin->w_cursor.col = 0; 1085 if (line_count < 0 && u_save_cursor() == FAIL) { 1086 break; 1087 } 1088 if (next_leader_len > 0) { 1089 del_bytes(next_leader_len, false, false); 1090 mark_col_adjust(curwin->w_cursor.lnum, 0, 0, -next_leader_len, 0); 1091 } else if (second_indent > 0) { // the "leader" for FO_Q_SECOND 1092 int indent = (int)getwhitecols_curline(); 1093 1094 if (indent > 0) { 1095 del_bytes(indent, false, false); 1096 mark_col_adjust(curwin->w_cursor.lnum, 0, 0, -indent, 0); 1097 } 1098 } 1099 curwin->w_cursor.lnum--; 1100 if (do_join(2, true, false, false, false) == FAIL) { 1101 beep_flush(); 1102 break; 1103 } 1104 first_par_line = false; 1105 // If the line is getting long, format it next time 1106 force_format = get_cursor_line_len() > max_len; 1107 } 1108 } 1109 line_breakcheck(); 1110 } 1111 }