xref: /vim-8.2.3635/src/textformat.c (revision 2d2970ea)
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 }
1089