xref: /vim-8.2.3635/src/textformat.c (revision 818ff25c)
111abd095SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
211abd095SBram Moolenaar  *
311abd095SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
411abd095SBram Moolenaar  *
511abd095SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
611abd095SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
711abd095SBram Moolenaar  * See README.txt for an overview of the Vim source code.
811abd095SBram Moolenaar  */
911abd095SBram Moolenaar 
1011abd095SBram Moolenaar /*
1111abd095SBram Moolenaar  * textformat.c: text formatting functions
1211abd095SBram Moolenaar  */
1311abd095SBram Moolenaar 
1411abd095SBram Moolenaar #include "vim.h"
1511abd095SBram Moolenaar 
1611abd095SBram Moolenaar static int	did_add_space = FALSE;	// auto_format() added an extra space
1711abd095SBram Moolenaar 					// under the cursor
1811abd095SBram Moolenaar 
1911abd095SBram Moolenaar #define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
2011abd095SBram Moolenaar 
2111abd095SBram Moolenaar /*
2211abd095SBram Moolenaar  * Return TRUE if format option 'x' is in effect.
2311abd095SBram Moolenaar  * Take care of no formatting when 'paste' is set.
2411abd095SBram Moolenaar  */
2511abd095SBram Moolenaar     int
has_format_option(int x)2611abd095SBram Moolenaar has_format_option(int x)
2711abd095SBram Moolenaar {
2811abd095SBram Moolenaar     if (p_paste)
2911abd095SBram Moolenaar 	return FALSE;
3011abd095SBram Moolenaar     return (vim_strchr(curbuf->b_p_fo, x) != NULL);
3111abd095SBram Moolenaar }
3211abd095SBram Moolenaar 
3311abd095SBram Moolenaar /*
3411abd095SBram Moolenaar  * Format text at the current insert position.
3511abd095SBram Moolenaar  *
3611abd095SBram Moolenaar  * If the INSCHAR_COM_LIST flag is present, then the value of second_indent
3711abd095SBram Moolenaar  * will be the comment leader length sent to open_line().
3811abd095SBram Moolenaar  */
3911abd095SBram Moolenaar     void
internal_format(int textwidth,int second_indent,int flags,int format_only,int c)4011abd095SBram Moolenaar internal_format(
4111abd095SBram Moolenaar     int		textwidth,
4211abd095SBram Moolenaar     int		second_indent,
4311abd095SBram Moolenaar     int		flags,
4411abd095SBram Moolenaar     int		format_only,
4511abd095SBram Moolenaar     int		c) // character to be inserted (can be NUL)
4611abd095SBram Moolenaar {
4711abd095SBram Moolenaar     int		cc;
48e52702f0SBram Moolenaar     int		skip_pos;
4911abd095SBram Moolenaar     int		save_char = NUL;
5011abd095SBram Moolenaar     int		haveto_redraw = FALSE;
5111abd095SBram Moolenaar     int		fo_ins_blank = has_format_option(FO_INS_BLANK);
5211abd095SBram Moolenaar     int		fo_multibyte = has_format_option(FO_MBYTE_BREAK);
53e52702f0SBram Moolenaar     int		fo_rigor_tw  = has_format_option(FO_RIGOROUS_TW);
5411abd095SBram Moolenaar     int		fo_white_par = has_format_option(FO_WHITE_PAR);
5511abd095SBram Moolenaar     int		first_line = TRUE;
5611abd095SBram Moolenaar     colnr_T	leader_len;
5711abd095SBram Moolenaar     int		no_leader = FALSE;
5811abd095SBram Moolenaar     int		do_comments = (flags & INSCHAR_DO_COM);
5911abd095SBram Moolenaar #ifdef FEAT_LINEBREAK
6011abd095SBram Moolenaar     int		has_lbr = curwin->w_p_lbr;
6111abd095SBram Moolenaar 
6211abd095SBram Moolenaar     // make sure win_lbr_chartabsize() counts correctly
6311abd095SBram Moolenaar     curwin->w_p_lbr = FALSE;
6411abd095SBram Moolenaar #endif
6511abd095SBram Moolenaar 
6611abd095SBram Moolenaar     // When 'ai' is off we don't want a space under the cursor to be
6711abd095SBram Moolenaar     // deleted.  Replace it with an 'x' temporarily.
6811abd095SBram Moolenaar     if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG))
6911abd095SBram Moolenaar     {
7011abd095SBram Moolenaar 	cc = gchar_cursor();
7111abd095SBram Moolenaar 	if (VIM_ISWHITE(cc))
7211abd095SBram Moolenaar 	{
7311abd095SBram Moolenaar 	    save_char = cc;
7411abd095SBram Moolenaar 	    pchar_cursor('x');
7511abd095SBram Moolenaar 	}
7611abd095SBram Moolenaar     }
7711abd095SBram Moolenaar 
7811abd095SBram Moolenaar     // Repeat breaking lines, until the current line is not too long.
7911abd095SBram Moolenaar     while (!got_int)
8011abd095SBram Moolenaar     {
8111abd095SBram Moolenaar 	int	startcol;		// Cursor column at entry
8211abd095SBram Moolenaar 	int	wantcol;		// column at textwidth border
8311abd095SBram Moolenaar 	int	foundcol;		// column for start of spaces
8411abd095SBram Moolenaar 	int	end_foundcol = 0;	// column for start of word
8511abd095SBram Moolenaar 	colnr_T	len;
8611abd095SBram Moolenaar 	colnr_T	virtcol;
8711abd095SBram Moolenaar 	int	orig_col = 0;
8811abd095SBram Moolenaar 	char_u	*saved_text = NULL;
8911abd095SBram Moolenaar 	colnr_T	col;
9011abd095SBram Moolenaar 	colnr_T	end_col;
9111abd095SBram Moolenaar 	int	wcc;			// counter for whitespace chars
9211abd095SBram Moolenaar 
9311abd095SBram Moolenaar 	virtcol = get_nolist_virtcol()
9411abd095SBram Moolenaar 		+ char2cells(c != NUL ? c : gchar_cursor());
9511abd095SBram Moolenaar 	if (virtcol <= (colnr_T)textwidth)
9611abd095SBram Moolenaar 	    break;
9711abd095SBram Moolenaar 
9811abd095SBram Moolenaar 	if (no_leader)
9911abd095SBram Moolenaar 	    do_comments = FALSE;
10011abd095SBram Moolenaar 	else if (!(flags & INSCHAR_FORMAT)
10111abd095SBram Moolenaar 				       && has_format_option(FO_WRAP_COMS))
10211abd095SBram Moolenaar 	    do_comments = TRUE;
10311abd095SBram Moolenaar 
10411abd095SBram Moolenaar 	// Don't break until after the comment leader
10511abd095SBram Moolenaar 	if (do_comments)
10611abd095SBram Moolenaar 	    leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE);
10711abd095SBram Moolenaar 	else
10811abd095SBram Moolenaar 	    leader_len = 0;
10911abd095SBram Moolenaar 
11011abd095SBram Moolenaar 	// If the line doesn't start with a comment leader, then don't
11111abd095SBram Moolenaar 	// start one in a following broken line.  Avoids that a %word
11211abd095SBram Moolenaar 	// moved to the start of the next line causes all following lines
11311abd095SBram Moolenaar 	// to start with %.
11411abd095SBram Moolenaar 	if (leader_len == 0)
11511abd095SBram Moolenaar 	    no_leader = TRUE;
11611abd095SBram Moolenaar 	if (!(flags & INSCHAR_FORMAT)
11711abd095SBram Moolenaar 		&& leader_len == 0
11811abd095SBram Moolenaar 		&& !has_format_option(FO_WRAP))
11911abd095SBram Moolenaar 
12011abd095SBram Moolenaar 	    break;
12111abd095SBram Moolenaar 	if ((startcol = curwin->w_cursor.col) == 0)
12211abd095SBram Moolenaar 	    break;
12311abd095SBram Moolenaar 
12411abd095SBram Moolenaar 	// find column of textwidth border
12511abd095SBram Moolenaar 	coladvance((colnr_T)textwidth);
12611abd095SBram Moolenaar 	wantcol = curwin->w_cursor.col;
12711abd095SBram Moolenaar 
12811abd095SBram Moolenaar 	curwin->w_cursor.col = startcol;
12911abd095SBram Moolenaar 	foundcol = 0;
130e52702f0SBram Moolenaar 	skip_pos = 0;
13111abd095SBram Moolenaar 
13211abd095SBram Moolenaar 	// Find position to break at.
13311abd095SBram Moolenaar 	// Stop at first entered white when 'formatoptions' has 'v'
13411abd095SBram Moolenaar 	while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
13511abd095SBram Moolenaar 		    || (flags & INSCHAR_FORMAT)
13611abd095SBram Moolenaar 		    || curwin->w_cursor.lnum != Insstart.lnum
13711abd095SBram Moolenaar 		    || curwin->w_cursor.col >= Insstart.col)
13811abd095SBram Moolenaar 	{
13911abd095SBram Moolenaar 	    if (curwin->w_cursor.col == startcol && c != NUL)
14011abd095SBram Moolenaar 		cc = c;
14111abd095SBram Moolenaar 	    else
14211abd095SBram Moolenaar 		cc = gchar_cursor();
14311abd095SBram Moolenaar 	    if (WHITECHAR(cc))
14411abd095SBram Moolenaar 	    {
14511abd095SBram Moolenaar 		// remember position of blank just before text
14611abd095SBram Moolenaar 		end_col = curwin->w_cursor.col;
14711abd095SBram Moolenaar 
14811abd095SBram Moolenaar 		// find start of sequence of blanks
14911abd095SBram Moolenaar 		wcc = 0;
15011abd095SBram Moolenaar 		while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
15111abd095SBram Moolenaar 		{
15211abd095SBram Moolenaar 		    dec_cursor();
15311abd095SBram Moolenaar 		    cc = gchar_cursor();
15411abd095SBram Moolenaar 
15511abd095SBram Moolenaar 		    // Increment count of how many whitespace chars in this
15611abd095SBram Moolenaar 		    // group; we only need to know if it's more than one.
15711abd095SBram Moolenaar 		    if (wcc < 2)
15811abd095SBram Moolenaar 		        wcc++;
15911abd095SBram Moolenaar 		}
16011abd095SBram Moolenaar 		if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
16111abd095SBram Moolenaar 		    break;		// only spaces in front of text
16211abd095SBram Moolenaar 
16311abd095SBram Moolenaar 		// Don't break after a period when 'formatoptions' has 'p' and
16411abd095SBram Moolenaar 		// there are less than two spaces.
16511abd095SBram Moolenaar 		if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2)
16611abd095SBram Moolenaar 		    continue;
16711abd095SBram Moolenaar 
16811abd095SBram Moolenaar 		// Don't break until after the comment leader
16911abd095SBram Moolenaar 		if (curwin->w_cursor.col < leader_len)
17011abd095SBram Moolenaar 		    break;
17111abd095SBram Moolenaar 		if (has_format_option(FO_ONE_LETTER))
17211abd095SBram Moolenaar 		{
17311abd095SBram Moolenaar 		    // do not break after one-letter words
17411abd095SBram Moolenaar 		    if (curwin->w_cursor.col == 0)
17511abd095SBram Moolenaar 			break;	// one-letter word at begin
17611abd095SBram Moolenaar 		    // do not break "#a b" when 'tw' is 2
17711abd095SBram Moolenaar 		    if (curwin->w_cursor.col <= leader_len)
17811abd095SBram Moolenaar 			break;
17911abd095SBram Moolenaar 		    col = curwin->w_cursor.col;
18011abd095SBram Moolenaar 		    dec_cursor();
18111abd095SBram Moolenaar 		    cc = gchar_cursor();
18211abd095SBram Moolenaar 
18311abd095SBram Moolenaar 		    if (WHITECHAR(cc))
18411abd095SBram Moolenaar 			continue;	// one-letter, continue
18511abd095SBram Moolenaar 		    curwin->w_cursor.col = col;
18611abd095SBram Moolenaar 		}
18711abd095SBram Moolenaar 
18811abd095SBram Moolenaar 		inc_cursor();
18911abd095SBram Moolenaar 
19011abd095SBram Moolenaar 		end_foundcol = end_col + 1;
19111abd095SBram Moolenaar 		foundcol = curwin->w_cursor.col;
19211abd095SBram Moolenaar 		if (curwin->w_cursor.col <= (colnr_T)wantcol)
19311abd095SBram Moolenaar 		    break;
19411abd095SBram Moolenaar 	    }
195e52702f0SBram Moolenaar 	    else if ((cc >= 0x100 || !utf_allow_break_before(cc)) && fo_multibyte)
19611abd095SBram Moolenaar 	    {
197e52702f0SBram Moolenaar 		int ncc;
198e52702f0SBram Moolenaar 		int allow_break;
199e52702f0SBram Moolenaar 
20011abd095SBram Moolenaar 		// Break after or before a multi-byte character.
20111abd095SBram Moolenaar 		if (curwin->w_cursor.col != startcol)
20211abd095SBram Moolenaar 		{
20311abd095SBram Moolenaar 		    // Don't break until after the comment leader
20411abd095SBram Moolenaar 		    if (curwin->w_cursor.col < leader_len)
20511abd095SBram Moolenaar 			break;
20611abd095SBram Moolenaar 		    col = curwin->w_cursor.col;
20711abd095SBram Moolenaar 		    inc_cursor();
208e52702f0SBram Moolenaar 		    ncc = gchar_cursor();
209e52702f0SBram Moolenaar 
210e52702f0SBram Moolenaar 		    allow_break =
211e52702f0SBram Moolenaar 			(enc_utf8 && utf_allow_break(cc, ncc))
212e52702f0SBram Moolenaar 			|| enc_dbcs;
213e52702f0SBram Moolenaar 
214e52702f0SBram Moolenaar 		    // If we have already checked this position, skip!
215e52702f0SBram Moolenaar 		    if (curwin->w_cursor.col != skip_pos && allow_break)
21611abd095SBram Moolenaar 		    {
21711abd095SBram Moolenaar 			foundcol = curwin->w_cursor.col;
21811abd095SBram Moolenaar 			end_foundcol = foundcol;
21911abd095SBram Moolenaar 			if (curwin->w_cursor.col <= (colnr_T)wantcol)
22011abd095SBram Moolenaar 			    break;
22111abd095SBram Moolenaar 		    }
22211abd095SBram Moolenaar 		    curwin->w_cursor.col = col;
22311abd095SBram Moolenaar 		}
22411abd095SBram Moolenaar 
22511abd095SBram Moolenaar 		if (curwin->w_cursor.col == 0)
22611abd095SBram Moolenaar 		    break;
22711abd095SBram Moolenaar 
228e52702f0SBram Moolenaar 		ncc = cc;
22911abd095SBram Moolenaar 		col = curwin->w_cursor.col;
23011abd095SBram Moolenaar 
23111abd095SBram Moolenaar 		dec_cursor();
23211abd095SBram Moolenaar 		cc = gchar_cursor();
23311abd095SBram Moolenaar 
23411abd095SBram Moolenaar 		if (WHITECHAR(cc))
23511abd095SBram Moolenaar 		    continue;		// break with space
236e52702f0SBram Moolenaar 		// Don't break until after the comment leader.
23711abd095SBram Moolenaar 		if (curwin->w_cursor.col < leader_len)
23811abd095SBram Moolenaar 		    break;
23911abd095SBram Moolenaar 
24011abd095SBram Moolenaar 		curwin->w_cursor.col = col;
241e52702f0SBram Moolenaar 		skip_pos = curwin->w_cursor.col;
24211abd095SBram Moolenaar 
243e52702f0SBram Moolenaar 		allow_break =
244e52702f0SBram Moolenaar 		    (enc_utf8 && utf_allow_break(cc, ncc))
245e52702f0SBram Moolenaar 		    || enc_dbcs;
246e52702f0SBram Moolenaar 
247e52702f0SBram Moolenaar 		// Must handle this to respect line break prohibition.
248e52702f0SBram Moolenaar 		if (allow_break)
249e52702f0SBram Moolenaar 		{
25011abd095SBram Moolenaar 		    foundcol = curwin->w_cursor.col;
25111abd095SBram Moolenaar 		    end_foundcol = foundcol;
252e52702f0SBram Moolenaar 		}
25311abd095SBram Moolenaar 		if (curwin->w_cursor.col <= (colnr_T)wantcol)
254e52702f0SBram Moolenaar 		{
255e52702f0SBram Moolenaar 		    int ncc_allow_break =
256e52702f0SBram Moolenaar 			 (enc_utf8 && utf_allow_break_before(ncc)) || enc_dbcs;
257e52702f0SBram Moolenaar 
258e52702f0SBram Moolenaar 		    if (allow_break)
25911abd095SBram Moolenaar 			break;
260e52702f0SBram Moolenaar 		    if (!ncc_allow_break && !fo_rigor_tw)
261e52702f0SBram Moolenaar 		    {
262e52702f0SBram Moolenaar 			// Enable at most 1 punct hang outside of textwidth.
263e52702f0SBram Moolenaar 			if (curwin->w_cursor.col == startcol)
264e52702f0SBram Moolenaar 			{
265e52702f0SBram Moolenaar 			    // We are inserting a non-breakable char, postpone
266e52702f0SBram Moolenaar 			    // line break check to next insert.
267e52702f0SBram Moolenaar 			    end_foundcol = foundcol = 0;
268e52702f0SBram Moolenaar 			    break;
269e52702f0SBram Moolenaar 			}
270e52702f0SBram Moolenaar 
271e52702f0SBram Moolenaar 			// Neither cc nor ncc is NUL if we are here, so
272e52702f0SBram Moolenaar 			// it's safe to inc_cursor.
273e52702f0SBram Moolenaar 			col = curwin->w_cursor.col;
274e52702f0SBram Moolenaar 
275e52702f0SBram Moolenaar 			inc_cursor();
276e52702f0SBram Moolenaar 			cc  = ncc;
277e52702f0SBram Moolenaar 			ncc = gchar_cursor();
278e52702f0SBram Moolenaar 			// handle insert
279e52702f0SBram Moolenaar 			ncc = (ncc != NUL) ? ncc : c;
280e52702f0SBram Moolenaar 
281e52702f0SBram Moolenaar 			allow_break =
282e52702f0SBram Moolenaar 				(enc_utf8 && utf_allow_break(cc, ncc))
283e52702f0SBram Moolenaar 				|| enc_dbcs;
284e52702f0SBram Moolenaar 
285e52702f0SBram Moolenaar 			if (allow_break)
286e52702f0SBram Moolenaar 			{
287e52702f0SBram Moolenaar 			    // Break only when we are not at end of line.
288e52702f0SBram Moolenaar 			    end_foundcol = foundcol =
289e52702f0SBram Moolenaar 				      ncc == NUL? 0 : curwin->w_cursor.col;
290e52702f0SBram Moolenaar 			    break;
291e52702f0SBram Moolenaar 			}
292e52702f0SBram Moolenaar 			curwin->w_cursor.col = col;
293e52702f0SBram Moolenaar 		    }
294e52702f0SBram Moolenaar 		}
29511abd095SBram Moolenaar 	    }
29611abd095SBram Moolenaar 	    if (curwin->w_cursor.col == 0)
29711abd095SBram Moolenaar 		break;
29811abd095SBram Moolenaar 	    dec_cursor();
29911abd095SBram Moolenaar 	}
30011abd095SBram Moolenaar 
30111abd095SBram Moolenaar 	if (foundcol == 0)		// no spaces, cannot break line
30211abd095SBram Moolenaar 	{
30311abd095SBram Moolenaar 	    curwin->w_cursor.col = startcol;
30411abd095SBram Moolenaar 	    break;
30511abd095SBram Moolenaar 	}
30611abd095SBram Moolenaar 
30711abd095SBram Moolenaar 	// Going to break the line, remove any "$" now.
30811abd095SBram Moolenaar 	undisplay_dollar();
30911abd095SBram Moolenaar 
31011abd095SBram Moolenaar 	// Offset between cursor position and line break is used by replace
31111abd095SBram Moolenaar 	// stack functions.  VREPLACE does not use this, and backspaces
31211abd095SBram Moolenaar 	// over the text instead.
31311abd095SBram Moolenaar 	if (State & VREPLACE_FLAG)
31411abd095SBram Moolenaar 	    orig_col = startcol;	// Will start backspacing from here
31511abd095SBram Moolenaar 	else
31611abd095SBram Moolenaar 	    replace_offset = startcol - end_foundcol;
31711abd095SBram Moolenaar 
31811abd095SBram Moolenaar 	// adjust startcol for spaces that will be deleted and
31911abd095SBram Moolenaar 	// characters that will remain on top line
32011abd095SBram Moolenaar 	curwin->w_cursor.col = foundcol;
32111abd095SBram Moolenaar 	while ((cc = gchar_cursor(), WHITECHAR(cc))
32211abd095SBram Moolenaar 		    && (!fo_white_par || curwin->w_cursor.col < startcol))
32311abd095SBram Moolenaar 	    inc_cursor();
32411abd095SBram Moolenaar 	startcol -= curwin->w_cursor.col;
32511abd095SBram Moolenaar 	if (startcol < 0)
32611abd095SBram Moolenaar 	    startcol = 0;
32711abd095SBram Moolenaar 
32811abd095SBram Moolenaar 	if (State & VREPLACE_FLAG)
32911abd095SBram Moolenaar 	{
33011abd095SBram Moolenaar 	    // In VREPLACE mode, we will backspace over the text to be
33111abd095SBram Moolenaar 	    // wrapped, so save a copy now to put on the next line.
33211abd095SBram Moolenaar 	    saved_text = vim_strsave(ml_get_cursor());
33311abd095SBram Moolenaar 	    curwin->w_cursor.col = orig_col;
33411abd095SBram Moolenaar 	    if (saved_text == NULL)
33511abd095SBram Moolenaar 		break;	// Can't do it, out of memory
33611abd095SBram Moolenaar 	    saved_text[startcol] = NUL;
33711abd095SBram Moolenaar 
33811abd095SBram Moolenaar 	    // Backspace over characters that will move to the next line
33911abd095SBram Moolenaar 	    if (!fo_white_par)
34011abd095SBram Moolenaar 		backspace_until_column(foundcol);
34111abd095SBram Moolenaar 	}
34211abd095SBram Moolenaar 	else
34311abd095SBram Moolenaar 	{
34411abd095SBram Moolenaar 	    // put cursor after pos. to break line
34511abd095SBram Moolenaar 	    if (!fo_white_par)
34611abd095SBram Moolenaar 		curwin->w_cursor.col = foundcol;
34711abd095SBram Moolenaar 	}
34811abd095SBram Moolenaar 
34911abd095SBram Moolenaar 	// Split the line just before the margin.
35011abd095SBram Moolenaar 	// Only insert/delete lines, but don't really redraw the window.
35111abd095SBram Moolenaar 	open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
35211abd095SBram Moolenaar 		+ (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
35311abd095SBram Moolenaar 		+ (do_comments ? OPENLINE_DO_COM : 0)
35411abd095SBram Moolenaar 		+ ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
35511abd095SBram Moolenaar 		, ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
35611abd095SBram Moolenaar 	if (!(flags & INSCHAR_COM_LIST))
35711abd095SBram Moolenaar 	    old_indent = 0;
35811abd095SBram Moolenaar 
35911abd095SBram Moolenaar 	replace_offset = 0;
36011abd095SBram Moolenaar 	if (first_line)
36111abd095SBram Moolenaar 	{
36211abd095SBram Moolenaar 	    if (!(flags & INSCHAR_COM_LIST))
36311abd095SBram Moolenaar 	    {
36411abd095SBram Moolenaar 		// This section is for auto-wrap of numeric lists.  When not
36511abd095SBram Moolenaar 		// in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST
36611abd095SBram Moolenaar 		// flag will be set and open_line() will handle it (as seen
36711abd095SBram Moolenaar 		// above).  The code here (and in get_number_indent()) will
36811abd095SBram Moolenaar 		// recognize comments if needed...
36911abd095SBram Moolenaar 		if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
37011abd095SBram Moolenaar 		    second_indent =
37111abd095SBram Moolenaar 				 get_number_indent(curwin->w_cursor.lnum - 1);
37211abd095SBram Moolenaar 		if (second_indent >= 0)
37311abd095SBram Moolenaar 		{
37411abd095SBram Moolenaar 		    if (State & VREPLACE_FLAG)
37511abd095SBram Moolenaar 			change_indent(INDENT_SET, second_indent,
37611abd095SBram Moolenaar 							    FALSE, NUL, TRUE);
37711abd095SBram Moolenaar 		    else
37811abd095SBram Moolenaar 			if (leader_len > 0 && second_indent - leader_len > 0)
37911abd095SBram Moolenaar 		    {
38011abd095SBram Moolenaar 			int i;
38111abd095SBram Moolenaar 			int padding = second_indent - leader_len;
38211abd095SBram Moolenaar 
38311abd095SBram Moolenaar 			// We started at the first_line of a numbered list
38411abd095SBram Moolenaar 			// that has a comment.  the open_line() function has
38511abd095SBram Moolenaar 			// inserted the proper comment leader and positioned
38611abd095SBram Moolenaar 			// the cursor at the end of the split line.  Now we
38711abd095SBram Moolenaar 			// add the additional whitespace needed after the
38811abd095SBram Moolenaar 			// comment leader for the numbered list.
38911abd095SBram Moolenaar 			for (i = 0; i < padding; i++)
39011abd095SBram Moolenaar 			    ins_str((char_u *)" ");
39111abd095SBram Moolenaar 		    }
39211abd095SBram Moolenaar 		    else
39311abd095SBram Moolenaar 		    {
39411abd095SBram Moolenaar 			(void)set_indent(second_indent, SIN_CHANGED);
39511abd095SBram Moolenaar 		    }
39611abd095SBram Moolenaar 		}
39711abd095SBram Moolenaar 	    }
39811abd095SBram Moolenaar 	    first_line = FALSE;
39911abd095SBram Moolenaar 	}
40011abd095SBram Moolenaar 
40111abd095SBram Moolenaar 	if (State & VREPLACE_FLAG)
40211abd095SBram Moolenaar 	{
40311abd095SBram Moolenaar 	    // In VREPLACE mode we have backspaced over the text to be
40411abd095SBram Moolenaar 	    // moved, now we re-insert it into the new line.
40511abd095SBram Moolenaar 	    ins_bytes(saved_text);
40611abd095SBram Moolenaar 	    vim_free(saved_text);
40711abd095SBram Moolenaar 	}
40811abd095SBram Moolenaar 	else
40911abd095SBram Moolenaar 	{
41011abd095SBram Moolenaar 	    // Check if cursor is not past the NUL off the line, cindent
41111abd095SBram Moolenaar 	    // may have added or removed indent.
41211abd095SBram Moolenaar 	    curwin->w_cursor.col += startcol;
41311abd095SBram Moolenaar 	    len = (colnr_T)STRLEN(ml_get_curline());
41411abd095SBram Moolenaar 	    if (curwin->w_cursor.col > len)
41511abd095SBram Moolenaar 		curwin->w_cursor.col = len;
41611abd095SBram Moolenaar 	}
41711abd095SBram Moolenaar 
41811abd095SBram Moolenaar 	haveto_redraw = TRUE;
41911abd095SBram Moolenaar #ifdef FEAT_CINDENT
42011abd095SBram Moolenaar 	set_can_cindent(TRUE);
42111abd095SBram Moolenaar #endif
42211abd095SBram Moolenaar 	// moved the cursor, don't autoindent or cindent now
42311abd095SBram Moolenaar 	did_ai = FALSE;
42411abd095SBram Moolenaar #ifdef FEAT_SMARTINDENT
42511abd095SBram Moolenaar 	did_si = FALSE;
42611abd095SBram Moolenaar 	can_si = FALSE;
42711abd095SBram Moolenaar 	can_si_back = FALSE;
42811abd095SBram Moolenaar #endif
42911abd095SBram Moolenaar 	line_breakcheck();
43011abd095SBram Moolenaar     }
43111abd095SBram Moolenaar 
43211abd095SBram Moolenaar     if (save_char != NUL)		// put back space after cursor
43311abd095SBram Moolenaar 	pchar_cursor(save_char);
43411abd095SBram Moolenaar 
43511abd095SBram Moolenaar #ifdef FEAT_LINEBREAK
43611abd095SBram Moolenaar     curwin->w_p_lbr = has_lbr;
43711abd095SBram Moolenaar #endif
43811abd095SBram Moolenaar     if (!format_only && haveto_redraw)
43911abd095SBram Moolenaar     {
44011abd095SBram Moolenaar 	update_topline();
44111abd095SBram Moolenaar 	redraw_curbuf_later(VALID);
44211abd095SBram Moolenaar     }
44311abd095SBram Moolenaar }
44411abd095SBram Moolenaar 
44511abd095SBram Moolenaar /*
44611abd095SBram Moolenaar  * Blank lines, and lines containing only the comment leader, are left
44711abd095SBram Moolenaar  * untouched by the formatting.  The function returns TRUE in this
44811abd095SBram Moolenaar  * case.  It also returns TRUE when a line starts with the end of a comment
44911abd095SBram Moolenaar  * ('e' in comment flags), so that this line is skipped, and not joined to the
45011abd095SBram Moolenaar  * previous line.  A new paragraph starts after a blank line, or when the
45111abd095SBram Moolenaar  * comment leader changes -- webb.
45211abd095SBram Moolenaar  */
45311abd095SBram Moolenaar     static int
fmt_check_par(linenr_T lnum,int * leader_len,char_u ** leader_flags,int do_comments)45411abd095SBram Moolenaar fmt_check_par(
45511abd095SBram Moolenaar     linenr_T	lnum,
45611abd095SBram Moolenaar     int		*leader_len,
45711abd095SBram Moolenaar     char_u	**leader_flags,
45811abd095SBram Moolenaar     int		do_comments)
45911abd095SBram Moolenaar {
46011abd095SBram Moolenaar     char_u	*flags = NULL;	    // init for GCC
46111abd095SBram Moolenaar     char_u	*ptr;
46211abd095SBram Moolenaar 
46311abd095SBram Moolenaar     ptr = ml_get(lnum);
46411abd095SBram Moolenaar     if (do_comments)
46511abd095SBram Moolenaar 	*leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE);
46611abd095SBram Moolenaar     else
46711abd095SBram Moolenaar 	*leader_len = 0;
46811abd095SBram Moolenaar 
46911abd095SBram Moolenaar     if (*leader_len > 0)
47011abd095SBram Moolenaar     {
47111abd095SBram Moolenaar 	// Search for 'e' flag in comment leader flags.
47211abd095SBram Moolenaar 	flags = *leader_flags;
47311abd095SBram Moolenaar 	while (*flags && *flags != ':' && *flags != COM_END)
47411abd095SBram Moolenaar 	    ++flags;
47511abd095SBram Moolenaar     }
47611abd095SBram Moolenaar 
47711abd095SBram Moolenaar     return (*skipwhite(ptr + *leader_len) == NUL
47811abd095SBram Moolenaar 	    || (*leader_len > 0 && *flags == COM_END)
47911abd095SBram Moolenaar 	    || startPS(lnum, NUL, FALSE));
48011abd095SBram Moolenaar }
48111abd095SBram Moolenaar 
48211abd095SBram Moolenaar /*
48311abd095SBram Moolenaar  * Return TRUE if line "lnum" ends in a white character.
48411abd095SBram Moolenaar  */
48511abd095SBram Moolenaar     static int
ends_in_white(linenr_T lnum)48611abd095SBram Moolenaar ends_in_white(linenr_T lnum)
48711abd095SBram Moolenaar {
48811abd095SBram Moolenaar     char_u	*s = ml_get(lnum);
48911abd095SBram Moolenaar     size_t	l;
49011abd095SBram Moolenaar 
49111abd095SBram Moolenaar     if (*s == NUL)
49211abd095SBram Moolenaar 	return FALSE;
49311abd095SBram Moolenaar     // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro
49411abd095SBram Moolenaar     // invocation may call function multiple times".
49511abd095SBram Moolenaar     l = STRLEN(s) - 1;
49611abd095SBram Moolenaar     return VIM_ISWHITE(s[l]);
49711abd095SBram Moolenaar }
49811abd095SBram Moolenaar 
49911abd095SBram Moolenaar /*
50011abd095SBram Moolenaar  * Return TRUE if the two comment leaders given are the same.  "lnum" is
50111abd095SBram Moolenaar  * the first line.  White-space is ignored.  Note that the whole of
50211abd095SBram Moolenaar  * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
50311abd095SBram Moolenaar  */
50411abd095SBram Moolenaar     static int
same_leader(linenr_T lnum,int leader1_len,char_u * leader1_flags,int leader2_len,char_u * leader2_flags)50511abd095SBram Moolenaar same_leader(
50611abd095SBram Moolenaar     linenr_T lnum,
50711abd095SBram Moolenaar     int	    leader1_len,
50811abd095SBram Moolenaar     char_u  *leader1_flags,
50911abd095SBram Moolenaar     int	    leader2_len,
51011abd095SBram Moolenaar     char_u  *leader2_flags)
51111abd095SBram Moolenaar {
51211abd095SBram Moolenaar     int	    idx1 = 0, idx2 = 0;
51311abd095SBram Moolenaar     char_u  *p;
51411abd095SBram Moolenaar     char_u  *line1;
51511abd095SBram Moolenaar     char_u  *line2;
51611abd095SBram Moolenaar 
51711abd095SBram Moolenaar     if (leader1_len == 0)
51811abd095SBram Moolenaar 	return (leader2_len == 0);
51911abd095SBram Moolenaar 
52011abd095SBram Moolenaar     // If first leader has 'f' flag, the lines can be joined only if the
52111abd095SBram Moolenaar     // second line does not have a leader.
52211abd095SBram Moolenaar     // If first leader has 'e' flag, the lines can never be joined.
52311abd095SBram Moolenaar     // If fist leader has 's' flag, the lines can only be joined if there is
52411abd095SBram Moolenaar     // some text after it and the second line has the 'm' flag.
52511abd095SBram Moolenaar     if (leader1_flags != NULL)
52611abd095SBram Moolenaar     {
52711abd095SBram Moolenaar 	for (p = leader1_flags; *p && *p != ':'; ++p)
52811abd095SBram Moolenaar 	{
52911abd095SBram Moolenaar 	    if (*p == COM_FIRST)
53011abd095SBram Moolenaar 		return (leader2_len == 0);
53111abd095SBram Moolenaar 	    if (*p == COM_END)
53211abd095SBram Moolenaar 		return FALSE;
53311abd095SBram Moolenaar 	    if (*p == COM_START)
53411abd095SBram Moolenaar 	    {
53511abd095SBram Moolenaar 		if (*(ml_get(lnum) + leader1_len) == NUL)
53611abd095SBram Moolenaar 		    return FALSE;
53711abd095SBram Moolenaar 		if (leader2_flags == NULL || leader2_len == 0)
53811abd095SBram Moolenaar 		    return FALSE;
53911abd095SBram Moolenaar 		for (p = leader2_flags; *p && *p != ':'; ++p)
54011abd095SBram Moolenaar 		    if (*p == COM_MIDDLE)
54111abd095SBram Moolenaar 			return TRUE;
54211abd095SBram Moolenaar 		return FALSE;
54311abd095SBram Moolenaar 	    }
54411abd095SBram Moolenaar 	}
54511abd095SBram Moolenaar     }
54611abd095SBram Moolenaar 
54711abd095SBram Moolenaar     // Get current line and next line, compare the leaders.
54811abd095SBram Moolenaar     // The first line has to be saved, only one line can be locked at a time.
54911abd095SBram Moolenaar     line1 = vim_strsave(ml_get(lnum));
55011abd095SBram Moolenaar     if (line1 != NULL)
55111abd095SBram Moolenaar     {
55211abd095SBram Moolenaar 	for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1)
55311abd095SBram Moolenaar 	    ;
55411abd095SBram Moolenaar 	line2 = ml_get(lnum + 1);
55511abd095SBram Moolenaar 	for (idx2 = 0; idx2 < leader2_len; ++idx2)
55611abd095SBram Moolenaar 	{
55711abd095SBram Moolenaar 	    if (!VIM_ISWHITE(line2[idx2]))
55811abd095SBram Moolenaar 	    {
55911abd095SBram Moolenaar 		if (line1[idx1++] != line2[idx2])
56011abd095SBram Moolenaar 		    break;
56111abd095SBram Moolenaar 	    }
56211abd095SBram Moolenaar 	    else
56311abd095SBram Moolenaar 		while (VIM_ISWHITE(line1[idx1]))
56411abd095SBram Moolenaar 		    ++idx1;
56511abd095SBram Moolenaar 	}
56611abd095SBram Moolenaar 	vim_free(line1);
56711abd095SBram Moolenaar     }
56811abd095SBram Moolenaar     return (idx2 == leader2_len && idx1 == leader1_len);
56911abd095SBram Moolenaar }
57011abd095SBram Moolenaar 
57111abd095SBram Moolenaar /*
57211abd095SBram Moolenaar  * Return TRUE when a paragraph starts in line "lnum".  Return FALSE when the
57311abd095SBram Moolenaar  * previous line is in the same paragraph.  Used for auto-formatting.
57411abd095SBram Moolenaar  */
57511abd095SBram Moolenaar     static int
paragraph_start(linenr_T lnum)57611abd095SBram Moolenaar paragraph_start(linenr_T lnum)
57711abd095SBram Moolenaar {
57811abd095SBram Moolenaar     char_u	*p;
57911abd095SBram Moolenaar     int		leader_len = 0;		// leader len of current line
58011abd095SBram Moolenaar     char_u	*leader_flags = NULL;	// flags for leader of current line
58111abd095SBram Moolenaar     int		next_leader_len;	// leader len of next line
58211abd095SBram Moolenaar     char_u	*next_leader_flags;	// flags for leader of next line
58311abd095SBram Moolenaar     int		do_comments;		// format comments
58411abd095SBram Moolenaar 
58511abd095SBram Moolenaar     if (lnum <= 1)
58611abd095SBram Moolenaar 	return TRUE;		// start of the file
58711abd095SBram Moolenaar 
58811abd095SBram Moolenaar     p = ml_get(lnum - 1);
58911abd095SBram Moolenaar     if (*p == NUL)
59011abd095SBram Moolenaar 	return TRUE;		// after empty line
59111abd095SBram Moolenaar 
59211abd095SBram Moolenaar     do_comments = has_format_option(FO_Q_COMS);
59311abd095SBram Moolenaar     if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments))
59411abd095SBram Moolenaar 	return TRUE;		// after non-paragraph line
59511abd095SBram Moolenaar 
59611abd095SBram Moolenaar     if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments))
59711abd095SBram Moolenaar 	return TRUE;		// "lnum" is not a paragraph line
59811abd095SBram Moolenaar 
59911abd095SBram Moolenaar     if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1))
60011abd095SBram Moolenaar 	return TRUE;		// missing trailing space in previous line.
60111abd095SBram Moolenaar 
60211abd095SBram Moolenaar     if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0))
60311abd095SBram Moolenaar 	return TRUE;		// numbered item starts in "lnum".
60411abd095SBram Moolenaar 
60511abd095SBram Moolenaar     if (!same_leader(lnum - 1, leader_len, leader_flags,
60611abd095SBram Moolenaar 					  next_leader_len, next_leader_flags))
60711abd095SBram Moolenaar 	return TRUE;		// change of comment leader.
60811abd095SBram Moolenaar 
60911abd095SBram Moolenaar     return FALSE;
61011abd095SBram Moolenaar }
61111abd095SBram Moolenaar 
61211abd095SBram Moolenaar /*
61311abd095SBram Moolenaar  * Called after inserting or deleting text: When 'formatoptions' includes the
61411abd095SBram Moolenaar  * 'a' flag format from the current line until the end of the paragraph.
61511abd095SBram Moolenaar  * Keep the cursor at the same position relative to the text.
61611abd095SBram Moolenaar  * The caller must have saved the cursor line for undo, following ones will be
61711abd095SBram Moolenaar  * saved here.
61811abd095SBram Moolenaar  */
61911abd095SBram Moolenaar     void
auto_format(int trailblank,int prev_line)62011abd095SBram Moolenaar auto_format(
62111abd095SBram Moolenaar     int		trailblank,	// when TRUE also format with trailing blank
62211abd095SBram Moolenaar     int		prev_line)	// may start in previous line
62311abd095SBram Moolenaar {
62411abd095SBram Moolenaar     pos_T	pos;
62511abd095SBram Moolenaar     colnr_T	len;
62611abd095SBram Moolenaar     char_u	*old;
62711abd095SBram Moolenaar     char_u	*new, *pnew;
62811abd095SBram Moolenaar     int		wasatend;
62911abd095SBram Moolenaar     int		cc;
63011abd095SBram Moolenaar 
63111abd095SBram Moolenaar     if (!has_format_option(FO_AUTO))
63211abd095SBram Moolenaar 	return;
63311abd095SBram Moolenaar 
63411abd095SBram Moolenaar     pos = curwin->w_cursor;
63511abd095SBram Moolenaar     old = ml_get_curline();
63611abd095SBram Moolenaar 
63711abd095SBram Moolenaar     // may remove added space
63811abd095SBram Moolenaar     check_auto_format(FALSE);
63911abd095SBram Moolenaar 
64011abd095SBram Moolenaar     // Don't format in Insert mode when the cursor is on a trailing blank, the
64111abd095SBram Moolenaar     // user might insert normal text next.  Also skip formatting when "1" is
64211abd095SBram Moolenaar     // in 'formatoptions' and there is a single character before the cursor.
64311abd095SBram Moolenaar     // Otherwise the line would be broken and when typing another non-white
64411abd095SBram Moolenaar     // next they are not joined back together.
64511abd095SBram Moolenaar     wasatend = (pos.col == (colnr_T)STRLEN(old));
64611abd095SBram Moolenaar     if (*old != NUL && !trailblank && wasatend)
64711abd095SBram Moolenaar     {
64811abd095SBram Moolenaar 	dec_cursor();
64911abd095SBram Moolenaar 	cc = gchar_cursor();
65011abd095SBram Moolenaar 	if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
65111abd095SBram Moolenaar 					  && has_format_option(FO_ONE_LETTER))
65211abd095SBram Moolenaar 	    dec_cursor();
65311abd095SBram Moolenaar 	cc = gchar_cursor();
65411abd095SBram Moolenaar 	if (WHITECHAR(cc))
65511abd095SBram Moolenaar 	{
65611abd095SBram Moolenaar 	    curwin->w_cursor = pos;
65711abd095SBram Moolenaar 	    return;
65811abd095SBram Moolenaar 	}
65911abd095SBram Moolenaar 	curwin->w_cursor = pos;
66011abd095SBram Moolenaar     }
66111abd095SBram Moolenaar 
66211abd095SBram Moolenaar     // With the 'c' flag in 'formatoptions' and 't' missing: only format
66311abd095SBram Moolenaar     // comments.
66411abd095SBram Moolenaar     if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
66511abd095SBram Moolenaar 				&& get_leader_len(old, NULL, FALSE, TRUE) == 0)
66611abd095SBram Moolenaar 	return;
66711abd095SBram Moolenaar 
66811abd095SBram Moolenaar     // May start formatting in a previous line, so that after "x" a word is
66911abd095SBram Moolenaar     // moved to the previous line if it fits there now.  Only when this is not
67011abd095SBram Moolenaar     // the start of a paragraph.
67111abd095SBram Moolenaar     if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
67211abd095SBram Moolenaar     {
67311abd095SBram Moolenaar 	--curwin->w_cursor.lnum;
67411abd095SBram Moolenaar 	if (u_save_cursor() == FAIL)
67511abd095SBram Moolenaar 	    return;
67611abd095SBram Moolenaar     }
67711abd095SBram Moolenaar 
67811abd095SBram Moolenaar     // Do the formatting and restore the cursor position.  "saved_cursor" will
67911abd095SBram Moolenaar     // be adjusted for the text formatting.
68011abd095SBram Moolenaar     saved_cursor = pos;
68111abd095SBram Moolenaar     format_lines((linenr_T)-1, FALSE);
68211abd095SBram Moolenaar     curwin->w_cursor = saved_cursor;
68311abd095SBram Moolenaar     saved_cursor.lnum = 0;
68411abd095SBram Moolenaar 
68511abd095SBram Moolenaar     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
68611abd095SBram Moolenaar     {
68711abd095SBram Moolenaar 	// "cannot happen"
68811abd095SBram Moolenaar 	curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
68911abd095SBram Moolenaar 	coladvance((colnr_T)MAXCOL);
69011abd095SBram Moolenaar     }
69111abd095SBram Moolenaar     else
69211abd095SBram Moolenaar 	check_cursor_col();
69311abd095SBram Moolenaar 
69411abd095SBram Moolenaar     // Insert mode: If the cursor is now after the end of the line while it
69511abd095SBram Moolenaar     // previously wasn't, the line was broken.  Because of the rule above we
69611abd095SBram Moolenaar     // need to add a space when 'w' is in 'formatoptions' to keep a paragraph
69711abd095SBram Moolenaar     // formatted.
69811abd095SBram Moolenaar     if (!wasatend && has_format_option(FO_WHITE_PAR))
69911abd095SBram Moolenaar     {
70011abd095SBram Moolenaar 	new = ml_get_curline();
70111abd095SBram Moolenaar 	len = (colnr_T)STRLEN(new);
70211abd095SBram Moolenaar 	if (curwin->w_cursor.col == len)
70311abd095SBram Moolenaar 	{
70411abd095SBram Moolenaar 	    pnew = vim_strnsave(new, len + 2);
70511abd095SBram Moolenaar 	    pnew[len] = ' ';
70611abd095SBram Moolenaar 	    pnew[len + 1] = NUL;
70711abd095SBram Moolenaar 	    ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
70811abd095SBram Moolenaar 	    // remove the space later
70911abd095SBram Moolenaar 	    did_add_space = TRUE;
71011abd095SBram Moolenaar 	}
71111abd095SBram Moolenaar 	else
71211abd095SBram Moolenaar 	    // may remove added space
71311abd095SBram Moolenaar 	    check_auto_format(FALSE);
71411abd095SBram Moolenaar     }
71511abd095SBram Moolenaar 
71611abd095SBram Moolenaar     check_cursor();
71711abd095SBram Moolenaar }
71811abd095SBram Moolenaar 
71911abd095SBram Moolenaar /*
72011abd095SBram Moolenaar  * When an extra space was added to continue a paragraph for auto-formatting,
72111abd095SBram Moolenaar  * delete it now.  The space must be under the cursor, just after the insert
72211abd095SBram Moolenaar  * position.
72311abd095SBram Moolenaar  */
72411abd095SBram Moolenaar     void
check_auto_format(int end_insert)72511abd095SBram Moolenaar check_auto_format(
72611abd095SBram Moolenaar     int		end_insert)	    // TRUE when ending Insert mode
72711abd095SBram Moolenaar {
72811abd095SBram Moolenaar     int		c = ' ';
72911abd095SBram Moolenaar     int		cc;
73011abd095SBram Moolenaar 
73111abd095SBram Moolenaar     if (did_add_space)
73211abd095SBram Moolenaar     {
73311abd095SBram Moolenaar 	cc = gchar_cursor();
73411abd095SBram Moolenaar 	if (!WHITECHAR(cc))
73511abd095SBram Moolenaar 	    // Somehow the space was removed already.
73611abd095SBram Moolenaar 	    did_add_space = FALSE;
73711abd095SBram Moolenaar 	else
73811abd095SBram Moolenaar 	{
73911abd095SBram Moolenaar 	    if (!end_insert)
74011abd095SBram Moolenaar 	    {
74111abd095SBram Moolenaar 		inc_cursor();
74211abd095SBram Moolenaar 		c = gchar_cursor();
74311abd095SBram Moolenaar 		dec_cursor();
74411abd095SBram Moolenaar 	    }
74511abd095SBram Moolenaar 	    if (c != NUL)
74611abd095SBram Moolenaar 	    {
74711abd095SBram Moolenaar 		// The space is no longer at the end of the line, delete it.
74811abd095SBram Moolenaar 		del_char(FALSE);
74911abd095SBram Moolenaar 		did_add_space = FALSE;
75011abd095SBram Moolenaar 	    }
75111abd095SBram Moolenaar 	}
75211abd095SBram Moolenaar     }
75311abd095SBram Moolenaar }
75411abd095SBram Moolenaar 
75511abd095SBram Moolenaar /*
75611abd095SBram Moolenaar  * Find out textwidth to be used for formatting:
75711abd095SBram Moolenaar  *	if 'textwidth' option is set, use it
75811abd095SBram Moolenaar  *	else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin'
75911abd095SBram Moolenaar  *	if invalid value, use 0.
76011abd095SBram Moolenaar  *	Set default to window width (maximum 79) for "gq" operator.
76111abd095SBram Moolenaar  */
76211abd095SBram Moolenaar     int
comp_textwidth(int ff)76311abd095SBram Moolenaar comp_textwidth(
76411abd095SBram Moolenaar     int		ff)	// force formatting (for "gq" command)
76511abd095SBram Moolenaar {
76611abd095SBram Moolenaar     int		textwidth;
76711abd095SBram Moolenaar 
76811abd095SBram Moolenaar     textwidth = curbuf->b_p_tw;
76911abd095SBram Moolenaar     if (textwidth == 0 && curbuf->b_p_wm)
77011abd095SBram Moolenaar     {
77111abd095SBram Moolenaar 	// The width is the window width minus 'wrapmargin' minus all the
77211abd095SBram Moolenaar 	// things that add to the margin.
77311abd095SBram Moolenaar 	textwidth = curwin->w_width - curbuf->b_p_wm;
77411abd095SBram Moolenaar #ifdef FEAT_CMDWIN
77511abd095SBram Moolenaar 	if (cmdwin_type != 0)
77611abd095SBram Moolenaar 	    textwidth -= 1;
77711abd095SBram Moolenaar #endif
77811abd095SBram Moolenaar #ifdef FEAT_FOLDING
77911abd095SBram Moolenaar 	textwidth -= curwin->w_p_fdc;
78011abd095SBram Moolenaar #endif
78111abd095SBram Moolenaar #ifdef FEAT_SIGNS
78211abd095SBram Moolenaar 	if (signcolumn_on(curwin))
78311abd095SBram Moolenaar 	    textwidth -= 1;
78411abd095SBram Moolenaar #endif
78511abd095SBram Moolenaar 	if (curwin->w_p_nu || curwin->w_p_rnu)
78611abd095SBram Moolenaar 	    textwidth -= 8;
78711abd095SBram Moolenaar     }
78811abd095SBram Moolenaar     if (textwidth < 0)
78911abd095SBram Moolenaar 	textwidth = 0;
79011abd095SBram Moolenaar     if (ff && textwidth == 0)
79111abd095SBram Moolenaar     {
79211abd095SBram Moolenaar 	textwidth = curwin->w_width - 1;
79311abd095SBram Moolenaar 	if (textwidth > 79)
79411abd095SBram Moolenaar 	    textwidth = 79;
79511abd095SBram Moolenaar     }
79611abd095SBram Moolenaar     return textwidth;
79711abd095SBram Moolenaar }
79811abd095SBram Moolenaar 
79911abd095SBram Moolenaar /*
80011abd095SBram Moolenaar  * Implementation of the format operator 'gq'.
80111abd095SBram Moolenaar  */
80211abd095SBram Moolenaar     void
op_format(oparg_T * oap,int keep_cursor)80311abd095SBram Moolenaar op_format(
80411abd095SBram Moolenaar     oparg_T	*oap,
80511abd095SBram Moolenaar     int		keep_cursor)		// keep cursor on same text char
80611abd095SBram Moolenaar {
80711abd095SBram Moolenaar     long	old_line_count = curbuf->b_ml.ml_line_count;
80811abd095SBram Moolenaar 
80911abd095SBram Moolenaar     // Place the cursor where the "gq" or "gw" command was given, so that "u"
81011abd095SBram Moolenaar     // can put it back there.
81111abd095SBram Moolenaar     curwin->w_cursor = oap->cursor_start;
81211abd095SBram Moolenaar 
81311abd095SBram Moolenaar     if (u_save((linenr_T)(oap->start.lnum - 1),
81411abd095SBram Moolenaar 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
81511abd095SBram Moolenaar 	return;
81611abd095SBram Moolenaar     curwin->w_cursor = oap->start;
81711abd095SBram Moolenaar 
81811abd095SBram Moolenaar     if (oap->is_VIsual)
81911abd095SBram Moolenaar 	// When there is no change: need to remove the Visual selection
82011abd095SBram Moolenaar 	redraw_curbuf_later(INVERTED);
82111abd095SBram Moolenaar 
822e1004401SBram Moolenaar     if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
82311abd095SBram Moolenaar 	// Set '[ mark at the start of the formatted area
82411abd095SBram Moolenaar 	curbuf->b_op_start = oap->start;
82511abd095SBram Moolenaar 
82611abd095SBram Moolenaar     // For "gw" remember the cursor position and put it back below (adjusted
82711abd095SBram Moolenaar     // for joined and split lines).
82811abd095SBram Moolenaar     if (keep_cursor)
82911abd095SBram Moolenaar 	saved_cursor = oap->cursor_start;
83011abd095SBram Moolenaar 
83111abd095SBram Moolenaar     format_lines(oap->line_count, keep_cursor);
83211abd095SBram Moolenaar 
83311abd095SBram Moolenaar     // Leave the cursor at the first non-blank of the last formatted line.
83411abd095SBram Moolenaar     // If the cursor was moved one line back (e.g. with "Q}") go to the next
83511abd095SBram Moolenaar     // line, so "." will do the next lines.
83611abd095SBram Moolenaar     if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
83711abd095SBram Moolenaar 	++curwin->w_cursor.lnum;
83811abd095SBram Moolenaar     beginline(BL_WHITE | BL_FIX);
83911abd095SBram Moolenaar     old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
84011abd095SBram Moolenaar     msgmore(old_line_count);
84111abd095SBram Moolenaar 
842e1004401SBram Moolenaar     if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
84311abd095SBram Moolenaar 	// put '] mark on the end of the formatted area
84411abd095SBram Moolenaar 	curbuf->b_op_end = curwin->w_cursor;
84511abd095SBram Moolenaar 
84611abd095SBram Moolenaar     if (keep_cursor)
84711abd095SBram Moolenaar     {
84811abd095SBram Moolenaar 	curwin->w_cursor = saved_cursor;
84911abd095SBram Moolenaar 	saved_cursor.lnum = 0;
85011abd095SBram Moolenaar     }
85111abd095SBram Moolenaar 
85211abd095SBram Moolenaar     if (oap->is_VIsual)
85311abd095SBram Moolenaar     {
85411abd095SBram Moolenaar 	win_T	*wp;
85511abd095SBram Moolenaar 
85611abd095SBram Moolenaar 	FOR_ALL_WINDOWS(wp)
85711abd095SBram Moolenaar 	{
85811abd095SBram Moolenaar 	    if (wp->w_old_cursor_lnum != 0)
85911abd095SBram Moolenaar 	    {
86011abd095SBram Moolenaar 		// When lines have been inserted or deleted, adjust the end of
86111abd095SBram Moolenaar 		// the Visual area to be redrawn.
86211abd095SBram Moolenaar 		if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum)
86311abd095SBram Moolenaar 		    wp->w_old_cursor_lnum += old_line_count;
86411abd095SBram Moolenaar 		else
86511abd095SBram Moolenaar 		    wp->w_old_visual_lnum += old_line_count;
86611abd095SBram Moolenaar 	    }
86711abd095SBram Moolenaar 	}
86811abd095SBram Moolenaar     }
86911abd095SBram Moolenaar }
87011abd095SBram Moolenaar 
87111abd095SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
87211abd095SBram Moolenaar /*
87311abd095SBram Moolenaar  * Implementation of the format operator 'gq' for when using 'formatexpr'.
87411abd095SBram Moolenaar  */
87511abd095SBram Moolenaar     void
op_formatexpr(oparg_T * oap)87611abd095SBram Moolenaar op_formatexpr(oparg_T *oap)
87711abd095SBram Moolenaar {
87811abd095SBram Moolenaar     if (oap->is_VIsual)
87911abd095SBram Moolenaar 	// When there is no change: need to remove the Visual selection
88011abd095SBram Moolenaar 	redraw_curbuf_later(INVERTED);
88111abd095SBram Moolenaar 
88211abd095SBram Moolenaar     if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0)
88311abd095SBram Moolenaar 	// As documented: when 'formatexpr' returns non-zero fall back to
88411abd095SBram Moolenaar 	// internal formatting.
88511abd095SBram Moolenaar 	op_format(oap, FALSE);
88611abd095SBram Moolenaar }
88711abd095SBram Moolenaar 
88811abd095SBram Moolenaar     int
fex_format(linenr_T lnum,long count,int c)88911abd095SBram Moolenaar fex_format(
89011abd095SBram Moolenaar     linenr_T	lnum,
89111abd095SBram Moolenaar     long	count,
89211abd095SBram Moolenaar     int		c)	// character to be inserted
89311abd095SBram Moolenaar {
89411abd095SBram Moolenaar     int		use_sandbox = was_set_insecurely((char_u *)"formatexpr",
89511abd095SBram Moolenaar 								   OPT_LOCAL);
89611abd095SBram Moolenaar     int		r;
89711abd095SBram Moolenaar     char_u	*fex;
89811abd095SBram Moolenaar 
89911abd095SBram Moolenaar     // Set v:lnum to the first line number and v:count to the number of lines.
90011abd095SBram Moolenaar     // Set v:char to the character to be inserted (can be NUL).
90111abd095SBram Moolenaar     set_vim_var_nr(VV_LNUM, lnum);
90211abd095SBram Moolenaar     set_vim_var_nr(VV_COUNT, count);
90311abd095SBram Moolenaar     set_vim_var_char(c);
90411abd095SBram Moolenaar 
90511abd095SBram Moolenaar     // Make a copy, the option could be changed while calling it.
90611abd095SBram Moolenaar     fex = vim_strsave(curbuf->b_p_fex);
90711abd095SBram Moolenaar     if (fex == NULL)
90811abd095SBram Moolenaar 	return 0;
90911abd095SBram Moolenaar 
91011abd095SBram Moolenaar     // Evaluate the function.
91111abd095SBram Moolenaar     if (use_sandbox)
91211abd095SBram Moolenaar 	++sandbox;
91311abd095SBram Moolenaar     r = (int)eval_to_number(fex);
91411abd095SBram Moolenaar     if (use_sandbox)
91511abd095SBram Moolenaar 	--sandbox;
91611abd095SBram Moolenaar 
91711abd095SBram Moolenaar     set_vim_var_string(VV_CHAR, NULL, -1);
91811abd095SBram Moolenaar     vim_free(fex);
91911abd095SBram Moolenaar 
92011abd095SBram Moolenaar     return r;
92111abd095SBram Moolenaar }
92211abd095SBram Moolenaar #endif
92311abd095SBram Moolenaar 
92411abd095SBram Moolenaar /*
92511abd095SBram Moolenaar  * Format "line_count" lines, starting at the cursor position.
92611abd095SBram Moolenaar  * When "line_count" is negative, format until the end of the paragraph.
92711abd095SBram Moolenaar  * Lines after the cursor line are saved for undo, caller must have saved the
92811abd095SBram Moolenaar  * first line.
92911abd095SBram Moolenaar  */
93011abd095SBram Moolenaar     void
format_lines(linenr_T line_count,int avoid_fex)93111abd095SBram Moolenaar format_lines(
93211abd095SBram Moolenaar     linenr_T	line_count,
93311abd095SBram Moolenaar     int		avoid_fex)		// don't use 'formatexpr'
93411abd095SBram Moolenaar {
93511abd095SBram Moolenaar     int		max_len;
93611abd095SBram Moolenaar     int		is_not_par;		// current line not part of parag.
93711abd095SBram Moolenaar     int		next_is_not_par;	// next line not part of paragraph
93811abd095SBram Moolenaar     int		is_end_par;		// at end of paragraph
93911abd095SBram Moolenaar     int		prev_is_end_par = FALSE;// prev. line not part of parag.
94011abd095SBram Moolenaar     int		next_is_start_par = FALSE;
94111abd095SBram Moolenaar     int		leader_len = 0;		// leader len of current line
94211abd095SBram Moolenaar     int		next_leader_len;	// leader len of next line
94311abd095SBram Moolenaar     char_u	*leader_flags = NULL;	// flags for leader of current line
94411abd095SBram Moolenaar     char_u	*next_leader_flags;	// flags for leader of next line
94511abd095SBram Moolenaar     int		do_comments;		// format comments
94611abd095SBram Moolenaar     int		do_comments_list = 0;	// format comments with 'n' or '2'
94711abd095SBram Moolenaar     int		advance = TRUE;
94811abd095SBram Moolenaar     int		second_indent = -1;	// indent for second line (comment
94911abd095SBram Moolenaar 					// aware)
95011abd095SBram Moolenaar     int		do_second_indent;
95111abd095SBram Moolenaar     int		do_number_indent;
95211abd095SBram Moolenaar     int		do_trail_white;
95311abd095SBram Moolenaar     int		first_par_line = TRUE;
95411abd095SBram Moolenaar     int		smd_save;
95511abd095SBram Moolenaar     long	count;
95611abd095SBram Moolenaar     int		need_set_indent = TRUE;	// set indent of next paragraph
95711abd095SBram Moolenaar     int		force_format = FALSE;
95811abd095SBram Moolenaar     int		old_State = State;
95911abd095SBram Moolenaar 
96011abd095SBram Moolenaar     // length of a line to force formatting: 3 * 'tw'
96111abd095SBram Moolenaar     max_len = comp_textwidth(TRUE) * 3;
96211abd095SBram Moolenaar 
96311abd095SBram Moolenaar     // check for 'q', '2' and '1' in 'formatoptions'
96411abd095SBram Moolenaar     do_comments = has_format_option(FO_Q_COMS);
96511abd095SBram Moolenaar     do_second_indent = has_format_option(FO_Q_SECOND);
96611abd095SBram Moolenaar     do_number_indent = has_format_option(FO_Q_NUMBER);
96711abd095SBram Moolenaar     do_trail_white = has_format_option(FO_WHITE_PAR);
96811abd095SBram Moolenaar 
96911abd095SBram Moolenaar     // Get info about the previous and current line.
97011abd095SBram Moolenaar     if (curwin->w_cursor.lnum > 1)
97111abd095SBram Moolenaar 	is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
97211abd095SBram Moolenaar 				, &leader_len, &leader_flags, do_comments);
97311abd095SBram Moolenaar     else
97411abd095SBram Moolenaar 	is_not_par = TRUE;
97511abd095SBram Moolenaar     next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
97611abd095SBram Moolenaar 			  , &next_leader_len, &next_leader_flags, do_comments);
97711abd095SBram Moolenaar     is_end_par = (is_not_par || next_is_not_par);
97811abd095SBram Moolenaar     if (!is_end_par && do_trail_white)
97911abd095SBram Moolenaar 	is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1);
98011abd095SBram Moolenaar 
98111abd095SBram Moolenaar     curwin->w_cursor.lnum--;
98211abd095SBram Moolenaar     for (count = line_count; count != 0 && !got_int; --count)
98311abd095SBram Moolenaar     {
98411abd095SBram Moolenaar 	// Advance to next paragraph.
98511abd095SBram Moolenaar 	if (advance)
98611abd095SBram Moolenaar 	{
98711abd095SBram Moolenaar 	    curwin->w_cursor.lnum++;
98811abd095SBram Moolenaar 	    prev_is_end_par = is_end_par;
98911abd095SBram Moolenaar 	    is_not_par = next_is_not_par;
99011abd095SBram Moolenaar 	    leader_len = next_leader_len;
99111abd095SBram Moolenaar 	    leader_flags = next_leader_flags;
99211abd095SBram Moolenaar 	}
99311abd095SBram Moolenaar 
99411abd095SBram Moolenaar 	// The last line to be formatted.
99511abd095SBram Moolenaar 	if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
99611abd095SBram Moolenaar 	{
99711abd095SBram Moolenaar 	    next_is_not_par = TRUE;
99811abd095SBram Moolenaar 	    next_leader_len = 0;
99911abd095SBram Moolenaar 	    next_leader_flags = NULL;
100011abd095SBram Moolenaar 	}
100111abd095SBram Moolenaar 	else
100211abd095SBram Moolenaar 	{
100311abd095SBram Moolenaar 	    next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1
100411abd095SBram Moolenaar 			  , &next_leader_len, &next_leader_flags, do_comments);
100511abd095SBram Moolenaar 	    if (do_number_indent)
100611abd095SBram Moolenaar 		next_is_start_par =
100711abd095SBram Moolenaar 			   (get_number_indent(curwin->w_cursor.lnum + 1) > 0);
100811abd095SBram Moolenaar 	}
100911abd095SBram Moolenaar 	advance = TRUE;
101011abd095SBram Moolenaar 	is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
101111abd095SBram Moolenaar 	if (!is_end_par && do_trail_white)
101211abd095SBram Moolenaar 	    is_end_par = !ends_in_white(curwin->w_cursor.lnum);
101311abd095SBram Moolenaar 
101411abd095SBram Moolenaar 	// Skip lines that are not in a paragraph.
101511abd095SBram Moolenaar 	if (is_not_par)
101611abd095SBram Moolenaar 	{
101711abd095SBram Moolenaar 	    if (line_count < 0)
101811abd095SBram Moolenaar 		break;
101911abd095SBram Moolenaar 	}
102011abd095SBram Moolenaar 	else
102111abd095SBram Moolenaar 	{
102211abd095SBram Moolenaar 	    // For the first line of a paragraph, check indent of second line.
102311abd095SBram Moolenaar 	    // Don't do this for comments and empty lines.
102411abd095SBram Moolenaar 	    if (first_par_line
102511abd095SBram Moolenaar 		    && (do_second_indent || do_number_indent)
102611abd095SBram Moolenaar 		    && prev_is_end_par
102711abd095SBram Moolenaar 		    && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
102811abd095SBram Moolenaar 	    {
102911abd095SBram Moolenaar 		if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1))
103011abd095SBram Moolenaar 		{
103111abd095SBram Moolenaar 		    if (leader_len == 0 && next_leader_len == 0)
103211abd095SBram Moolenaar 		    {
103311abd095SBram Moolenaar 			// no comment found
103411abd095SBram Moolenaar 			second_indent =
103511abd095SBram Moolenaar 				   get_indent_lnum(curwin->w_cursor.lnum + 1);
103611abd095SBram Moolenaar 		    }
103711abd095SBram Moolenaar 		    else
103811abd095SBram Moolenaar 		    {
103911abd095SBram Moolenaar 			second_indent = next_leader_len;
104011abd095SBram Moolenaar 			do_comments_list = 1;
104111abd095SBram Moolenaar 		    }
104211abd095SBram Moolenaar 		}
104311abd095SBram Moolenaar 		else if (do_number_indent)
104411abd095SBram Moolenaar 		{
104511abd095SBram Moolenaar 		    if (leader_len == 0 && next_leader_len == 0)
104611abd095SBram Moolenaar 		    {
104711abd095SBram Moolenaar 			// no comment found
104811abd095SBram Moolenaar 			second_indent =
104911abd095SBram Moolenaar 				     get_number_indent(curwin->w_cursor.lnum);
105011abd095SBram Moolenaar 		    }
105111abd095SBram Moolenaar 		    else
105211abd095SBram Moolenaar 		    {
105311abd095SBram Moolenaar 			// get_number_indent() is now "comment aware"...
105411abd095SBram Moolenaar 			second_indent =
105511abd095SBram Moolenaar 				     get_number_indent(curwin->w_cursor.lnum);
105611abd095SBram Moolenaar 			do_comments_list = 1;
105711abd095SBram Moolenaar 		    }
105811abd095SBram Moolenaar 		}
105911abd095SBram Moolenaar 	    }
106011abd095SBram Moolenaar 
106111abd095SBram Moolenaar 	    // When the comment leader changes, it's the end of the paragraph.
106211abd095SBram Moolenaar 	    if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count
106311abd095SBram Moolenaar 		    || !same_leader(curwin->w_cursor.lnum,
106411abd095SBram Moolenaar 					leader_len, leader_flags,
106511abd095SBram Moolenaar 					   next_leader_len, next_leader_flags))
106611abd095SBram Moolenaar 		is_end_par = TRUE;
106711abd095SBram Moolenaar 
106811abd095SBram Moolenaar 	    // If we have got to the end of a paragraph, or the line is
106911abd095SBram Moolenaar 	    // getting long, format it.
107011abd095SBram Moolenaar 	    if (is_end_par || force_format)
107111abd095SBram Moolenaar 	    {
107211abd095SBram Moolenaar 		if (need_set_indent)
1073*818ff25cSChristian Brabandt 		{
1074*818ff25cSChristian Brabandt 		    int		indent = 0; // amount of indent needed
1075*818ff25cSChristian Brabandt 
107611abd095SBram Moolenaar 		    // replace indent in first line with minimal number of
107711abd095SBram Moolenaar 		    // tabs and spaces, according to current options
1078*818ff25cSChristian Brabandt # ifdef FEAT_LISP
1079*818ff25cSChristian Brabandt 		    if (curbuf->b_p_lisp)
1080*818ff25cSChristian Brabandt 			indent = get_lisp_indent();
1081*818ff25cSChristian Brabandt 		    else
1082*818ff25cSChristian Brabandt # endif
1083*818ff25cSChristian Brabandt 		    {
1084*818ff25cSChristian Brabandt #ifdef FEAT_CINDENT
1085*818ff25cSChristian Brabandt 			if (cindent_on())
1086*818ff25cSChristian Brabandt 			{
1087*818ff25cSChristian Brabandt 			    indent =
1088*818ff25cSChristian Brabandt # ifdef FEAT_EVAL
1089*818ff25cSChristian Brabandt 				 *curbuf->b_p_inde != NUL ? get_expr_indent() :
1090*818ff25cSChristian Brabandt # endif
1091*818ff25cSChristian Brabandt 				 get_c_indent();
1092*818ff25cSChristian Brabandt 			}
1093*818ff25cSChristian Brabandt 			else
1094*818ff25cSChristian Brabandt #endif
1095*818ff25cSChristian Brabandt 			    indent = get_indent();
1096*818ff25cSChristian Brabandt 		    }
1097*818ff25cSChristian Brabandt 		    (void)set_indent(indent, SIN_CHANGED);
1098*818ff25cSChristian Brabandt 		}
109911abd095SBram Moolenaar 
110011abd095SBram Moolenaar 		// put cursor on last non-space
110111abd095SBram Moolenaar 		State = NORMAL;	// don't go past end-of-line
110211abd095SBram Moolenaar 		coladvance((colnr_T)MAXCOL);
110311abd095SBram Moolenaar 		while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
110411abd095SBram Moolenaar 		    dec_cursor();
110511abd095SBram Moolenaar 
110611abd095SBram Moolenaar 		// do the formatting, without 'showmode'
110711abd095SBram Moolenaar 		State = INSERT;	// for open_line()
110811abd095SBram Moolenaar 		smd_save = p_smd;
110911abd095SBram Moolenaar 		p_smd = FALSE;
111011abd095SBram Moolenaar 		insertchar(NUL, INSCHAR_FORMAT
111111abd095SBram Moolenaar 			+ (do_comments ? INSCHAR_DO_COM : 0)
111211abd095SBram Moolenaar 			+ (do_comments && do_comments_list
111311abd095SBram Moolenaar 						       ? INSCHAR_COM_LIST : 0)
111411abd095SBram Moolenaar 			+ (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
111511abd095SBram Moolenaar 		State = old_State;
111611abd095SBram Moolenaar 		p_smd = smd_save;
111711abd095SBram Moolenaar 		second_indent = -1;
111811abd095SBram Moolenaar 		// at end of par.: need to set indent of next par.
111911abd095SBram Moolenaar 		need_set_indent = is_end_par;
112011abd095SBram Moolenaar 		if (is_end_par)
112111abd095SBram Moolenaar 		{
112211abd095SBram Moolenaar 		    // When called with a negative line count, break at the
112311abd095SBram Moolenaar 		    // end of the paragraph.
112411abd095SBram Moolenaar 		    if (line_count < 0)
112511abd095SBram Moolenaar 			break;
112611abd095SBram Moolenaar 		    first_par_line = TRUE;
112711abd095SBram Moolenaar 		}
112811abd095SBram Moolenaar 		force_format = FALSE;
112911abd095SBram Moolenaar 	    }
113011abd095SBram Moolenaar 
113111abd095SBram Moolenaar 	    // When still in same paragraph, join the lines together.  But
113211abd095SBram Moolenaar 	    // first delete the leader from the second line.
113311abd095SBram Moolenaar 	    if (!is_end_par)
113411abd095SBram Moolenaar 	    {
113511abd095SBram Moolenaar 		advance = FALSE;
113611abd095SBram Moolenaar 		curwin->w_cursor.lnum++;
113711abd095SBram Moolenaar 		curwin->w_cursor.col = 0;
113811abd095SBram Moolenaar 		if (line_count < 0 && u_save_cursor() == FAIL)
113911abd095SBram Moolenaar 		    break;
114011abd095SBram Moolenaar 		if (next_leader_len > 0)
114111abd095SBram Moolenaar 		{
114211abd095SBram Moolenaar 		    (void)del_bytes((long)next_leader_len, FALSE, FALSE);
114311abd095SBram Moolenaar 		    mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
114411abd095SBram Moolenaar 						    (long)-next_leader_len, 0);
114511abd095SBram Moolenaar 		}
114611abd095SBram Moolenaar 		else if (second_indent > 0)  // the "leader" for FO_Q_SECOND
114711abd095SBram Moolenaar 		{
114811abd095SBram Moolenaar 		    int indent = getwhitecols_curline();
114911abd095SBram Moolenaar 
115011abd095SBram Moolenaar 		    if (indent > 0)
115111abd095SBram Moolenaar 		    {
115211abd095SBram Moolenaar 			(void)del_bytes(indent, FALSE, FALSE);
115311abd095SBram Moolenaar 			mark_col_adjust(curwin->w_cursor.lnum,
115411abd095SBram Moolenaar 					       (colnr_T)0, 0L, (long)-indent, 0);
115511abd095SBram Moolenaar 		    }
115611abd095SBram Moolenaar 		}
115711abd095SBram Moolenaar 		curwin->w_cursor.lnum--;
115811abd095SBram Moolenaar 		if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL)
115911abd095SBram Moolenaar 		{
116011abd095SBram Moolenaar 		    beep_flush();
116111abd095SBram Moolenaar 		    break;
116211abd095SBram Moolenaar 		}
116311abd095SBram Moolenaar 		first_par_line = FALSE;
116411abd095SBram Moolenaar 		// If the line is getting long, format it next time
116511abd095SBram Moolenaar 		if (STRLEN(ml_get_curline()) > (size_t)max_len)
116611abd095SBram Moolenaar 		    force_format = TRUE;
116711abd095SBram Moolenaar 		else
116811abd095SBram Moolenaar 		    force_format = FALSE;
116911abd095SBram Moolenaar 	    }
117011abd095SBram Moolenaar 	}
117111abd095SBram Moolenaar 	line_breakcheck();
117211abd095SBram Moolenaar     }
117311abd095SBram Moolenaar }
1174