comparison src/textformat.c @ 20237:918245588b50 v8.2.0674

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