xref: /vim-8.2.3635/src/screen.c (revision 6555500b)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar 
10071d4279SBram Moolenaar /*
117528d1f6SBram Moolenaar  * screen.c: Lower level code for displaying on the screen.
12071d4279SBram Moolenaar  *
13071d4279SBram Moolenaar  * Output to the screen (console, terminal emulator or GUI window) is minimized
14071d4279SBram Moolenaar  * by remembering what is already on the screen, and only updating the parts
15071d4279SBram Moolenaar  * that changed.
16071d4279SBram Moolenaar  *
17071d4279SBram Moolenaar  * ScreenLines[off]  Contains a copy of the whole screen, as it is currently
18071d4279SBram Moolenaar  *		     displayed (excluding text written by external commands).
19071d4279SBram Moolenaar  * ScreenAttrs[off]  Contains the associated attributes.
20071d4279SBram Moolenaar  * LineOffset[row]   Contains the offset into ScreenLines*[] and ScreenAttrs[]
21071d4279SBram Moolenaar  *		     for each line.
22071d4279SBram Moolenaar  * LineWraps[row]    Flag for each line whether it wraps to the next line.
23071d4279SBram Moolenaar  *
24071d4279SBram Moolenaar  * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25071d4279SBram Moolenaar  * one character which occupies two display cells.
26071d4279SBram Moolenaar  * For UTF-8 a multi-byte character is converted to Unicode and stored in
27071d4279SBram Moolenaar  * ScreenLinesUC[].  ScreenLines[] contains the first byte only.  For an ASCII
2870c49c1aSBram Moolenaar  * character without composing chars ScreenLinesUC[] will be 0 and
2970c49c1aSBram Moolenaar  * ScreenLinesC[][] is not used.  When the character occupies two display
3070c49c1aSBram Moolenaar  * cells the next byte in ScreenLines[] is 0.
31362e1a30SBram Moolenaar  * ScreenLinesC[][] contain up to 'maxcombine' composing characters
3270c49c1aSBram Moolenaar  * (drawn on top of the first character).  There is 0 after the last one used.
33071d4279SBram Moolenaar  * ScreenLines2[] is only used for euc-jp to store the second byte if the
34071d4279SBram Moolenaar  * first byte is 0x8e (single-width character).
35071d4279SBram Moolenaar  *
36071d4279SBram Moolenaar  * The screen_*() functions write to the screen and handle updating
37071d4279SBram Moolenaar  * ScreenLines[].
38071d4279SBram Moolenaar  */
39071d4279SBram Moolenaar 
40071d4279SBram Moolenaar #include "vim.h"
41071d4279SBram Moolenaar 
42071d4279SBram Moolenaar /*
43071d4279SBram Moolenaar  * The attributes that are actually active for writing to the screen.
44071d4279SBram Moolenaar  */
45071d4279SBram Moolenaar static int	screen_attr = 0;
46071d4279SBram Moolenaar 
47baaa7e9eSBram Moolenaar static void screen_char_2(unsigned off, int row, int col);
48baaa7e9eSBram Moolenaar static void screenclear2(void);
49cfce7171SBram Moolenaar static void lineclear(unsigned off, int width, int attr);
50baaa7e9eSBram Moolenaar static void lineinvalid(unsigned off, int width);
51cfce7171SBram Moolenaar static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
52baaa7e9eSBram Moolenaar static void win_rest_invalid(win_T *wp);
53baaa7e9eSBram Moolenaar static void msg_pos_mode(void);
54baaa7e9eSBram Moolenaar static void recording_mode(int attr);
55071d4279SBram Moolenaar 
5663d9e730SBram Moolenaar // Ugly global: overrule attribute used by screen_char()
57071d4279SBram Moolenaar static int screen_char_attr = 0;
58071d4279SBram Moolenaar 
59860cae1cSBram Moolenaar #if defined(FEAT_CONCEAL) || defined(PROTO)
60f5963f71SBram Moolenaar /*
61f5963f71SBram Moolenaar  * Return TRUE if the cursor line in window "wp" may be concealed, according
62f5963f71SBram Moolenaar  * to the 'concealcursor' option.
63f5963f71SBram Moolenaar  */
64f5963f71SBram Moolenaar     int
conceal_cursor_line(win_T * wp)6505540976SBram Moolenaar conceal_cursor_line(win_T *wp)
66f5963f71SBram Moolenaar {
67f5963f71SBram Moolenaar     int		c;
68f5963f71SBram Moolenaar 
69f5963f71SBram Moolenaar     if (*wp->w_p_cocu == NUL)
70f5963f71SBram Moolenaar 	return FALSE;
71f5963f71SBram Moolenaar     if (get_real_state() & VISUAL)
72f5963f71SBram Moolenaar 	c = 'v';
73f5963f71SBram Moolenaar     else if (State & INSERT)
74f5963f71SBram Moolenaar 	c = 'i';
75f5963f71SBram Moolenaar     else if (State & NORMAL)
76f5963f71SBram Moolenaar 	c = 'n';
77ca8c9867SBram Moolenaar     else if (State & CMDLINE)
78ca8c9867SBram Moolenaar 	c = 'c';
79f5963f71SBram Moolenaar     else
80f5963f71SBram Moolenaar 	return FALSE;
81f5963f71SBram Moolenaar     return vim_strchr(wp->w_p_cocu, c) != NULL;
82f5963f71SBram Moolenaar }
83f5963f71SBram Moolenaar 
84f5963f71SBram Moolenaar /*
85f5963f71SBram Moolenaar  * Check if the cursor line needs to be redrawn because of 'concealcursor'.
86ea042677SBram Moolenaar  * To be called after changing the state, "was_concealed" is the value of
87ea042677SBram Moolenaar  * "conceal_cursor_line()" before the change.
88ea042677SBram Moolenaar  * "
89f5963f71SBram Moolenaar  */
90f5963f71SBram Moolenaar     void
conceal_check_cursor_line(int was_concealed)91ea042677SBram Moolenaar conceal_check_cursor_line(int was_concealed)
92f5963f71SBram Moolenaar {
93ea042677SBram Moolenaar     if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin) != was_concealed)
94f5963f71SBram Moolenaar     {
95ea042677SBram Moolenaar 	int wcol = curwin->w_wcol;
96ea042677SBram Moolenaar 
97f5963f71SBram Moolenaar 	need_cursor_line_redraw = TRUE;
9863d9e730SBram Moolenaar 	// Need to recompute cursor column, e.g., when starting Visual mode
9963d9e730SBram Moolenaar 	// without concealing.
100f5963f71SBram Moolenaar 	curs_columns(TRUE);
101ea042677SBram Moolenaar 
102ea042677SBram Moolenaar 	// When concealing now w_wcol will be computed wrong, keep the previous
103ea042677SBram Moolenaar 	// value, it will be updated in win_line().
104ea042677SBram Moolenaar 	if (!was_concealed)
105ea042677SBram Moolenaar 	    curwin->w_wcol = wcol;
106f5963f71SBram Moolenaar     }
107f5963f71SBram Moolenaar }
108071d4279SBram Moolenaar #endif
109071d4279SBram Moolenaar 
11060cdb300SBram Moolenaar /*
11160cdb300SBram Moolenaar  * Get 'wincolor' attribute for window "wp".  If not set and "wp" is a popup
11260cdb300SBram Moolenaar  * window then get the "Pmenu" highlight attribute.
11360cdb300SBram Moolenaar  */
114a540f8aaSBram Moolenaar     int
get_wcr_attr(win_T * wp)11560cdb300SBram Moolenaar get_wcr_attr(win_T *wp)
11660cdb300SBram Moolenaar {
11760cdb300SBram Moolenaar     int wcr_attr = 0;
11860cdb300SBram Moolenaar 
11960cdb300SBram Moolenaar     if (*wp->w_p_wcr != NUL)
12060cdb300SBram Moolenaar 	wcr_attr = syn_name2attr(wp->w_p_wcr);
12105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
122c363fe15SBram Moolenaar     else if (WIN_IS_POPUP(wp))
12362a0cb44SBram Moolenaar     {
12462a0cb44SBram Moolenaar 	if (wp->w_popup_flags & POPF_INFO)
12562a0cb44SBram Moolenaar 	    wcr_attr = HL_ATTR(HLF_PSI);    // PmenuSel
12662a0cb44SBram Moolenaar 	else
12762a0cb44SBram Moolenaar 	    wcr_attr = HL_ATTR(HLF_PNI);    // Pmenu
12862a0cb44SBram Moolenaar     }
12960cdb300SBram Moolenaar #endif
13060cdb300SBram Moolenaar     return wcr_attr;
13160cdb300SBram Moolenaar }
13260cdb300SBram Moolenaar 
133071d4279SBram Moolenaar /*
1348ee4c01bSBram Moolenaar  * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
1358ee4c01bSBram Moolenaar  * Return the new offset.
1368ee4c01bSBram Moolenaar  */
1378ee4c01bSBram Moolenaar     static int
screen_fill_end(win_T * wp,int c1,int c2,int off,int width,int row,int endrow,int attr)1388ee4c01bSBram Moolenaar screen_fill_end(
1398ee4c01bSBram Moolenaar 	win_T *wp,
1408ee4c01bSBram Moolenaar 	int	c1,
1418ee4c01bSBram Moolenaar 	int	c2,
1428ee4c01bSBram Moolenaar 	int	off,
1438ee4c01bSBram Moolenaar 	int	width,
1448ee4c01bSBram Moolenaar 	int	row,
1458ee4c01bSBram Moolenaar 	int	endrow,
1468ee4c01bSBram Moolenaar 	int	attr)
1478ee4c01bSBram Moolenaar {
1488ee4c01bSBram Moolenaar     int	    nn = off + width;
1498ee4c01bSBram Moolenaar 
1508ee4c01bSBram Moolenaar     if (nn > wp->w_width)
1518ee4c01bSBram Moolenaar 	nn = wp->w_width;
1528ee4c01bSBram Moolenaar #ifdef FEAT_RIGHTLEFT
1538ee4c01bSBram Moolenaar     if (wp->w_p_rl)
1548ee4c01bSBram Moolenaar     {
1558ee4c01bSBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
1568ee4c01bSBram Moolenaar 		W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
1578ee4c01bSBram Moolenaar 		c1, c2, attr);
1588ee4c01bSBram Moolenaar     }
1598ee4c01bSBram Moolenaar     else
1608ee4c01bSBram Moolenaar #endif
1618ee4c01bSBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
1628ee4c01bSBram Moolenaar 		wp->w_wincol + off, (int)wp->w_wincol + nn,
1638ee4c01bSBram Moolenaar 		c1, c2, attr);
1648ee4c01bSBram Moolenaar     return nn;
1658ee4c01bSBram Moolenaar }
1668ee4c01bSBram Moolenaar 
1678ee4c01bSBram Moolenaar /*
1688ee4c01bSBram Moolenaar  * Clear lines near the end the window and mark the unused lines with "c1".
1698ee4c01bSBram Moolenaar  * use "c2" as the filler character.
1708ee4c01bSBram Moolenaar  * When "draw_margin" is TRUE then draw the sign, fold and number columns.
171071d4279SBram Moolenaar  */
1727528d1f6SBram Moolenaar     void
win_draw_end(win_T * wp,int c1,int c2,int draw_margin,int row,int endrow,hlf_T hl)17305540976SBram Moolenaar win_draw_end(
17405540976SBram Moolenaar     win_T	*wp,
17505540976SBram Moolenaar     int		c1,
17605540976SBram Moolenaar     int		c2,
1778ee4c01bSBram Moolenaar     int		draw_margin,
17805540976SBram Moolenaar     int		row,
17905540976SBram Moolenaar     int		endrow,
18005540976SBram Moolenaar     hlf_T	hl)
181071d4279SBram Moolenaar {
182071d4279SBram Moolenaar     int		n = 0;
183193ffd1dSBram Moolenaar     int		attr = HL_ATTR(hl);
18460cdb300SBram Moolenaar     int		wcr_attr = get_wcr_attr(wp);
185193ffd1dSBram Moolenaar 
186193ffd1dSBram Moolenaar     attr = hl_combine_attr(wcr_attr, attr);
1878ee4c01bSBram Moolenaar 
1888ee4c01bSBram Moolenaar     if (draw_margin)
1898ee4c01bSBram Moolenaar     {
1901c93429cSBram Moolenaar #ifdef FEAT_FOLDING
1911c93429cSBram Moolenaar 	int	fdc = compute_foldcolumn(wp, 0);
1928ee4c01bSBram Moolenaar 
1938ee4c01bSBram Moolenaar 	if (fdc > 0)
1948ee4c01bSBram Moolenaar 	    // draw the fold column
1958ee4c01bSBram Moolenaar 	    n = screen_fill_end(wp, ' ', ' ', n, fdc,
196193ffd1dSBram Moolenaar 		      row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
1971c93429cSBram Moolenaar #endif
1988ee4c01bSBram Moolenaar #ifdef FEAT_SIGNS
1998ee4c01bSBram Moolenaar 	if (signcolumn_on(wp))
2008ee4c01bSBram Moolenaar 	    // draw the sign column
2018ee4c01bSBram Moolenaar 	    n = screen_fill_end(wp, ' ', ' ', n, 2,
202193ffd1dSBram Moolenaar 		      row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
2038ee4c01bSBram Moolenaar #endif
2048ee4c01bSBram Moolenaar 	if ((wp->w_p_nu || wp->w_p_rnu)
2058ee4c01bSBram Moolenaar 				  && vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
2068ee4c01bSBram Moolenaar 	    // draw the number column
2078ee4c01bSBram Moolenaar 	    n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
208193ffd1dSBram Moolenaar 		       row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
2098ee4c01bSBram Moolenaar     }
210071d4279SBram Moolenaar 
211071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
212071d4279SBram Moolenaar     if (wp->w_p_rl)
213071d4279SBram Moolenaar     {
214071d4279SBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2158ee4c01bSBram Moolenaar 		wp->w_wincol, W_ENDCOL(wp) - 1 - n,
216193ffd1dSBram Moolenaar 		c2, c2, attr);
217071d4279SBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2188ee4c01bSBram Moolenaar 		W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
219193ffd1dSBram Moolenaar 		c1, c2, attr);
220071d4279SBram Moolenaar     }
221071d4279SBram Moolenaar     else
222071d4279SBram Moolenaar #endif
223071d4279SBram Moolenaar     {
224071d4279SBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2258ee4c01bSBram Moolenaar 		wp->w_wincol + n, (int)W_ENDCOL(wp),
226193ffd1dSBram Moolenaar 		c1, c2, attr);
227071d4279SBram Moolenaar     }
2288ee4c01bSBram Moolenaar 
229071d4279SBram Moolenaar     set_empty_rows(wp, row);
230071d4279SBram Moolenaar }
231071d4279SBram Moolenaar 
2327528d1f6SBram Moolenaar #if defined(FEAT_FOLDING) || defined(PROTO)
233071d4279SBram Moolenaar /*
2341c93429cSBram Moolenaar  * Compute the width of the foldcolumn.  Based on 'foldcolumn' and how much
2351c93429cSBram Moolenaar  * space is available for window "wp", minus "col".
2361c93429cSBram Moolenaar  */
2377528d1f6SBram Moolenaar     int
compute_foldcolumn(win_T * wp,int col)23805540976SBram Moolenaar compute_foldcolumn(win_T *wp, int col)
2391c93429cSBram Moolenaar {
2401c93429cSBram Moolenaar     int fdc = wp->w_p_fdc;
2411c93429cSBram Moolenaar     int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
2420263146bSBram Moolenaar     int wwidth = wp->w_width;
2431c93429cSBram Moolenaar 
2441c93429cSBram Moolenaar     if (fdc > wwidth - (col + wmw))
2451c93429cSBram Moolenaar 	fdc = wwidth - (col + wmw);
2461c93429cSBram Moolenaar     return fdc;
2471c93429cSBram Moolenaar }
2481c93429cSBram Moolenaar 
2491c93429cSBram Moolenaar /*
250071d4279SBram Moolenaar  * Fill the foldcolumn at "p" for window "wp".
251d5cdbeb8SBram Moolenaar  * Only to be called when 'foldcolumn' > 0.
2524fa11757SBram Moolenaar  * Returns the number of bytes stored in 'p'. When non-multibyte characters are
2534fa11757SBram Moolenaar  * used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
2544fa11757SBram Moolenaar  * this will be greater than 'fdc'.
255071d4279SBram Moolenaar  */
2564fa11757SBram Moolenaar     size_t
fill_foldcolumn(char_u * p,win_T * wp,int closed,linenr_T lnum)25705540976SBram Moolenaar fill_foldcolumn(
25805540976SBram Moolenaar     char_u	*p,
25905540976SBram Moolenaar     win_T	*wp,
26063d9e730SBram Moolenaar     int		closed,		// TRUE of FALSE
26163d9e730SBram Moolenaar     linenr_T	lnum)		// current line number
262071d4279SBram Moolenaar {
263071d4279SBram Moolenaar     int		i = 0;
264071d4279SBram Moolenaar     int		level;
265071d4279SBram Moolenaar     int		first_level;
266578b49e4SBram Moolenaar     int		empty;
2671c93429cSBram Moolenaar     int		fdc = compute_foldcolumn(wp, 0);
2684fa11757SBram Moolenaar     size_t	byte_counter = 0;
2694fa11757SBram Moolenaar     int		symbol = 0;
2704fa11757SBram Moolenaar     int		len = 0;
271071d4279SBram Moolenaar 
27263d9e730SBram Moolenaar     // Init to all spaces.
2734fa11757SBram Moolenaar     vim_memset(p, ' ', MAX_MCO * fdc + 1);
274071d4279SBram Moolenaar 
275071d4279SBram Moolenaar     level = win_foldinfo.fi_level;
2761c93429cSBram Moolenaar     empty = (fdc == 1) ? 0 : 1;
277578b49e4SBram Moolenaar 
27863d9e730SBram Moolenaar     // If the column is too narrow, we start at the lowest level that
279008bff96SBram Moolenaar     // fits and use numbers to indicate the depth.
2801c93429cSBram Moolenaar     first_level = level - fdc - closed + 1 + empty;
281071d4279SBram Moolenaar     if (first_level < 1)
282071d4279SBram Moolenaar 	first_level = 1;
283071d4279SBram Moolenaar 
2844fa11757SBram Moolenaar     for (i = 0; i < MIN(fdc, level); i++)
285071d4279SBram Moolenaar     {
286071d4279SBram Moolenaar 	if (win_foldinfo.fi_lnum == lnum
287071d4279SBram Moolenaar 		&& first_level + i >= win_foldinfo.fi_low_level)
2884fa11757SBram Moolenaar 	    symbol = fill_foldopen;
289071d4279SBram Moolenaar 	else if (first_level == 1)
2904fa11757SBram Moolenaar 	    symbol = fill_foldsep;
291071d4279SBram Moolenaar 	else if (first_level + i <= 9)
2924fa11757SBram Moolenaar 	    symbol = '0' + first_level + i;
293071d4279SBram Moolenaar 	else
2944fa11757SBram Moolenaar 	    symbol = '>';
2954fa11757SBram Moolenaar 
2964fa11757SBram Moolenaar 	len = utf_char2bytes(symbol, &p[byte_counter]);
2974fa11757SBram Moolenaar 	byte_counter += len;
2984fa11757SBram Moolenaar 	if (first_level + i >= level)
2994fa11757SBram Moolenaar 	{
3004fa11757SBram Moolenaar 	    i++;
301071d4279SBram Moolenaar 	    break;
302071d4279SBram Moolenaar 	}
303071d4279SBram Moolenaar     }
3044fa11757SBram Moolenaar 
305071d4279SBram Moolenaar     if (closed)
3064fa11757SBram Moolenaar     {
3074fa11757SBram Moolenaar 	if (symbol != 0)
308196a1f74SBram Moolenaar 	{
309196a1f74SBram Moolenaar 	    // rollback length and the character
3104fa11757SBram Moolenaar 	    byte_counter -= len;
311196a1f74SBram Moolenaar 	    if (len > 1)
312196a1f74SBram Moolenaar 		// for a multibyte character, erase all the bytes
313196a1f74SBram Moolenaar 		vim_memset(p + byte_counter, ' ', len);
314196a1f74SBram Moolenaar 	}
3154fa11757SBram Moolenaar 	symbol = fill_foldclosed;
3164fa11757SBram Moolenaar 	len = utf_char2bytes(symbol, &p[byte_counter]);
3174fa11757SBram Moolenaar 	byte_counter += len;
3184fa11757SBram Moolenaar     }
3194fa11757SBram Moolenaar 
3204fa11757SBram Moolenaar     return MAX(byte_counter + (fdc - i), (size_t)fdc);
321071d4279SBram Moolenaar }
32263d9e730SBram Moolenaar #endif // FEAT_FOLDING
323071d4279SBram Moolenaar 
324362e1a30SBram Moolenaar /*
325362e1a30SBram Moolenaar  * Return if the composing characters at "off_from" and "off_to" differ.
32670c49c1aSBram Moolenaar  * Only to be used when ScreenLinesUC[off_from] != 0.
327362e1a30SBram Moolenaar  */
328362e1a30SBram Moolenaar     static int
comp_char_differs(int off_from,int off_to)32905540976SBram Moolenaar comp_char_differs(int off_from, int off_to)
330362e1a30SBram Moolenaar {
331362e1a30SBram Moolenaar     int	    i;
332362e1a30SBram Moolenaar 
333362e1a30SBram Moolenaar     for (i = 0; i < Screen_mco; ++i)
334362e1a30SBram Moolenaar     {
335362e1a30SBram Moolenaar 	if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
336362e1a30SBram Moolenaar 	    return TRUE;
337362e1a30SBram Moolenaar 	if (ScreenLinesC[i][off_from] == 0)
338362e1a30SBram Moolenaar 	    break;
339362e1a30SBram Moolenaar     }
340362e1a30SBram Moolenaar     return FALSE;
341362e1a30SBram Moolenaar }
342362e1a30SBram Moolenaar 
343071d4279SBram Moolenaar /*
344071d4279SBram Moolenaar  * Check whether the given character needs redrawing:
345071d4279SBram Moolenaar  * - the (first byte of the) character is different
346071d4279SBram Moolenaar  * - the attributes are different
347071d4279SBram Moolenaar  * - the character is multi-byte and the next byte is different
34888f3d3a2SBram Moolenaar  * - the character is two cells wide and the second cell differs.
349071d4279SBram Moolenaar  */
350071d4279SBram Moolenaar     static int
char_needs_redraw(int off_from,int off_to,int cols)35105540976SBram Moolenaar char_needs_redraw(int off_from, int off_to, int cols)
352071d4279SBram Moolenaar {
353071d4279SBram Moolenaar     if (cols > 0
354071d4279SBram Moolenaar 	    && ((ScreenLines[off_from] != ScreenLines[off_to]
355071d4279SBram Moolenaar 		    || ScreenAttrs[off_from] != ScreenAttrs[off_to])
356071d4279SBram Moolenaar 		|| (enc_dbcs != 0
357071d4279SBram Moolenaar 		    && MB_BYTE2LEN(ScreenLines[off_from]) > 1
358071d4279SBram Moolenaar 		    && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
359071d4279SBram Moolenaar 			? ScreenLines2[off_from] != ScreenLines2[off_to]
360071d4279SBram Moolenaar 			: (cols > 1 && ScreenLines[off_from + 1]
361071d4279SBram Moolenaar 						 != ScreenLines[off_to + 1])))
362071d4279SBram Moolenaar 		|| (enc_utf8
363071d4279SBram Moolenaar 		    && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
364071d4279SBram Moolenaar 			|| (ScreenLinesUC[off_from] != 0
36588f3d3a2SBram Moolenaar 			    && comp_char_differs(off_from, off_to))
366451cf637SBram Moolenaar 			|| ((*mb_off2cells)(off_from, off_from + cols) > 1
367451cf637SBram Moolenaar 			    && ScreenLines[off_from + 1]
368a12a161bSBram Moolenaar 						!= ScreenLines[off_to + 1])))))
369071d4279SBram Moolenaar 	return TRUE;
370071d4279SBram Moolenaar     return FALSE;
371071d4279SBram Moolenaar }
372071d4279SBram Moolenaar 
373cb8bbe9bSBram Moolenaar #if defined(FEAT_TERMINAL) || defined(PROTO)
374cb8bbe9bSBram Moolenaar /*
375cb8bbe9bSBram Moolenaar  * Return the index in ScreenLines[] for the current screen line.
376cb8bbe9bSBram Moolenaar  */
377cb8bbe9bSBram Moolenaar     int
screen_get_current_line_off()378cb8bbe9bSBram Moolenaar screen_get_current_line_off()
379cb8bbe9bSBram Moolenaar {
380cb8bbe9bSBram Moolenaar     return (int)(current_ScreenLine - ScreenLines);
381cb8bbe9bSBram Moolenaar }
382cb8bbe9bSBram Moolenaar #endif
383cb8bbe9bSBram Moolenaar 
38405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
385c662ec99SBram Moolenaar /*
386c662ec99SBram Moolenaar  * Return TRUE if this position has a higher level popup or this cell is
387c662ec99SBram Moolenaar  * transparent in the current popup.
388c662ec99SBram Moolenaar  */
389c662ec99SBram Moolenaar     static int
blocked_by_popup(int row,int col)390c662ec99SBram Moolenaar blocked_by_popup(int row, int col)
391c662ec99SBram Moolenaar {
392c662ec99SBram Moolenaar     int off;
393c662ec99SBram Moolenaar 
394c662ec99SBram Moolenaar     if (!popup_visible)
395c662ec99SBram Moolenaar 	return FALSE;
396c662ec99SBram Moolenaar     off = row * screen_Columns + col;
397c662ec99SBram Moolenaar     return popup_mask[off] > screen_zindex || popup_transparent[off];
398c662ec99SBram Moolenaar }
399c662ec99SBram Moolenaar #endif
400c662ec99SBram Moolenaar 
401071d4279SBram Moolenaar /*
4027528d1f6SBram Moolenaar  * Reset the highlighting.  Used before clearing the screen.
4037528d1f6SBram Moolenaar  */
4047528d1f6SBram Moolenaar     void
reset_screen_attr(void)4057528d1f6SBram Moolenaar reset_screen_attr(void)
4067528d1f6SBram Moolenaar {
4077528d1f6SBram Moolenaar #ifdef FEAT_GUI
4087528d1f6SBram Moolenaar     if (gui.in_use)
4097528d1f6SBram Moolenaar 	// Use a code that will reset gui.highlight_mask in
4107528d1f6SBram Moolenaar 	// gui_stop_highlight().
4117528d1f6SBram Moolenaar 	screen_attr = HL_ALL + 1;
4127528d1f6SBram Moolenaar     else
4137528d1f6SBram Moolenaar #endif
4147528d1f6SBram Moolenaar 	// Use attributes that is very unlikely to appear in text.
4157528d1f6SBram Moolenaar 	screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
4167528d1f6SBram Moolenaar }
4177528d1f6SBram Moolenaar 
4187528d1f6SBram Moolenaar /*
419071d4279SBram Moolenaar  * Move one "cooked" screen line to the screen, but only the characters that
420071d4279SBram Moolenaar  * have actually changed.  Handle insert/delete character.
421071d4279SBram Moolenaar  * "coloff" gives the first column on the screen for this line.
422071d4279SBram Moolenaar  * "endcol" gives the columns where valid characters are.
423071d4279SBram Moolenaar  * "clear_width" is the width of the window.  It's > 0 if the rest of the line
424071d4279SBram Moolenaar  * needs to be cleared, negative otherwise.
4254d784b21SBram Moolenaar  * "flags" can have bits:
4264d784b21SBram Moolenaar  * SLF_POPUP	    popup window
4274d784b21SBram Moolenaar  * SLF_RIGHTLEFT    rightleft window:
428071d4279SBram Moolenaar  *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
429071d4279SBram Moolenaar  *    When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
430071d4279SBram Moolenaar  */
431cb8bbe9bSBram Moolenaar     void
screen_line(int row,int coloff,int endcol,int clear_width,int flags UNUSED)43205540976SBram Moolenaar screen_line(
43305540976SBram Moolenaar     int	    row,
43405540976SBram Moolenaar     int	    coloff,
43505540976SBram Moolenaar     int	    endcol,
436cb8bbe9bSBram Moolenaar     int	    clear_width,
4374d784b21SBram Moolenaar     int	    flags UNUSED)
438071d4279SBram Moolenaar {
439071d4279SBram Moolenaar     unsigned	    off_from;
440071d4279SBram Moolenaar     unsigned	    off_to;
441367329baSBram Moolenaar     unsigned	    max_off_from;
442367329baSBram Moolenaar     unsigned	    max_off_to;
443071d4279SBram Moolenaar     int		    col = 0;
444071d4279SBram Moolenaar     int		    hl;
44563d9e730SBram Moolenaar     int		    force = FALSE;	// force update rest of the line
44663d9e730SBram Moolenaar     int		    redraw_this		// bool: does character need redraw?
447071d4279SBram Moolenaar #ifdef FEAT_GUI
44863d9e730SBram Moolenaar 				= TRUE	// For GUI when while-loop empty
449071d4279SBram Moolenaar #endif
450071d4279SBram Moolenaar 				;
45163d9e730SBram Moolenaar     int		    redraw_next;	// redraw_this for next character
452071d4279SBram Moolenaar     int		    clear_next = FALSE;
45363d9e730SBram Moolenaar     int		    char_cells;		// 1: normal char
45463d9e730SBram Moolenaar 					// 2: occupies two display cells
455071d4279SBram Moolenaar # define CHAR_CELLS char_cells
456071d4279SBram Moolenaar 
45763d9e730SBram Moolenaar     // Check for illegal row and col, just in case.
4585ad15df9SBram Moolenaar     if (row >= Rows)
4595ad15df9SBram Moolenaar 	row = Rows - 1;
4605ad15df9SBram Moolenaar     if (endcol > Columns)
4615ad15df9SBram Moolenaar 	endcol = Columns;
4625ad15df9SBram Moolenaar 
463071d4279SBram Moolenaar # ifdef FEAT_CLIPBOARD
464071d4279SBram Moolenaar     clip_may_clear_selection(row, row);
465071d4279SBram Moolenaar # endif
466071d4279SBram Moolenaar 
467071d4279SBram Moolenaar     off_from = (unsigned)(current_ScreenLine - ScreenLines);
468071d4279SBram Moolenaar     off_to = LineOffset[row] + coloff;
469367329baSBram Moolenaar     max_off_from = off_from + screen_Columns;
470367329baSBram Moolenaar     max_off_to = LineOffset[row] + screen_Columns;
471071d4279SBram Moolenaar 
472071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4734d784b21SBram Moolenaar     if (flags & SLF_RIGHTLEFT)
474071d4279SBram Moolenaar     {
47563d9e730SBram Moolenaar 	// Clear rest first, because it's left of the text.
476071d4279SBram Moolenaar 	if (clear_width > 0)
477071d4279SBram Moolenaar 	{
478071d4279SBram Moolenaar 	    while (col <= endcol && ScreenLines[off_to] == ' '
479071d4279SBram Moolenaar 		    && ScreenAttrs[off_to] == 0
480a12a161bSBram Moolenaar 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
481071d4279SBram Moolenaar 	    {
482071d4279SBram Moolenaar 		++off_to;
483071d4279SBram Moolenaar 		++col;
484071d4279SBram Moolenaar 	    }
485071d4279SBram Moolenaar 	    if (col <= endcol)
486071d4279SBram Moolenaar 		screen_fill(row, row + 1, col + coloff,
487071d4279SBram Moolenaar 					    endcol + coloff + 1, ' ', ' ', 0);
488071d4279SBram Moolenaar 	}
489071d4279SBram Moolenaar 	col = endcol + 1;
490071d4279SBram Moolenaar 	off_to = LineOffset[row] + col + coloff;
491071d4279SBram Moolenaar 	off_from += col;
492071d4279SBram Moolenaar 	endcol = (clear_width > 0 ? clear_width : -clear_width);
493071d4279SBram Moolenaar     }
49463d9e730SBram Moolenaar #endif // FEAT_RIGHTLEFT
495071d4279SBram Moolenaar 
49605ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
49792e25ab2SBram Moolenaar     // First char of a popup window may go on top of the right half of a
49892e25ab2SBram Moolenaar     // double-wide character. Clear the left half to avoid it getting the popup
49992e25ab2SBram Moolenaar     // window background color.
500927495b1SBram Moolenaar     if (coloff > 0 && enc_utf8
501927495b1SBram Moolenaar 		   && ScreenLines[off_to] == 0
502dc0cf1dbSBram Moolenaar 		   && ScreenLinesUC[off_to - 1] != 0
503dc0cf1dbSBram Moolenaar 		   && (*mb_char2cells)(ScreenLinesUC[off_to - 1]) > 1)
50492e25ab2SBram Moolenaar     {
50592e25ab2SBram Moolenaar 	ScreenLines[off_to - 1] = ' ';
50692e25ab2SBram Moolenaar 	ScreenLinesUC[off_to - 1] = 0;
50792e25ab2SBram Moolenaar 	screen_char(off_to - 1, row, col + coloff - 1);
50892e25ab2SBram Moolenaar     }
50992e25ab2SBram Moolenaar #endif
51092e25ab2SBram Moolenaar 
511071d4279SBram Moolenaar     redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
512071d4279SBram Moolenaar 
513071d4279SBram Moolenaar     while (col < endcol)
514071d4279SBram Moolenaar     {
515071d4279SBram Moolenaar 	if (has_mbyte && (col + 1 < endcol))
516367329baSBram Moolenaar 	    char_cells = (*mb_off2cells)(off_from, max_off_from);
517071d4279SBram Moolenaar 	else
518071d4279SBram Moolenaar 	    char_cells = 1;
519071d4279SBram Moolenaar 
520071d4279SBram Moolenaar 	redraw_this = redraw_next;
521071d4279SBram Moolenaar 	redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
522071d4279SBram Moolenaar 			      off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
523071d4279SBram Moolenaar 
524071d4279SBram Moolenaar #ifdef FEAT_GUI
52563d9e730SBram Moolenaar 	// If the next character was bold, then redraw the current character to
52663d9e730SBram Moolenaar 	// remove any pixels that might have spilt over into us.  This only
52763d9e730SBram Moolenaar 	// happens in the GUI.
528071d4279SBram Moolenaar 	if (redraw_next && gui.in_use)
529071d4279SBram Moolenaar 	{
530071d4279SBram Moolenaar 	    hl = ScreenAttrs[off_to + CHAR_CELLS];
531600dddcfSBram Moolenaar 	    if (hl > HL_ALL)
532600dddcfSBram Moolenaar 		hl = syn_attr2attr(hl);
533600dddcfSBram Moolenaar 	    if (hl & HL_BOLD)
534071d4279SBram Moolenaar 		redraw_this = TRUE;
535071d4279SBram Moolenaar 	}
536071d4279SBram Moolenaar #endif
53705ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
538c662ec99SBram Moolenaar 	if (blocked_by_popup(row, col + coloff))
53933796b39SBram Moolenaar 	    redraw_this = FALSE;
54033796b39SBram Moolenaar #endif
541071d4279SBram Moolenaar 	if (redraw_this)
542071d4279SBram Moolenaar 	{
543071d4279SBram Moolenaar 	    /*
544071d4279SBram Moolenaar 	     * Special handling when 'xs' termcap flag set (hpterm):
545071d4279SBram Moolenaar 	     * Attributes for characters are stored at the position where the
546071d4279SBram Moolenaar 	     * cursor is when writing the highlighting code.  The
547071d4279SBram Moolenaar 	     * start-highlighting code must be written with the cursor on the
548071d4279SBram Moolenaar 	     * first highlighted character.  The stop-highlighting code must
549071d4279SBram Moolenaar 	     * be written with the cursor just after the last highlighted
550071d4279SBram Moolenaar 	     * character.
551c4568ab3SBram Moolenaar 	     * Overwriting a character doesn't remove its highlighting.  Need
552071d4279SBram Moolenaar 	     * to clear the rest of the line, and force redrawing it
553071d4279SBram Moolenaar 	     * completely.
554071d4279SBram Moolenaar 	     */
555071d4279SBram Moolenaar 	    if (       p_wiv
556071d4279SBram Moolenaar 		    && !force
557071d4279SBram Moolenaar #ifdef FEAT_GUI
558071d4279SBram Moolenaar 		    && !gui.in_use
559071d4279SBram Moolenaar #endif
560071d4279SBram Moolenaar 		    && ScreenAttrs[off_to] != 0
561071d4279SBram Moolenaar 		    && ScreenAttrs[off_from] != ScreenAttrs[off_to])
562071d4279SBram Moolenaar 	    {
563071d4279SBram Moolenaar 		/*
564071d4279SBram Moolenaar 		 * Need to remove highlighting attributes here.
565071d4279SBram Moolenaar 		 */
566071d4279SBram Moolenaar 		windgoto(row, col + coloff);
56763d9e730SBram Moolenaar 		out_str(T_CE);		// clear rest of this screen line
56863d9e730SBram Moolenaar 		screen_start();		// don't know where cursor is now
56963d9e730SBram Moolenaar 		force = TRUE;		// force redraw of rest of the line
57063d9e730SBram Moolenaar 		redraw_next = TRUE;	// or else next char would miss out
571071d4279SBram Moolenaar 
572071d4279SBram Moolenaar 		/*
573071d4279SBram Moolenaar 		 * If the previous character was highlighted, need to stop
574071d4279SBram Moolenaar 		 * highlighting at this character.
575071d4279SBram Moolenaar 		 */
576071d4279SBram Moolenaar 		if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
577071d4279SBram Moolenaar 		{
578071d4279SBram Moolenaar 		    screen_attr = ScreenAttrs[off_to - 1];
579071d4279SBram Moolenaar 		    term_windgoto(row, col + coloff);
580071d4279SBram Moolenaar 		    screen_stop_highlight();
581071d4279SBram Moolenaar 		}
582071d4279SBram Moolenaar 		else
58363d9e730SBram Moolenaar 		    screen_attr = 0;	    // highlighting has stopped
584071d4279SBram Moolenaar 	    }
585071d4279SBram Moolenaar 	    if (enc_dbcs != 0)
586071d4279SBram Moolenaar 	    {
58763d9e730SBram Moolenaar 		// Check if overwriting a double-byte with a single-byte or
58863d9e730SBram Moolenaar 		// the other way around requires another character to be
58963d9e730SBram Moolenaar 		// redrawn.  For UTF-8 this isn't needed, because comparing
59063d9e730SBram Moolenaar 		// ScreenLinesUC[] is sufficient.
591071d4279SBram Moolenaar 		if (char_cells == 1
592071d4279SBram Moolenaar 			&& col + 1 < endcol
593367329baSBram Moolenaar 			&& (*mb_off2cells)(off_to, max_off_to) > 1)
594071d4279SBram Moolenaar 		{
59563d9e730SBram Moolenaar 		    // Writing a single-cell character over a double-cell
59663d9e730SBram Moolenaar 		    // character: need to redraw the next cell.
597071d4279SBram Moolenaar 		    ScreenLines[off_to + 1] = 0;
598071d4279SBram Moolenaar 		    redraw_next = TRUE;
599071d4279SBram Moolenaar 		}
600071d4279SBram Moolenaar 		else if (char_cells == 2
601071d4279SBram Moolenaar 			&& col + 2 < endcol
602367329baSBram Moolenaar 			&& (*mb_off2cells)(off_to, max_off_to) == 1
603367329baSBram Moolenaar 			&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)
604071d4279SBram Moolenaar 		{
60563d9e730SBram Moolenaar 		    // Writing the second half of a double-cell character over
60663d9e730SBram Moolenaar 		    // a double-cell character: need to redraw the second
60763d9e730SBram Moolenaar 		    // cell.
608071d4279SBram Moolenaar 		    ScreenLines[off_to + 2] = 0;
609071d4279SBram Moolenaar 		    redraw_next = TRUE;
610071d4279SBram Moolenaar 		}
611071d4279SBram Moolenaar 
612071d4279SBram Moolenaar 		if (enc_dbcs == DBCS_JPNU)
613071d4279SBram Moolenaar 		    ScreenLines2[off_to] = ScreenLines2[off_from];
614071d4279SBram Moolenaar 	    }
61563d9e730SBram Moolenaar 	    // When writing a single-width character over a double-width
61663d9e730SBram Moolenaar 	    // character and at the end of the redrawn text, need to clear out
61763d9e730SBram Moolenaar 	    // the right halve of the old character.
61863d9e730SBram Moolenaar 	    // Also required when writing the right halve of a double-width
61963d9e730SBram Moolenaar 	    // char over the left halve of an existing one.
620071d4279SBram Moolenaar 	    if (has_mbyte && col + char_cells == endcol
621071d4279SBram Moolenaar 		    && ((char_cells == 1
622367329baSBram Moolenaar 			    && (*mb_off2cells)(off_to, max_off_to) > 1)
623071d4279SBram Moolenaar 			|| (char_cells == 2
624367329baSBram Moolenaar 			    && (*mb_off2cells)(off_to, max_off_to) == 1
625367329baSBram Moolenaar 			    && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
626071d4279SBram Moolenaar 		clear_next = TRUE;
627071d4279SBram Moolenaar 
628071d4279SBram Moolenaar 	    ScreenLines[off_to] = ScreenLines[off_from];
629071d4279SBram Moolenaar 	    if (enc_utf8)
630071d4279SBram Moolenaar 	    {
631071d4279SBram Moolenaar 		ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
632071d4279SBram Moolenaar 		if (ScreenLinesUC[off_from] != 0)
633071d4279SBram Moolenaar 		{
634362e1a30SBram Moolenaar 		    int	    i;
635362e1a30SBram Moolenaar 
636362e1a30SBram Moolenaar 		    for (i = 0; i < Screen_mco; ++i)
637362e1a30SBram Moolenaar 			ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
638071d4279SBram Moolenaar 		}
639071d4279SBram Moolenaar 	    }
640071d4279SBram Moolenaar 	    if (char_cells == 2)
641071d4279SBram Moolenaar 		ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
642071d4279SBram Moolenaar 
643071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
64463d9e730SBram Moolenaar 	    // The bold trick makes a single column of pixels appear in the
64563d9e730SBram Moolenaar 	    // next character.  When a bold character is removed, the next
64663d9e730SBram Moolenaar 	    // character should be redrawn too.  This happens for our own GUI
64763d9e730SBram Moolenaar 	    // and for some xterms.
648071d4279SBram Moolenaar 	    if (
649071d4279SBram Moolenaar # ifdef FEAT_GUI
650071d4279SBram Moolenaar 		    gui.in_use
651071d4279SBram Moolenaar # endif
652071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
653071d4279SBram Moolenaar 		    ||
654071d4279SBram Moolenaar # endif
655071d4279SBram Moolenaar # ifdef UNIX
656071d4279SBram Moolenaar 		    term_is_xterm
657071d4279SBram Moolenaar # endif
658071d4279SBram Moolenaar 		    )
659071d4279SBram Moolenaar 	    {
660071d4279SBram Moolenaar 		hl = ScreenAttrs[off_to];
661600dddcfSBram Moolenaar 		if (hl > HL_ALL)
662600dddcfSBram Moolenaar 		    hl = syn_attr2attr(hl);
663600dddcfSBram Moolenaar 		if (hl & HL_BOLD)
664071d4279SBram Moolenaar 		    redraw_next = TRUE;
665071d4279SBram Moolenaar 	    }
666071d4279SBram Moolenaar #endif
667071d4279SBram Moolenaar 	    ScreenAttrs[off_to] = ScreenAttrs[off_from];
668a12a161bSBram Moolenaar 
66963d9e730SBram Moolenaar 	    // For simplicity set the attributes of second half of a
67063d9e730SBram Moolenaar 	    // double-wide character equal to the first half.
671910f66f9SBram Moolenaar 	    if (char_cells == 2)
672071d4279SBram Moolenaar 		ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
673910f66f9SBram Moolenaar 
674910f66f9SBram Moolenaar 	    if (enc_dbcs != 0 && char_cells == 2)
675071d4279SBram Moolenaar 		screen_char_2(off_to, row, col + coloff);
676071d4279SBram Moolenaar 	    else
677071d4279SBram Moolenaar 		screen_char(off_to, row, col + coloff);
678071d4279SBram Moolenaar 	}
679071d4279SBram Moolenaar 	else if (  p_wiv
680071d4279SBram Moolenaar #ifdef FEAT_GUI
681071d4279SBram Moolenaar 		&& !gui.in_use
682071d4279SBram Moolenaar #endif
683071d4279SBram Moolenaar 		&& col + coloff > 0)
684071d4279SBram Moolenaar 	{
685071d4279SBram Moolenaar 	    if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
686071d4279SBram Moolenaar 	    {
687071d4279SBram Moolenaar 		/*
688071d4279SBram Moolenaar 		 * Don't output stop-highlight when moving the cursor, it will
689071d4279SBram Moolenaar 		 * stop the highlighting when it should continue.
690071d4279SBram Moolenaar 		 */
691071d4279SBram Moolenaar 		screen_attr = 0;
692071d4279SBram Moolenaar 	    }
693071d4279SBram Moolenaar 	    else if (screen_attr != 0)
694071d4279SBram Moolenaar 		screen_stop_highlight();
695071d4279SBram Moolenaar 	}
696071d4279SBram Moolenaar 
697071d4279SBram Moolenaar 	off_to += CHAR_CELLS;
698071d4279SBram Moolenaar 	off_from += CHAR_CELLS;
699071d4279SBram Moolenaar 	col += CHAR_CELLS;
700071d4279SBram Moolenaar     }
701071d4279SBram Moolenaar 
702071d4279SBram Moolenaar     if (clear_next)
703071d4279SBram Moolenaar     {
70463d9e730SBram Moolenaar 	// Clear the second half of a double-wide character of which the left
70563d9e730SBram Moolenaar 	// half was overwritten with a single-wide character.
706071d4279SBram Moolenaar 	ScreenLines[off_to] = ' ';
707071d4279SBram Moolenaar 	if (enc_utf8)
708071d4279SBram Moolenaar 	    ScreenLinesUC[off_to] = 0;
709071d4279SBram Moolenaar 	screen_char(off_to, row, col + coloff);
710071d4279SBram Moolenaar     }
711071d4279SBram Moolenaar 
712071d4279SBram Moolenaar     if (clear_width > 0
713071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
7144d784b21SBram Moolenaar 		    && !(flags & SLF_RIGHTLEFT)
715071d4279SBram Moolenaar #endif
716071d4279SBram Moolenaar 				   )
717071d4279SBram Moolenaar     {
718071d4279SBram Moolenaar #ifdef FEAT_GUI
719071d4279SBram Moolenaar 	int startCol = col;
720071d4279SBram Moolenaar #endif
721071d4279SBram Moolenaar 
72263d9e730SBram Moolenaar 	// blank out the rest of the line
723071d4279SBram Moolenaar 	while (col < clear_width && ScreenLines[off_to] == ' '
724071d4279SBram Moolenaar 						  && ScreenAttrs[off_to] == 0
725a12a161bSBram Moolenaar 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
726071d4279SBram Moolenaar 	{
727071d4279SBram Moolenaar 	    ++off_to;
728071d4279SBram Moolenaar 	    ++col;
729071d4279SBram Moolenaar 	}
730071d4279SBram Moolenaar 	if (col < clear_width)
731071d4279SBram Moolenaar 	{
732071d4279SBram Moolenaar #ifdef FEAT_GUI
733071d4279SBram Moolenaar 	    /*
734071d4279SBram Moolenaar 	     * In the GUI, clearing the rest of the line may leave pixels
735071d4279SBram Moolenaar 	     * behind if the first character cleared was bold.  Some bold
736071d4279SBram Moolenaar 	     * fonts spill over the left.  In this case we redraw the previous
737071d4279SBram Moolenaar 	     * character too.  If we didn't skip any blanks above, then we
738071d4279SBram Moolenaar 	     * only redraw if the character wasn't already redrawn anyway.
739071d4279SBram Moolenaar 	     */
7409c697322SBram Moolenaar 	    if (gui.in_use && (col > startCol || !redraw_this))
741071d4279SBram Moolenaar 	    {
742071d4279SBram Moolenaar 		hl = ScreenAttrs[off_to];
743071d4279SBram Moolenaar 		if (hl > HL_ALL || (hl & HL_BOLD))
7449c697322SBram Moolenaar 		{
7459c697322SBram Moolenaar 		    int prev_cells = 1;
746a12a161bSBram Moolenaar 
7479c697322SBram Moolenaar 		    if (enc_utf8)
74863d9e730SBram Moolenaar 			// for utf-8, ScreenLines[char_offset + 1] == 0 means
74963d9e730SBram Moolenaar 			// that its width is 2.
7509c697322SBram Moolenaar 			prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
7519c697322SBram Moolenaar 		    else if (enc_dbcs != 0)
7529c697322SBram Moolenaar 		    {
75363d9e730SBram Moolenaar 			// find previous character by counting from first
75463d9e730SBram Moolenaar 			// column and get its width.
7559c697322SBram Moolenaar 			unsigned off = LineOffset[row];
756367329baSBram Moolenaar 			unsigned max_off = LineOffset[row] + screen_Columns;
7579c697322SBram Moolenaar 
7589c697322SBram Moolenaar 			while (off < off_to)
7599c697322SBram Moolenaar 			{
760367329baSBram Moolenaar 			    prev_cells = (*mb_off2cells)(off, max_off);
7619c697322SBram Moolenaar 			    off += prev_cells;
7629c697322SBram Moolenaar 			}
7639c697322SBram Moolenaar 		    }
7649c697322SBram Moolenaar 
7659c697322SBram Moolenaar 		    if (enc_dbcs != 0 && prev_cells > 1)
7669c697322SBram Moolenaar 			screen_char_2(off_to - prev_cells, row,
7679c697322SBram Moolenaar 						   col + coloff - prev_cells);
7689c697322SBram Moolenaar 		    else
7699c697322SBram Moolenaar 			screen_char(off_to - prev_cells, row,
7709c697322SBram Moolenaar 						   col + coloff - prev_cells);
7719c697322SBram Moolenaar 		}
772071d4279SBram Moolenaar 	    }
773071d4279SBram Moolenaar #endif
774071d4279SBram Moolenaar 	    screen_fill(row, row + 1, col + coloff, clear_width + coloff,
775071d4279SBram Moolenaar 								 ' ', ' ', 0);
776071d4279SBram Moolenaar 	    off_to += clear_width - col;
777071d4279SBram Moolenaar 	    col = clear_width;
778071d4279SBram Moolenaar 	}
779071d4279SBram Moolenaar     }
780071d4279SBram Moolenaar 
7814d784b21SBram Moolenaar     if (clear_width > 0
78205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
7834d784b21SBram Moolenaar 	    && !(flags & SLF_POPUP)  // no separator for popup window
7844d784b21SBram Moolenaar #endif
7854d784b21SBram Moolenaar 	    )
786071d4279SBram Moolenaar     {
7874d784b21SBram Moolenaar 	// For a window that has a right neighbor, draw the separator char
788aef5c62aSBram Moolenaar 	// right of the window contents.  But not on top of a popup window.
7894d784b21SBram Moolenaar 	if (coloff + col < Columns)
790071d4279SBram Moolenaar 	{
79105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
792c662ec99SBram Moolenaar 	    if (!blocked_by_popup(row, col + coloff))
793aef5c62aSBram Moolenaar #endif
794aef5c62aSBram Moolenaar 	    {
795071d4279SBram Moolenaar 		int c;
796071d4279SBram Moolenaar 
797071d4279SBram Moolenaar 		c = fillchar_vsep(&hl);
798c60c4f6eSBram Moolenaar 		if (ScreenLines[off_to] != (schar_T)c
799362e1a30SBram Moolenaar 			|| (enc_utf8 && (int)ScreenLinesUC[off_to]
800362e1a30SBram Moolenaar 							!= (c >= 0x80 ? c : 0))
801071d4279SBram Moolenaar 			|| ScreenAttrs[off_to] != hl)
802071d4279SBram Moolenaar 		{
803071d4279SBram Moolenaar 		    ScreenLines[off_to] = c;
804071d4279SBram Moolenaar 		    ScreenAttrs[off_to] = hl;
805071d4279SBram Moolenaar 		    if (enc_utf8)
806071d4279SBram Moolenaar 		    {
807071d4279SBram Moolenaar 			if (c >= 0x80)
808071d4279SBram Moolenaar 			{
809071d4279SBram Moolenaar 			    ScreenLinesUC[off_to] = c;
810362e1a30SBram Moolenaar 			    ScreenLinesC[0][off_to] = 0;
811071d4279SBram Moolenaar 			}
812071d4279SBram Moolenaar 			else
813071d4279SBram Moolenaar 			    ScreenLinesUC[off_to] = 0;
814071d4279SBram Moolenaar 		    }
815071d4279SBram Moolenaar 		    screen_char(off_to, row, col + coloff);
816071d4279SBram Moolenaar 		}
817071d4279SBram Moolenaar 	    }
818aef5c62aSBram Moolenaar 	}
819071d4279SBram Moolenaar 	else
820071d4279SBram Moolenaar 	    LineWraps[row] = FALSE;
821071d4279SBram Moolenaar     }
822071d4279SBram Moolenaar }
823071d4279SBram Moolenaar 
8240fa313a7SBram Moolenaar #if defined(FEAT_RIGHTLEFT) || defined(PROTO)
825071d4279SBram Moolenaar /*
8260fa313a7SBram Moolenaar  * Mirror text "str" for right-left displaying.
8270fa313a7SBram Moolenaar  * Only works for single-byte characters (e.g., numbers).
828071d4279SBram Moolenaar  */
8290fa313a7SBram Moolenaar     void
rl_mirror(char_u * str)83005540976SBram Moolenaar rl_mirror(char_u *str)
831071d4279SBram Moolenaar {
832071d4279SBram Moolenaar     char_u	*p1, *p2;
833071d4279SBram Moolenaar     int		t;
834071d4279SBram Moolenaar 
835071d4279SBram Moolenaar     for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
836071d4279SBram Moolenaar     {
837071d4279SBram Moolenaar 	t = *p1;
838071d4279SBram Moolenaar 	*p1 = *p2;
839071d4279SBram Moolenaar 	*p2 = t;
840071d4279SBram Moolenaar     }
841071d4279SBram Moolenaar }
842071d4279SBram Moolenaar #endif
843071d4279SBram Moolenaar 
844071d4279SBram Moolenaar /*
845071d4279SBram Moolenaar  * Draw the verticap separator right of window "wp" starting with line "row".
846071d4279SBram Moolenaar  */
8477528d1f6SBram Moolenaar     void
draw_vsep_win(win_T * wp,int row)84805540976SBram Moolenaar draw_vsep_win(win_T *wp, int row)
849071d4279SBram Moolenaar {
850071d4279SBram Moolenaar     int		hl;
851071d4279SBram Moolenaar     int		c;
852071d4279SBram Moolenaar 
853071d4279SBram Moolenaar     if (wp->w_vsep_width)
854071d4279SBram Moolenaar     {
85563d9e730SBram Moolenaar 	// draw the vertical separator right of this window
856071d4279SBram Moolenaar 	c = fillchar_vsep(&hl);
857071d4279SBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
858071d4279SBram Moolenaar 		W_ENDCOL(wp), W_ENDCOL(wp) + 1,
859071d4279SBram Moolenaar 		c, ' ', hl);
860071d4279SBram Moolenaar     }
861071d4279SBram Moolenaar }
862071d4279SBram Moolenaar 
863071d4279SBram Moolenaar #ifdef FEAT_WILDMENU
864baaa7e9eSBram Moolenaar static int skip_status_match_char(expand_T *xp, char_u *s);
865071d4279SBram Moolenaar 
866071d4279SBram Moolenaar /*
867367329baSBram Moolenaar  * Get the length of an item as it will be shown in the status line.
868071d4279SBram Moolenaar  */
869071d4279SBram Moolenaar     static int
status_match_len(expand_T * xp,char_u * s)87005540976SBram Moolenaar status_match_len(expand_T *xp, char_u *s)
871071d4279SBram Moolenaar {
872071d4279SBram Moolenaar     int	len = 0;
873071d4279SBram Moolenaar 
874071d4279SBram Moolenaar #ifdef FEAT_MENU
875071d4279SBram Moolenaar     int emenu = (xp->xp_context == EXPAND_MENUS
876071d4279SBram Moolenaar 	    || xp->xp_context == EXPAND_MENUNAMES);
877071d4279SBram Moolenaar 
87863d9e730SBram Moolenaar     // Check for menu separators - replace with '|'.
879071d4279SBram Moolenaar     if (emenu && menu_is_separator(s))
880071d4279SBram Moolenaar 	return 1;
881071d4279SBram Moolenaar #endif
882071d4279SBram Moolenaar 
883071d4279SBram Moolenaar     while (*s != NUL)
884071d4279SBram Moolenaar     {
8857693ec6eSBram Moolenaar 	s += skip_status_match_char(xp, s);
88681695250SBram Moolenaar 	len += ptr2cells(s);
88791acfffcSBram Moolenaar 	MB_PTR_ADV(s);
888071d4279SBram Moolenaar     }
889071d4279SBram Moolenaar 
890071d4279SBram Moolenaar     return len;
891071d4279SBram Moolenaar }
892071d4279SBram Moolenaar 
893071d4279SBram Moolenaar /*
8947693ec6eSBram Moolenaar  * Return the number of characters that should be skipped in a status match.
89535c54e56SBram Moolenaar  * These are backslashes used for escaping.  Do show backslashes in help tags.
89635c54e56SBram Moolenaar  */
89735c54e56SBram Moolenaar     static int
skip_status_match_char(expand_T * xp,char_u * s)89805540976SBram Moolenaar skip_status_match_char(expand_T *xp, char_u *s)
89935c54e56SBram Moolenaar {
9007693ec6eSBram Moolenaar     if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
90135c54e56SBram Moolenaar #ifdef FEAT_MENU
90235c54e56SBram Moolenaar 	    || ((xp->xp_context == EXPAND_MENUS
90335c54e56SBram Moolenaar 		    || xp->xp_context == EXPAND_MENUNAMES)
90435c54e56SBram Moolenaar 			  && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
90535c54e56SBram Moolenaar #endif
9067693ec6eSBram Moolenaar 	   )
9077693ec6eSBram Moolenaar     {
9087693ec6eSBram Moolenaar #ifndef BACKSLASH_IN_FILENAME
9097693ec6eSBram Moolenaar 	if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
9107693ec6eSBram Moolenaar 	    return 2;
9117693ec6eSBram Moolenaar #endif
9127693ec6eSBram Moolenaar 	return 1;
9137693ec6eSBram Moolenaar     }
9147693ec6eSBram Moolenaar     return 0;
91535c54e56SBram Moolenaar }
91635c54e56SBram Moolenaar 
91735c54e56SBram Moolenaar /*
918071d4279SBram Moolenaar  * Show wildchar matches in the status line.
919071d4279SBram Moolenaar  * Show at least the "match" item.
920071d4279SBram Moolenaar  * We start at item 'first_match' in the list and show all matches that fit.
921071d4279SBram Moolenaar  *
922071d4279SBram Moolenaar  * If inversion is possible we use it. Else '=' characters are used.
923071d4279SBram Moolenaar  */
924071d4279SBram Moolenaar     void
win_redr_status_matches(expand_T * xp,int num_matches,char_u ** matches,int match,int showtail)92505540976SBram Moolenaar win_redr_status_matches(
92605540976SBram Moolenaar     expand_T	*xp,
92705540976SBram Moolenaar     int		num_matches,
92863d9e730SBram Moolenaar     char_u	**matches,	// list of matches
92905540976SBram Moolenaar     int		match,
93005540976SBram Moolenaar     int		showtail)
931071d4279SBram Moolenaar {
932071d4279SBram Moolenaar #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
933071d4279SBram Moolenaar     int		row;
934071d4279SBram Moolenaar     char_u	*buf;
935071d4279SBram Moolenaar     int		len;
93663d9e730SBram Moolenaar     int		clen;		// length in screen cells
937071d4279SBram Moolenaar     int		fillchar;
938071d4279SBram Moolenaar     int		attr;
939071d4279SBram Moolenaar     int		i;
940071d4279SBram Moolenaar     int		highlight = TRUE;
941071d4279SBram Moolenaar     char_u	*selstart = NULL;
942071d4279SBram Moolenaar     int		selstart_col = 0;
943071d4279SBram Moolenaar     char_u	*selend = NULL;
944071d4279SBram Moolenaar     static int	first_match = 0;
945071d4279SBram Moolenaar     int		add_left = FALSE;
946071d4279SBram Moolenaar     char_u	*s;
947071d4279SBram Moolenaar #ifdef FEAT_MENU
948071d4279SBram Moolenaar     int		emenu;
949071d4279SBram Moolenaar #endif
950071d4279SBram Moolenaar     int		l;
951071d4279SBram Moolenaar 
95263d9e730SBram Moolenaar     if (matches == NULL)	// interrupted completion?
953071d4279SBram Moolenaar 	return;
954071d4279SBram Moolenaar 
9551cd871b5SBram Moolenaar     if (has_mbyte)
956964b3746SBram Moolenaar 	buf = alloc(Columns * MB_MAXBYTES + 1);
9571cd871b5SBram Moolenaar     else
958964b3746SBram Moolenaar 	buf = alloc(Columns + 1);
959071d4279SBram Moolenaar     if (buf == NULL)
960071d4279SBram Moolenaar 	return;
961071d4279SBram Moolenaar 
96263d9e730SBram Moolenaar     if (match == -1)	// don't show match but original text
963071d4279SBram Moolenaar     {
964071d4279SBram Moolenaar 	match = 0;
965071d4279SBram Moolenaar 	highlight = FALSE;
966071d4279SBram Moolenaar     }
96763d9e730SBram Moolenaar     // count 1 for the ending ">"
968071d4279SBram Moolenaar     clen = status_match_len(xp, L_MATCH(match)) + 3;
969071d4279SBram Moolenaar     if (match == 0)
970071d4279SBram Moolenaar 	first_match = 0;
971071d4279SBram Moolenaar     else if (match < first_match)
972071d4279SBram Moolenaar     {
97363d9e730SBram Moolenaar 	// jumping left, as far as we can go
974071d4279SBram Moolenaar 	first_match = match;
975071d4279SBram Moolenaar 	add_left = TRUE;
976071d4279SBram Moolenaar     }
977071d4279SBram Moolenaar     else
978071d4279SBram Moolenaar     {
97963d9e730SBram Moolenaar 	// check if match fits on the screen
980071d4279SBram Moolenaar 	for (i = first_match; i < match; ++i)
981071d4279SBram Moolenaar 	    clen += status_match_len(xp, L_MATCH(i)) + 2;
982071d4279SBram Moolenaar 	if (first_match > 0)
983071d4279SBram Moolenaar 	    clen += 2;
98463d9e730SBram Moolenaar 	// jumping right, put match at the left
985071d4279SBram Moolenaar 	if ((long)clen > Columns)
986071d4279SBram Moolenaar 	{
987071d4279SBram Moolenaar 	    first_match = match;
98863d9e730SBram Moolenaar 	    // if showing the last match, we can add some on the left
989071d4279SBram Moolenaar 	    clen = 2;
990071d4279SBram Moolenaar 	    for (i = match; i < num_matches; ++i)
991071d4279SBram Moolenaar 	    {
992071d4279SBram Moolenaar 		clen += status_match_len(xp, L_MATCH(i)) + 2;
993071d4279SBram Moolenaar 		if ((long)clen >= Columns)
994071d4279SBram Moolenaar 		    break;
995071d4279SBram Moolenaar 	    }
996071d4279SBram Moolenaar 	    if (i == num_matches)
997071d4279SBram Moolenaar 		add_left = TRUE;
998071d4279SBram Moolenaar 	}
999071d4279SBram Moolenaar     }
1000071d4279SBram Moolenaar     if (add_left)
1001071d4279SBram Moolenaar 	while (first_match > 0)
1002071d4279SBram Moolenaar 	{
1003071d4279SBram Moolenaar 	    clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
1004071d4279SBram Moolenaar 	    if ((long)clen >= Columns)
1005071d4279SBram Moolenaar 		break;
1006071d4279SBram Moolenaar 	    --first_match;
1007071d4279SBram Moolenaar 	}
1008071d4279SBram Moolenaar 
10093633cf52SBram Moolenaar     fillchar = fillchar_status(&attr, curwin);
1010071d4279SBram Moolenaar 
1011071d4279SBram Moolenaar     if (first_match == 0)
1012071d4279SBram Moolenaar     {
1013071d4279SBram Moolenaar 	*buf = NUL;
1014071d4279SBram Moolenaar 	len = 0;
1015071d4279SBram Moolenaar     }
1016071d4279SBram Moolenaar     else
1017071d4279SBram Moolenaar     {
1018071d4279SBram Moolenaar 	STRCPY(buf, "< ");
1019071d4279SBram Moolenaar 	len = 2;
1020071d4279SBram Moolenaar     }
1021071d4279SBram Moolenaar     clen = len;
1022071d4279SBram Moolenaar 
1023071d4279SBram Moolenaar     i = first_match;
1024071d4279SBram Moolenaar     while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
1025071d4279SBram Moolenaar     {
1026071d4279SBram Moolenaar 	if (i == match)
1027071d4279SBram Moolenaar 	{
1028071d4279SBram Moolenaar 	    selstart = buf + len;
1029071d4279SBram Moolenaar 	    selstart_col = clen;
1030071d4279SBram Moolenaar 	}
1031071d4279SBram Moolenaar 
1032071d4279SBram Moolenaar 	s = L_MATCH(i);
103363d9e730SBram Moolenaar 	// Check for menu separators - replace with '|'
1034071d4279SBram Moolenaar #ifdef FEAT_MENU
1035071d4279SBram Moolenaar 	emenu = (xp->xp_context == EXPAND_MENUS
1036071d4279SBram Moolenaar 		|| xp->xp_context == EXPAND_MENUNAMES);
1037071d4279SBram Moolenaar 	if (emenu && menu_is_separator(s))
1038071d4279SBram Moolenaar 	{
1039071d4279SBram Moolenaar 	    STRCPY(buf + len, transchar('|'));
1040071d4279SBram Moolenaar 	    l = (int)STRLEN(buf + len);
1041071d4279SBram Moolenaar 	    len += l;
1042071d4279SBram Moolenaar 	    clen += l;
1043071d4279SBram Moolenaar 	}
1044071d4279SBram Moolenaar 	else
1045071d4279SBram Moolenaar #endif
1046071d4279SBram Moolenaar 	    for ( ; *s != NUL; ++s)
1047071d4279SBram Moolenaar 	{
10487693ec6eSBram Moolenaar 	    s += skip_status_match_char(xp, s);
1049071d4279SBram Moolenaar 	    clen += ptr2cells(s);
10500fa313a7SBram Moolenaar 	    if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
1051071d4279SBram Moolenaar 	    {
1052071d4279SBram Moolenaar 		STRNCPY(buf + len, s, l);
1053071d4279SBram Moolenaar 		s += l - 1;
1054071d4279SBram Moolenaar 		len += l;
1055071d4279SBram Moolenaar 	    }
1056071d4279SBram Moolenaar 	    else
1057071d4279SBram Moolenaar 	    {
1058071d4279SBram Moolenaar 		STRCPY(buf + len, transchar_byte(*s));
1059071d4279SBram Moolenaar 		len += (int)STRLEN(buf + len);
1060071d4279SBram Moolenaar 	    }
1061071d4279SBram Moolenaar 	}
1062071d4279SBram Moolenaar 	if (i == match)
1063071d4279SBram Moolenaar 	    selend = buf + len;
1064071d4279SBram Moolenaar 
1065071d4279SBram Moolenaar 	*(buf + len++) = ' ';
1066071d4279SBram Moolenaar 	*(buf + len++) = ' ';
1067071d4279SBram Moolenaar 	clen += 2;
1068071d4279SBram Moolenaar 	if (++i == num_matches)
1069071d4279SBram Moolenaar 		break;
1070071d4279SBram Moolenaar     }
1071071d4279SBram Moolenaar 
1072071d4279SBram Moolenaar     if (i != num_matches)
1073071d4279SBram Moolenaar     {
1074071d4279SBram Moolenaar 	*(buf + len++) = '>';
1075071d4279SBram Moolenaar 	++clen;
1076071d4279SBram Moolenaar     }
1077071d4279SBram Moolenaar 
1078071d4279SBram Moolenaar     buf[len] = NUL;
1079071d4279SBram Moolenaar 
1080071d4279SBram Moolenaar     row = cmdline_row - 1;
1081071d4279SBram Moolenaar     if (row >= 0)
1082071d4279SBram Moolenaar     {
1083071d4279SBram Moolenaar 	if (wild_menu_showing == 0)
1084071d4279SBram Moolenaar 	{
1085071d4279SBram Moolenaar 	    if (msg_scrolled > 0)
1086071d4279SBram Moolenaar 	    {
108763d9e730SBram Moolenaar 		// Put the wildmenu just above the command line.  If there is
108863d9e730SBram Moolenaar 		// no room, scroll the screen one line up.
1089071d4279SBram Moolenaar 		if (cmdline_row == Rows - 1)
1090071d4279SBram Moolenaar 		{
1091cfce7171SBram Moolenaar 		    screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
1092071d4279SBram Moolenaar 		    ++msg_scrolled;
1093071d4279SBram Moolenaar 		}
1094071d4279SBram Moolenaar 		else
1095071d4279SBram Moolenaar 		{
1096071d4279SBram Moolenaar 		    ++cmdline_row;
1097071d4279SBram Moolenaar 		    ++row;
1098071d4279SBram Moolenaar 		}
1099071d4279SBram Moolenaar 		wild_menu_showing = WM_SCROLLED;
1100071d4279SBram Moolenaar 	    }
1101071d4279SBram Moolenaar 	    else
1102071d4279SBram Moolenaar 	    {
110363d9e730SBram Moolenaar 		// Create status line if needed by setting 'laststatus' to 2.
110463d9e730SBram Moolenaar 		// Set 'winminheight' to zero to avoid that the window is
110563d9e730SBram Moolenaar 		// resized.
1106071d4279SBram Moolenaar 		if (lastwin->w_status_height == 0)
1107071d4279SBram Moolenaar 		{
1108071d4279SBram Moolenaar 		    save_p_ls = p_ls;
1109071d4279SBram Moolenaar 		    save_p_wmh = p_wmh;
1110071d4279SBram Moolenaar 		    p_ls = 2;
1111071d4279SBram Moolenaar 		    p_wmh = 0;
1112071d4279SBram Moolenaar 		    last_status(FALSE);
1113071d4279SBram Moolenaar 		}
1114071d4279SBram Moolenaar 		wild_menu_showing = WM_SHOWN;
1115071d4279SBram Moolenaar 	    }
1116071d4279SBram Moolenaar 	}
1117071d4279SBram Moolenaar 
1118071d4279SBram Moolenaar 	screen_puts(buf, row, 0, attr);
1119071d4279SBram Moolenaar 	if (selstart != NULL && highlight)
1120071d4279SBram Moolenaar 	{
1121071d4279SBram Moolenaar 	    *selend = NUL;
11228820b486SBram Moolenaar 	    screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
1123071d4279SBram Moolenaar 	}
1124071d4279SBram Moolenaar 
1125071d4279SBram Moolenaar 	screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
1126071d4279SBram Moolenaar     }
1127071d4279SBram Moolenaar 
1128071d4279SBram Moolenaar     win_redraw_last_status(topframe);
1129071d4279SBram Moolenaar     vim_free(buf);
1130071d4279SBram Moolenaar }
1131071d4279SBram Moolenaar #endif
1132071d4279SBram Moolenaar 
1133071d4279SBram Moolenaar /*
1134071d4279SBram Moolenaar  * Return TRUE if the status line of window "wp" is connected to the status
1135071d4279SBram Moolenaar  * line of the window right of it.  If not, then it's a vertical separator.
1136071d4279SBram Moolenaar  * Only call if (wp->w_vsep_width != 0).
1137071d4279SBram Moolenaar  */
1138071d4279SBram Moolenaar     int
stl_connected(win_T * wp)113905540976SBram Moolenaar stl_connected(win_T *wp)
1140071d4279SBram Moolenaar {
1141071d4279SBram Moolenaar     frame_T	*fr;
1142071d4279SBram Moolenaar 
1143071d4279SBram Moolenaar     fr = wp->w_frame;
1144071d4279SBram Moolenaar     while (fr->fr_parent != NULL)
1145071d4279SBram Moolenaar     {
1146071d4279SBram Moolenaar 	if (fr->fr_parent->fr_layout == FR_COL)
1147071d4279SBram Moolenaar 	{
1148071d4279SBram Moolenaar 	    if (fr->fr_next != NULL)
1149071d4279SBram Moolenaar 		break;
1150071d4279SBram Moolenaar 	}
1151071d4279SBram Moolenaar 	else
1152071d4279SBram Moolenaar 	{
1153071d4279SBram Moolenaar 	    if (fr->fr_next != NULL)
1154071d4279SBram Moolenaar 		return TRUE;
1155071d4279SBram Moolenaar 	}
1156071d4279SBram Moolenaar 	fr = fr->fr_parent;
1157071d4279SBram Moolenaar     }
1158071d4279SBram Moolenaar     return FALSE;
1159071d4279SBram Moolenaar }
1160071d4279SBram Moolenaar 
1161071d4279SBram Moolenaar 
1162071d4279SBram Moolenaar /*
1163071d4279SBram Moolenaar  * Get the value to show for the language mappings, active 'keymap'.
1164071d4279SBram Moolenaar  */
1165071d4279SBram Moolenaar     int
get_keymap_str(win_T * wp,char_u * fmt,char_u * buf,int len)116605540976SBram Moolenaar get_keymap_str(
116705540976SBram Moolenaar     win_T	*wp,
116863d9e730SBram Moolenaar     char_u	*fmt,	    // format string containing one %s item
116963d9e730SBram Moolenaar     char_u	*buf,	    // buffer for the result
117063d9e730SBram Moolenaar     int		len)	    // length of buffer
1171071d4279SBram Moolenaar {
1172071d4279SBram Moolenaar     char_u	*p;
1173071d4279SBram Moolenaar 
1174071d4279SBram Moolenaar     if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
1175071d4279SBram Moolenaar 	return FALSE;
1176071d4279SBram Moolenaar 
1177071d4279SBram Moolenaar     {
1178071d4279SBram Moolenaar #ifdef FEAT_EVAL
1179071d4279SBram Moolenaar 	buf_T	*old_curbuf = curbuf;
1180071d4279SBram Moolenaar 	win_T	*old_curwin = curwin;
1181071d4279SBram Moolenaar 	char_u	*s;
1182071d4279SBram Moolenaar 
1183071d4279SBram Moolenaar 	curbuf = wp->w_buffer;
1184071d4279SBram Moolenaar 	curwin = wp;
118563d9e730SBram Moolenaar 	STRCPY(buf, "b:keymap_name");	// must be writable
1186071d4279SBram Moolenaar 	++emsg_skip;
1187b171fb17SBram Moolenaar 	s = p = eval_to_string(buf, FALSE);
1188071d4279SBram Moolenaar 	--emsg_skip;
1189071d4279SBram Moolenaar 	curbuf = old_curbuf;
1190071d4279SBram Moolenaar 	curwin = old_curwin;
1191071d4279SBram Moolenaar 	if (p == NULL || *p == NUL)
1192071d4279SBram Moolenaar #endif
1193071d4279SBram Moolenaar 	{
1194071d4279SBram Moolenaar #ifdef FEAT_KEYMAP
1195071d4279SBram Moolenaar 	    if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
1196071d4279SBram Moolenaar 		p = wp->w_buffer->b_p_keymap;
1197071d4279SBram Moolenaar 	    else
1198071d4279SBram Moolenaar #endif
1199071d4279SBram Moolenaar 		p = (char_u *)"lang";
1200071d4279SBram Moolenaar 	}
120173ac0c42SBram Moolenaar 	if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
1202071d4279SBram Moolenaar 	    buf[0] = NUL;
1203071d4279SBram Moolenaar #ifdef FEAT_EVAL
1204071d4279SBram Moolenaar 	vim_free(s);
1205071d4279SBram Moolenaar #endif
1206071d4279SBram Moolenaar     }
1207071d4279SBram Moolenaar     return buf[0] != NUL;
1208071d4279SBram Moolenaar }
1209071d4279SBram Moolenaar 
1210071d4279SBram Moolenaar #if defined(FEAT_STL_OPT) || defined(PROTO)
1211071d4279SBram Moolenaar /*
1212faa959a8SBram Moolenaar  * Redraw the status line or ruler of window "wp".
1213faa959a8SBram Moolenaar  * When "wp" is NULL redraw the tab pages line from 'tabline'.
1214071d4279SBram Moolenaar  */
12157528d1f6SBram Moolenaar     void
win_redr_custom(win_T * wp,int draw_ruler)121605540976SBram Moolenaar win_redr_custom(
121705540976SBram Moolenaar     win_T	*wp,
12187528d1f6SBram Moolenaar     int		draw_ruler)	// TRUE or FALSE
1219071d4279SBram Moolenaar {
12201d633413SBram Moolenaar     static int	entered = FALSE;
1221071d4279SBram Moolenaar     int		attr;
1222071d4279SBram Moolenaar     int		curattr;
1223071d4279SBram Moolenaar     int		row;
1224071d4279SBram Moolenaar     int		col = 0;
1225071d4279SBram Moolenaar     int		maxwidth;
1226071d4279SBram Moolenaar     int		width;
1227071d4279SBram Moolenaar     int		n;
1228071d4279SBram Moolenaar     int		len;
1229071d4279SBram Moolenaar     int		fillchar;
1230071d4279SBram Moolenaar     char_u	buf[MAXPATHL];
1231362f3569SBram Moolenaar     char_u	*stl;
1232071d4279SBram Moolenaar     char_u	*p;
12338133cc6bSBram Moolenaar     stl_hlrec_T *hltab;
12348133cc6bSBram Moolenaar     stl_hlrec_T *tabtab;
1235faa959a8SBram Moolenaar     int		use_sandbox = FALSE;
12366145285cSBram Moolenaar     win_T	*ewp;
12376145285cSBram Moolenaar     int		p_crb_save;
1238071d4279SBram Moolenaar 
12397528d1f6SBram Moolenaar     // There is a tiny chance that this gets called recursively: When
12407528d1f6SBram Moolenaar     // redrawing a status line triggers redrawing the ruler or tabline.
12417528d1f6SBram Moolenaar     // Avoid trouble by not allowing recursion.
12421d633413SBram Moolenaar     if (entered)
12431d633413SBram Moolenaar 	return;
12441d633413SBram Moolenaar     entered = TRUE;
12451d633413SBram Moolenaar 
12467528d1f6SBram Moolenaar     // setup environment for the task at hand
1247faa959a8SBram Moolenaar     if (wp == NULL)
1248faa959a8SBram Moolenaar     {
12497528d1f6SBram Moolenaar 	// Use 'tabline'.  Always at the first line of the screen.
1250362f3569SBram Moolenaar 	stl = p_tal;
1251faa959a8SBram Moolenaar 	row = 0;
125265c923adSBram Moolenaar 	fillchar = ' ';
12538820b486SBram Moolenaar 	attr = HL_ATTR(HLF_TPF);
1254faa959a8SBram Moolenaar 	maxwidth = Columns;
1255faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1256d1f56e68SBram Moolenaar 	use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
1257faa959a8SBram Moolenaar # endif
1258faa959a8SBram Moolenaar     }
1259faa959a8SBram Moolenaar     else
1260faa959a8SBram Moolenaar     {
126149c51b82SBram Moolenaar 	row = statusline_row(wp);
12623633cf52SBram Moolenaar 	fillchar = fillchar_status(&attr, wp);
12630263146bSBram Moolenaar 	maxwidth = wp->w_width;
1264faa959a8SBram Moolenaar 
12659372a11cSBram Moolenaar 	if (draw_ruler)
1266071d4279SBram Moolenaar 	{
1267362f3569SBram Moolenaar 	    stl = p_ruf;
12687528d1f6SBram Moolenaar 	    // advance past any leading group spec - implicit in ru_col
1269362f3569SBram Moolenaar 	    if (*stl == '%')
1270071d4279SBram Moolenaar 	    {
1271362f3569SBram Moolenaar 		if (*++stl == '-')
1272362f3569SBram Moolenaar 		    stl++;
1273362f3569SBram Moolenaar 		if (atoi((char *)stl))
1274362f3569SBram Moolenaar 		    while (VIM_ISDIGIT(*stl))
1275362f3569SBram Moolenaar 			stl++;
1276362f3569SBram Moolenaar 		if (*stl++ != '(')
1277362f3569SBram Moolenaar 		    stl = p_ruf;
1278071d4279SBram Moolenaar 	    }
12790263146bSBram Moolenaar 	    col = ru_col - (Columns - wp->w_width);
12800263146bSBram Moolenaar 	    if (col < (wp->w_width + 1) / 2)
12810263146bSBram Moolenaar 		col = (wp->w_width + 1) / 2;
12820263146bSBram Moolenaar 	    maxwidth = wp->w_width - col;
1283071d4279SBram Moolenaar 	    if (!wp->w_status_height)
1284071d4279SBram Moolenaar 	    {
1285071d4279SBram Moolenaar 		row = Rows - 1;
12867528d1f6SBram Moolenaar 		--maxwidth;	// writing in last column may cause scrolling
1287071d4279SBram Moolenaar 		fillchar = ' ';
1288071d4279SBram Moolenaar 		attr = 0;
1289071d4279SBram Moolenaar 	    }
1290faa959a8SBram Moolenaar 
1291faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1292d1f56e68SBram Moolenaar 	    use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
1293faa959a8SBram Moolenaar # endif
1294071d4279SBram Moolenaar 	}
1295faa959a8SBram Moolenaar 	else
1296faa959a8SBram Moolenaar 	{
1297faa959a8SBram Moolenaar 	    if (*wp->w_p_stl != NUL)
1298362f3569SBram Moolenaar 		stl = wp->w_p_stl;
1299faa959a8SBram Moolenaar 	    else
1300362f3569SBram Moolenaar 		stl = p_stl;
1301faa959a8SBram Moolenaar # ifdef FEAT_EVAL
1302d1f56e68SBram Moolenaar 	    use_sandbox = was_set_insecurely((char_u *)"statusline",
1303d1f56e68SBram Moolenaar 					 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
1304faa959a8SBram Moolenaar # endif
1305faa959a8SBram Moolenaar 	}
1306faa959a8SBram Moolenaar 
130753f8174eSBram Moolenaar 	col += wp->w_wincol;
1308faa959a8SBram Moolenaar     }
1309071d4279SBram Moolenaar 
1310faa959a8SBram Moolenaar     if (maxwidth <= 0)
13111d633413SBram Moolenaar 	goto theend;
1312faa959a8SBram Moolenaar 
13137528d1f6SBram Moolenaar     // Temporarily reset 'cursorbind', we don't want a side effect from moving
13147528d1f6SBram Moolenaar     // the cursor away and back.
13156145285cSBram Moolenaar     ewp = wp == NULL ? curwin : wp;
13166145285cSBram Moolenaar     p_crb_save = ewp->w_p_crb;
13176145285cSBram Moolenaar     ewp->w_p_crb = FALSE;
13186145285cSBram Moolenaar 
13197528d1f6SBram Moolenaar     // Make a copy, because the statusline may include a function call that
13207528d1f6SBram Moolenaar     // might change the option value and free the memory.
1321362f3569SBram Moolenaar     stl = vim_strsave(stl);
13226145285cSBram Moolenaar     width = build_stl_str_hl(ewp, buf, sizeof(buf),
1323362f3569SBram Moolenaar 				stl, use_sandbox,
13248133cc6bSBram Moolenaar 				fillchar, maxwidth, &hltab, &tabtab);
1325362f3569SBram Moolenaar     vim_free(stl);
13266145285cSBram Moolenaar     ewp->w_p_crb = p_crb_save;
1327071d4279SBram Moolenaar 
13287528d1f6SBram Moolenaar     // Make all characters printable.
13297c5676b5SBram Moolenaar     p = transstr(buf);
13307c5676b5SBram Moolenaar     if (p != NULL)
13317c5676b5SBram Moolenaar     {
13327c5676b5SBram Moolenaar 	vim_strncpy(buf, p, sizeof(buf) - 1);
13337c5676b5SBram Moolenaar 	vim_free(p);
13347c5676b5SBram Moolenaar     }
13357c5676b5SBram Moolenaar 
13367528d1f6SBram Moolenaar     // fill up with "fillchar"
13377c5676b5SBram Moolenaar     len = (int)STRLEN(buf);
13382c4278fcSBram Moolenaar     while (width < maxwidth && len < (int)sizeof(buf) - 1)
1339071d4279SBram Moolenaar     {
1340071d4279SBram Moolenaar 	len += (*mb_char2bytes)(fillchar, buf + len);
1341071d4279SBram Moolenaar 	++width;
1342071d4279SBram Moolenaar     }
1343071d4279SBram Moolenaar     buf[len] = NUL;
1344071d4279SBram Moolenaar 
1345d1f56e68SBram Moolenaar     /*
1346d1f56e68SBram Moolenaar      * Draw each snippet with the specified highlighting.
1347d1f56e68SBram Moolenaar      */
1348071d4279SBram Moolenaar     curattr = attr;
1349071d4279SBram Moolenaar     p = buf;
1350d1f56e68SBram Moolenaar     for (n = 0; hltab[n].start != NULL; n++)
1351071d4279SBram Moolenaar     {
1352d1f56e68SBram Moolenaar 	len = (int)(hltab[n].start - p);
1353071d4279SBram Moolenaar 	screen_puts_len(p, len, row, col, curattr);
1354071d4279SBram Moolenaar 	col += vim_strnsize(p, len);
1355d1f56e68SBram Moolenaar 	p = hltab[n].start;
1356071d4279SBram Moolenaar 
1357d1f56e68SBram Moolenaar 	if (hltab[n].userhl == 0)
1358071d4279SBram Moolenaar 	    curattr = attr;
1359d1f56e68SBram Moolenaar 	else if (hltab[n].userhl < 0)
1360d1f56e68SBram Moolenaar 	    curattr = syn_id2attr(-hltab[n].userhl);
1361bce4f62dSBram Moolenaar #ifdef FEAT_TERMINAL
136205fbfdcdSBram Moolenaar 	else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
136305fbfdcdSBram Moolenaar 						   && wp->w_status_height != 0)
136405fbfdcdSBram Moolenaar 	    curattr = highlight_stltermnc[hltab[n].userhl - 1];
1365bce4f62dSBram Moolenaar 	else if (wp != NULL && bt_terminal(wp->w_buffer)
1366bce4f62dSBram Moolenaar 						   && wp->w_status_height != 0)
1367bce4f62dSBram Moolenaar 	    curattr = highlight_stlterm[hltab[n].userhl - 1];
1368bce4f62dSBram Moolenaar #endif
1369238a5649SBram Moolenaar 	else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
1370d1f56e68SBram Moolenaar 	    curattr = highlight_stlnc[hltab[n].userhl - 1];
1371071d4279SBram Moolenaar 	else
1372d1f56e68SBram Moolenaar 	    curattr = highlight_user[hltab[n].userhl - 1];
1373071d4279SBram Moolenaar     }
1374071d4279SBram Moolenaar     screen_puts(p, row, col, curattr);
1375d1f56e68SBram Moolenaar 
1376d1f56e68SBram Moolenaar     if (wp == NULL)
1377d1f56e68SBram Moolenaar     {
13787528d1f6SBram Moolenaar 	// Fill the TabPageIdxs[] array for clicking in the tab pagesline.
1379d1f56e68SBram Moolenaar 	col = 0;
1380d1f56e68SBram Moolenaar 	len = 0;
1381d1f56e68SBram Moolenaar 	p = buf;
1382d1f56e68SBram Moolenaar 	fillchar = 0;
1383d1f56e68SBram Moolenaar 	for (n = 0; tabtab[n].start != NULL; n++)
1384d1f56e68SBram Moolenaar 	{
1385d1f56e68SBram Moolenaar 	    len += vim_strnsize(p, (int)(tabtab[n].start - p));
1386d1f56e68SBram Moolenaar 	    while (col < len)
1387d1f56e68SBram Moolenaar 		TabPageIdxs[col++] = fillchar;
1388d1f56e68SBram Moolenaar 	    p = tabtab[n].start;
1389d1f56e68SBram Moolenaar 	    fillchar = tabtab[n].userhl;
1390d1f56e68SBram Moolenaar 	}
1391d1f56e68SBram Moolenaar 	while (col < Columns)
1392d1f56e68SBram Moolenaar 	    TabPageIdxs[col++] = fillchar;
1393d1f56e68SBram Moolenaar     }
13941d633413SBram Moolenaar 
13951d633413SBram Moolenaar theend:
13961d633413SBram Moolenaar     entered = FALSE;
1397071d4279SBram Moolenaar }
1398071d4279SBram Moolenaar 
13997528d1f6SBram Moolenaar #endif // FEAT_STL_OPT
1400071d4279SBram Moolenaar 
1401071d4279SBram Moolenaar /*
1402071d4279SBram Moolenaar  * Output a single character directly to the screen and update ScreenLines.
1403071d4279SBram Moolenaar  */
1404071d4279SBram Moolenaar     void
screen_putchar(int c,int row,int col,int attr)140505540976SBram Moolenaar screen_putchar(int c, int row, int col, int attr)
1406071d4279SBram Moolenaar {
1407071d4279SBram Moolenaar     char_u	buf[MB_MAXBYTES + 1];
1408071d4279SBram Moolenaar 
14099a920d8cSBram Moolenaar     if (has_mbyte)
1410071d4279SBram Moolenaar 	buf[(*mb_char2bytes)(c, buf)] = NUL;
14119a920d8cSBram Moolenaar     else
14129a920d8cSBram Moolenaar     {
1413071d4279SBram Moolenaar 	buf[0] = c;
1414071d4279SBram Moolenaar 	buf[1] = NUL;
14159a920d8cSBram Moolenaar     }
1416071d4279SBram Moolenaar     screen_puts(buf, row, col, attr);
1417071d4279SBram Moolenaar }
1418071d4279SBram Moolenaar 
1419071d4279SBram Moolenaar /*
1420071d4279SBram Moolenaar  * Get a single character directly from ScreenLines into "bytes[]".
1421071d4279SBram Moolenaar  * Also return its attribute in *attrp;
1422071d4279SBram Moolenaar  */
1423071d4279SBram Moolenaar     void
screen_getbytes(int row,int col,char_u * bytes,int * attrp)142405540976SBram Moolenaar screen_getbytes(int row, int col, char_u *bytes, int *attrp)
1425071d4279SBram Moolenaar {
1426071d4279SBram Moolenaar     unsigned off;
1427071d4279SBram Moolenaar 
14287528d1f6SBram Moolenaar     // safety check
1429071d4279SBram Moolenaar     if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
1430071d4279SBram Moolenaar     {
1431071d4279SBram Moolenaar 	off = LineOffset[row] + col;
1432071d4279SBram Moolenaar 	*attrp = ScreenAttrs[off];
1433071d4279SBram Moolenaar 	bytes[0] = ScreenLines[off];
1434071d4279SBram Moolenaar 	bytes[1] = NUL;
1435071d4279SBram Moolenaar 
1436071d4279SBram Moolenaar 	if (enc_utf8 && ScreenLinesUC[off] != 0)
1437071d4279SBram Moolenaar 	    bytes[utfc_char2bytes(off, bytes)] = NUL;
1438071d4279SBram Moolenaar 	else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
1439071d4279SBram Moolenaar 	{
1440071d4279SBram Moolenaar 	    bytes[0] = ScreenLines[off];
1441071d4279SBram Moolenaar 	    bytes[1] = ScreenLines2[off];
1442071d4279SBram Moolenaar 	    bytes[2] = NUL;
1443071d4279SBram Moolenaar 	}
1444071d4279SBram Moolenaar 	else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
1445071d4279SBram Moolenaar 	{
1446071d4279SBram Moolenaar 	    bytes[1] = ScreenLines[off + 1];
1447071d4279SBram Moolenaar 	    bytes[2] = NUL;
1448071d4279SBram Moolenaar 	}
1449071d4279SBram Moolenaar     }
1450071d4279SBram Moolenaar }
1451071d4279SBram Moolenaar 
1452362e1a30SBram Moolenaar /*
1453362e1a30SBram Moolenaar  * Return TRUE if composing characters for screen posn "off" differs from
1454362e1a30SBram Moolenaar  * composing characters in "u8cc".
145570c49c1aSBram Moolenaar  * Only to be used when ScreenLinesUC[off] != 0.
1456362e1a30SBram Moolenaar  */
1457362e1a30SBram Moolenaar     static int
screen_comp_differs(int off,int * u8cc)145805540976SBram Moolenaar screen_comp_differs(int off, int *u8cc)
1459362e1a30SBram Moolenaar {
1460362e1a30SBram Moolenaar     int	    i;
1461362e1a30SBram Moolenaar 
1462362e1a30SBram Moolenaar     for (i = 0; i < Screen_mco; ++i)
1463362e1a30SBram Moolenaar     {
1464362e1a30SBram Moolenaar 	if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
1465362e1a30SBram Moolenaar 	    return TRUE;
1466362e1a30SBram Moolenaar 	if (u8cc[i] == 0)
1467362e1a30SBram Moolenaar 	    break;
1468362e1a30SBram Moolenaar     }
1469362e1a30SBram Moolenaar     return FALSE;
1470362e1a30SBram Moolenaar }
1471362e1a30SBram Moolenaar 
1472071d4279SBram Moolenaar /*
1473071d4279SBram Moolenaar  * Put string '*text' on the screen at position 'row' and 'col', with
1474071d4279SBram Moolenaar  * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
1475071d4279SBram Moolenaar  * Note: only outputs within one row, message is truncated at screen boundary!
1476071d4279SBram Moolenaar  * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
1477071d4279SBram Moolenaar  */
1478071d4279SBram Moolenaar     void
screen_puts(char_u * text,int row,int col,int attr)147905540976SBram Moolenaar screen_puts(
148005540976SBram Moolenaar     char_u	*text,
148105540976SBram Moolenaar     int		row,
148205540976SBram Moolenaar     int		col,
148305540976SBram Moolenaar     int		attr)
1484071d4279SBram Moolenaar {
1485071d4279SBram Moolenaar     screen_puts_len(text, -1, row, col, attr);
1486071d4279SBram Moolenaar }
1487071d4279SBram Moolenaar 
1488071d4279SBram Moolenaar /*
1489071d4279SBram Moolenaar  * Like screen_puts(), but output "text[len]".  When "len" is -1 output up to
1490071d4279SBram Moolenaar  * a NUL.
1491071d4279SBram Moolenaar  */
1492071d4279SBram Moolenaar     void
screen_puts_len(char_u * text,int textlen,int row,int col,int attr)149305540976SBram Moolenaar screen_puts_len(
149405540976SBram Moolenaar     char_u	*text,
149505540976SBram Moolenaar     int		textlen,
149605540976SBram Moolenaar     int		row,
149705540976SBram Moolenaar     int		col,
149805540976SBram Moolenaar     int		attr)
1499071d4279SBram Moolenaar {
1500071d4279SBram Moolenaar     unsigned	off;
1501071d4279SBram Moolenaar     char_u	*ptr = text;
1502e4c21e68SBram Moolenaar     int		len = textlen;
1503071d4279SBram Moolenaar     int		c;
1504367329baSBram Moolenaar     unsigned	max_off;
1505071d4279SBram Moolenaar     int		mbyte_blen = 1;
1506071d4279SBram Moolenaar     int		mbyte_cells = 1;
1507071d4279SBram Moolenaar     int		u8c = 0;
1508362e1a30SBram Moolenaar     int		u8cc[MAX_MCO];
1509071d4279SBram Moolenaar     int		clear_next_cell = FALSE;
1510071d4279SBram Moolenaar #ifdef FEAT_ARABIC
15117528d1f6SBram Moolenaar     int		prev_c = 0;		// previous Arabic character
1512362e1a30SBram Moolenaar     int		pc, nc, nc1;
1513362e1a30SBram Moolenaar     int		pcc[MAX_MCO];
1514071d4279SBram Moolenaar #endif
15152bea291aSBram Moolenaar     int		force_redraw_this;
15162bea291aSBram Moolenaar     int		force_redraw_next = FALSE;
15172bea291aSBram Moolenaar     int		need_redraw;
1518071d4279SBram Moolenaar 
15190b4c9eddSBram Moolenaar     // Safety check. The check for negative row and column is to fix issue
15200b4c9eddSBram Moolenaar     // #4102. TODO: find out why row/col could be negative.
15210b4c9eddSBram Moolenaar     if (ScreenLines == NULL
15220b4c9eddSBram Moolenaar 	    || row >= screen_Rows || row < 0
15230b4c9eddSBram Moolenaar 	    || col >= screen_Columns || col < 0)
1524071d4279SBram Moolenaar 	return;
15252bea291aSBram Moolenaar     off = LineOffset[row] + col;
1526071d4279SBram Moolenaar 
15277528d1f6SBram Moolenaar     // When drawing over the right halve of a double-wide char clear out the
15287528d1f6SBram Moolenaar     // left halve.  Only needed in a terminal.
15297693ec6eSBram Moolenaar     if (has_mbyte && col > 0 && col < screen_Columns
1530c236c16dSBram Moolenaar #ifdef FEAT_GUI
1531c236c16dSBram Moolenaar 	    && !gui.in_use
1532c236c16dSBram Moolenaar #endif
1533c236c16dSBram Moolenaar 	    && mb_fix_col(col, row) != col)
15342bea291aSBram Moolenaar     {
15352bea291aSBram Moolenaar 	ScreenLines[off - 1] = ' ';
15362bea291aSBram Moolenaar 	ScreenAttrs[off - 1] = 0;
15372bea291aSBram Moolenaar 	if (enc_utf8)
15382bea291aSBram Moolenaar 	{
15392bea291aSBram Moolenaar 	    ScreenLinesUC[off - 1] = 0;
15402bea291aSBram Moolenaar 	    ScreenLinesC[0][off - 1] = 0;
15412bea291aSBram Moolenaar 	}
15427528d1f6SBram Moolenaar 	// redraw the previous cell, make it empty
15432bea291aSBram Moolenaar 	screen_char(off - 1, row, col - 1);
15447528d1f6SBram Moolenaar 	// force the cell at "col" to be redrawn
15452bea291aSBram Moolenaar 	force_redraw_next = TRUE;
15462bea291aSBram Moolenaar     }
1547c236c16dSBram Moolenaar 
1548367329baSBram Moolenaar     max_off = LineOffset[row] + screen_Columns;
1549a064ac85SBram Moolenaar     while (col < screen_Columns
1550a064ac85SBram Moolenaar 	    && (len < 0 || (int)(ptr - text) < len)
1551a064ac85SBram Moolenaar 	    && *ptr != NUL)
1552071d4279SBram Moolenaar     {
1553071d4279SBram Moolenaar 	c = *ptr;
155463d9e730SBram Moolenaar 	// check if this is the first byte of a multibyte
1555071d4279SBram Moolenaar 	if (has_mbyte)
1556071d4279SBram Moolenaar 	{
1557071d4279SBram Moolenaar 	    if (enc_utf8 && len > 0)
15580fa313a7SBram Moolenaar 		mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
1559071d4279SBram Moolenaar 	    else
15600fa313a7SBram Moolenaar 		mbyte_blen = (*mb_ptr2len)(ptr);
1561071d4279SBram Moolenaar 	    if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1562071d4279SBram Moolenaar 		mbyte_cells = 1;
1563071d4279SBram Moolenaar 	    else if (enc_dbcs != 0)
1564071d4279SBram Moolenaar 		mbyte_cells = mbyte_blen;
156563d9e730SBram Moolenaar 	    else	// enc_utf8
1566071d4279SBram Moolenaar 	    {
1567071d4279SBram Moolenaar 		if (len >= 0)
1568362e1a30SBram Moolenaar 		    u8c = utfc_ptr2char_len(ptr, u8cc,
1569071d4279SBram Moolenaar 						   (int)((text + len) - ptr));
1570071d4279SBram Moolenaar 		else
1571362e1a30SBram Moolenaar 		    u8c = utfc_ptr2char(ptr, u8cc);
1572071d4279SBram Moolenaar 		mbyte_cells = utf_char2cells(u8c);
1573071d4279SBram Moolenaar #ifdef FEAT_ARABIC
1574071d4279SBram Moolenaar 		if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
1575071d4279SBram Moolenaar 		{
157663d9e730SBram Moolenaar 		    // Do Arabic shaping.
1577071d4279SBram Moolenaar 		    if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
1578071d4279SBram Moolenaar 		    {
157963d9e730SBram Moolenaar 			// Past end of string to be displayed.
1580071d4279SBram Moolenaar 			nc = NUL;
1581071d4279SBram Moolenaar 			nc1 = NUL;
1582071d4279SBram Moolenaar 		    }
1583071d4279SBram Moolenaar 		    else
1584362e1a30SBram Moolenaar 		    {
158554620188SBram Moolenaar 			nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
158654620188SBram Moolenaar 				      (int)((text + len) - ptr - mbyte_blen));
1587362e1a30SBram Moolenaar 			nc1 = pcc[0];
1588362e1a30SBram Moolenaar 		    }
1589071d4279SBram Moolenaar 		    pc = prev_c;
1590071d4279SBram Moolenaar 		    prev_c = u8c;
1591362e1a30SBram Moolenaar 		    u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
1592071d4279SBram Moolenaar 		}
1593071d4279SBram Moolenaar 		else
1594071d4279SBram Moolenaar 		    prev_c = u8c;
1595071d4279SBram Moolenaar #endif
1596e4ebd29eSBram Moolenaar 		if (col + mbyte_cells > screen_Columns)
1597e4ebd29eSBram Moolenaar 		{
159863d9e730SBram Moolenaar 		    // Only 1 cell left, but character requires 2 cells:
159963d9e730SBram Moolenaar 		    // display a '>' in the last column to avoid wrapping.
1600e4ebd29eSBram Moolenaar 		    c = '>';
1601e4ebd29eSBram Moolenaar 		    mbyte_cells = 1;
1602e4ebd29eSBram Moolenaar 		}
1603071d4279SBram Moolenaar 	    }
1604071d4279SBram Moolenaar 	}
1605071d4279SBram Moolenaar 
16062bea291aSBram Moolenaar 	force_redraw_this = force_redraw_next;
16072bea291aSBram Moolenaar 	force_redraw_next = FALSE;
16082bea291aSBram Moolenaar 
16092bea291aSBram Moolenaar 	need_redraw = ScreenLines[off] != c
1610071d4279SBram Moolenaar 		|| (mbyte_cells == 2
1611071d4279SBram Moolenaar 		    && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
1612071d4279SBram Moolenaar 		|| (enc_dbcs == DBCS_JPNU
1613071d4279SBram Moolenaar 		    && c == 0x8e
1614071d4279SBram Moolenaar 		    && ScreenLines2[off] != ptr[1])
1615071d4279SBram Moolenaar 		|| (enc_utf8
161670c49c1aSBram Moolenaar 		    && (ScreenLinesUC[off] !=
161770c49c1aSBram Moolenaar 				(u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
161870c49c1aSBram Moolenaar 			|| (ScreenLinesUC[off] != 0
161970c49c1aSBram Moolenaar 					  && screen_comp_differs(off, u8cc))))
1620071d4279SBram Moolenaar 		|| ScreenAttrs[off] != attr
16212bea291aSBram Moolenaar 		|| exmode_active;
16222bea291aSBram Moolenaar 
162324a5ac5dSBram Moolenaar 	if ((need_redraw || force_redraw_this)
162405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
1625c662ec99SBram Moolenaar 		&& !blocked_by_popup(row, col)
162624a5ac5dSBram Moolenaar #endif
162724a5ac5dSBram Moolenaar 	   )
1628071d4279SBram Moolenaar 	{
1629071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
163063d9e730SBram Moolenaar 	    // The bold trick makes a single row of pixels appear in the next
163163d9e730SBram Moolenaar 	    // character.  When a bold character is removed, the next
163263d9e730SBram Moolenaar 	    // character should be redrawn too.  This happens for our own GUI
163363d9e730SBram Moolenaar 	    // and for some xterms.
16342bea291aSBram Moolenaar 	    if (need_redraw && ScreenLines[off] != ' ' && (
1635071d4279SBram Moolenaar # ifdef FEAT_GUI
1636071d4279SBram Moolenaar 		    gui.in_use
1637071d4279SBram Moolenaar # endif
1638071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
1639071d4279SBram Moolenaar 		    ||
1640071d4279SBram Moolenaar # endif
1641071d4279SBram Moolenaar # ifdef UNIX
1642071d4279SBram Moolenaar 		    term_is_xterm
1643071d4279SBram Moolenaar # endif
16442bea291aSBram Moolenaar 		    ))
1645071d4279SBram Moolenaar 	    {
16462bea291aSBram Moolenaar 		int	n = ScreenAttrs[off];
1647071d4279SBram Moolenaar 
16482bea291aSBram Moolenaar 		if (n > HL_ALL)
16492bea291aSBram Moolenaar 		    n = syn_attr2attr(n);
16502bea291aSBram Moolenaar 		if (n & HL_BOLD)
16512bea291aSBram Moolenaar 		    force_redraw_next = TRUE;
1652071d4279SBram Moolenaar 	    }
1653071d4279SBram Moolenaar #endif
165463d9e730SBram Moolenaar 	    // When at the end of the text and overwriting a two-cell
165563d9e730SBram Moolenaar 	    // character with a one-cell character, need to clear the next
165663d9e730SBram Moolenaar 	    // cell.  Also when overwriting the left halve of a two-cell char
165763d9e730SBram Moolenaar 	    // with the right halve of a two-cell char.  Do this only once
165863d9e730SBram Moolenaar 	    // (mb_off2cells() may return 2 on the right halve).
1659071d4279SBram Moolenaar 	    if (clear_next_cell)
1660071d4279SBram Moolenaar 		clear_next_cell = FALSE;
1661071d4279SBram Moolenaar 	    else if (has_mbyte
1662071d4279SBram Moolenaar 		    && (len < 0 ? ptr[mbyte_blen] == NUL
1663071d4279SBram Moolenaar 					     : ptr + mbyte_blen >= text + len)
1664367329baSBram Moolenaar 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1665071d4279SBram Moolenaar 			|| (mbyte_cells == 2
1666367329baSBram Moolenaar 			    && (*mb_off2cells)(off, max_off) == 1
1667367329baSBram Moolenaar 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
1668071d4279SBram Moolenaar 		clear_next_cell = TRUE;
1669071d4279SBram Moolenaar 
167063d9e730SBram Moolenaar 	    // Make sure we never leave a second byte of a double-byte behind,
167163d9e730SBram Moolenaar 	    // it confuses mb_off2cells().
1672071d4279SBram Moolenaar 	    if (enc_dbcs
1673367329baSBram Moolenaar 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1674071d4279SBram Moolenaar 			|| (mbyte_cells == 2
1675367329baSBram Moolenaar 			    && (*mb_off2cells)(off, max_off) == 1
1676367329baSBram Moolenaar 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
1677071d4279SBram Moolenaar 		ScreenLines[off + mbyte_blen] = 0;
1678071d4279SBram Moolenaar 	    ScreenLines[off] = c;
1679071d4279SBram Moolenaar 	    ScreenAttrs[off] = attr;
1680071d4279SBram Moolenaar 	    if (enc_utf8)
1681071d4279SBram Moolenaar 	    {
1682362e1a30SBram Moolenaar 		if (c < 0x80 && u8cc[0] == 0)
1683071d4279SBram Moolenaar 		    ScreenLinesUC[off] = 0;
1684071d4279SBram Moolenaar 		else
1685071d4279SBram Moolenaar 		{
1686362e1a30SBram Moolenaar 		    int	    i;
1687362e1a30SBram Moolenaar 
1688071d4279SBram Moolenaar 		    ScreenLinesUC[off] = u8c;
1689362e1a30SBram Moolenaar 		    for (i = 0; i < Screen_mco; ++i)
1690362e1a30SBram Moolenaar 		    {
1691362e1a30SBram Moolenaar 			ScreenLinesC[i][off] = u8cc[i];
1692362e1a30SBram Moolenaar 			if (u8cc[i] == 0)
1693362e1a30SBram Moolenaar 			    break;
1694362e1a30SBram Moolenaar 		    }
1695071d4279SBram Moolenaar 		}
1696071d4279SBram Moolenaar 		if (mbyte_cells == 2)
1697071d4279SBram Moolenaar 		{
1698071d4279SBram Moolenaar 		    ScreenLines[off + 1] = 0;
1699071d4279SBram Moolenaar 		    ScreenAttrs[off + 1] = attr;
1700071d4279SBram Moolenaar 		}
1701071d4279SBram Moolenaar 		screen_char(off, row, col);
1702071d4279SBram Moolenaar 	    }
1703071d4279SBram Moolenaar 	    else if (mbyte_cells == 2)
1704071d4279SBram Moolenaar 	    {
1705071d4279SBram Moolenaar 		ScreenLines[off + 1] = ptr[1];
1706071d4279SBram Moolenaar 		ScreenAttrs[off + 1] = attr;
1707071d4279SBram Moolenaar 		screen_char_2(off, row, col);
1708071d4279SBram Moolenaar 	    }
1709071d4279SBram Moolenaar 	    else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1710071d4279SBram Moolenaar 	    {
1711071d4279SBram Moolenaar 		ScreenLines2[off] = ptr[1];
1712071d4279SBram Moolenaar 		screen_char(off, row, col);
1713071d4279SBram Moolenaar 	    }
1714071d4279SBram Moolenaar 	    else
1715071d4279SBram Moolenaar 		screen_char(off, row, col);
1716071d4279SBram Moolenaar 	}
1717071d4279SBram Moolenaar 	if (has_mbyte)
1718071d4279SBram Moolenaar 	{
1719071d4279SBram Moolenaar 	    off += mbyte_cells;
1720071d4279SBram Moolenaar 	    col += mbyte_cells;
1721071d4279SBram Moolenaar 	    ptr += mbyte_blen;
1722071d4279SBram Moolenaar 	    if (clear_next_cell)
1723e4c21e68SBram Moolenaar 	    {
172463d9e730SBram Moolenaar 		// This only happens at the end, display one space next.
1725071d4279SBram Moolenaar 		ptr = (char_u *)" ";
1726e4c21e68SBram Moolenaar 		len = -1;
1727e4c21e68SBram Moolenaar 	    }
1728071d4279SBram Moolenaar 	}
1729071d4279SBram Moolenaar 	else
1730071d4279SBram Moolenaar 	{
1731071d4279SBram Moolenaar 	    ++off;
1732071d4279SBram Moolenaar 	    ++col;
1733071d4279SBram Moolenaar 	    ++ptr;
1734071d4279SBram Moolenaar 	}
1735071d4279SBram Moolenaar     }
17362bea291aSBram Moolenaar 
173763d9e730SBram Moolenaar     // If we detected the next character needs to be redrawn, but the text
173863d9e730SBram Moolenaar     // doesn't extend up to there, update the character here.
17392bea291aSBram Moolenaar     if (force_redraw_next && col < screen_Columns)
17402bea291aSBram Moolenaar     {
17412bea291aSBram Moolenaar 	if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
17422bea291aSBram Moolenaar 	    screen_char_2(off, row, col);
17432bea291aSBram Moolenaar 	else
17442bea291aSBram Moolenaar 	    screen_char(off, row, col);
17452bea291aSBram Moolenaar     }
1746071d4279SBram Moolenaar }
1747071d4279SBram Moolenaar 
17487528d1f6SBram Moolenaar #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
1749071d4279SBram Moolenaar /*
17506ee10162SBram Moolenaar  * Prepare for 'hlsearch' highlighting.
1751071d4279SBram Moolenaar  */
17527528d1f6SBram Moolenaar     void
start_search_hl(void)175305540976SBram Moolenaar start_search_hl(void)
1754071d4279SBram Moolenaar {
1755071d4279SBram Moolenaar     if (p_hls && !no_hlsearch)
1756071d4279SBram Moolenaar     {
17570b6849e9SBram Moolenaar 	end_search_hl();  // just in case it wasn't called before
17587528d1f6SBram Moolenaar 	last_pat_prog(&screen_search_hl.rm);
17597528d1f6SBram Moolenaar 	screen_search_hl.attr = HL_ATTR(HLF_L);
176091a4e822SBram Moolenaar # ifdef FEAT_RELTIME
176163d9e730SBram Moolenaar 	// Set the time limit to 'redrawtime'.
17627528d1f6SBram Moolenaar 	profile_setlimit(p_rdt, &screen_search_hl.tm);
176391a4e822SBram Moolenaar # endif
1764071d4279SBram Moolenaar     }
1765071d4279SBram Moolenaar }
1766071d4279SBram Moolenaar 
1767071d4279SBram Moolenaar /*
17686ee10162SBram Moolenaar  * Clean up for 'hlsearch' highlighting.
1769071d4279SBram Moolenaar  */
17707528d1f6SBram Moolenaar     void
end_search_hl(void)177105540976SBram Moolenaar end_search_hl(void)
1772071d4279SBram Moolenaar {
17737528d1f6SBram Moolenaar     if (screen_search_hl.rm.regprog != NULL)
1774071d4279SBram Moolenaar     {
17757528d1f6SBram Moolenaar 	vim_regfree(screen_search_hl.rm.regprog);
17767528d1f6SBram Moolenaar 	screen_search_hl.rm.regprog = NULL;
1777071d4279SBram Moolenaar     }
1778071d4279SBram Moolenaar }
1779de993ea6SBram Moolenaar #endif
1780b3414595SBram Moolenaar 
1781071d4279SBram Moolenaar       static void
screen_start_highlight(int attr)178205540976SBram Moolenaar screen_start_highlight(int attr)
1783071d4279SBram Moolenaar {
1784071d4279SBram Moolenaar     attrentry_T *aep = NULL;
1785071d4279SBram Moolenaar 
1786071d4279SBram Moolenaar     screen_attr = attr;
1787071d4279SBram Moolenaar     if (full_screen
17884f97475dSBram Moolenaar #ifdef MSWIN
1789071d4279SBram Moolenaar 		    && termcap_active
1790071d4279SBram Moolenaar #endif
1791071d4279SBram Moolenaar 				       )
1792071d4279SBram Moolenaar     {
1793071d4279SBram Moolenaar #ifdef FEAT_GUI
1794071d4279SBram Moolenaar 	if (gui.in_use)
1795071d4279SBram Moolenaar 	{
1796071d4279SBram Moolenaar 	    char	buf[20];
1797071d4279SBram Moolenaar 
179863d9e730SBram Moolenaar 	    // The GUI handles this internally.
1799d1f56e68SBram Moolenaar 	    sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
1800071d4279SBram Moolenaar 	    OUT_STR(buf);
1801071d4279SBram Moolenaar 	}
1802071d4279SBram Moolenaar 	else
1803071d4279SBram Moolenaar #endif
1804071d4279SBram Moolenaar 	{
180563d9e730SBram Moolenaar 	    if (attr > HL_ALL)				// special HL attr.
1806071d4279SBram Moolenaar 	    {
18078a633e34SBram Moolenaar 		if (IS_CTERM)
1808071d4279SBram Moolenaar 		    aep = syn_cterm_attr2entry(attr);
1809071d4279SBram Moolenaar 		else
1810071d4279SBram Moolenaar 		    aep = syn_term_attr2entry(attr);
181163d9e730SBram Moolenaar 		if (aep == NULL)	    // did ":syntax clear"
1812071d4279SBram Moolenaar 		    attr = 0;
1813071d4279SBram Moolenaar 		else
1814071d4279SBram Moolenaar 		    attr = aep->ae_attr;
1815071d4279SBram Moolenaar 	    }
1816a050b947SBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1817a050b947SBram Moolenaar 	    if (use_vtp())
1818a050b947SBram Moolenaar 	    {
1819a050b947SBram Moolenaar 		guicolor_T  defguifg, defguibg;
1820a050b947SBram Moolenaar 		int	    defctermfg, defctermbg;
1821a050b947SBram Moolenaar 
1822a050b947SBram Moolenaar 		// If FG and BG are unset, the color is undefined when
1823a050b947SBram Moolenaar 		// BOLD+INVERSE. Use Normal as the default value.
1824a050b947SBram Moolenaar 		get_default_console_color(&defctermfg, &defctermbg, &defguifg,
1825a050b947SBram Moolenaar 								    &defguibg);
1826a050b947SBram Moolenaar 
1827a050b947SBram Moolenaar 		if (p_tgc)
1828a050b947SBram Moolenaar 		{
1829a050b947SBram Moolenaar 		    if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.fg_rgb))
1830a050b947SBram Moolenaar 			term_fg_rgb_color(defguifg);
1831a050b947SBram Moolenaar 		    if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.bg_rgb))
1832a050b947SBram Moolenaar 			term_bg_rgb_color(defguibg);
1833a050b947SBram Moolenaar 		}
1834a050b947SBram Moolenaar 		else if (t_colors >= 256)
1835a050b947SBram Moolenaar 		{
1836a050b947SBram Moolenaar 		    if (aep == NULL || aep->ae_u.cterm.fg_color == 0)
1837a050b947SBram Moolenaar 			term_fg_color(defctermfg);
1838a050b947SBram Moolenaar 		    if (aep == NULL || aep->ae_u.cterm.bg_color == 0)
1839a050b947SBram Moolenaar 			term_bg_color(defctermbg);
1840a050b947SBram Moolenaar 		}
1841a050b947SBram Moolenaar 	    }
1842a050b947SBram Moolenaar #endif
184363d9e730SBram Moolenaar 	    if ((attr & HL_BOLD) && *T_MD != NUL)	// bold
1844071d4279SBram Moolenaar 		out_str(T_MD);
1845d4fc577eSBram Moolenaar 	    else if (aep != NULL && cterm_normal_fg_bold && (
184661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1847d4fc577eSBram Moolenaar 			p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1848d4fc577eSBram Moolenaar 			  ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
1849d4fc577eSBram Moolenaar 			  :
18508a633e34SBram Moolenaar #endif
1851d4fc577eSBram Moolenaar 			    t_colors > 1 && aep->ae_u.cterm.fg_color))
185263d9e730SBram Moolenaar 		// If the Normal FG color has BOLD attribute and the new HL
185363d9e730SBram Moolenaar 		// has a FG color defined, clear BOLD.
1854d1f56e68SBram Moolenaar 		out_str(T_ME);
185563d9e730SBram Moolenaar 	    if ((attr & HL_STANDOUT) && *T_SO != NUL)	// standout
1856071d4279SBram Moolenaar 		out_str(T_SO);
185763d9e730SBram Moolenaar 	    if ((attr & HL_UNDERCURL) && *T_UCS != NUL) // undercurl
18588b9e20afSBram Moolenaar 		out_str(T_UCS);
185963d9e730SBram Moolenaar 	    if (((attr & HL_UNDERLINE)	    // underline or undercurl
186045a0000dSBram Moolenaar 			|| ((attr & HL_UNDERCURL) && *T_UCS == NUL))
186145a0000dSBram Moolenaar 		    && *T_US != NUL)
1862071d4279SBram Moolenaar 		out_str(T_US);
186363d9e730SBram Moolenaar 	    if ((attr & HL_ITALIC) && *T_CZH != NUL)	// italic
1864071d4279SBram Moolenaar 		out_str(T_CZH);
186563d9e730SBram Moolenaar 	    if ((attr & HL_INVERSE) && *T_MR != NUL)	// inverse (reverse)
1866071d4279SBram Moolenaar 		out_str(T_MR);
186763d9e730SBram Moolenaar 	    if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL)	// strike
1868cf4b00c8SBram Moolenaar 		out_str(T_STS);
1869071d4279SBram Moolenaar 
1870071d4279SBram Moolenaar 	    /*
1871071d4279SBram Moolenaar 	     * Output the color or start string after bold etc., in case the
1872071d4279SBram Moolenaar 	     * bold etc. override the color setting.
1873071d4279SBram Moolenaar 	     */
1874071d4279SBram Moolenaar 	    if (aep != NULL)
1875071d4279SBram Moolenaar 	    {
187661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
187763d9e730SBram Moolenaar 		// When 'termguicolors' is set but fg or bg is unset,
187863d9e730SBram Moolenaar 		// fall back to the cterm colors.   This helps for SpellBad,
187963d9e730SBram Moolenaar 		// where the GUI uses a red undercurl.
1880d4fc577eSBram Moolenaar 		if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
18818a633e34SBram Moolenaar 		{
18821b58cdd1SBram Moolenaar 		    if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
18838a633e34SBram Moolenaar 			term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
1884d4fc577eSBram Moolenaar 		}
1885d4fc577eSBram Moolenaar 		else
1886d4fc577eSBram Moolenaar #endif
1887d4fc577eSBram Moolenaar 		if (t_colors > 1)
1888d4fc577eSBram Moolenaar 		{
1889d4fc577eSBram Moolenaar 		    if (aep->ae_u.cterm.fg_color)
1890d4fc577eSBram Moolenaar 			term_fg_color(aep->ae_u.cterm.fg_color - 1);
1891d4fc577eSBram Moolenaar 		}
1892d4fc577eSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1893d4fc577eSBram Moolenaar 		if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
1894d4fc577eSBram Moolenaar 		{
18951b58cdd1SBram Moolenaar 		    if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
18968a633e34SBram Moolenaar 			term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
18978a633e34SBram Moolenaar 		}
18988a633e34SBram Moolenaar 		else
18998a633e34SBram Moolenaar #endif
1900071d4279SBram Moolenaar 		if (t_colors > 1)
1901071d4279SBram Moolenaar 		{
1902071d4279SBram Moolenaar 		    if (aep->ae_u.cterm.bg_color)
1903071d4279SBram Moolenaar 			term_bg_color(aep->ae_u.cterm.bg_color - 1);
1904071d4279SBram Moolenaar 		}
1905e023e88bSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1906e023e88bSBram Moolenaar 		if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
1907e023e88bSBram Moolenaar 		{
1908e023e88bSBram Moolenaar 		    if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
1909e023e88bSBram Moolenaar 			term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
1910e023e88bSBram Moolenaar 		}
1911e023e88bSBram Moolenaar 		else
1912e023e88bSBram Moolenaar #endif
1913e023e88bSBram Moolenaar 		if (t_colors > 1)
1914e023e88bSBram Moolenaar 		{
1915e023e88bSBram Moolenaar 		    if (aep->ae_u.cterm.ul_color)
1916e023e88bSBram Moolenaar 			term_ul_color(aep->ae_u.cterm.ul_color - 1);
1917e023e88bSBram Moolenaar 		}
1918d4fc577eSBram Moolenaar 
1919f708ac59SBram Moolenaar 		if (!IS_CTERM)
1920071d4279SBram Moolenaar 		{
1921071d4279SBram Moolenaar 		    if (aep->ae_u.term.start != NULL)
1922071d4279SBram Moolenaar 			out_str(aep->ae_u.term.start);
1923071d4279SBram Moolenaar 		}
1924071d4279SBram Moolenaar 	    }
1925071d4279SBram Moolenaar 	}
1926071d4279SBram Moolenaar     }
1927071d4279SBram Moolenaar }
1928071d4279SBram Moolenaar 
1929071d4279SBram Moolenaar       void
screen_stop_highlight(void)193005540976SBram Moolenaar screen_stop_highlight(void)
1931071d4279SBram Moolenaar {
193263d9e730SBram Moolenaar     int	    do_ME = FALSE;	    // output T_ME code
19334e5534faSBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
193409307e3bSBram Moolenaar     int	    do_ME_fg = FALSE, do_ME_bg = FALSE;
19354e5534faSBram Moolenaar #endif
1936071d4279SBram Moolenaar 
1937071d4279SBram Moolenaar     if (screen_attr != 0
19384f97475dSBram Moolenaar #ifdef MSWIN
1939071d4279SBram Moolenaar 			&& termcap_active
1940071d4279SBram Moolenaar #endif
1941071d4279SBram Moolenaar 					   )
1942071d4279SBram Moolenaar     {
1943071d4279SBram Moolenaar #ifdef FEAT_GUI
1944071d4279SBram Moolenaar 	if (gui.in_use)
1945071d4279SBram Moolenaar 	{
1946071d4279SBram Moolenaar 	    char	buf[20];
1947071d4279SBram Moolenaar 
194863d9e730SBram Moolenaar 	    // use internal GUI code
1949071d4279SBram Moolenaar 	    sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
1950071d4279SBram Moolenaar 	    OUT_STR(buf);
1951071d4279SBram Moolenaar 	}
1952071d4279SBram Moolenaar 	else
1953071d4279SBram Moolenaar #endif
1954071d4279SBram Moolenaar 	{
195563d9e730SBram Moolenaar 	    if (screen_attr > HL_ALL)			// special HL attr.
1956071d4279SBram Moolenaar 	    {
1957071d4279SBram Moolenaar 		attrentry_T *aep;
1958071d4279SBram Moolenaar 
19598a633e34SBram Moolenaar 		if (IS_CTERM)
1960071d4279SBram Moolenaar 		{
1961071d4279SBram Moolenaar 		    /*
1962071d4279SBram Moolenaar 		     * Assume that t_me restores the original colors!
1963071d4279SBram Moolenaar 		     */
1964071d4279SBram Moolenaar 		    aep = syn_cterm_attr2entry(screen_attr);
1965d4fc577eSBram Moolenaar 		    if (aep != NULL && ((
196661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1967d4fc577eSBram Moolenaar 			    p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1968d4fc577eSBram Moolenaar 				? aep->ae_u.cterm.fg_rgb != INVALCOLOR
19694e5534faSBram Moolenaar # ifdef FEAT_VTP
19704e5534faSBram Moolenaar 				    ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
19714e5534faSBram Moolenaar # endif
1972d4fc577eSBram Moolenaar 				:
19738a633e34SBram Moolenaar #endif
1974d4fc577eSBram Moolenaar 				aep->ae_u.cterm.fg_color) || (
197561be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
1976d4fc577eSBram Moolenaar 			    p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
1977d4fc577eSBram Moolenaar 				? aep->ae_u.cterm.bg_rgb != INVALCOLOR
19784e5534faSBram Moolenaar # ifdef FEAT_VTP
19794e5534faSBram Moolenaar 				    ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
19804e5534faSBram Moolenaar # endif
1981d4fc577eSBram Moolenaar 				:
19828a633e34SBram Moolenaar #endif
1983d4fc577eSBram Moolenaar 				aep->ae_u.cterm.bg_color)))
1984071d4279SBram Moolenaar 			do_ME = TRUE;
19854e5534faSBram Moolenaar #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
19864e5534faSBram Moolenaar 		    if (use_vtp())
19874e5534faSBram Moolenaar 		    {
19884e5534faSBram Moolenaar 			if (do_ME_fg && do_ME_bg)
19894e5534faSBram Moolenaar 			    do_ME = TRUE;
19904e5534faSBram Moolenaar 
19914e5534faSBram Moolenaar 			// FG and BG cannot be separated in T_ME, which is not
19924e5534faSBram Moolenaar 			// efficient.
19934e5534faSBram Moolenaar 			if (!do_ME && do_ME_fg)
19944e5534faSBram Moolenaar 			    out_str((char_u *)"\033|39m"); // restore FG
19954e5534faSBram Moolenaar 			if (!do_ME && do_ME_bg)
19964e5534faSBram Moolenaar 			    out_str((char_u *)"\033|49m"); // restore BG
19974e5534faSBram Moolenaar 		    }
19984e5534faSBram Moolenaar 		    else
19994e5534faSBram Moolenaar 		    {
20004e5534faSBram Moolenaar 			// Process FG and BG at once.
20014e5534faSBram Moolenaar 			if (!do_ME)
20024e5534faSBram Moolenaar 			    do_ME = do_ME_fg | do_ME_bg;
20034e5534faSBram Moolenaar 		    }
20044e5534faSBram Moolenaar #endif
2005071d4279SBram Moolenaar 		}
2006071d4279SBram Moolenaar 		else
2007071d4279SBram Moolenaar 		{
2008071d4279SBram Moolenaar 		    aep = syn_term_attr2entry(screen_attr);
2009071d4279SBram Moolenaar 		    if (aep != NULL && aep->ae_u.term.stop != NULL)
2010071d4279SBram Moolenaar 		    {
2011071d4279SBram Moolenaar 			if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
2012071d4279SBram Moolenaar 			    do_ME = TRUE;
2013071d4279SBram Moolenaar 			else
2014071d4279SBram Moolenaar 			    out_str(aep->ae_u.term.stop);
2015071d4279SBram Moolenaar 		    }
2016071d4279SBram Moolenaar 		}
201763d9e730SBram Moolenaar 		if (aep == NULL)	    // did ":syntax clear"
2018071d4279SBram Moolenaar 		    screen_attr = 0;
2019071d4279SBram Moolenaar 		else
2020071d4279SBram Moolenaar 		    screen_attr = aep->ae_attr;
2021071d4279SBram Moolenaar 	    }
2022071d4279SBram Moolenaar 
2023071d4279SBram Moolenaar 	    /*
2024071d4279SBram Moolenaar 	     * Often all ending-codes are equal to T_ME.  Avoid outputting the
2025071d4279SBram Moolenaar 	     * same sequence several times.
2026071d4279SBram Moolenaar 	     */
2027071d4279SBram Moolenaar 	    if (screen_attr & HL_STANDOUT)
2028071d4279SBram Moolenaar 	    {
2029071d4279SBram Moolenaar 		if (STRCMP(T_SE, T_ME) == 0)
2030071d4279SBram Moolenaar 		    do_ME = TRUE;
2031071d4279SBram Moolenaar 		else
2032071d4279SBram Moolenaar 		    out_str(T_SE);
2033071d4279SBram Moolenaar 	    }
203445a0000dSBram Moolenaar 	    if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
20358b9e20afSBram Moolenaar 	    {
20368b9e20afSBram Moolenaar 		if (STRCMP(T_UCE, T_ME) == 0)
20378b9e20afSBram Moolenaar 		    do_ME = TRUE;
20388b9e20afSBram Moolenaar 		else
20398b9e20afSBram Moolenaar 		    out_str(T_UCE);
20408b9e20afSBram Moolenaar 	    }
20418b9e20afSBram Moolenaar 	    if ((screen_attr & HL_UNDERLINE)
204245a0000dSBram Moolenaar 			    || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
2043071d4279SBram Moolenaar 	    {
2044071d4279SBram Moolenaar 		if (STRCMP(T_UE, T_ME) == 0)
2045071d4279SBram Moolenaar 		    do_ME = TRUE;
2046071d4279SBram Moolenaar 		else
2047071d4279SBram Moolenaar 		    out_str(T_UE);
2048071d4279SBram Moolenaar 	    }
2049071d4279SBram Moolenaar 	    if (screen_attr & HL_ITALIC)
2050071d4279SBram Moolenaar 	    {
2051071d4279SBram Moolenaar 		if (STRCMP(T_CZR, T_ME) == 0)
2052071d4279SBram Moolenaar 		    do_ME = TRUE;
2053071d4279SBram Moolenaar 		else
2054071d4279SBram Moolenaar 		    out_str(T_CZR);
2055071d4279SBram Moolenaar 	    }
2056cf4b00c8SBram Moolenaar 	    if (screen_attr & HL_STRIKETHROUGH)
2057cf4b00c8SBram Moolenaar 	    {
2058cf4b00c8SBram Moolenaar 		if (STRCMP(T_STE, T_ME) == 0)
2059cf4b00c8SBram Moolenaar 		    do_ME = TRUE;
2060cf4b00c8SBram Moolenaar 		else
2061cf4b00c8SBram Moolenaar 		    out_str(T_STE);
2062cf4b00c8SBram Moolenaar 	    }
2063071d4279SBram Moolenaar 	    if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
2064071d4279SBram Moolenaar 		out_str(T_ME);
2065071d4279SBram Moolenaar 
206661be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
206761be73bbSBram Moolenaar 	    if (p_tgc)
20688a633e34SBram Moolenaar 	    {
20691b58cdd1SBram Moolenaar 		if (cterm_normal_fg_gui_color != INVALCOLOR)
20708a633e34SBram Moolenaar 		    term_fg_rgb_color(cterm_normal_fg_gui_color);
20711b58cdd1SBram Moolenaar 		if (cterm_normal_bg_gui_color != INVALCOLOR)
20728a633e34SBram Moolenaar 		    term_bg_rgb_color(cterm_normal_bg_gui_color);
2073e023e88bSBram Moolenaar 		if (cterm_normal_ul_gui_color != INVALCOLOR)
2074e023e88bSBram Moolenaar 		    term_ul_rgb_color(cterm_normal_ul_gui_color);
20758a633e34SBram Moolenaar 	    }
20768a633e34SBram Moolenaar 	    else
20778a633e34SBram Moolenaar #endif
20788a633e34SBram Moolenaar 	    {
2079071d4279SBram Moolenaar 		if (t_colors > 1)
2080071d4279SBram Moolenaar 		{
208163d9e730SBram Moolenaar 		    // set Normal cterm colors
2082071d4279SBram Moolenaar 		    if (cterm_normal_fg_color != 0)
2083071d4279SBram Moolenaar 			term_fg_color(cterm_normal_fg_color - 1);
2084071d4279SBram Moolenaar 		    if (cterm_normal_bg_color != 0)
2085071d4279SBram Moolenaar 			term_bg_color(cterm_normal_bg_color - 1);
2086e023e88bSBram Moolenaar 		    if (cterm_normal_ul_color != 0)
2087e023e88bSBram Moolenaar 			term_ul_color(cterm_normal_ul_color - 1);
2088071d4279SBram Moolenaar 		    if (cterm_normal_fg_bold)
2089071d4279SBram Moolenaar 			out_str(T_MD);
2090071d4279SBram Moolenaar 		}
2091071d4279SBram Moolenaar 	    }
2092071d4279SBram Moolenaar 	}
20938a633e34SBram Moolenaar     }
2094071d4279SBram Moolenaar     screen_attr = 0;
2095071d4279SBram Moolenaar }
2096071d4279SBram Moolenaar 
2097071d4279SBram Moolenaar /*
2098071d4279SBram Moolenaar  * Reset the colors for a cterm.  Used when leaving Vim.
2099071d4279SBram Moolenaar  * The machine specific code may override this again.
2100071d4279SBram Moolenaar  */
2101071d4279SBram Moolenaar     void
reset_cterm_colors(void)210205540976SBram Moolenaar reset_cterm_colors(void)
2103071d4279SBram Moolenaar {
21048a633e34SBram Moolenaar     if (IS_CTERM)
2105071d4279SBram Moolenaar     {
210663d9e730SBram Moolenaar 	// set Normal cterm colors
210761be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
21081b58cdd1SBram Moolenaar 	if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
21091b58cdd1SBram Moolenaar 		 || cterm_normal_bg_gui_color != INVALCOLOR)
21101b58cdd1SBram Moolenaar 		: (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
21118a633e34SBram Moolenaar #else
2112071d4279SBram Moolenaar 	if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
21138a633e34SBram Moolenaar #endif
2114071d4279SBram Moolenaar 	{
2115071d4279SBram Moolenaar 	    out_str(T_OP);
2116071d4279SBram Moolenaar 	    screen_attr = -1;
2117071d4279SBram Moolenaar 	}
2118071d4279SBram Moolenaar 	if (cterm_normal_fg_bold)
2119071d4279SBram Moolenaar 	{
2120071d4279SBram Moolenaar 	    out_str(T_ME);
2121071d4279SBram Moolenaar 	    screen_attr = -1;
2122071d4279SBram Moolenaar 	}
2123071d4279SBram Moolenaar     }
2124071d4279SBram Moolenaar }
2125071d4279SBram Moolenaar 
2126071d4279SBram Moolenaar /*
2127071d4279SBram Moolenaar  * Put character ScreenLines["off"] on the screen at position "row" and "col",
2128071d4279SBram Moolenaar  * using the attributes from ScreenAttrs["off"].
2129071d4279SBram Moolenaar  */
21307528d1f6SBram Moolenaar     void
screen_char(unsigned off,int row,int col)213105540976SBram Moolenaar screen_char(unsigned off, int row, int col)
2132071d4279SBram Moolenaar {
2133071d4279SBram Moolenaar     int		attr;
2134071d4279SBram Moolenaar 
213563d9e730SBram Moolenaar     // Check for illegal values, just in case (could happen just after
213663d9e730SBram Moolenaar     // resizing).
2137071d4279SBram Moolenaar     if (row >= screen_Rows || col >= screen_Columns)
2138071d4279SBram Moolenaar 	return;
2139071d4279SBram Moolenaar 
214033796b39SBram Moolenaar     // Skip if under the popup menu.
214133796b39SBram Moolenaar     // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
2142*6555500bSBakudankun     if (pum_under_menu(row, col, TRUE)
214305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
214433796b39SBram Moolenaar 	    && screen_zindex <= POPUPMENU_ZINDEX
214533796b39SBram Moolenaar #endif
214633796b39SBram Moolenaar 	    )
2147ae654385SBram Moolenaar 	return;
214805ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
2149c662ec99SBram Moolenaar     if (blocked_by_popup(row, col))
215033796b39SBram Moolenaar 	return;
215133796b39SBram Moolenaar #endif
215233796b39SBram Moolenaar 
215363d9e730SBram Moolenaar     // Outputting a character in the last cell on the screen may scroll the
215463d9e730SBram Moolenaar     // screen up.  Only do it when the "xn" termcap property is set, otherwise
215563d9e730SBram Moolenaar     // mark the character invalid (update it when scrolled up).
2156494838a3SBram Moolenaar     if (*T_XN == NUL
2157494838a3SBram Moolenaar 	    && row == screen_Rows - 1 && col == screen_Columns - 1
2158071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
215963d9e730SBram Moolenaar 	    // account for first command-line character in rightleft mode
2160071d4279SBram Moolenaar 	    && !cmdmsg_rl
2161071d4279SBram Moolenaar #endif
2162071d4279SBram Moolenaar        )
2163071d4279SBram Moolenaar     {
2164071d4279SBram Moolenaar 	ScreenAttrs[off] = (sattr_T)-1;
2165071d4279SBram Moolenaar 	return;
2166071d4279SBram Moolenaar     }
2167071d4279SBram Moolenaar 
2168071d4279SBram Moolenaar     /*
2169071d4279SBram Moolenaar      * Stop highlighting first, so it's easier to move the cursor.
2170071d4279SBram Moolenaar      */
2171071d4279SBram Moolenaar     if (screen_char_attr != 0)
2172071d4279SBram Moolenaar 	attr = screen_char_attr;
2173071d4279SBram Moolenaar     else
2174071d4279SBram Moolenaar 	attr = ScreenAttrs[off];
2175071d4279SBram Moolenaar     if (screen_attr != attr)
2176071d4279SBram Moolenaar 	screen_stop_highlight();
2177071d4279SBram Moolenaar 
2178071d4279SBram Moolenaar     windgoto(row, col);
2179071d4279SBram Moolenaar 
2180071d4279SBram Moolenaar     if (screen_attr != attr)
2181071d4279SBram Moolenaar 	screen_start_highlight(attr);
2182071d4279SBram Moolenaar 
2183071d4279SBram Moolenaar     if (enc_utf8 && ScreenLinesUC[off] != 0)
2184071d4279SBram Moolenaar     {
2185071d4279SBram Moolenaar 	char_u	    buf[MB_MAXBYTES + 1];
2186071d4279SBram Moolenaar 
2187cb070084SBram Moolenaar 	if (utf_ambiguous_width(ScreenLinesUC[off]))
2188fae8ed1fSBram Moolenaar 	{
2189fae8ed1fSBram Moolenaar 	    if (*p_ambw == 'd'
2190fae8ed1fSBram Moolenaar #ifdef FEAT_GUI
2191fae8ed1fSBram Moolenaar 		    && !gui.in_use
2192fae8ed1fSBram Moolenaar #endif
2193fae8ed1fSBram Moolenaar 		    )
2194fae8ed1fSBram Moolenaar 	    {
219563d9e730SBram Moolenaar 		// Clear the two screen cells. If the character is actually
219663d9e730SBram Moolenaar 		// single width it won't change the second cell.
2197fae8ed1fSBram Moolenaar 		out_str((char_u *)"  ");
2198fae8ed1fSBram Moolenaar 		term_windgoto(row, col);
2199fae8ed1fSBram Moolenaar 	    }
220063d9e730SBram Moolenaar 	    // not sure where the cursor is after drawing the ambiguous width
220163d9e730SBram Moolenaar 	    // character
2202cb070084SBram Moolenaar 	    screen_cur_col = 9999;
2203fae8ed1fSBram Moolenaar 	}
2204cb070084SBram Moolenaar 	else if (utf_char2cells(ScreenLinesUC[off]) > 1)
2205071d4279SBram Moolenaar 	    ++screen_cur_col;
2206fae8ed1fSBram Moolenaar 
220763d9e730SBram Moolenaar 	// Convert the UTF-8 character to bytes and write it.
2208fae8ed1fSBram Moolenaar 	buf[utfc_char2bytes(off, buf)] = NUL;
2209fae8ed1fSBram Moolenaar 	out_str(buf);
2210071d4279SBram Moolenaar     }
2211071d4279SBram Moolenaar     else
2212071d4279SBram Moolenaar     {
2213071d4279SBram Moolenaar 	out_flush_check();
2214071d4279SBram Moolenaar 	out_char(ScreenLines[off]);
221563d9e730SBram Moolenaar 	// double-byte character in single-width cell
2216071d4279SBram Moolenaar 	if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2217071d4279SBram Moolenaar 	    out_char(ScreenLines2[off]);
2218071d4279SBram Moolenaar     }
2219071d4279SBram Moolenaar 
2220071d4279SBram Moolenaar     screen_cur_col++;
2221071d4279SBram Moolenaar }
2222071d4279SBram Moolenaar 
2223071d4279SBram Moolenaar /*
2224071d4279SBram Moolenaar  * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
2225071d4279SBram Moolenaar  * on the screen at position 'row' and 'col'.
2226071d4279SBram Moolenaar  * The attributes of the first byte is used for all.  This is required to
2227071d4279SBram Moolenaar  * output the two bytes of a double-byte character with nothing in between.
2228071d4279SBram Moolenaar  */
2229071d4279SBram Moolenaar     static void
screen_char_2(unsigned off,int row,int col)223005540976SBram Moolenaar screen_char_2(unsigned off, int row, int col)
2231071d4279SBram Moolenaar {
223263d9e730SBram Moolenaar     // Check for illegal values (could be wrong when screen was resized).
2233071d4279SBram Moolenaar     if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
2234071d4279SBram Moolenaar 	return;
2235071d4279SBram Moolenaar 
223663d9e730SBram Moolenaar     // Outputting the last character on the screen may scrollup the screen.
223763d9e730SBram Moolenaar     // Don't to it!  Mark the character invalid (update it when scrolled up)
2238071d4279SBram Moolenaar     if (row == screen_Rows - 1 && col >= screen_Columns - 2)
2239071d4279SBram Moolenaar     {
2240071d4279SBram Moolenaar 	ScreenAttrs[off] = (sattr_T)-1;
2241071d4279SBram Moolenaar 	return;
2242071d4279SBram Moolenaar     }
2243071d4279SBram Moolenaar 
224463d9e730SBram Moolenaar     // Output the first byte normally (positions the cursor), then write the
224563d9e730SBram Moolenaar     // second byte directly.
2246071d4279SBram Moolenaar     screen_char(off, row, col);
2247071d4279SBram Moolenaar     out_char(ScreenLines[off + 1]);
2248071d4279SBram Moolenaar     ++screen_cur_col;
2249071d4279SBram Moolenaar }
2250071d4279SBram Moolenaar 
2251071d4279SBram Moolenaar /*
2252071d4279SBram Moolenaar  * Draw a rectangle of the screen, inverted when "invert" is TRUE.
2253071d4279SBram Moolenaar  * This uses the contents of ScreenLines[] and doesn't change it.
2254071d4279SBram Moolenaar  */
2255071d4279SBram Moolenaar     void
screen_draw_rectangle(int row,int col,int height,int width,int invert)225605540976SBram Moolenaar screen_draw_rectangle(
225705540976SBram Moolenaar     int		row,
225805540976SBram Moolenaar     int		col,
225905540976SBram Moolenaar     int		height,
226005540976SBram Moolenaar     int		width,
226105540976SBram Moolenaar     int		invert)
2262071d4279SBram Moolenaar {
2263071d4279SBram Moolenaar     int		r, c;
2264071d4279SBram Moolenaar     int		off;
2265367329baSBram Moolenaar     int		max_off;
2266071d4279SBram Moolenaar 
226763d9e730SBram Moolenaar     // Can't use ScreenLines unless initialized
2268482aaeb0SBram Moolenaar     if (ScreenLines == NULL)
2269482aaeb0SBram Moolenaar 	return;
2270482aaeb0SBram Moolenaar 
2271071d4279SBram Moolenaar     if (invert)
2272071d4279SBram Moolenaar 	screen_char_attr = HL_INVERSE;
2273071d4279SBram Moolenaar     for (r = row; r < row + height; ++r)
2274071d4279SBram Moolenaar     {
2275071d4279SBram Moolenaar 	off = LineOffset[r];
2276367329baSBram Moolenaar 	max_off = off + screen_Columns;
2277071d4279SBram Moolenaar 	for (c = col; c < col + width; ++c)
2278071d4279SBram Moolenaar 	{
2279367329baSBram Moolenaar 	    if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
2280071d4279SBram Moolenaar 	    {
2281071d4279SBram Moolenaar 		screen_char_2(off + c, r, c);
2282071d4279SBram Moolenaar 		++c;
2283071d4279SBram Moolenaar 	    }
2284071d4279SBram Moolenaar 	    else
2285071d4279SBram Moolenaar 	    {
2286071d4279SBram Moolenaar 		screen_char(off + c, r, c);
2287367329baSBram Moolenaar 		if (utf_off2cells(off + c, max_off) > 1)
2288071d4279SBram Moolenaar 		    ++c;
2289071d4279SBram Moolenaar 	    }
2290071d4279SBram Moolenaar 	}
2291071d4279SBram Moolenaar     }
2292071d4279SBram Moolenaar     screen_char_attr = 0;
2293071d4279SBram Moolenaar }
2294071d4279SBram Moolenaar 
2295071d4279SBram Moolenaar /*
2296071d4279SBram Moolenaar  * Redraw the characters for a vertically split window.
2297071d4279SBram Moolenaar  */
2298071d4279SBram Moolenaar     static void
redraw_block(int row,int end,win_T * wp)229905540976SBram Moolenaar redraw_block(int row, int end, win_T *wp)
2300071d4279SBram Moolenaar {
2301071d4279SBram Moolenaar     int		col;
2302071d4279SBram Moolenaar     int		width;
2303071d4279SBram Moolenaar 
2304071d4279SBram Moolenaar # ifdef FEAT_CLIPBOARD
2305071d4279SBram Moolenaar     clip_may_clear_selection(row, end - 1);
2306071d4279SBram Moolenaar # endif
2307071d4279SBram Moolenaar 
2308071d4279SBram Moolenaar     if (wp == NULL)
2309071d4279SBram Moolenaar     {
2310071d4279SBram Moolenaar 	col = 0;
2311071d4279SBram Moolenaar 	width = Columns;
2312071d4279SBram Moolenaar     }
2313071d4279SBram Moolenaar     else
2314071d4279SBram Moolenaar     {
2315071d4279SBram Moolenaar 	col = wp->w_wincol;
2316071d4279SBram Moolenaar 	width = wp->w_width;
2317071d4279SBram Moolenaar     }
2318071d4279SBram Moolenaar     screen_draw_rectangle(row, col, end - row, width, FALSE);
2319071d4279SBram Moolenaar }
2320071d4279SBram Moolenaar 
23217528d1f6SBram Moolenaar     void
space_to_screenline(int off,int attr)23221b9645deSBram Moolenaar space_to_screenline(int off, int attr)
23231b9645deSBram Moolenaar {
23241b9645deSBram Moolenaar     ScreenLines[off] = ' ';
23251b9645deSBram Moolenaar     ScreenAttrs[off] = attr;
23261b9645deSBram Moolenaar     if (enc_utf8)
23271b9645deSBram Moolenaar 	ScreenLinesUC[off] = 0;
23281b9645deSBram Moolenaar }
23291b9645deSBram Moolenaar 
2330071d4279SBram Moolenaar /*
2331071d4279SBram Moolenaar  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
2332071d4279SBram Moolenaar  * with character 'c1' in first column followed by 'c2' in the other columns.
2333071d4279SBram Moolenaar  * Use attributes 'attr'.
2334071d4279SBram Moolenaar  */
2335071d4279SBram Moolenaar     void
screen_fill(int start_row,int end_row,int start_col,int end_col,int c1,int c2,int attr)233605540976SBram Moolenaar screen_fill(
233705540976SBram Moolenaar 	int	start_row,
233805540976SBram Moolenaar 	int	end_row,
233905540976SBram Moolenaar 	int	start_col,
234005540976SBram Moolenaar 	int	end_col,
234105540976SBram Moolenaar 	int	c1,
234205540976SBram Moolenaar 	int	c2,
234305540976SBram Moolenaar 	int	attr)
2344071d4279SBram Moolenaar {
2345071d4279SBram Moolenaar     int	    row;
2346071d4279SBram Moolenaar     int	    col;
2347071d4279SBram Moolenaar     int	    off;
2348071d4279SBram Moolenaar     int	    end_off;
2349071d4279SBram Moolenaar     int	    did_delete;
2350071d4279SBram Moolenaar     int	    c;
2351071d4279SBram Moolenaar     int	    norm_term;
2352071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
2353071d4279SBram Moolenaar     int	    force_next = FALSE;
2354071d4279SBram Moolenaar #endif
2355071d4279SBram Moolenaar 
235663d9e730SBram Moolenaar     if (end_row > screen_Rows)		// safety check
2357071d4279SBram Moolenaar 	end_row = screen_Rows;
235863d9e730SBram Moolenaar     if (end_col > screen_Columns)	// safety check
2359071d4279SBram Moolenaar 	end_col = screen_Columns;
2360071d4279SBram Moolenaar     if (ScreenLines == NULL
2361071d4279SBram Moolenaar 	    || start_row >= end_row
236263d9e730SBram Moolenaar 	    || start_col >= end_col)	// nothing to do
2363071d4279SBram Moolenaar 	return;
2364071d4279SBram Moolenaar 
236563d9e730SBram Moolenaar     // it's a "normal" terminal when not in a GUI or cterm
2366071d4279SBram Moolenaar     norm_term = (
2367071d4279SBram Moolenaar #ifdef FEAT_GUI
2368071d4279SBram Moolenaar 	    !gui.in_use &&
2369071d4279SBram Moolenaar #endif
23708a633e34SBram Moolenaar 	    !IS_CTERM);
2371071d4279SBram Moolenaar     for (row = start_row; row < end_row; ++row)
2372071d4279SBram Moolenaar     {
2373c236c16dSBram Moolenaar 	if (has_mbyte
2374c236c16dSBram Moolenaar #ifdef FEAT_GUI
2375c236c16dSBram Moolenaar 		&& !gui.in_use
2376c236c16dSBram Moolenaar #endif
2377c236c16dSBram Moolenaar 	   )
2378c236c16dSBram Moolenaar 	{
237963d9e730SBram Moolenaar 	    // When drawing over the right halve of a double-wide char clear
238063d9e730SBram Moolenaar 	    // out the left halve.  When drawing over the left halve of a
238163d9e730SBram Moolenaar 	    // double wide-char clear out the right halve.  Only needed in a
238263d9e730SBram Moolenaar 	    // terminal.
23837693ec6eSBram Moolenaar 	    if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
2384d91ffe98SBram Moolenaar 		screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
2385a1aed629SBram Moolenaar 	    if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
2386d91ffe98SBram Moolenaar 		screen_puts_len((char_u *)" ", 1, row, end_col, 0);
2387c236c16dSBram Moolenaar 	}
2388071d4279SBram Moolenaar 	/*
2389071d4279SBram Moolenaar 	 * Try to use delete-line termcap code, when no attributes or in a
2390071d4279SBram Moolenaar 	 * "normal" terminal, where a bold/italic space is just a
2391071d4279SBram Moolenaar 	 * space.
2392071d4279SBram Moolenaar 	 */
2393071d4279SBram Moolenaar 	did_delete = FALSE;
2394071d4279SBram Moolenaar 	if (c2 == ' '
2395071d4279SBram Moolenaar 		&& end_col == Columns
2396071d4279SBram Moolenaar 		&& can_clear(T_CE)
2397071d4279SBram Moolenaar 		&& (attr == 0
2398071d4279SBram Moolenaar 		    || (norm_term
2399071d4279SBram Moolenaar 			&& attr <= HL_ALL
2400071d4279SBram Moolenaar 			&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
2401071d4279SBram Moolenaar 	{
2402071d4279SBram Moolenaar 	    /*
2403071d4279SBram Moolenaar 	     * check if we really need to clear something
2404071d4279SBram Moolenaar 	     */
2405071d4279SBram Moolenaar 	    col = start_col;
240663d9e730SBram Moolenaar 	    if (c1 != ' ')			// don't clear first char
2407071d4279SBram Moolenaar 		++col;
2408071d4279SBram Moolenaar 
2409071d4279SBram Moolenaar 	    off = LineOffset[row] + col;
2410071d4279SBram Moolenaar 	    end_off = LineOffset[row] + end_col;
2411071d4279SBram Moolenaar 
241263d9e730SBram Moolenaar 	    // skip blanks (used often, keep it fast!)
2413071d4279SBram Moolenaar 	    if (enc_utf8)
2414071d4279SBram Moolenaar 		while (off < end_off && ScreenLines[off] == ' '
2415071d4279SBram Moolenaar 			  && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
2416071d4279SBram Moolenaar 		    ++off;
2417071d4279SBram Moolenaar 	    else
2418071d4279SBram Moolenaar 		while (off < end_off && ScreenLines[off] == ' '
2419071d4279SBram Moolenaar 						     && ScreenAttrs[off] == 0)
2420071d4279SBram Moolenaar 		    ++off;
242163d9e730SBram Moolenaar 	    if (off < end_off)		// something to be cleared
2422071d4279SBram Moolenaar 	    {
2423071d4279SBram Moolenaar 		col = off - LineOffset[row];
2424071d4279SBram Moolenaar 		screen_stop_highlight();
242563d9e730SBram Moolenaar 		term_windgoto(row, col);// clear rest of this screen line
2426071d4279SBram Moolenaar 		out_str(T_CE);
242763d9e730SBram Moolenaar 		screen_start();		// don't know where cursor is now
2428071d4279SBram Moolenaar 		col = end_col - col;
242963d9e730SBram Moolenaar 		while (col--)		// clear chars in ScreenLines
2430071d4279SBram Moolenaar 		{
24311b9645deSBram Moolenaar 		    space_to_screenline(off, 0);
2432071d4279SBram Moolenaar 		    ++off;
2433071d4279SBram Moolenaar 		}
2434071d4279SBram Moolenaar 	    }
243563d9e730SBram Moolenaar 	    did_delete = TRUE;		// the chars are cleared now
2436071d4279SBram Moolenaar 	}
2437071d4279SBram Moolenaar 
2438071d4279SBram Moolenaar 	off = LineOffset[row] + start_col;
2439071d4279SBram Moolenaar 	c = c1;
2440071d4279SBram Moolenaar 	for (col = start_col; col < end_col; ++col)
2441071d4279SBram Moolenaar 	{
244233796b39SBram Moolenaar 	    if ((ScreenLines[off] != c
2443362e1a30SBram Moolenaar 		    || (enc_utf8 && (int)ScreenLinesUC[off]
2444362e1a30SBram Moolenaar 						       != (c >= 0x80 ? c : 0))
2445071d4279SBram Moolenaar 		    || ScreenAttrs[off] != attr
2446071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
2447071d4279SBram Moolenaar 		    || force_next
2448071d4279SBram Moolenaar #endif
2449071d4279SBram Moolenaar 		    )
245005ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
245133796b39SBram Moolenaar 		    // Skip if under a(nother) popup.
2452c662ec99SBram Moolenaar 		    && !blocked_by_popup(row, col)
245333796b39SBram Moolenaar #endif
245433796b39SBram Moolenaar 	       )
2455071d4279SBram Moolenaar 	    {
2456071d4279SBram Moolenaar #if defined(FEAT_GUI) || defined(UNIX)
245763d9e730SBram Moolenaar 		// The bold trick may make a single row of pixels appear in
245863d9e730SBram Moolenaar 		// the next character.  When a bold character is removed, the
245963d9e730SBram Moolenaar 		// next character should be redrawn too.  This happens for our
246063d9e730SBram Moolenaar 		// own GUI and for some xterms.
2461071d4279SBram Moolenaar 		if (
2462071d4279SBram Moolenaar # ifdef FEAT_GUI
2463071d4279SBram Moolenaar 			gui.in_use
2464071d4279SBram Moolenaar # endif
2465071d4279SBram Moolenaar # if defined(FEAT_GUI) && defined(UNIX)
2466071d4279SBram Moolenaar 			||
2467071d4279SBram Moolenaar # endif
2468071d4279SBram Moolenaar # ifdef UNIX
2469071d4279SBram Moolenaar 			term_is_xterm
2470071d4279SBram Moolenaar # endif
2471071d4279SBram Moolenaar 		   )
2472071d4279SBram Moolenaar 		{
2473071d4279SBram Moolenaar 		    if (ScreenLines[off] != ' '
2474071d4279SBram Moolenaar 			    && (ScreenAttrs[off] > HL_ALL
2475071d4279SBram Moolenaar 				|| ScreenAttrs[off] & HL_BOLD))
2476071d4279SBram Moolenaar 			force_next = TRUE;
2477071d4279SBram Moolenaar 		    else
2478071d4279SBram Moolenaar 			force_next = FALSE;
2479071d4279SBram Moolenaar 		}
2480071d4279SBram Moolenaar #endif
2481071d4279SBram Moolenaar 		ScreenLines[off] = c;
2482071d4279SBram Moolenaar 		if (enc_utf8)
2483071d4279SBram Moolenaar 		{
2484071d4279SBram Moolenaar 		    if (c >= 0x80)
2485071d4279SBram Moolenaar 		    {
2486071d4279SBram Moolenaar 			ScreenLinesUC[off] = c;
2487362e1a30SBram Moolenaar 			ScreenLinesC[0][off] = 0;
2488071d4279SBram Moolenaar 		    }
2489071d4279SBram Moolenaar 		    else
2490071d4279SBram Moolenaar 			ScreenLinesUC[off] = 0;
2491071d4279SBram Moolenaar 		}
2492071d4279SBram Moolenaar 		ScreenAttrs[off] = attr;
2493071d4279SBram Moolenaar 		if (!did_delete || c != ' ')
2494071d4279SBram Moolenaar 		    screen_char(off, row, col);
2495071d4279SBram Moolenaar 	    }
2496071d4279SBram Moolenaar 	    ++off;
2497071d4279SBram Moolenaar 	    if (col == start_col)
2498071d4279SBram Moolenaar 	    {
2499071d4279SBram Moolenaar 		if (did_delete)
2500071d4279SBram Moolenaar 		    break;
2501071d4279SBram Moolenaar 		c = c2;
2502071d4279SBram Moolenaar 	    }
2503071d4279SBram Moolenaar 	}
2504071d4279SBram Moolenaar 	if (end_col == Columns)
2505071d4279SBram Moolenaar 	    LineWraps[row] = FALSE;
250663d9e730SBram Moolenaar 	if (row == Rows - 1)		// overwritten the command line
2507071d4279SBram Moolenaar 	{
2508071d4279SBram Moolenaar 	    redraw_cmdline = TRUE;
25095bab555cSBram Moolenaar 	    if (start_col == 0 && end_col == Columns
25105bab555cSBram Moolenaar 		    && c1 == ' ' && c2 == ' ' && attr == 0)
251163d9e730SBram Moolenaar 		clear_cmdline = FALSE;	// command line has been cleared
2512d12f5c17SBram Moolenaar 	    if (start_col == 0)
251363d9e730SBram Moolenaar 		mode_displayed = FALSE; // mode cleared or overwritten
2514071d4279SBram Moolenaar 	}
2515071d4279SBram Moolenaar     }
2516071d4279SBram Moolenaar }
2517071d4279SBram Moolenaar 
2518071d4279SBram Moolenaar /*
2519071d4279SBram Moolenaar  * Check if there should be a delay.  Used before clearing or redrawing the
2520071d4279SBram Moolenaar  * screen or the command line.
2521071d4279SBram Moolenaar  */
2522071d4279SBram Moolenaar     void
check_for_delay(int check_msg_scroll)252305540976SBram Moolenaar check_for_delay(int check_msg_scroll)
2524071d4279SBram Moolenaar {
2525071d4279SBram Moolenaar     if ((emsg_on_display || (check_msg_scroll && msg_scroll))
2526071d4279SBram Moolenaar 	    && !did_wait_return
252728ee892aSBram Moolenaar 	    && emsg_silent == 0
252828ee892aSBram Moolenaar 	    && !in_assert_fails)
2529071d4279SBram Moolenaar     {
2530071d4279SBram Moolenaar 	out_flush();
2531eda1da0cSBram Moolenaar 	ui_delay(1006L, TRUE);
2532071d4279SBram Moolenaar 	emsg_on_display = FALSE;
2533071d4279SBram Moolenaar 	if (check_msg_scroll)
2534071d4279SBram Moolenaar 	    msg_scroll = FALSE;
2535071d4279SBram Moolenaar     }
2536071d4279SBram Moolenaar }
2537071d4279SBram Moolenaar 
2538071d4279SBram Moolenaar /*
2539ca57ab54SBram Moolenaar  * Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
2540ca57ab54SBram Moolenaar  */
2541ca57ab54SBram Moolenaar     static void
clear_TabPageIdxs(void)2542ca57ab54SBram Moolenaar clear_TabPageIdxs(void)
2543ca57ab54SBram Moolenaar {
2544ca57ab54SBram Moolenaar     int		scol;
2545ca57ab54SBram Moolenaar 
2546ca57ab54SBram Moolenaar     for (scol = 0; scol < Columns; ++scol)
2547ca57ab54SBram Moolenaar 	TabPageIdxs[scol] = 0;
2548ca57ab54SBram Moolenaar }
2549ca57ab54SBram Moolenaar 
2550ca57ab54SBram Moolenaar /*
2551071d4279SBram Moolenaar  * screen_valid -  allocate screen buffers if size changed
255270b2a56dSBram Moolenaar  *   If "doclear" is TRUE: clear screen if it has been resized.
2553071d4279SBram Moolenaar  *	Returns TRUE if there is a valid screen to write to.
2554071d4279SBram Moolenaar  *	Returns FALSE when starting up and screen not initialized yet.
2555071d4279SBram Moolenaar  */
2556071d4279SBram Moolenaar     int
screen_valid(int doclear)255705540976SBram Moolenaar screen_valid(int doclear)
2558071d4279SBram Moolenaar {
255963d9e730SBram Moolenaar     screenalloc(doclear);	   // allocate screen buffers if size changed
2560071d4279SBram Moolenaar     return (ScreenLines != NULL);
2561071d4279SBram Moolenaar }
2562071d4279SBram Moolenaar 
2563071d4279SBram Moolenaar /*
2564071d4279SBram Moolenaar  * Resize the shell to Rows and Columns.
2565071d4279SBram Moolenaar  * Allocate ScreenLines[] and associated items.
2566071d4279SBram Moolenaar  *
2567071d4279SBram Moolenaar  * There may be some time between setting Rows and Columns and (re)allocating
2568071d4279SBram Moolenaar  * ScreenLines[].  This happens when starting up and when (manually) changing
2569071d4279SBram Moolenaar  * the shell size.  Always use screen_Rows and screen_Columns to access items
2570071d4279SBram Moolenaar  * in ScreenLines[].  Use Rows and Columns for positioning text etc. where the
2571071d4279SBram Moolenaar  * final size of the shell is needed.
2572071d4279SBram Moolenaar  */
2573071d4279SBram Moolenaar     void
screenalloc(int doclear)257405540976SBram Moolenaar screenalloc(int doclear)
2575071d4279SBram Moolenaar {
2576071d4279SBram Moolenaar     int		    new_row, old_row;
2577071d4279SBram Moolenaar #ifdef FEAT_GUI
2578071d4279SBram Moolenaar     int		    old_Rows;
2579071d4279SBram Moolenaar #endif
2580071d4279SBram Moolenaar     win_T	    *wp;
2581071d4279SBram Moolenaar     int		    outofmem = FALSE;
2582071d4279SBram Moolenaar     int		    len;
2583071d4279SBram Moolenaar     schar_T	    *new_ScreenLines;
2584071d4279SBram Moolenaar     u8char_T	    *new_ScreenLinesUC = NULL;
2585362e1a30SBram Moolenaar     u8char_T	    *new_ScreenLinesC[MAX_MCO];
2586071d4279SBram Moolenaar     schar_T	    *new_ScreenLines2 = NULL;
2587362e1a30SBram Moolenaar     int		    i;
2588071d4279SBram Moolenaar     sattr_T	    *new_ScreenAttrs;
2589071d4279SBram Moolenaar     unsigned	    *new_LineOffset;
2590071d4279SBram Moolenaar     char_u	    *new_LineWraps;
2591d1f56e68SBram Moolenaar     short	    *new_TabPageIdxs;
259205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
259333796b39SBram Moolenaar     short	    *new_popup_mask;
25944c063a0dSBram Moolenaar     short	    *new_popup_mask_next;
2595c662ec99SBram Moolenaar     char	    *new_popup_transparent;
259633796b39SBram Moolenaar #endif
2597f740b29aSBram Moolenaar     tabpage_T	    *tp;
259863d9e730SBram Moolenaar     static int	    entered = FALSE;		// avoid recursiveness
259963d9e730SBram Moolenaar     static int	    done_outofmem_msg = FALSE;	// did outofmem message
260087e817c5SBram Moolenaar     int		    retry_count = 0;
2601071d4279SBram Moolenaar 
260287e817c5SBram Moolenaar retry:
2603071d4279SBram Moolenaar     /*
2604071d4279SBram Moolenaar      * Allocation of the screen buffers is done only when the size changes and
2605071d4279SBram Moolenaar      * when Rows and Columns have been set and we have started doing full
2606071d4279SBram Moolenaar      * screen stuff.
2607071d4279SBram Moolenaar      */
2608071d4279SBram Moolenaar     if ((ScreenLines != NULL
2609071d4279SBram Moolenaar 		&& Rows == screen_Rows
2610071d4279SBram Moolenaar 		&& Columns == screen_Columns
2611071d4279SBram Moolenaar 		&& enc_utf8 == (ScreenLinesUC != NULL)
2612071d4279SBram Moolenaar 		&& (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
2613a12a161bSBram Moolenaar 		&& p_mco == Screen_mco)
2614071d4279SBram Moolenaar 	    || Rows == 0
2615071d4279SBram Moolenaar 	    || Columns == 0
2616071d4279SBram Moolenaar 	    || (!full_screen && ScreenLines == NULL))
2617071d4279SBram Moolenaar 	return;
2618071d4279SBram Moolenaar 
2619071d4279SBram Moolenaar     /*
2620071d4279SBram Moolenaar      * It's possible that we produce an out-of-memory message below, which
2621071d4279SBram Moolenaar      * will cause this function to be called again.  To break the loop, just
2622071d4279SBram Moolenaar      * return here.
2623071d4279SBram Moolenaar      */
2624071d4279SBram Moolenaar     if (entered)
2625071d4279SBram Moolenaar 	return;
2626071d4279SBram Moolenaar     entered = TRUE;
2627071d4279SBram Moolenaar 
2628a3f2ecdeSBram Moolenaar     /*
2629a3f2ecdeSBram Moolenaar      * Note that the window sizes are updated before reallocating the arrays,
2630a3f2ecdeSBram Moolenaar      * thus we must not redraw here!
2631a3f2ecdeSBram Moolenaar      */
2632a3f2ecdeSBram Moolenaar     ++RedrawingDisabled;
2633a3f2ecdeSBram Moolenaar 
263463d9e730SBram Moolenaar     win_new_shellsize();    // fit the windows in the new sized shell
2635071d4279SBram Moolenaar 
2636b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
2637b3f74069SBram Moolenaar     vim_lock_screen();  // be safe, put it here
2638b3f74069SBram Moolenaar #endif
2639b3f74069SBram Moolenaar 
264063d9e730SBram Moolenaar     comp_col();		// recompute columns for shown command and ruler
2641071d4279SBram Moolenaar 
2642071d4279SBram Moolenaar     /*
2643071d4279SBram Moolenaar      * We're changing the size of the screen.
2644071d4279SBram Moolenaar      * - Allocate new arrays for ScreenLines and ScreenAttrs.
2645071d4279SBram Moolenaar      * - Move lines from the old arrays into the new arrays, clear extra
2646071d4279SBram Moolenaar      *	 lines (unless the screen is going to be cleared).
2647071d4279SBram Moolenaar      * - Free the old arrays.
2648071d4279SBram Moolenaar      *
2649071d4279SBram Moolenaar      * If anything fails, make ScreenLines NULL, so we don't do anything!
2650071d4279SBram Moolenaar      * Continuing with the old ScreenLines may result in a crash, because the
2651071d4279SBram Moolenaar      * size is wrong.
2652071d4279SBram Moolenaar      */
2653f740b29aSBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
2654071d4279SBram Moolenaar 	win_free_lsize(wp);
26555e9b4540SBram Moolenaar     if (aucmd_win != NULL)
26565e9b4540SBram Moolenaar 	win_free_lsize(aucmd_win);
265705ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
26588caaf825SBram Moolenaar     // global popup windows
2659aeea7215SBram Moolenaar     FOR_ALL_POPUPWINS(wp)
26608caaf825SBram Moolenaar 	win_free_lsize(wp);
26618caaf825SBram Moolenaar     // tab-local popup windows
26628caaf825SBram Moolenaar     FOR_ALL_TABPAGES(tp)
2663aeea7215SBram Moolenaar 	FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
26648caaf825SBram Moolenaar 	    win_free_lsize(wp);
26658caaf825SBram Moolenaar #endif
2666071d4279SBram Moolenaar 
2667c799fe20SBram Moolenaar     new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2668216b7106SBram Moolenaar     vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
2669071d4279SBram Moolenaar     if (enc_utf8)
2670071d4279SBram Moolenaar     {
2671c799fe20SBram Moolenaar 	new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
2672362e1a30SBram Moolenaar 	for (i = 0; i < p_mco; ++i)
2673c799fe20SBram Moolenaar 	    new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
2674c799fe20SBram Moolenaar 							 (Rows + 1) * Columns);
2675071d4279SBram Moolenaar     }
2676071d4279SBram Moolenaar     if (enc_dbcs == DBCS_JPNU)
2677c799fe20SBram Moolenaar 	new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2678c799fe20SBram Moolenaar     new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
2679c799fe20SBram Moolenaar     new_LineOffset = LALLOC_MULT(unsigned, Rows);
2680c799fe20SBram Moolenaar     new_LineWraps = LALLOC_MULT(char_u, Rows);
2681c799fe20SBram Moolenaar     new_TabPageIdxs = LALLOC_MULT(short, Columns);
268205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
268333796b39SBram Moolenaar     new_popup_mask = LALLOC_MULT(short, Rows * Columns);
26844c063a0dSBram Moolenaar     new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
2685c662ec99SBram Moolenaar     new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
268633796b39SBram Moolenaar #endif
2687071d4279SBram Moolenaar 
2688faa959a8SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
2689071d4279SBram Moolenaar     {
2690071d4279SBram Moolenaar 	if (win_alloc_lines(wp) == FAIL)
2691071d4279SBram Moolenaar 	{
2692071d4279SBram Moolenaar 	    outofmem = TRUE;
2693bb9c7d1cSBram Moolenaar 	    goto give_up;
2694071d4279SBram Moolenaar 	}
2695071d4279SBram Moolenaar     }
26965e9b4540SBram Moolenaar     if (aucmd_win != NULL && aucmd_win->w_lines == NULL
26975e9b4540SBram Moolenaar 					&& win_alloc_lines(aucmd_win) == FAIL)
2698746ebd3bSBram Moolenaar 	outofmem = TRUE;
269905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
27008caaf825SBram Moolenaar     // global popup windows
2701aeea7215SBram Moolenaar     FOR_ALL_POPUPWINS(wp)
27028caaf825SBram Moolenaar 	if (win_alloc_lines(wp) == FAIL)
27038caaf825SBram Moolenaar 	{
27048caaf825SBram Moolenaar 	    outofmem = TRUE;
27058caaf825SBram Moolenaar 	    goto give_up;
27068caaf825SBram Moolenaar 	}
27078caaf825SBram Moolenaar     // tab-local popup windows
27088caaf825SBram Moolenaar     FOR_ALL_TABPAGES(tp)
2709aeea7215SBram Moolenaar 	FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
27108caaf825SBram Moolenaar 	    if (win_alloc_lines(wp) == FAIL)
27118caaf825SBram Moolenaar 	    {
27128caaf825SBram Moolenaar 		outofmem = TRUE;
27138caaf825SBram Moolenaar 		goto give_up;
27148caaf825SBram Moolenaar 	    }
27158caaf825SBram Moolenaar #endif
27168caaf825SBram Moolenaar 
2717bb9c7d1cSBram Moolenaar give_up:
2718071d4279SBram Moolenaar 
2719362e1a30SBram Moolenaar     for (i = 0; i < p_mco; ++i)
2720362e1a30SBram Moolenaar 	if (new_ScreenLinesC[i] == NULL)
2721362e1a30SBram Moolenaar 	    break;
2722071d4279SBram Moolenaar     if (new_ScreenLines == NULL
2723362e1a30SBram Moolenaar 	    || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
2724071d4279SBram Moolenaar 	    || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
2725071d4279SBram Moolenaar 	    || new_ScreenAttrs == NULL
2726071d4279SBram Moolenaar 	    || new_LineOffset == NULL
2727071d4279SBram Moolenaar 	    || new_LineWraps == NULL
2728f740b29aSBram Moolenaar 	    || new_TabPageIdxs == NULL
272905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
273033796b39SBram Moolenaar 	    || new_popup_mask == NULL
27314c063a0dSBram Moolenaar 	    || new_popup_mask_next == NULL
2732c662ec99SBram Moolenaar 	    || new_popup_transparent == NULL
273333796b39SBram Moolenaar #endif
2734071d4279SBram Moolenaar 	    || outofmem)
2735071d4279SBram Moolenaar     {
273689d4032cSBram Moolenaar 	if (ScreenLines != NULL || !done_outofmem_msg)
2737482aaeb0SBram Moolenaar 	{
273863d9e730SBram Moolenaar 	    // guess the size
2739482aaeb0SBram Moolenaar 	    do_outofmem_msg((long_u)((Rows + 1) * Columns));
2740482aaeb0SBram Moolenaar 
274163d9e730SBram Moolenaar 	    // Remember we did this to avoid getting outofmem messages over
274263d9e730SBram Moolenaar 	    // and over again.
274389d4032cSBram Moolenaar 	    done_outofmem_msg = TRUE;
2744482aaeb0SBram Moolenaar 	}
2745d23a8236SBram Moolenaar 	VIM_CLEAR(new_ScreenLines);
2746d23a8236SBram Moolenaar 	VIM_CLEAR(new_ScreenLinesUC);
2747362e1a30SBram Moolenaar 	for (i = 0; i < p_mco; ++i)
2748d23a8236SBram Moolenaar 	    VIM_CLEAR(new_ScreenLinesC[i]);
2749d23a8236SBram Moolenaar 	VIM_CLEAR(new_ScreenLines2);
2750d23a8236SBram Moolenaar 	VIM_CLEAR(new_ScreenAttrs);
2751d23a8236SBram Moolenaar 	VIM_CLEAR(new_LineOffset);
2752d23a8236SBram Moolenaar 	VIM_CLEAR(new_LineWraps);
2753d23a8236SBram Moolenaar 	VIM_CLEAR(new_TabPageIdxs);
275405ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
275533796b39SBram Moolenaar 	VIM_CLEAR(new_popup_mask);
27564c063a0dSBram Moolenaar 	VIM_CLEAR(new_popup_mask_next);
2757c662ec99SBram Moolenaar 	VIM_CLEAR(new_popup_transparent);
275833796b39SBram Moolenaar #endif
2759071d4279SBram Moolenaar     }
2760071d4279SBram Moolenaar     else
2761071d4279SBram Moolenaar     {
276289d4032cSBram Moolenaar 	done_outofmem_msg = FALSE;
2763482aaeb0SBram Moolenaar 
2764071d4279SBram Moolenaar 	for (new_row = 0; new_row < Rows; ++new_row)
2765071d4279SBram Moolenaar 	{
2766071d4279SBram Moolenaar 	    new_LineOffset[new_row] = new_row * Columns;
2767071d4279SBram Moolenaar 	    new_LineWraps[new_row] = FALSE;
2768071d4279SBram Moolenaar 
2769071d4279SBram Moolenaar 	    /*
2770071d4279SBram Moolenaar 	     * If the screen is not going to be cleared, copy as much as
2771071d4279SBram Moolenaar 	     * possible from the old screen to the new one and clear the rest
2772071d4279SBram Moolenaar 	     * (used when resizing the window at the "--more--" prompt or when
2773071d4279SBram Moolenaar 	     * executing an external command, for the GUI).
2774071d4279SBram Moolenaar 	     */
277570b2a56dSBram Moolenaar 	    if (!doclear)
2776071d4279SBram Moolenaar 	    {
2777071d4279SBram Moolenaar 		(void)vim_memset(new_ScreenLines + new_row * Columns,
2778071d4279SBram Moolenaar 				      ' ', (size_t)Columns * sizeof(schar_T));
2779071d4279SBram Moolenaar 		if (enc_utf8)
2780071d4279SBram Moolenaar 		{
2781071d4279SBram Moolenaar 		    (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
2782071d4279SBram Moolenaar 				       0, (size_t)Columns * sizeof(u8char_T));
2783362e1a30SBram Moolenaar 		    for (i = 0; i < p_mco; ++i)
2784362e1a30SBram Moolenaar 			(void)vim_memset(new_ScreenLinesC[i]
2785362e1a30SBram Moolenaar 							  + new_row * Columns,
2786071d4279SBram Moolenaar 				       0, (size_t)Columns * sizeof(u8char_T));
2787071d4279SBram Moolenaar 		}
2788071d4279SBram Moolenaar 		if (enc_dbcs == DBCS_JPNU)
2789071d4279SBram Moolenaar 		    (void)vim_memset(new_ScreenLines2 + new_row * Columns,
2790071d4279SBram Moolenaar 				       0, (size_t)Columns * sizeof(schar_T));
2791071d4279SBram Moolenaar 		(void)vim_memset(new_ScreenAttrs + new_row * Columns,
2792071d4279SBram Moolenaar 					0, (size_t)Columns * sizeof(sattr_T));
2793071d4279SBram Moolenaar 		old_row = new_row + (screen_Rows - Rows);
2794482aaeb0SBram Moolenaar 		if (old_row >= 0 && ScreenLines != NULL)
2795071d4279SBram Moolenaar 		{
2796071d4279SBram Moolenaar 		    if (screen_Columns < Columns)
2797071d4279SBram Moolenaar 			len = screen_Columns;
2798071d4279SBram Moolenaar 		    else
2799071d4279SBram Moolenaar 			len = Columns;
280063d9e730SBram Moolenaar 		    // When switching to utf-8 don't copy characters, they
280163d9e730SBram Moolenaar 		    // may be invalid now.  Also when p_mco changes.
2802362e1a30SBram Moolenaar 		    if (!(enc_utf8 && ScreenLinesUC == NULL)
2803362e1a30SBram Moolenaar 						       && p_mco == Screen_mco)
2804071d4279SBram Moolenaar 			mch_memmove(new_ScreenLines + new_LineOffset[new_row],
2805071d4279SBram Moolenaar 				ScreenLines + LineOffset[old_row],
2806071d4279SBram Moolenaar 				(size_t)len * sizeof(schar_T));
2807362e1a30SBram Moolenaar 		    if (enc_utf8 && ScreenLinesUC != NULL
2808362e1a30SBram Moolenaar 						       && p_mco == Screen_mco)
2809071d4279SBram Moolenaar 		    {
2810071d4279SBram Moolenaar 			mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
2811071d4279SBram Moolenaar 				ScreenLinesUC + LineOffset[old_row],
2812071d4279SBram Moolenaar 				(size_t)len * sizeof(u8char_T));
2813362e1a30SBram Moolenaar 			for (i = 0; i < p_mco; ++i)
2814362e1a30SBram Moolenaar 			    mch_memmove(new_ScreenLinesC[i]
2815362e1a30SBram Moolenaar 						    + new_LineOffset[new_row],
2816362e1a30SBram Moolenaar 				ScreenLinesC[i] + LineOffset[old_row],
2817071d4279SBram Moolenaar 				(size_t)len * sizeof(u8char_T));
2818071d4279SBram Moolenaar 		    }
2819071d4279SBram Moolenaar 		    if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
2820071d4279SBram Moolenaar 			mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
2821071d4279SBram Moolenaar 				ScreenLines2 + LineOffset[old_row],
2822071d4279SBram Moolenaar 				(size_t)len * sizeof(schar_T));
2823071d4279SBram Moolenaar 		    mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
2824071d4279SBram Moolenaar 			    ScreenAttrs + LineOffset[old_row],
2825071d4279SBram Moolenaar 			    (size_t)len * sizeof(sattr_T));
2826071d4279SBram Moolenaar 		}
2827071d4279SBram Moolenaar 	    }
2828071d4279SBram Moolenaar 	}
282963d9e730SBram Moolenaar 	// Use the last line of the screen for the current line.
2830071d4279SBram Moolenaar 	current_ScreenLine = new_ScreenLines + Rows * Columns;
28316ace95e9SBram Moolenaar 
283205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
28336ace95e9SBram Moolenaar 	vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
28346ace95e9SBram Moolenaar 	vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
28356ace95e9SBram Moolenaar #endif
2836071d4279SBram Moolenaar     }
2837071d4279SBram Moolenaar 
28381ec484f5SBram Moolenaar     free_screenlines();
28391ec484f5SBram Moolenaar 
28406ace95e9SBram Moolenaar     // NOTE: this may result in all pointers to become NULL.
2841071d4279SBram Moolenaar     ScreenLines = new_ScreenLines;
2842071d4279SBram Moolenaar     ScreenLinesUC = new_ScreenLinesUC;
2843362e1a30SBram Moolenaar     for (i = 0; i < p_mco; ++i)
2844362e1a30SBram Moolenaar 	ScreenLinesC[i] = new_ScreenLinesC[i];
2845362e1a30SBram Moolenaar     Screen_mco = p_mco;
2846071d4279SBram Moolenaar     ScreenLines2 = new_ScreenLines2;
2847071d4279SBram Moolenaar     ScreenAttrs = new_ScreenAttrs;
2848071d4279SBram Moolenaar     LineOffset = new_LineOffset;
2849071d4279SBram Moolenaar     LineWraps = new_LineWraps;
2850f740b29aSBram Moolenaar     TabPageIdxs = new_TabPageIdxs;
285105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
285233796b39SBram Moolenaar     popup_mask = new_popup_mask;
2853c662ec99SBram Moolenaar     popup_mask_next = new_popup_mask_next;
2854c662ec99SBram Moolenaar     popup_transparent = new_popup_transparent;
285533796b39SBram Moolenaar     popup_mask_refresh = TRUE;
285633796b39SBram Moolenaar #endif
2857071d4279SBram Moolenaar 
285863d9e730SBram Moolenaar     // It's important that screen_Rows and screen_Columns reflect the actual
285963d9e730SBram Moolenaar     // size of ScreenLines[].  Set them before calling anything.
2860071d4279SBram Moolenaar #ifdef FEAT_GUI
2861071d4279SBram Moolenaar     old_Rows = screen_Rows;
2862071d4279SBram Moolenaar #endif
2863071d4279SBram Moolenaar     screen_Rows = Rows;
2864071d4279SBram Moolenaar     screen_Columns = Columns;
2865071d4279SBram Moolenaar 
286663d9e730SBram Moolenaar     must_redraw = CLEAR;	// need to clear the screen later
286770b2a56dSBram Moolenaar     if (doclear)
2868071d4279SBram Moolenaar 	screenclear2();
2869071d4279SBram Moolenaar #ifdef FEAT_GUI
2870071d4279SBram Moolenaar     else if (gui.in_use
2871071d4279SBram Moolenaar 	    && !gui.starting
2872071d4279SBram Moolenaar 	    && ScreenLines != NULL
2873071d4279SBram Moolenaar 	    && old_Rows != Rows)
2874071d4279SBram Moolenaar     {
28757c003aa3SBram Moolenaar 	gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
28767c003aa3SBram Moolenaar 
28777c003aa3SBram Moolenaar 	// Adjust the position of the cursor, for when executing an external
28787c003aa3SBram Moolenaar 	// command.
287963d9e730SBram Moolenaar 	if (msg_row >= Rows)		// Rows got smaller
288063d9e730SBram Moolenaar 	    msg_row = Rows - 1;		// put cursor at last row
288163d9e730SBram Moolenaar 	else if (Rows > old_Rows)	// Rows got bigger
288263d9e730SBram Moolenaar 	    msg_row += Rows - old_Rows; // put cursor in same place
288363d9e730SBram Moolenaar 	if (msg_col >= Columns)		// Columns got smaller
288463d9e730SBram Moolenaar 	    msg_col = Columns - 1;	// put cursor at last column
2885071d4279SBram Moolenaar     }
2886071d4279SBram Moolenaar #endif
2887ca57ab54SBram Moolenaar     clear_TabPageIdxs();
2888071d4279SBram Moolenaar 
2889b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
2890b3f74069SBram Moolenaar     vim_unlock_screen();
2891b3f74069SBram Moolenaar #endif
2892b3f74069SBram Moolenaar 
2893071d4279SBram Moolenaar     entered = FALSE;
2894a3f2ecdeSBram Moolenaar     --RedrawingDisabled;
28957d47b6eeSBram Moolenaar 
289687e817c5SBram Moolenaar     /*
289787e817c5SBram Moolenaar      * Do not apply autocommands more than 3 times to avoid an endless loop
289887e817c5SBram Moolenaar      * in case applying autocommands always changes Rows or Columns.
289987e817c5SBram Moolenaar      */
290087e817c5SBram Moolenaar     if (starting == 0 && ++retry_count <= 3)
290187e817c5SBram Moolenaar     {
29027d47b6eeSBram Moolenaar 	apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
290363d9e730SBram Moolenaar 	// In rare cases, autocommands may have altered Rows or Columns,
290463d9e730SBram Moolenaar 	// jump back to check if we need to allocate the screen again.
290587e817c5SBram Moolenaar 	goto retry;
290687e817c5SBram Moolenaar     }
2907071d4279SBram Moolenaar }
2908071d4279SBram Moolenaar 
2909071d4279SBram Moolenaar     void
free_screenlines(void)291005540976SBram Moolenaar free_screenlines(void)
29111ec484f5SBram Moolenaar {
2912362e1a30SBram Moolenaar     int		i;
2913362e1a30SBram Moolenaar 
291433796b39SBram Moolenaar     VIM_CLEAR(ScreenLinesUC);
2915362e1a30SBram Moolenaar     for (i = 0; i < Screen_mco; ++i)
291633796b39SBram Moolenaar 	VIM_CLEAR(ScreenLinesC[i]);
291733796b39SBram Moolenaar     VIM_CLEAR(ScreenLines2);
291833796b39SBram Moolenaar     VIM_CLEAR(ScreenLines);
291933796b39SBram Moolenaar     VIM_CLEAR(ScreenAttrs);
292033796b39SBram Moolenaar     VIM_CLEAR(LineOffset);
292133796b39SBram Moolenaar     VIM_CLEAR(LineWraps);
292233796b39SBram Moolenaar     VIM_CLEAR(TabPageIdxs);
292305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
292433796b39SBram Moolenaar     VIM_CLEAR(popup_mask);
29254c063a0dSBram Moolenaar     VIM_CLEAR(popup_mask_next);
2926c662ec99SBram Moolenaar     VIM_CLEAR(popup_transparent);
292733796b39SBram Moolenaar #endif
29281ec484f5SBram Moolenaar }
29291ec484f5SBram Moolenaar 
29301ec484f5SBram Moolenaar     void
screenclear(void)293105540976SBram Moolenaar screenclear(void)
2932071d4279SBram Moolenaar {
2933071d4279SBram Moolenaar     check_for_delay(FALSE);
293463d9e730SBram Moolenaar     screenalloc(FALSE);	    // allocate screen buffers if size changed
293563d9e730SBram Moolenaar     screenclear2();	    // clear the screen
2936071d4279SBram Moolenaar }
2937071d4279SBram Moolenaar 
2938071d4279SBram Moolenaar     static void
screenclear2(void)293905540976SBram Moolenaar screenclear2(void)
2940071d4279SBram Moolenaar {
2941071d4279SBram Moolenaar     int	    i;
2942071d4279SBram Moolenaar 
2943071d4279SBram Moolenaar     if (starting == NO_SCREEN || ScreenLines == NULL
2944071d4279SBram Moolenaar #ifdef FEAT_GUI
2945071d4279SBram Moolenaar 	    || (gui.in_use && gui.starting)
2946071d4279SBram Moolenaar #endif
2947071d4279SBram Moolenaar 	    )
2948071d4279SBram Moolenaar 	return;
2949071d4279SBram Moolenaar 
2950071d4279SBram Moolenaar #ifdef FEAT_GUI
2951071d4279SBram Moolenaar     if (!gui.in_use)
2952071d4279SBram Moolenaar #endif
295363d9e730SBram Moolenaar 	screen_attr = -1;	// force setting the Normal colors
295463d9e730SBram Moolenaar     screen_stop_highlight();	// don't want highlighting here
2955071d4279SBram Moolenaar 
2956071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
295763d9e730SBram Moolenaar     // disable selection without redrawing it
2958071d4279SBram Moolenaar     clip_scroll_selection(9999);
2959071d4279SBram Moolenaar #endif
2960071d4279SBram Moolenaar 
296163d9e730SBram Moolenaar     // blank out ScreenLines
2962071d4279SBram Moolenaar     for (i = 0; i < Rows; ++i)
2963071d4279SBram Moolenaar     {
2964cfce7171SBram Moolenaar 	lineclear(LineOffset[i], (int)Columns, 0);
2965071d4279SBram Moolenaar 	LineWraps[i] = FALSE;
2966071d4279SBram Moolenaar     }
2967071d4279SBram Moolenaar 
2968071d4279SBram Moolenaar     if (can_clear(T_CL))
2969071d4279SBram Moolenaar     {
297063d9e730SBram Moolenaar 	out_str(T_CL);		// clear the display
2971071d4279SBram Moolenaar 	clear_cmdline = FALSE;
2972d12f5c17SBram Moolenaar 	mode_displayed = FALSE;
2973071d4279SBram Moolenaar     }
2974071d4279SBram Moolenaar     else
2975071d4279SBram Moolenaar     {
297663d9e730SBram Moolenaar 	// can't clear the screen, mark all chars with invalid attributes
2977071d4279SBram Moolenaar 	for (i = 0; i < Rows; ++i)
2978071d4279SBram Moolenaar 	    lineinvalid(LineOffset[i], (int)Columns);
2979071d4279SBram Moolenaar 	clear_cmdline = TRUE;
2980071d4279SBram Moolenaar     }
2981071d4279SBram Moolenaar 
298263d9e730SBram Moolenaar     screen_cleared = TRUE;	// can use contents of ScreenLines now
2983071d4279SBram Moolenaar 
2984071d4279SBram Moolenaar     win_rest_invalid(firstwin);
2985071d4279SBram Moolenaar     redraw_cmdline = TRUE;
2986997fb4baSBram Moolenaar     redraw_tabline = TRUE;
298763d9e730SBram Moolenaar     if (must_redraw == CLEAR)	// no need to clear again
2988071d4279SBram Moolenaar 	must_redraw = NOT_VALID;
2989071d4279SBram Moolenaar     compute_cmdrow();
299063d9e730SBram Moolenaar     msg_row = cmdline_row;	// put cursor on last line for messages
2991071d4279SBram Moolenaar     msg_col = 0;
299263d9e730SBram Moolenaar     screen_start();		// don't know where cursor is now
299363d9e730SBram Moolenaar     msg_scrolled = 0;		// can't scroll back
2994071d4279SBram Moolenaar     msg_didany = FALSE;
2995071d4279SBram Moolenaar     msg_didout = FALSE;
2996071d4279SBram Moolenaar }
2997071d4279SBram Moolenaar 
2998071d4279SBram Moolenaar /*
2999071d4279SBram Moolenaar  * Clear one line in ScreenLines.
3000071d4279SBram Moolenaar  */
3001071d4279SBram Moolenaar     static void
lineclear(unsigned off,int width,int attr)3002cfce7171SBram Moolenaar lineclear(unsigned off, int width, int attr)
3003071d4279SBram Moolenaar {
3004071d4279SBram Moolenaar     (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
3005071d4279SBram Moolenaar     if (enc_utf8)
3006071d4279SBram Moolenaar 	(void)vim_memset(ScreenLinesUC + off, 0,
3007071d4279SBram Moolenaar 					  (size_t)width * sizeof(u8char_T));
3008cfce7171SBram Moolenaar     (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
3009071d4279SBram Moolenaar }
3010071d4279SBram Moolenaar 
3011071d4279SBram Moolenaar /*
3012071d4279SBram Moolenaar  * Mark one line in ScreenLines invalid by setting the attributes to an
3013071d4279SBram Moolenaar  * invalid value.
3014071d4279SBram Moolenaar  */
3015071d4279SBram Moolenaar     static void
lineinvalid(unsigned off,int width)301605540976SBram Moolenaar lineinvalid(unsigned off, int width)
3017071d4279SBram Moolenaar {
3018071d4279SBram Moolenaar     (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
3019071d4279SBram Moolenaar }
3020071d4279SBram Moolenaar 
3021071d4279SBram Moolenaar /*
302296916ac6SBram Moolenaar  * To be called when characters were sent to the terminal directly, outputting
302396916ac6SBram Moolenaar  * test on "screen_lnum".
302496916ac6SBram Moolenaar  */
302596916ac6SBram Moolenaar     void
line_was_clobbered(int screen_lnum)302696916ac6SBram Moolenaar line_was_clobbered(int screen_lnum)
302796916ac6SBram Moolenaar {
302896916ac6SBram Moolenaar     lineinvalid(LineOffset[screen_lnum], (int)Columns);
302996916ac6SBram Moolenaar }
303096916ac6SBram Moolenaar 
303196916ac6SBram Moolenaar /*
3032071d4279SBram Moolenaar  * Copy part of a Screenline for vertically split window "wp".
3033071d4279SBram Moolenaar  */
3034071d4279SBram Moolenaar     static void
linecopy(int to,int from,win_T * wp)303505540976SBram Moolenaar linecopy(int to, int from, win_T *wp)
3036071d4279SBram Moolenaar {
3037071d4279SBram Moolenaar     unsigned	off_to = LineOffset[to] + wp->w_wincol;
3038071d4279SBram Moolenaar     unsigned	off_from = LineOffset[from] + wp->w_wincol;
3039071d4279SBram Moolenaar 
3040071d4279SBram Moolenaar     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
3041071d4279SBram Moolenaar 	    wp->w_width * sizeof(schar_T));
3042071d4279SBram Moolenaar     if (enc_utf8)
3043071d4279SBram Moolenaar     {
3044362e1a30SBram Moolenaar 	int	i;
3045362e1a30SBram Moolenaar 
3046071d4279SBram Moolenaar 	mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
3047071d4279SBram Moolenaar 		wp->w_width * sizeof(u8char_T));
3048362e1a30SBram Moolenaar 	for (i = 0; i < p_mco; ++i)
3049362e1a30SBram Moolenaar 	    mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
3050071d4279SBram Moolenaar 		    wp->w_width * sizeof(u8char_T));
3051071d4279SBram Moolenaar     }
3052071d4279SBram Moolenaar     if (enc_dbcs == DBCS_JPNU)
3053071d4279SBram Moolenaar 	mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
3054071d4279SBram Moolenaar 		wp->w_width * sizeof(schar_T));
3055071d4279SBram Moolenaar     mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
3056071d4279SBram Moolenaar 	    wp->w_width * sizeof(sattr_T));
3057071d4279SBram Moolenaar }
3058071d4279SBram Moolenaar 
3059071d4279SBram Moolenaar /*
3060071d4279SBram Moolenaar  * Return TRUE if clearing with term string "p" would work.
3061071d4279SBram Moolenaar  * It can't work when the string is empty or it won't set the right background.
306233796b39SBram Moolenaar  * Don't clear to end-of-line when there are popups, it may cause flicker.
3063071d4279SBram Moolenaar  */
3064071d4279SBram Moolenaar     int
can_clear(char_u * p)306505540976SBram Moolenaar can_clear(char_u *p)
3066071d4279SBram Moolenaar {
3067071d4279SBram Moolenaar     return (*p != NUL && (t_colors <= 1
3068071d4279SBram Moolenaar #ifdef FEAT_GUI
3069071d4279SBram Moolenaar 		|| gui.in_use
3070071d4279SBram Moolenaar #endif
307161be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
30721b58cdd1SBram Moolenaar 		|| (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
3073d18f672fSBram Moolenaar 		|| (!p_tgc && cterm_normal_bg_color == 0)
3074d18f672fSBram Moolenaar #else
3075d18f672fSBram Moolenaar 		|| cterm_normal_bg_color == 0
30768a633e34SBram Moolenaar #endif
307733796b39SBram Moolenaar 		|| *T_UT != NUL)
307805ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
307933796b39SBram Moolenaar 	    && !(p == T_CE && popup_visible)
308033796b39SBram Moolenaar #endif
308133796b39SBram Moolenaar 	    );
3082071d4279SBram Moolenaar }
3083071d4279SBram Moolenaar 
3084071d4279SBram Moolenaar /*
3085071d4279SBram Moolenaar  * Reset cursor position. Use whenever cursor was moved because of outputting
3086071d4279SBram Moolenaar  * something directly to the screen (shell commands) or a terminal control
3087071d4279SBram Moolenaar  * code.
3088071d4279SBram Moolenaar  */
3089071d4279SBram Moolenaar     void
screen_start(void)309005540976SBram Moolenaar screen_start(void)
3091071d4279SBram Moolenaar {
3092071d4279SBram Moolenaar     screen_cur_row = screen_cur_col = 9999;
3093071d4279SBram Moolenaar }
3094071d4279SBram Moolenaar 
3095071d4279SBram Moolenaar /*
3096071d4279SBram Moolenaar  * Move the cursor to position "row","col" in the screen.
3097071d4279SBram Moolenaar  * This tries to find the most efficient way to move, minimizing the number of
3098071d4279SBram Moolenaar  * characters sent to the terminal.
3099071d4279SBram Moolenaar  */
3100071d4279SBram Moolenaar     void
windgoto(int row,int col)310105540976SBram Moolenaar windgoto(int row, int col)
3102071d4279SBram Moolenaar {
3103e2cc9702SBram Moolenaar     sattr_T	    *p;
3104071d4279SBram Moolenaar     int		    i;
3105071d4279SBram Moolenaar     int		    plan;
3106071d4279SBram Moolenaar     int		    cost;
3107071d4279SBram Moolenaar     int		    wouldbe_col;
3108071d4279SBram Moolenaar     int		    noinvcurs;
3109071d4279SBram Moolenaar     char_u	    *bs;
3110071d4279SBram Moolenaar     int		    goto_cost;
3111071d4279SBram Moolenaar     int		    attr;
3112071d4279SBram Moolenaar 
311363d9e730SBram Moolenaar #define GOTO_COST   7	// assume a term_windgoto() takes about 7 chars
311463d9e730SBram Moolenaar #define HIGHL_COST  5	// assume unhighlight takes 5 chars
3115071d4279SBram Moolenaar 
3116071d4279SBram Moolenaar #define PLAN_LE	    1
3117071d4279SBram Moolenaar #define PLAN_CR	    2
3118071d4279SBram Moolenaar #define PLAN_NL	    3
3119071d4279SBram Moolenaar #define PLAN_WRITE  4
312063d9e730SBram Moolenaar     // Can't use ScreenLines unless initialized
3121071d4279SBram Moolenaar     if (ScreenLines == NULL)
3122071d4279SBram Moolenaar 	return;
3123071d4279SBram Moolenaar     if (col != screen_cur_col || row != screen_cur_row)
3124071d4279SBram Moolenaar     {
312563d9e730SBram Moolenaar 	// Check for valid position.
312663d9e730SBram Moolenaar 	if (row < 0)	// window without text lines?
3127071d4279SBram Moolenaar 	    row = 0;
3128071d4279SBram Moolenaar 	if (row >= screen_Rows)
3129071d4279SBram Moolenaar 	    row = screen_Rows - 1;
3130071d4279SBram Moolenaar 	if (col >= screen_Columns)
3131071d4279SBram Moolenaar 	    col = screen_Columns - 1;
3132071d4279SBram Moolenaar 
313363d9e730SBram Moolenaar 	// check if no cursor movement is allowed in highlight mode
3134071d4279SBram Moolenaar 	if (screen_attr && *T_MS == NUL)
3135071d4279SBram Moolenaar 	    noinvcurs = HIGHL_COST;
3136071d4279SBram Moolenaar 	else
3137071d4279SBram Moolenaar 	    noinvcurs = 0;
3138071d4279SBram Moolenaar 	goto_cost = GOTO_COST + noinvcurs;
3139071d4279SBram Moolenaar 
3140071d4279SBram Moolenaar 	/*
3141071d4279SBram Moolenaar 	 * Plan how to do the positioning:
3142071d4279SBram Moolenaar 	 * 1. Use CR to move it to column 0, same row.
3143071d4279SBram Moolenaar 	 * 2. Use T_LE to move it a few columns to the left.
3144071d4279SBram Moolenaar 	 * 3. Use NL to move a few lines down, column 0.
3145071d4279SBram Moolenaar 	 * 4. Move a few columns to the right with T_ND or by writing chars.
3146071d4279SBram Moolenaar 	 *
3147071d4279SBram Moolenaar 	 * Don't do this if the cursor went beyond the last column, the cursor
3148071d4279SBram Moolenaar 	 * position is unknown then (some terminals wrap, some don't )
3149071d4279SBram Moolenaar 	 *
31502c7a7638SBram Moolenaar 	 * First check if the highlighting attributes allow us to write
3151071d4279SBram Moolenaar 	 * characters to move the cursor to the right.
3152071d4279SBram Moolenaar 	 */
3153071d4279SBram Moolenaar 	if (row >= screen_cur_row && screen_cur_col < Columns)
3154071d4279SBram Moolenaar 	{
3155071d4279SBram Moolenaar 	    /*
3156071d4279SBram Moolenaar 	     * If the cursor is in the same row, bigger col, we can use CR
3157071d4279SBram Moolenaar 	     * or T_LE.
3158071d4279SBram Moolenaar 	     */
315963d9e730SBram Moolenaar 	    bs = NULL;			    // init for GCC
3160071d4279SBram Moolenaar 	    attr = screen_attr;
3161071d4279SBram Moolenaar 	    if (row == screen_cur_row && col < screen_cur_col)
3162071d4279SBram Moolenaar 	    {
316363d9e730SBram Moolenaar 		// "le" is preferred over "bc", because "bc" is obsolete
3164071d4279SBram Moolenaar 		if (*T_LE)
316563d9e730SBram Moolenaar 		    bs = T_LE;		    // "cursor left"
3166071d4279SBram Moolenaar 		else
316763d9e730SBram Moolenaar 		    bs = T_BC;		    // "backspace character (old)
3168071d4279SBram Moolenaar 		if (*bs)
3169071d4279SBram Moolenaar 		    cost = (screen_cur_col - col) * (int)STRLEN(bs);
3170071d4279SBram Moolenaar 		else
3171071d4279SBram Moolenaar 		    cost = 999;
317263d9e730SBram Moolenaar 		if (col + 1 < cost)	    // using CR is less characters
3173071d4279SBram Moolenaar 		{
3174071d4279SBram Moolenaar 		    plan = PLAN_CR;
3175071d4279SBram Moolenaar 		    wouldbe_col = 0;
317663d9e730SBram Moolenaar 		    cost = 1;		    // CR is just one character
3177071d4279SBram Moolenaar 		}
3178071d4279SBram Moolenaar 		else
3179071d4279SBram Moolenaar 		{
3180071d4279SBram Moolenaar 		    plan = PLAN_LE;
3181071d4279SBram Moolenaar 		    wouldbe_col = col;
3182071d4279SBram Moolenaar 		}
318363d9e730SBram Moolenaar 		if (noinvcurs)		    // will stop highlighting
3184071d4279SBram Moolenaar 		{
3185071d4279SBram Moolenaar 		    cost += noinvcurs;
3186071d4279SBram Moolenaar 		    attr = 0;
3187071d4279SBram Moolenaar 		}
3188071d4279SBram Moolenaar 	    }
3189071d4279SBram Moolenaar 
3190071d4279SBram Moolenaar 	    /*
3191071d4279SBram Moolenaar 	     * If the cursor is above where we want to be, we can use CR LF.
3192071d4279SBram Moolenaar 	     */
3193071d4279SBram Moolenaar 	    else if (row > screen_cur_row)
3194071d4279SBram Moolenaar 	    {
3195071d4279SBram Moolenaar 		plan = PLAN_NL;
3196071d4279SBram Moolenaar 		wouldbe_col = 0;
319763d9e730SBram Moolenaar 		cost = (row - screen_cur_row) * 2;  // CR LF
319863d9e730SBram Moolenaar 		if (noinvcurs)		    // will stop highlighting
3199071d4279SBram Moolenaar 		{
3200071d4279SBram Moolenaar 		    cost += noinvcurs;
3201071d4279SBram Moolenaar 		    attr = 0;
3202071d4279SBram Moolenaar 		}
3203071d4279SBram Moolenaar 	    }
3204071d4279SBram Moolenaar 
3205071d4279SBram Moolenaar 	    /*
3206071d4279SBram Moolenaar 	     * If the cursor is in the same row, smaller col, just use write.
3207071d4279SBram Moolenaar 	     */
3208071d4279SBram Moolenaar 	    else
3209071d4279SBram Moolenaar 	    {
3210071d4279SBram Moolenaar 		plan = PLAN_WRITE;
3211071d4279SBram Moolenaar 		wouldbe_col = screen_cur_col;
3212071d4279SBram Moolenaar 		cost = 0;
3213071d4279SBram Moolenaar 	    }
3214071d4279SBram Moolenaar 
3215071d4279SBram Moolenaar 	    /*
3216071d4279SBram Moolenaar 	     * Check if any characters that need to be written have the
3217071d4279SBram Moolenaar 	     * correct attributes.  Also avoid UTF-8 characters.
3218071d4279SBram Moolenaar 	     */
3219071d4279SBram Moolenaar 	    i = col - wouldbe_col;
3220071d4279SBram Moolenaar 	    if (i > 0)
3221071d4279SBram Moolenaar 		cost += i;
3222071d4279SBram Moolenaar 	    if (cost < goto_cost && i > 0)
3223071d4279SBram Moolenaar 	    {
3224071d4279SBram Moolenaar 		/*
3225071d4279SBram Moolenaar 		 * Check if the attributes are correct without additionally
3226071d4279SBram Moolenaar 		 * stopping highlighting.
3227071d4279SBram Moolenaar 		 */
3228071d4279SBram Moolenaar 		p = ScreenAttrs + LineOffset[row] + wouldbe_col;
3229071d4279SBram Moolenaar 		while (i && *p++ == attr)
3230071d4279SBram Moolenaar 		    --i;
3231071d4279SBram Moolenaar 		if (i != 0)
3232071d4279SBram Moolenaar 		{
3233071d4279SBram Moolenaar 		    /*
3234071d4279SBram Moolenaar 		     * Try if it works when highlighting is stopped here.
3235071d4279SBram Moolenaar 		     */
3236071d4279SBram Moolenaar 		    if (*--p == 0)
3237071d4279SBram Moolenaar 		    {
3238071d4279SBram Moolenaar 			cost += noinvcurs;
3239071d4279SBram Moolenaar 			while (i && *p++ == 0)
3240071d4279SBram Moolenaar 			    --i;
3241071d4279SBram Moolenaar 		    }
3242071d4279SBram Moolenaar 		    if (i != 0)
324363d9e730SBram Moolenaar 			cost = 999;	// different attributes, don't do it
3244071d4279SBram Moolenaar 		}
3245071d4279SBram Moolenaar 		if (enc_utf8)
3246071d4279SBram Moolenaar 		{
324763d9e730SBram Moolenaar 		    // Don't use an UTF-8 char for positioning, it's slow.
3248071d4279SBram Moolenaar 		    for (i = wouldbe_col; i < col; ++i)
3249071d4279SBram Moolenaar 			if (ScreenLinesUC[LineOffset[row] + i] != 0)
3250071d4279SBram Moolenaar 			{
3251071d4279SBram Moolenaar 			    cost = 999;
3252071d4279SBram Moolenaar 			    break;
3253071d4279SBram Moolenaar 			}
3254071d4279SBram Moolenaar 		}
3255071d4279SBram Moolenaar 	    }
3256071d4279SBram Moolenaar 
3257071d4279SBram Moolenaar 	    /*
3258071d4279SBram Moolenaar 	     * We can do it without term_windgoto()!
3259071d4279SBram Moolenaar 	     */
3260071d4279SBram Moolenaar 	    if (cost < goto_cost)
3261071d4279SBram Moolenaar 	    {
3262071d4279SBram Moolenaar 		if (plan == PLAN_LE)
3263071d4279SBram Moolenaar 		{
3264071d4279SBram Moolenaar 		    if (noinvcurs)
3265071d4279SBram Moolenaar 			screen_stop_highlight();
3266071d4279SBram Moolenaar 		    while (screen_cur_col > col)
3267071d4279SBram Moolenaar 		    {
3268071d4279SBram Moolenaar 			out_str(bs);
3269071d4279SBram Moolenaar 			--screen_cur_col;
3270071d4279SBram Moolenaar 		    }
3271071d4279SBram Moolenaar 		}
3272071d4279SBram Moolenaar 		else if (plan == PLAN_CR)
3273071d4279SBram Moolenaar 		{
3274071d4279SBram Moolenaar 		    if (noinvcurs)
3275071d4279SBram Moolenaar 			screen_stop_highlight();
3276071d4279SBram Moolenaar 		    out_char('\r');
3277071d4279SBram Moolenaar 		    screen_cur_col = 0;
3278071d4279SBram Moolenaar 		}
3279071d4279SBram Moolenaar 		else if (plan == PLAN_NL)
3280071d4279SBram Moolenaar 		{
3281071d4279SBram Moolenaar 		    if (noinvcurs)
3282071d4279SBram Moolenaar 			screen_stop_highlight();
3283071d4279SBram Moolenaar 		    while (screen_cur_row < row)
3284071d4279SBram Moolenaar 		    {
3285071d4279SBram Moolenaar 			out_char('\n');
3286071d4279SBram Moolenaar 			++screen_cur_row;
3287071d4279SBram Moolenaar 		    }
3288071d4279SBram Moolenaar 		    screen_cur_col = 0;
3289071d4279SBram Moolenaar 		}
3290071d4279SBram Moolenaar 
3291071d4279SBram Moolenaar 		i = col - screen_cur_col;
3292071d4279SBram Moolenaar 		if (i > 0)
3293071d4279SBram Moolenaar 		{
3294071d4279SBram Moolenaar 		    /*
3295071d4279SBram Moolenaar 		     * Use cursor-right if it's one character only.  Avoids
3296071d4279SBram Moolenaar 		     * removing a line of pixels from the last bold char, when
3297071d4279SBram Moolenaar 		     * using the bold trick in the GUI.
3298071d4279SBram Moolenaar 		     */
3299071d4279SBram Moolenaar 		    if (T_ND[0] != NUL && T_ND[1] == NUL)
3300071d4279SBram Moolenaar 		    {
3301071d4279SBram Moolenaar 			while (i-- > 0)
3302071d4279SBram Moolenaar 			    out_char(*T_ND);
3303071d4279SBram Moolenaar 		    }
3304071d4279SBram Moolenaar 		    else
3305071d4279SBram Moolenaar 		    {
3306071d4279SBram Moolenaar 			int	off;
3307071d4279SBram Moolenaar 
3308071d4279SBram Moolenaar 			off = LineOffset[row] + screen_cur_col;
3309071d4279SBram Moolenaar 			while (i-- > 0)
3310071d4279SBram Moolenaar 			{
3311071d4279SBram Moolenaar 			    if (ScreenAttrs[off] != screen_attr)
3312071d4279SBram Moolenaar 				screen_stop_highlight();
3313071d4279SBram Moolenaar 			    out_flush_check();
3314071d4279SBram Moolenaar 			    out_char(ScreenLines[off]);
3315071d4279SBram Moolenaar 			    if (enc_dbcs == DBCS_JPNU
3316071d4279SBram Moolenaar 						  && ScreenLines[off] == 0x8e)
3317071d4279SBram Moolenaar 				out_char(ScreenLines2[off]);
3318071d4279SBram Moolenaar 			    ++off;
3319071d4279SBram Moolenaar 			}
3320071d4279SBram Moolenaar 		    }
3321071d4279SBram Moolenaar 		}
3322071d4279SBram Moolenaar 	    }
3323071d4279SBram Moolenaar 	}
3324071d4279SBram Moolenaar 	else
3325071d4279SBram Moolenaar 	    cost = 999;
3326071d4279SBram Moolenaar 
3327071d4279SBram Moolenaar 	if (cost >= goto_cost)
3328071d4279SBram Moolenaar 	{
3329071d4279SBram Moolenaar 	    if (noinvcurs)
3330071d4279SBram Moolenaar 		screen_stop_highlight();
3331597a4224SBram Moolenaar 	    if (row == screen_cur_row && (col > screen_cur_col)
3332597a4224SBram Moolenaar 							     && *T_CRI != NUL)
3333071d4279SBram Moolenaar 		term_cursor_right(col - screen_cur_col);
3334071d4279SBram Moolenaar 	    else
3335071d4279SBram Moolenaar 		term_windgoto(row, col);
3336071d4279SBram Moolenaar 	}
3337071d4279SBram Moolenaar 	screen_cur_row = row;
3338071d4279SBram Moolenaar 	screen_cur_col = col;
3339071d4279SBram Moolenaar     }
3340071d4279SBram Moolenaar }
3341071d4279SBram Moolenaar 
3342071d4279SBram Moolenaar /*
3343071d4279SBram Moolenaar  * Set cursor to its position in the current window.
3344071d4279SBram Moolenaar  */
3345071d4279SBram Moolenaar     void
setcursor(void)334605540976SBram Moolenaar setcursor(void)
3347071d4279SBram Moolenaar {
3348987723e0SBram Moolenaar     setcursor_mayforce(FALSE);
3349987723e0SBram Moolenaar }
3350987723e0SBram Moolenaar 
3351987723e0SBram Moolenaar /*
3352987723e0SBram Moolenaar  * Set cursor to its position in the current window.
3353987723e0SBram Moolenaar  * When "force" is TRUE also when not redrawing.
3354987723e0SBram Moolenaar  */
3355987723e0SBram Moolenaar     void
setcursor_mayforce(int force)3356987723e0SBram Moolenaar setcursor_mayforce(int force)
3357987723e0SBram Moolenaar {
3358987723e0SBram Moolenaar     if (force || redrawing())
3359071d4279SBram Moolenaar     {
3360071d4279SBram Moolenaar 	validate_cursor();
3361071d4279SBram Moolenaar 	windgoto(W_WINROW(curwin) + curwin->w_wrow,
336253f8174eSBram Moolenaar 		curwin->w_wincol + (
3363071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
336463d9e730SBram Moolenaar 		// With 'rightleft' set and the cursor on a double-wide
336563d9e730SBram Moolenaar 		// character, position it on the leftmost column.
3366a12a161bSBram Moolenaar 		curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
3367a12a161bSBram Moolenaar 		    - ((has_mbyte
3368561f9db8SBram Moolenaar 			   && (*mb_ptr2cells)(ml_get_cursor()) == 2
3369a12a161bSBram Moolenaar 			   && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
3370071d4279SBram Moolenaar #endif
3371071d4279SBram Moolenaar 							    curwin->w_wcol));
3372071d4279SBram Moolenaar     }
3373071d4279SBram Moolenaar }
3374071d4279SBram Moolenaar 
3375071d4279SBram Moolenaar 
3376071d4279SBram Moolenaar /*
33778603356bSBram Moolenaar  * Insert 'line_count' lines at 'row' in window 'wp'.
33788603356bSBram Moolenaar  * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
33798603356bSBram Moolenaar  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
3380071d4279SBram Moolenaar  * scrolling.
3381071d4279SBram Moolenaar  * Returns FAIL if the lines are not inserted, OK for success.
3382071d4279SBram Moolenaar  */
3383071d4279SBram Moolenaar     int
win_ins_lines(win_T * wp,int row,int line_count,int invalid,int mayclear)338405540976SBram Moolenaar win_ins_lines(
338505540976SBram Moolenaar     win_T	*wp,
338605540976SBram Moolenaar     int		row,
338705540976SBram Moolenaar     int		line_count,
338805540976SBram Moolenaar     int		invalid,
338905540976SBram Moolenaar     int		mayclear)
3390071d4279SBram Moolenaar {
3391071d4279SBram Moolenaar     int		did_delete;
3392071d4279SBram Moolenaar     int		nextrow;
3393071d4279SBram Moolenaar     int		lastrow;
3394071d4279SBram Moolenaar     int		retval;
3395071d4279SBram Moolenaar 
3396071d4279SBram Moolenaar     if (invalid)
3397071d4279SBram Moolenaar 	wp->w_lines_valid = 0;
3398071d4279SBram Moolenaar 
3399071d4279SBram Moolenaar     if (wp->w_height < 5)
3400071d4279SBram Moolenaar 	return FAIL;
3401071d4279SBram Moolenaar 
3402071d4279SBram Moolenaar     if (line_count > wp->w_height - row)
3403071d4279SBram Moolenaar 	line_count = wp->w_height - row;
3404071d4279SBram Moolenaar 
3405cfce7171SBram Moolenaar     retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
3406071d4279SBram Moolenaar     if (retval != MAYBE)
3407071d4279SBram Moolenaar 	return retval;
3408071d4279SBram Moolenaar 
3409071d4279SBram Moolenaar     /*
3410071d4279SBram Moolenaar      * If there is a next window or a status line, we first try to delete the
3411071d4279SBram Moolenaar      * lines at the bottom to avoid messing what is after the window.
3412c363fe15SBram Moolenaar      * If this fails and there are following windows, don't do anything to
3413c363fe15SBram Moolenaar      * avoid messing up those windows, better just redraw.
3414071d4279SBram Moolenaar      */
3415071d4279SBram Moolenaar     did_delete = FALSE;
3416071d4279SBram Moolenaar     if (wp->w_next != NULL || wp->w_status_height)
3417071d4279SBram Moolenaar     {
3418071d4279SBram Moolenaar 	if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3419cfce7171SBram Moolenaar 				  line_count, (int)Rows, FALSE, 0, NULL) == OK)
3420071d4279SBram Moolenaar 	    did_delete = TRUE;
3421071d4279SBram Moolenaar 	else if (wp->w_next)
3422071d4279SBram Moolenaar 	    return FAIL;
3423071d4279SBram Moolenaar     }
3424071d4279SBram Moolenaar     /*
3425071d4279SBram Moolenaar      * if no lines deleted, blank the lines that will end up below the window
3426071d4279SBram Moolenaar      */
3427071d4279SBram Moolenaar     if (!did_delete)
3428071d4279SBram Moolenaar     {
3429071d4279SBram Moolenaar 	wp->w_redr_status = TRUE;
3430071d4279SBram Moolenaar 	redraw_cmdline = TRUE;
3431e0de17d8SBram Moolenaar 	nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
3432071d4279SBram Moolenaar 	lastrow = nextrow + line_count;
3433071d4279SBram Moolenaar 	if (lastrow > Rows)
3434071d4279SBram Moolenaar 	    lastrow = Rows;
3435071d4279SBram Moolenaar 	screen_fill(nextrow - line_count, lastrow - line_count,
343653f8174eSBram Moolenaar 		  wp->w_wincol, (int)W_ENDCOL(wp),
3437071d4279SBram Moolenaar 		  ' ', ' ', 0);
3438071d4279SBram Moolenaar     }
3439071d4279SBram Moolenaar 
3440cfce7171SBram Moolenaar     if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
3441071d4279SBram Moolenaar 								      == FAIL)
3442071d4279SBram Moolenaar     {
3443c363fe15SBram Moolenaar 	// deletion will have messed up other windows
3444071d4279SBram Moolenaar 	if (did_delete)
3445071d4279SBram Moolenaar 	{
3446071d4279SBram Moolenaar 	    wp->w_redr_status = TRUE;
3447071d4279SBram Moolenaar 	    win_rest_invalid(W_NEXT(wp));
3448071d4279SBram Moolenaar 	}
3449071d4279SBram Moolenaar 	return FAIL;
3450071d4279SBram Moolenaar     }
3451071d4279SBram Moolenaar 
3452071d4279SBram Moolenaar     return OK;
3453071d4279SBram Moolenaar }
3454071d4279SBram Moolenaar 
3455071d4279SBram Moolenaar /*
34568603356bSBram Moolenaar  * Delete "line_count" window lines at "row" in window "wp".
3457071d4279SBram Moolenaar  * If "invalid" is TRUE curwin->w_lines[] is invalidated.
3458071d4279SBram Moolenaar  * If "mayclear" is TRUE the screen will be cleared if it is faster than
3459071d4279SBram Moolenaar  * scrolling
3460071d4279SBram Moolenaar  * Return OK for success, FAIL if the lines are not deleted.
3461071d4279SBram Moolenaar  */
3462071d4279SBram Moolenaar     int
win_del_lines(win_T * wp,int row,int line_count,int invalid,int mayclear,int clear_attr)346305540976SBram Moolenaar win_del_lines(
346405540976SBram Moolenaar     win_T	*wp,
346505540976SBram Moolenaar     int		row,
346605540976SBram Moolenaar     int		line_count,
346705540976SBram Moolenaar     int		invalid,
3468cfce7171SBram Moolenaar     int		mayclear,
346963d9e730SBram Moolenaar     int		clear_attr)	    // for clearing lines
3470071d4279SBram Moolenaar {
3471071d4279SBram Moolenaar     int		retval;
3472071d4279SBram Moolenaar 
3473071d4279SBram Moolenaar     if (invalid)
3474071d4279SBram Moolenaar 	wp->w_lines_valid = 0;
3475071d4279SBram Moolenaar 
3476071d4279SBram Moolenaar     if (line_count > wp->w_height - row)
3477071d4279SBram Moolenaar 	line_count = wp->w_height - row;
3478071d4279SBram Moolenaar 
3479cfce7171SBram Moolenaar     retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
3480071d4279SBram Moolenaar     if (retval != MAYBE)
3481071d4279SBram Moolenaar 	return retval;
3482071d4279SBram Moolenaar 
3483071d4279SBram Moolenaar     if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
3484cfce7171SBram Moolenaar 				   (int)Rows, FALSE, clear_attr, NULL) == FAIL)
3485071d4279SBram Moolenaar 	return FAIL;
3486071d4279SBram Moolenaar 
3487071d4279SBram Moolenaar     /*
3488071d4279SBram Moolenaar      * If there are windows or status lines below, try to put them at the
3489071d4279SBram Moolenaar      * correct place. If we can't do that, they have to be redrawn.
3490071d4279SBram Moolenaar      */
3491071d4279SBram Moolenaar     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
3492071d4279SBram Moolenaar     {
3493071d4279SBram Moolenaar 	if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3494cfce7171SBram Moolenaar 			      line_count, (int)Rows, clear_attr, NULL) == FAIL)
3495071d4279SBram Moolenaar 	{
3496071d4279SBram Moolenaar 	    wp->w_redr_status = TRUE;
3497071d4279SBram Moolenaar 	    win_rest_invalid(wp->w_next);
3498071d4279SBram Moolenaar 	}
3499071d4279SBram Moolenaar     }
3500071d4279SBram Moolenaar     /*
3501071d4279SBram Moolenaar      * If this is the last window and there is no status line, redraw the
3502071d4279SBram Moolenaar      * command line later.
3503071d4279SBram Moolenaar      */
3504071d4279SBram Moolenaar     else
3505071d4279SBram Moolenaar 	redraw_cmdline = TRUE;
3506071d4279SBram Moolenaar     return OK;
3507071d4279SBram Moolenaar }
3508071d4279SBram Moolenaar 
3509071d4279SBram Moolenaar /*
3510071d4279SBram Moolenaar  * Common code for win_ins_lines() and win_del_lines().
3511071d4279SBram Moolenaar  * Returns OK or FAIL when the work has been done.
3512071d4279SBram Moolenaar  * Returns MAYBE when not finished yet.
3513071d4279SBram Moolenaar  */
3514071d4279SBram Moolenaar     static int
win_do_lines(win_T * wp,int row,int line_count,int mayclear,int del,int clear_attr)351505540976SBram Moolenaar win_do_lines(
351605540976SBram Moolenaar     win_T	*wp,
351705540976SBram Moolenaar     int		row,
351805540976SBram Moolenaar     int		line_count,
351905540976SBram Moolenaar     int		mayclear,
3520cfce7171SBram Moolenaar     int		del,
3521cfce7171SBram Moolenaar     int		clear_attr)
3522071d4279SBram Moolenaar {
3523071d4279SBram Moolenaar     int		retval;
3524071d4279SBram Moolenaar 
3525071d4279SBram Moolenaar     if (!redrawing() || line_count <= 0)
3526071d4279SBram Moolenaar 	return FAIL;
3527071d4279SBram Moolenaar 
352833796b39SBram Moolenaar     // When inserting lines would result in loss of command output, just redraw
352933796b39SBram Moolenaar     // the lines.
353029ae377eSBram Moolenaar     if (no_win_do_lines_ins && !del)
353129ae377eSBram Moolenaar 	return FAIL;
353229ae377eSBram Moolenaar 
353333796b39SBram Moolenaar     // only a few lines left: redraw is faster
35344033c55eSBram Moolenaar     if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
3535071d4279SBram Moolenaar     {
353629ae377eSBram Moolenaar 	if (!no_win_do_lines_ins)
353733796b39SBram Moolenaar 	    screenclear();	    // will set wp->w_lines_valid to 0
3538071d4279SBram Moolenaar 	return FAIL;
3539071d4279SBram Moolenaar     }
3540071d4279SBram Moolenaar 
354105ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
35424c063a0dSBram Moolenaar     // this doesn't work when there are popups visible
354333796b39SBram Moolenaar     if (popup_visible)
354433796b39SBram Moolenaar 	return FAIL;
354533796b39SBram Moolenaar #endif
354633796b39SBram Moolenaar 
354733796b39SBram Moolenaar     // Delete all remaining lines
3548071d4279SBram Moolenaar     if (row + line_count >= wp->w_height)
3549071d4279SBram Moolenaar     {
3550071d4279SBram Moolenaar 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
355153f8174eSBram Moolenaar 		wp->w_wincol, (int)W_ENDCOL(wp),
3552071d4279SBram Moolenaar 		' ', ' ', 0);
3553071d4279SBram Moolenaar 	return OK;
3554071d4279SBram Moolenaar     }
3555071d4279SBram Moolenaar 
3556071d4279SBram Moolenaar     /*
355729ae377eSBram Moolenaar      * When scrolling, the message on the command line should be cleared,
3558071d4279SBram Moolenaar      * otherwise it will stay there forever.
355929ae377eSBram Moolenaar      * Don't do this when avoiding to insert lines.
3560071d4279SBram Moolenaar      */
356129ae377eSBram Moolenaar     if (!no_win_do_lines_ins)
3562071d4279SBram Moolenaar 	clear_cmdline = TRUE;
3563071d4279SBram Moolenaar 
3564071d4279SBram Moolenaar     /*
3565071d4279SBram Moolenaar      * If the terminal can set a scroll region, use that.
3566071d4279SBram Moolenaar      * Always do this in a vertically split window.  This will redraw from
3567071d4279SBram Moolenaar      * ScreenLines[] when t_CV isn't defined.  That's faster than using
3568071d4279SBram Moolenaar      * win_line().
3569071d4279SBram Moolenaar      * Don't use a scroll region when we are going to redraw the text, writing
357048e330afSBram Moolenaar      * a character in the lower right corner of the scroll region may cause a
357148e330afSBram Moolenaar      * scroll-up .
3572071d4279SBram Moolenaar      */
35730263146bSBram Moolenaar     if (scroll_region || wp->w_width != Columns)
3574071d4279SBram Moolenaar     {
3575071d4279SBram Moolenaar 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3576071d4279SBram Moolenaar 	    scroll_region_set(wp, row);
3577071d4279SBram Moolenaar 	if (del)
3578071d4279SBram Moolenaar 	    retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
3579cfce7171SBram Moolenaar 				    wp->w_height - row, FALSE, clear_attr, wp);
3580071d4279SBram Moolenaar 	else
3581071d4279SBram Moolenaar 	    retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
3582cfce7171SBram Moolenaar 					   wp->w_height - row, clear_attr, wp);
3583071d4279SBram Moolenaar 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3584071d4279SBram Moolenaar 	    scroll_region_reset();
3585071d4279SBram Moolenaar 	return retval;
3586071d4279SBram Moolenaar     }
3587071d4279SBram Moolenaar 
358863d9e730SBram Moolenaar     if (wp->w_next != NULL && p_tf) // don't delete/insert on fast terminal
3589071d4279SBram Moolenaar 	return FAIL;
3590071d4279SBram Moolenaar 
3591071d4279SBram Moolenaar     return MAYBE;
3592071d4279SBram Moolenaar }
3593071d4279SBram Moolenaar 
3594071d4279SBram Moolenaar /*
3595071d4279SBram Moolenaar  * window 'wp' and everything after it is messed up, mark it for redraw
3596071d4279SBram Moolenaar  */
3597071d4279SBram Moolenaar     static void
win_rest_invalid(win_T * wp)359805540976SBram Moolenaar win_rest_invalid(win_T *wp)
3599071d4279SBram Moolenaar {
3600071d4279SBram Moolenaar     while (wp != NULL)
3601071d4279SBram Moolenaar     {
3602071d4279SBram Moolenaar 	redraw_win_later(wp, NOT_VALID);
3603071d4279SBram Moolenaar 	wp->w_redr_status = TRUE;
3604071d4279SBram Moolenaar 	wp = wp->w_next;
3605071d4279SBram Moolenaar     }
3606071d4279SBram Moolenaar     redraw_cmdline = TRUE;
3607071d4279SBram Moolenaar }
3608071d4279SBram Moolenaar 
3609071d4279SBram Moolenaar /*
3610071d4279SBram Moolenaar  * The rest of the routines in this file perform screen manipulations. The
3611071d4279SBram Moolenaar  * given operation is performed physically on the screen. The corresponding
3612071d4279SBram Moolenaar  * change is also made to the internal screen image. In this way, the editor
3613071d4279SBram Moolenaar  * anticipates the effect of editing changes on the appearance of the screen.
3614071d4279SBram Moolenaar  * That way, when we call screenupdate a complete redraw isn't usually
3615071d4279SBram Moolenaar  * necessary. Another advantage is that we can keep adding code to anticipate
3616071d4279SBram Moolenaar  * screen changes, and in the meantime, everything still works.
3617071d4279SBram Moolenaar  */
3618071d4279SBram Moolenaar 
3619071d4279SBram Moolenaar /*
3620071d4279SBram Moolenaar  * types for inserting or deleting lines
3621071d4279SBram Moolenaar  */
3622071d4279SBram Moolenaar #define USE_T_CAL   1
3623071d4279SBram Moolenaar #define USE_T_CDL   2
3624071d4279SBram Moolenaar #define USE_T_AL    3
3625071d4279SBram Moolenaar #define USE_T_CE    4
3626071d4279SBram Moolenaar #define USE_T_DL    5
3627071d4279SBram Moolenaar #define USE_T_SR    6
3628071d4279SBram Moolenaar #define USE_NL	    7
3629071d4279SBram Moolenaar #define USE_T_CD    8
3630071d4279SBram Moolenaar #define USE_REDRAW  9
3631071d4279SBram Moolenaar 
3632071d4279SBram Moolenaar /*
3633071d4279SBram Moolenaar  * insert lines on the screen and update ScreenLines[]
3634071d4279SBram Moolenaar  * 'end' is the line after the scrolled part. Normally it is Rows.
3635071d4279SBram Moolenaar  * When scrolling region used 'off' is the offset from the top for the region.
3636071d4279SBram Moolenaar  * 'row' and 'end' are relative to the start of the region.
3637071d4279SBram Moolenaar  *
3638071d4279SBram Moolenaar  * return FAIL for failure, OK for success.
3639071d4279SBram Moolenaar  */
364087e25fdfSBram Moolenaar     int
screen_ins_lines(int off,int row,int line_count,int end,int clear_attr,win_T * wp)364105540976SBram Moolenaar screen_ins_lines(
364205540976SBram Moolenaar     int		off,
364305540976SBram Moolenaar     int		row,
364405540976SBram Moolenaar     int		line_count,
364505540976SBram Moolenaar     int		end,
3646cfce7171SBram Moolenaar     int		clear_attr,
364763d9e730SBram Moolenaar     win_T	*wp)	    // NULL or window to use width from
3648071d4279SBram Moolenaar {
3649071d4279SBram Moolenaar     int		i;
3650071d4279SBram Moolenaar     int		j;
3651071d4279SBram Moolenaar     unsigned	temp;
3652071d4279SBram Moolenaar     int		cursor_row;
3653bfa42467SBram Moolenaar     int		cursor_col = 0;
3654071d4279SBram Moolenaar     int		type;
3655071d4279SBram Moolenaar     int		result_empty;
3656071d4279SBram Moolenaar     int		can_ce = can_clear(T_CE);
3657071d4279SBram Moolenaar 
3658071d4279SBram Moolenaar     /*
3659071d4279SBram Moolenaar      * FAIL if
3660071d4279SBram Moolenaar      * - there is no valid screen
3661071d4279SBram Moolenaar      * - the screen has to be redrawn completely
3662071d4279SBram Moolenaar      * - the line count is less than one
3663071d4279SBram Moolenaar      * - the line count is more than 'ttyscroll'
366480dd3f9dSBram Moolenaar      * - redrawing for a callback and there is a modeless selection
366533796b39SBram Moolenaar      * - there is a popup window
3666071d4279SBram Moolenaar      */
366733796b39SBram Moolenaar      if (!screen_valid(TRUE)
366833796b39SBram Moolenaar 	     || line_count <= 0 || line_count > p_ttyscroll
366980dd3f9dSBram Moolenaar #ifdef FEAT_CLIPBOARD
367080dd3f9dSBram Moolenaar 	     || (clip_star.state != SELECT_CLEARED
367180dd3f9dSBram Moolenaar 						 && redrawing_for_callback > 0)
367280dd3f9dSBram Moolenaar #endif
367305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
367433796b39SBram Moolenaar 	     || popup_visible
367533796b39SBram Moolenaar #endif
367680dd3f9dSBram Moolenaar 	     )
3677071d4279SBram Moolenaar 	return FAIL;
3678071d4279SBram Moolenaar 
3679071d4279SBram Moolenaar     /*
3680071d4279SBram Moolenaar      * There are seven ways to insert lines:
3681071d4279SBram Moolenaar      * 0. When in a vertically split window and t_CV isn't set, redraw the
3682071d4279SBram Moolenaar      *    characters from ScreenLines[].
3683071d4279SBram Moolenaar      * 1. Use T_CD (clear to end of display) if it exists and the result of
3684071d4279SBram Moolenaar      *	  the insert is just empty lines
3685071d4279SBram Moolenaar      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
3686071d4279SBram Moolenaar      *	  present or line_count > 1. It looks better if we do all the inserts
3687071d4279SBram Moolenaar      *	  at once.
3688071d4279SBram Moolenaar      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
3689071d4279SBram Moolenaar      *	  insert is just empty lines and T_CE is not present or line_count >
3690071d4279SBram Moolenaar      *	  1.
3691071d4279SBram Moolenaar      * 4. Use T_AL (insert line) if it exists.
3692071d4279SBram Moolenaar      * 5. Use T_CE (erase line) if it exists and the result of the insert is
3693071d4279SBram Moolenaar      *	  just empty lines.
3694071d4279SBram Moolenaar      * 6. Use T_DL (delete line) if it exists and the result of the insert is
3695071d4279SBram Moolenaar      *	  just empty lines.
3696071d4279SBram Moolenaar      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
3697071d4279SBram Moolenaar      *	  the 'da' flag is not set or we have clear line capability.
3698071d4279SBram Moolenaar      * 8. redraw the characters from ScreenLines[].
3699071d4279SBram Moolenaar      *
3700071d4279SBram Moolenaar      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
3701071d4279SBram Moolenaar      * the scrollbar for the window. It does have insert line, use that if it
3702071d4279SBram Moolenaar      * exists.
3703071d4279SBram Moolenaar      */
3704071d4279SBram Moolenaar     result_empty = (row + line_count >= end);
3705071d4279SBram Moolenaar     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3706071d4279SBram Moolenaar 	type = USE_REDRAW;
37074033c55eSBram Moolenaar     else if (can_clear(T_CD) && result_empty)
3708071d4279SBram Moolenaar 	type = USE_T_CD;
3709071d4279SBram Moolenaar     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
3710071d4279SBram Moolenaar 	type = USE_T_CAL;
3711071d4279SBram Moolenaar     else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
3712071d4279SBram Moolenaar 	type = USE_T_CDL;
3713071d4279SBram Moolenaar     else if (*T_AL != NUL)
3714071d4279SBram Moolenaar 	type = USE_T_AL;
3715071d4279SBram Moolenaar     else if (can_ce && result_empty)
3716071d4279SBram Moolenaar 	type = USE_T_CE;
3717071d4279SBram Moolenaar     else if (*T_DL != NUL && result_empty)
3718071d4279SBram Moolenaar 	type = USE_T_DL;
3719071d4279SBram Moolenaar     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
3720071d4279SBram Moolenaar 	type = USE_T_SR;
3721071d4279SBram Moolenaar     else
3722071d4279SBram Moolenaar 	return FAIL;
3723071d4279SBram Moolenaar 
3724071d4279SBram Moolenaar     /*
3725071d4279SBram Moolenaar      * For clearing the lines screen_del_lines() is used. This will also take
3726071d4279SBram Moolenaar      * care of t_db if necessary.
3727071d4279SBram Moolenaar      */
3728071d4279SBram Moolenaar     if (type == USE_T_CD || type == USE_T_CDL ||
3729071d4279SBram Moolenaar 					 type == USE_T_CE || type == USE_T_DL)
3730cfce7171SBram Moolenaar 	return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
3731071d4279SBram Moolenaar 
3732071d4279SBram Moolenaar     /*
3733071d4279SBram Moolenaar      * If text is retained below the screen, first clear or delete as many
3734071d4279SBram Moolenaar      * lines at the bottom of the window as are about to be inserted so that
3735071d4279SBram Moolenaar      * the deleted lines won't later surface during a screen_del_lines.
3736071d4279SBram Moolenaar      */
3737071d4279SBram Moolenaar     if (*T_DB)
3738cfce7171SBram Moolenaar 	screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
3739071d4279SBram Moolenaar 
3740071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
374163d9e730SBram Moolenaar     // Remove a modeless selection when inserting lines halfway the screen
374263d9e730SBram Moolenaar     // or not the full width of the screen.
37434033c55eSBram Moolenaar     if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3744c0885aadSBram Moolenaar 	clip_clear_selection(&clip_star);
3745071d4279SBram Moolenaar     else
3746071d4279SBram Moolenaar 	clip_scroll_selection(-line_count);
3747071d4279SBram Moolenaar #endif
3748071d4279SBram Moolenaar 
3749b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
3750b3f74069SBram Moolenaar     vim_lock_screen();
3751b3f74069SBram Moolenaar #endif
3752b3f74069SBram Moolenaar 
3753071d4279SBram Moolenaar #ifdef FEAT_GUI
375463d9e730SBram Moolenaar     // Don't update the GUI cursor here, ScreenLines[] is invalid until the
375563d9e730SBram Moolenaar     // scrolling is actually carried out.
3756107abd2cSBram Moolenaar     gui_dont_update_cursor(row + off <= gui.cursor_row);
3757071d4279SBram Moolenaar #endif
3758071d4279SBram Moolenaar 
3759bfa42467SBram Moolenaar     if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3760bfa42467SBram Moolenaar 	cursor_col = wp->w_wincol;
3761bfa42467SBram Moolenaar 
376263d9e730SBram Moolenaar     if (*T_CCS != NUL)	   // cursor relative to region
3763071d4279SBram Moolenaar 	cursor_row = row;
3764071d4279SBram Moolenaar     else
3765071d4279SBram Moolenaar 	cursor_row = row + off;
3766071d4279SBram Moolenaar 
3767071d4279SBram Moolenaar     /*
3768071d4279SBram Moolenaar      * Shift LineOffset[] line_count down to reflect the inserted lines.
3769071d4279SBram Moolenaar      * Clear the inserted lines in ScreenLines[].
3770071d4279SBram Moolenaar      */
3771071d4279SBram Moolenaar     row += off;
3772071d4279SBram Moolenaar     end += off;
3773071d4279SBram Moolenaar     for (i = 0; i < line_count; ++i)
3774071d4279SBram Moolenaar     {
3775071d4279SBram Moolenaar 	if (wp != NULL && wp->w_width != Columns)
3776071d4279SBram Moolenaar 	{
377763d9e730SBram Moolenaar 	    // need to copy part of a line
3778071d4279SBram Moolenaar 	    j = end - 1 - i;
3779071d4279SBram Moolenaar 	    while ((j -= line_count) >= row)
3780071d4279SBram Moolenaar 		linecopy(j + line_count, j, wp);
3781071d4279SBram Moolenaar 	    j += line_count;
3782071d4279SBram Moolenaar 	    if (can_clear((char_u *)" "))
3783cfce7171SBram Moolenaar 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
3784cfce7171SBram Moolenaar 								   clear_attr);
3785071d4279SBram Moolenaar 	    else
3786071d4279SBram Moolenaar 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
3787071d4279SBram Moolenaar 	    LineWraps[j] = FALSE;
3788071d4279SBram Moolenaar 	}
3789071d4279SBram Moolenaar 	else
3790071d4279SBram Moolenaar 	{
3791071d4279SBram Moolenaar 	    j = end - 1 - i;
3792071d4279SBram Moolenaar 	    temp = LineOffset[j];
3793071d4279SBram Moolenaar 	    while ((j -= line_count) >= row)
3794071d4279SBram Moolenaar 	    {
3795071d4279SBram Moolenaar 		LineOffset[j + line_count] = LineOffset[j];
3796071d4279SBram Moolenaar 		LineWraps[j + line_count] = LineWraps[j];
3797071d4279SBram Moolenaar 	    }
3798071d4279SBram Moolenaar 	    LineOffset[j + line_count] = temp;
3799071d4279SBram Moolenaar 	    LineWraps[j + line_count] = FALSE;
3800071d4279SBram Moolenaar 	    if (can_clear((char_u *)" "))
3801cfce7171SBram Moolenaar 		lineclear(temp, (int)Columns, clear_attr);
3802071d4279SBram Moolenaar 	    else
3803071d4279SBram Moolenaar 		lineinvalid(temp, (int)Columns);
3804071d4279SBram Moolenaar 	}
3805071d4279SBram Moolenaar     }
3806071d4279SBram Moolenaar 
3807b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
3808b3f74069SBram Moolenaar     vim_unlock_screen();
3809b3f74069SBram Moolenaar #endif
3810b3f74069SBram Moolenaar 
3811071d4279SBram Moolenaar     screen_stop_highlight();
3812bfa42467SBram Moolenaar     windgoto(cursor_row, cursor_col);
3813cfce7171SBram Moolenaar     if (clear_attr != 0)
3814cfce7171SBram Moolenaar 	screen_start_highlight(clear_attr);
3815071d4279SBram Moolenaar 
381663d9e730SBram Moolenaar     // redraw the characters
3817071d4279SBram Moolenaar     if (type == USE_REDRAW)
3818071d4279SBram Moolenaar 	redraw_block(row, end, wp);
38194033c55eSBram Moolenaar     else if (type == USE_T_CAL)
3820071d4279SBram Moolenaar     {
3821071d4279SBram Moolenaar 	term_append_lines(line_count);
382263d9e730SBram Moolenaar 	screen_start();		// don't know where cursor is now
3823071d4279SBram Moolenaar     }
3824071d4279SBram Moolenaar     else
3825071d4279SBram Moolenaar     {
3826071d4279SBram Moolenaar 	for (i = 0; i < line_count; i++)
3827071d4279SBram Moolenaar 	{
3828071d4279SBram Moolenaar 	    if (type == USE_T_AL)
3829071d4279SBram Moolenaar 	    {
3830071d4279SBram Moolenaar 		if (i && cursor_row != 0)
3831bfa42467SBram Moolenaar 		    windgoto(cursor_row, cursor_col);
3832071d4279SBram Moolenaar 		out_str(T_AL);
3833071d4279SBram Moolenaar 	    }
383463d9e730SBram Moolenaar 	    else  // type == USE_T_SR
3835071d4279SBram Moolenaar 		out_str(T_SR);
383663d9e730SBram Moolenaar 	    screen_start();	    // don't know where cursor is now
3837071d4279SBram Moolenaar 	}
3838071d4279SBram Moolenaar     }
3839071d4279SBram Moolenaar 
3840071d4279SBram Moolenaar     /*
3841071d4279SBram Moolenaar      * With scroll-reverse and 'da' flag set we need to clear the lines that
3842071d4279SBram Moolenaar      * have been scrolled down into the region.
3843071d4279SBram Moolenaar      */
3844071d4279SBram Moolenaar     if (type == USE_T_SR && *T_DA)
3845071d4279SBram Moolenaar     {
3846071d4279SBram Moolenaar 	for (i = 0; i < line_count; ++i)
3847071d4279SBram Moolenaar 	{
3848bfa42467SBram Moolenaar 	    windgoto(off + i, cursor_col);
3849071d4279SBram Moolenaar 	    out_str(T_CE);
385063d9e730SBram Moolenaar 	    screen_start();	    // don't know where cursor is now
3851071d4279SBram Moolenaar 	}
3852071d4279SBram Moolenaar     }
3853071d4279SBram Moolenaar 
3854071d4279SBram Moolenaar #ifdef FEAT_GUI
3855071d4279SBram Moolenaar     gui_can_update_cursor();
3856071d4279SBram Moolenaar     if (gui.in_use)
385763d9e730SBram Moolenaar 	out_flush();	// always flush after a scroll
3858071d4279SBram Moolenaar #endif
3859071d4279SBram Moolenaar     return OK;
3860071d4279SBram Moolenaar }
3861071d4279SBram Moolenaar 
3862071d4279SBram Moolenaar /*
3863107abd2cSBram Moolenaar  * Delete lines on the screen and update ScreenLines[].
3864107abd2cSBram Moolenaar  * "end" is the line after the scrolled part. Normally it is Rows.
3865107abd2cSBram Moolenaar  * When scrolling region used "off" is the offset from the top for the region.
3866107abd2cSBram Moolenaar  * "row" and "end" are relative to the start of the region.
3867071d4279SBram Moolenaar  *
3868071d4279SBram Moolenaar  * Return OK for success, FAIL if the lines are not deleted.
3869071d4279SBram Moolenaar  */
3870071d4279SBram Moolenaar     int
screen_del_lines(int off,int row,int line_count,int end,int force,int clear_attr,win_T * wp UNUSED)387105540976SBram Moolenaar screen_del_lines(
387205540976SBram Moolenaar     int		off,
387305540976SBram Moolenaar     int		row,
387405540976SBram Moolenaar     int		line_count,
387505540976SBram Moolenaar     int		end,
387663d9e730SBram Moolenaar     int		force,		// even when line_count > p_ttyscroll
387763d9e730SBram Moolenaar     int		clear_attr,	// used for clearing lines
387863d9e730SBram Moolenaar     win_T	*wp UNUSED)	// NULL or window to use width from
3879071d4279SBram Moolenaar {
3880071d4279SBram Moolenaar     int		j;
3881071d4279SBram Moolenaar     int		i;
3882071d4279SBram Moolenaar     unsigned	temp;
3883071d4279SBram Moolenaar     int		cursor_row;
3884bfa42467SBram Moolenaar     int		cursor_col = 0;
3885071d4279SBram Moolenaar     int		cursor_end;
388663d9e730SBram Moolenaar     int		result_empty;	// result is empty until end of region
388763d9e730SBram Moolenaar     int		can_delete;	// deleting line codes can be used
3888071d4279SBram Moolenaar     int		type;
3889071d4279SBram Moolenaar 
3890071d4279SBram Moolenaar     /*
3891071d4279SBram Moolenaar      * FAIL if
3892071d4279SBram Moolenaar      * - there is no valid screen
3893071d4279SBram Moolenaar      * - the screen has to be redrawn completely
3894071d4279SBram Moolenaar      * - the line count is less than one
3895071d4279SBram Moolenaar      * - the line count is more than 'ttyscroll'
389680dd3f9dSBram Moolenaar      * - redrawing for a callback and there is a modeless selection
3897071d4279SBram Moolenaar      */
389880dd3f9dSBram Moolenaar     if (!screen_valid(TRUE) || line_count <= 0
389980dd3f9dSBram Moolenaar 					|| (!force && line_count > p_ttyscroll)
390080dd3f9dSBram Moolenaar #ifdef FEAT_CLIPBOARD
390180dd3f9dSBram Moolenaar 	     || (clip_star.state != SELECT_CLEARED
390280dd3f9dSBram Moolenaar 						 && redrawing_for_callback > 0)
390380dd3f9dSBram Moolenaar #endif
390480dd3f9dSBram Moolenaar        )
3905071d4279SBram Moolenaar 	return FAIL;
3906071d4279SBram Moolenaar 
3907071d4279SBram Moolenaar     /*
3908071d4279SBram Moolenaar      * Check if the rest of the current region will become empty.
3909071d4279SBram Moolenaar      */
3910071d4279SBram Moolenaar     result_empty = row + line_count >= end;
3911071d4279SBram Moolenaar 
3912071d4279SBram Moolenaar     /*
3913071d4279SBram Moolenaar      * We can delete lines only when 'db' flag not set or when 'ce' option
3914071d4279SBram Moolenaar      * available.
3915071d4279SBram Moolenaar      */
3916071d4279SBram Moolenaar     can_delete = (*T_DB == NUL || can_clear(T_CE));
3917071d4279SBram Moolenaar 
3918071d4279SBram Moolenaar     /*
3919071d4279SBram Moolenaar      * There are six ways to delete lines:
3920071d4279SBram Moolenaar      * 0. When in a vertically split window and t_CV isn't set, redraw the
3921071d4279SBram Moolenaar      *    characters from ScreenLines[].
3922071d4279SBram Moolenaar      * 1. Use T_CD if it exists and the result is empty.
3923071d4279SBram Moolenaar      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
3924071d4279SBram Moolenaar      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
3925071d4279SBram Moolenaar      *	  none of the other ways work.
3926071d4279SBram Moolenaar      * 4. Use T_CE (erase line) if the result is empty.
3927071d4279SBram Moolenaar      * 5. Use T_DL (delete line) if it exists.
3928071d4279SBram Moolenaar      * 6. redraw the characters from ScreenLines[].
3929071d4279SBram Moolenaar      */
3930071d4279SBram Moolenaar     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3931071d4279SBram Moolenaar 	type = USE_REDRAW;
39324033c55eSBram Moolenaar     else if (can_clear(T_CD) && result_empty)
3933071d4279SBram Moolenaar 	type = USE_T_CD;
3934071d4279SBram Moolenaar     else if (row == 0 && (
3935071d4279SBram Moolenaar #ifndef AMIGA
393663d9e730SBram Moolenaar 	// On the Amiga, somehow '\n' on the last line doesn't always scroll
393763d9e730SBram Moolenaar 	// up, so use delete-line command
3938071d4279SBram Moolenaar 			    line_count == 1 ||
3939071d4279SBram Moolenaar #endif
3940071d4279SBram Moolenaar 						*T_CDL == NUL))
3941071d4279SBram Moolenaar 	type = USE_NL;
3942071d4279SBram Moolenaar     else if (*T_CDL != NUL && line_count > 1 && can_delete)
3943071d4279SBram Moolenaar 	type = USE_T_CDL;
3944071d4279SBram Moolenaar     else if (can_clear(T_CE) && result_empty
39454033c55eSBram Moolenaar 	    && (wp == NULL || wp->w_width == Columns))
3946071d4279SBram Moolenaar 	type = USE_T_CE;
3947071d4279SBram Moolenaar     else if (*T_DL != NUL && can_delete)
3948071d4279SBram Moolenaar 	type = USE_T_DL;
3949071d4279SBram Moolenaar     else if (*T_CDL != NUL && can_delete)
3950071d4279SBram Moolenaar 	type = USE_T_CDL;
3951071d4279SBram Moolenaar     else
3952071d4279SBram Moolenaar 	return FAIL;
3953071d4279SBram Moolenaar 
3954071d4279SBram Moolenaar #ifdef FEAT_CLIPBOARD
395563d9e730SBram Moolenaar     // Remove a modeless selection when deleting lines halfway the screen or
395663d9e730SBram Moolenaar     // not the full width of the screen.
39574033c55eSBram Moolenaar     if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3958c0885aadSBram Moolenaar 	clip_clear_selection(&clip_star);
3959071d4279SBram Moolenaar     else
3960071d4279SBram Moolenaar 	clip_scroll_selection(line_count);
3961071d4279SBram Moolenaar #endif
3962071d4279SBram Moolenaar 
396392c461efSBram Moolenaar #ifdef FEAT_GUI_HAIKU
396492c461efSBram Moolenaar     vim_lock_screen();
396592c461efSBram Moolenaar #endif
396692c461efSBram Moolenaar 
3967071d4279SBram Moolenaar #ifdef FEAT_GUI
396863d9e730SBram Moolenaar     // Don't update the GUI cursor here, ScreenLines[] is invalid until the
396963d9e730SBram Moolenaar     // scrolling is actually carried out.
3970107abd2cSBram Moolenaar     gui_dont_update_cursor(gui.cursor_row >= row + off
3971107abd2cSBram Moolenaar 						&& gui.cursor_row < end + off);
3972071d4279SBram Moolenaar #endif
3973071d4279SBram Moolenaar 
3974bfa42467SBram Moolenaar     if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3975bfa42467SBram Moolenaar 	cursor_col = wp->w_wincol;
3976bfa42467SBram Moolenaar 
397763d9e730SBram Moolenaar     if (*T_CCS != NUL)	    // cursor relative to region
3978071d4279SBram Moolenaar     {
3979071d4279SBram Moolenaar 	cursor_row = row;
3980071d4279SBram Moolenaar 	cursor_end = end;
3981071d4279SBram Moolenaar     }
3982071d4279SBram Moolenaar     else
3983071d4279SBram Moolenaar     {
3984071d4279SBram Moolenaar 	cursor_row = row + off;
3985071d4279SBram Moolenaar 	cursor_end = end + off;
3986071d4279SBram Moolenaar     }
3987071d4279SBram Moolenaar 
3988071d4279SBram Moolenaar     /*
3989071d4279SBram Moolenaar      * Now shift LineOffset[] line_count up to reflect the deleted lines.
3990071d4279SBram Moolenaar      * Clear the inserted lines in ScreenLines[].
3991071d4279SBram Moolenaar      */
3992071d4279SBram Moolenaar     row += off;
3993071d4279SBram Moolenaar     end += off;
3994071d4279SBram Moolenaar     for (i = 0; i < line_count; ++i)
3995071d4279SBram Moolenaar     {
3996071d4279SBram Moolenaar 	if (wp != NULL && wp->w_width != Columns)
3997071d4279SBram Moolenaar 	{
399863d9e730SBram Moolenaar 	    // need to copy part of a line
3999071d4279SBram Moolenaar 	    j = row + i;
4000071d4279SBram Moolenaar 	    while ((j += line_count) <= end - 1)
4001071d4279SBram Moolenaar 		linecopy(j - line_count, j, wp);
4002071d4279SBram Moolenaar 	    j -= line_count;
4003071d4279SBram Moolenaar 	    if (can_clear((char_u *)" "))
4004cfce7171SBram Moolenaar 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
4005cfce7171SBram Moolenaar 								   clear_attr);
4006071d4279SBram Moolenaar 	    else
4007071d4279SBram Moolenaar 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
4008071d4279SBram Moolenaar 	    LineWraps[j] = FALSE;
4009071d4279SBram Moolenaar 	}
4010071d4279SBram Moolenaar 	else
4011071d4279SBram Moolenaar 	{
401263d9e730SBram Moolenaar 	    // whole width, moving the line pointers is faster
4013071d4279SBram Moolenaar 	    j = row + i;
4014071d4279SBram Moolenaar 	    temp = LineOffset[j];
4015071d4279SBram Moolenaar 	    while ((j += line_count) <= end - 1)
4016071d4279SBram Moolenaar 	    {
4017071d4279SBram Moolenaar 		LineOffset[j - line_count] = LineOffset[j];
4018071d4279SBram Moolenaar 		LineWraps[j - line_count] = LineWraps[j];
4019071d4279SBram Moolenaar 	    }
4020071d4279SBram Moolenaar 	    LineOffset[j - line_count] = temp;
4021071d4279SBram Moolenaar 	    LineWraps[j - line_count] = FALSE;
4022071d4279SBram Moolenaar 	    if (can_clear((char_u *)" "))
4023cfce7171SBram Moolenaar 		lineclear(temp, (int)Columns, clear_attr);
4024071d4279SBram Moolenaar 	    else
4025071d4279SBram Moolenaar 		lineinvalid(temp, (int)Columns);
4026071d4279SBram Moolenaar 	}
4027071d4279SBram Moolenaar     }
4028071d4279SBram Moolenaar 
4029b3f74069SBram Moolenaar #ifdef FEAT_GUI_HAIKU
4030b3f74069SBram Moolenaar     vim_unlock_screen();
4031b3f74069SBram Moolenaar #endif
4032b3f74069SBram Moolenaar 
4033cfce7171SBram Moolenaar     if (screen_attr != clear_attr)
4034071d4279SBram Moolenaar 	screen_stop_highlight();
4035cfce7171SBram Moolenaar     if (clear_attr != 0)
4036cfce7171SBram Moolenaar 	screen_start_highlight(clear_attr);
4037071d4279SBram Moolenaar 
403863d9e730SBram Moolenaar     // redraw the characters
4039071d4279SBram Moolenaar     if (type == USE_REDRAW)
4040071d4279SBram Moolenaar 	redraw_block(row, end, wp);
404163d9e730SBram Moolenaar     else if (type == USE_T_CD)	// delete the lines
4042071d4279SBram Moolenaar     {
4043bfa42467SBram Moolenaar 	windgoto(cursor_row, cursor_col);
4044071d4279SBram Moolenaar 	out_str(T_CD);
404563d9e730SBram Moolenaar 	screen_start();			// don't know where cursor is now
4046071d4279SBram Moolenaar     }
4047071d4279SBram Moolenaar     else if (type == USE_T_CDL)
4048071d4279SBram Moolenaar     {
4049bfa42467SBram Moolenaar 	windgoto(cursor_row, cursor_col);
4050071d4279SBram Moolenaar 	term_delete_lines(line_count);
405163d9e730SBram Moolenaar 	screen_start();			// don't know where cursor is now
4052071d4279SBram Moolenaar     }
4053071d4279SBram Moolenaar     /*
4054071d4279SBram Moolenaar      * Deleting lines at top of the screen or scroll region: Just scroll
4055071d4279SBram Moolenaar      * the whole screen (scroll region) up by outputting newlines on the
4056071d4279SBram Moolenaar      * last line.
4057071d4279SBram Moolenaar      */
4058071d4279SBram Moolenaar     else if (type == USE_NL)
4059071d4279SBram Moolenaar     {
4060bfa42467SBram Moolenaar 	windgoto(cursor_end - 1, cursor_col);
4061071d4279SBram Moolenaar 	for (i = line_count; --i >= 0; )
406263d9e730SBram Moolenaar 	    out_char('\n');		// cursor will remain on same line
4063071d4279SBram Moolenaar     }
4064071d4279SBram Moolenaar     else
4065071d4279SBram Moolenaar     {
4066071d4279SBram Moolenaar 	for (i = line_count; --i >= 0; )
4067071d4279SBram Moolenaar 	{
4068071d4279SBram Moolenaar 	    if (type == USE_T_DL)
4069071d4279SBram Moolenaar 	    {
4070bfa42467SBram Moolenaar 		windgoto(cursor_row, cursor_col);
407163d9e730SBram Moolenaar 		out_str(T_DL);		// delete a line
4072071d4279SBram Moolenaar 	    }
407363d9e730SBram Moolenaar 	    else // type == USE_T_CE
4074071d4279SBram Moolenaar 	    {
4075bfa42467SBram Moolenaar 		windgoto(cursor_row + i, cursor_col);
407663d9e730SBram Moolenaar 		out_str(T_CE);		// erase a line
4077071d4279SBram Moolenaar 	    }
407863d9e730SBram Moolenaar 	    screen_start();		// don't know where cursor is now
4079071d4279SBram Moolenaar 	}
4080071d4279SBram Moolenaar     }
4081071d4279SBram Moolenaar 
4082071d4279SBram Moolenaar     /*
4083071d4279SBram Moolenaar      * If the 'db' flag is set, we need to clear the lines that have been
4084071d4279SBram Moolenaar      * scrolled up at the bottom of the region.
4085071d4279SBram Moolenaar      */
4086071d4279SBram Moolenaar     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
4087071d4279SBram Moolenaar     {
4088071d4279SBram Moolenaar 	for (i = line_count; i > 0; --i)
4089071d4279SBram Moolenaar 	{
4090bfa42467SBram Moolenaar 	    windgoto(cursor_end - i, cursor_col);
409163d9e730SBram Moolenaar 	    out_str(T_CE);		// erase a line
409263d9e730SBram Moolenaar 	    screen_start();		// don't know where cursor is now
4093071d4279SBram Moolenaar 	}
4094071d4279SBram Moolenaar     }
4095071d4279SBram Moolenaar 
4096071d4279SBram Moolenaar #ifdef FEAT_GUI
4097071d4279SBram Moolenaar     gui_can_update_cursor();
4098071d4279SBram Moolenaar     if (gui.in_use)
409963d9e730SBram Moolenaar 	out_flush();	// always flush after a scroll
4100071d4279SBram Moolenaar #endif
4101071d4279SBram Moolenaar 
4102071d4279SBram Moolenaar     return OK;
4103071d4279SBram Moolenaar }
4104071d4279SBram Moolenaar 
4105071d4279SBram Moolenaar /*
4106cb574f41SBram Moolenaar  * Return TRUE when postponing displaying the mode message: when not redrawing
4107cb574f41SBram Moolenaar  * or inside a mapping.
4108cb574f41SBram Moolenaar  */
4109cb574f41SBram Moolenaar     int
skip_showmode()4110cb574f41SBram Moolenaar skip_showmode()
4111cb574f41SBram Moolenaar {
4112cb574f41SBram Moolenaar     // Call char_avail() only when we are going to show something, because it
4113cb574f41SBram Moolenaar     // takes a bit of time.  redrawing() may also call char_avail_avail().
4114cb574f41SBram Moolenaar     if (global_busy
4115cb574f41SBram Moolenaar 	    || msg_silent != 0
4116cb574f41SBram Moolenaar 	    || !redrawing()
4117cb574f41SBram Moolenaar 	    || (char_avail() && !KeyTyped))
4118cb574f41SBram Moolenaar     {
41194c25bd78SBram Moolenaar 	redraw_mode = TRUE;		// show mode later
4120cb574f41SBram Moolenaar 	return TRUE;
4121cb574f41SBram Moolenaar     }
4122cb574f41SBram Moolenaar     return FALSE;
4123cb574f41SBram Moolenaar }
4124cb574f41SBram Moolenaar 
4125cb574f41SBram Moolenaar /*
412681226e03SBram Moolenaar  * Show the current mode and ruler.
4127071d4279SBram Moolenaar  *
4128071d4279SBram Moolenaar  * If clear_cmdline is TRUE, clear the rest of the cmdline.
4129071d4279SBram Moolenaar  * If clear_cmdline is FALSE there may be a message there that needs to be
4130071d4279SBram Moolenaar  * cleared only if a mode is shown.
41314c25bd78SBram Moolenaar  * If redraw_mode is TRUE show or clear the mode.
4132071d4279SBram Moolenaar  * Return the length of the message (0 if no message).
4133071d4279SBram Moolenaar  */
4134071d4279SBram Moolenaar     int
showmode(void)413505540976SBram Moolenaar showmode(void)
4136071d4279SBram Moolenaar {
4137071d4279SBram Moolenaar     int		need_clear;
4138071d4279SBram Moolenaar     int		length = 0;
4139071d4279SBram Moolenaar     int		do_mode;
4140071d4279SBram Moolenaar     int		attr;
4141071d4279SBram Moolenaar     int		nwr_save;
4142071d4279SBram Moolenaar     int		sub_attr;
4143071d4279SBram Moolenaar 
41447df351ebSBram Moolenaar     do_mode = ((p_smd && msg_silent == 0)
41457df351ebSBram Moolenaar 	    && ((State & INSERT)
4146942b4541SBram Moolenaar 		|| restart_edit != NUL
4147f7ff6e85SBram Moolenaar 		|| VIsual_active));
41480b6d911eSBram Moolenaar     if (do_mode || reg_recording != 0)
4149071d4279SBram Moolenaar     {
4150cb574f41SBram Moolenaar 	if (skip_showmode())
4151cb574f41SBram Moolenaar 	    return 0;		// show mode later
4152071d4279SBram Moolenaar 
4153071d4279SBram Moolenaar 	nwr_save = need_wait_return;
4154071d4279SBram Moolenaar 
415563d9e730SBram Moolenaar 	// wait a bit before overwriting an important message
4156071d4279SBram Moolenaar 	check_for_delay(FALSE);
4157071d4279SBram Moolenaar 
415863d9e730SBram Moolenaar 	// if the cmdline is more than one line high, erase top lines
4159071d4279SBram Moolenaar 	need_clear = clear_cmdline;
4160071d4279SBram Moolenaar 	if (clear_cmdline && cmdline_row < Rows - 1)
416163d9e730SBram Moolenaar 	    msg_clr_cmdline();			// will reset clear_cmdline
4162071d4279SBram Moolenaar 
416363d9e730SBram Moolenaar 	// Position on the last line in the window, column 0
4164071d4279SBram Moolenaar 	msg_pos_mode();
4165071d4279SBram Moolenaar 	cursor_off();
416663d9e730SBram Moolenaar 	attr = HL_ATTR(HLF_CM);			// Highlight mode
4167071d4279SBram Moolenaar 	if (do_mode)
4168071d4279SBram Moolenaar 	{
416932526b3cSBram Moolenaar 	    msg_puts_attr("--", attr);
4170071d4279SBram Moolenaar #if defined(FEAT_XIM)
4171c236c16dSBram Moolenaar 	    if (
41720eda7ac7SBram Moolenaar # ifdef FEAT_GUI_GTK
4173c236c16dSBram Moolenaar 		    preedit_get_status()
4174c236c16dSBram Moolenaar # else
4175c236c16dSBram Moolenaar 		    im_get_status()
4176c236c16dSBram Moolenaar # endif
4177c236c16dSBram Moolenaar 	       )
417863d9e730SBram Moolenaar # ifdef FEAT_GUI_GTK // most of the time, it's not XIM being used
417932526b3cSBram Moolenaar 		msg_puts_attr(" IM", attr);
4180071d4279SBram Moolenaar # else
418132526b3cSBram Moolenaar 		msg_puts_attr(" XIM", attr);
4182071d4279SBram Moolenaar # endif
4183071d4279SBram Moolenaar #endif
418463d9e730SBram Moolenaar 	    // CTRL-X in Insert mode
4185ea389e91SBram Moolenaar 	    if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
4186071d4279SBram Moolenaar 	    {
418763d9e730SBram Moolenaar 		// These messages can get long, avoid a wrap in a narrow
418863d9e730SBram Moolenaar 		// window.  Prefer showing edit_submode_extra.
4189071d4279SBram Moolenaar 		length = (Rows - msg_row) * Columns - 3;
4190071d4279SBram Moolenaar 		if (edit_submode_extra != NULL)
4191071d4279SBram Moolenaar 		    length -= vim_strsize(edit_submode_extra);
4192071d4279SBram Moolenaar 		if (length > 0)
4193071d4279SBram Moolenaar 		{
4194071d4279SBram Moolenaar 		    if (edit_submode_pre != NULL)
4195071d4279SBram Moolenaar 			length -= vim_strsize(edit_submode_pre);
4196071d4279SBram Moolenaar 		    if (length - vim_strsize(edit_submode) > 0)
4197071d4279SBram Moolenaar 		    {
4198071d4279SBram Moolenaar 			if (edit_submode_pre != NULL)
419932526b3cSBram Moolenaar 			    msg_puts_attr((char *)edit_submode_pre, attr);
420032526b3cSBram Moolenaar 			msg_puts_attr((char *)edit_submode, attr);
4201071d4279SBram Moolenaar 		    }
4202071d4279SBram Moolenaar 		    if (edit_submode_extra != NULL)
4203071d4279SBram Moolenaar 		    {
420463d9e730SBram Moolenaar 			msg_puts_attr(" ", attr);  // add a space in between
4205071d4279SBram Moolenaar 			if ((int)edit_submode_highl < (int)HLF_COUNT)
42068820b486SBram Moolenaar 			    sub_attr = HL_ATTR(edit_submode_highl);
4207071d4279SBram Moolenaar 			else
4208071d4279SBram Moolenaar 			    sub_attr = attr;
420932526b3cSBram Moolenaar 			msg_puts_attr((char *)edit_submode_extra, sub_attr);
4210071d4279SBram Moolenaar 		    }
4211071d4279SBram Moolenaar 		}
4212071d4279SBram Moolenaar 	    }
4213071d4279SBram Moolenaar 	    else
4214071d4279SBram Moolenaar 	    {
4215071d4279SBram Moolenaar 		if (State & VREPLACE_FLAG)
421632526b3cSBram Moolenaar 		    msg_puts_attr(_(" VREPLACE"), attr);
42171f0bfe56SBram Moolenaar 		else if (State & REPLACE_FLAG)
421832526b3cSBram Moolenaar 		    msg_puts_attr(_(" REPLACE"), attr);
4219071d4279SBram Moolenaar 		else if (State & INSERT)
4220071d4279SBram Moolenaar 		{
4221071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4222071d4279SBram Moolenaar 		    if (p_ri)
422332526b3cSBram Moolenaar 			msg_puts_attr(_(" REVERSE"), attr);
4224071d4279SBram Moolenaar #endif
422532526b3cSBram Moolenaar 		    msg_puts_attr(_(" INSERT"), attr);
4226071d4279SBram Moolenaar 		}
4227957cf67dSBram Moolenaar 		else if (restart_edit == 'I' || restart_edit == 'i' ||
4228957cf67dSBram Moolenaar 			restart_edit == 'a' || restart_edit == 'A')
422932526b3cSBram Moolenaar 		    msg_puts_attr(_(" (insert)"), attr);
4230071d4279SBram Moolenaar 		else if (restart_edit == 'R')
423132526b3cSBram Moolenaar 		    msg_puts_attr(_(" (replace)"), attr);
4232071d4279SBram Moolenaar 		else if (restart_edit == 'V')
423332526b3cSBram Moolenaar 		    msg_puts_attr(_(" (vreplace)"), attr);
4234071d4279SBram Moolenaar #ifdef FEAT_RIGHTLEFT
4235071d4279SBram Moolenaar 		if (p_hkmap)
423632526b3cSBram Moolenaar 		    msg_puts_attr(_(" Hebrew"), attr);
4237071d4279SBram Moolenaar #endif
4238071d4279SBram Moolenaar #ifdef FEAT_KEYMAP
4239071d4279SBram Moolenaar 		if (State & LANGMAP)
4240071d4279SBram Moolenaar 		{
4241071d4279SBram Moolenaar # ifdef FEAT_ARABIC
4242071d4279SBram Moolenaar 		    if (curwin->w_p_arab)
424332526b3cSBram Moolenaar 			msg_puts_attr(_(" Arabic"), attr);
4244071d4279SBram Moolenaar 		    else
4245071d4279SBram Moolenaar # endif
424673ac0c42SBram Moolenaar 			if (get_keymap_str(curwin, (char_u *)" (%s)",
424773ac0c42SBram Moolenaar 							   NameBuff, MAXPATHL))
424832526b3cSBram Moolenaar 			    msg_puts_attr((char *)NameBuff, attr);
4249071d4279SBram Moolenaar 		}
4250071d4279SBram Moolenaar #endif
4251071d4279SBram Moolenaar 		if ((State & INSERT) && p_paste)
425232526b3cSBram Moolenaar 		    msg_puts_attr(_(" (paste)"), attr);
4253071d4279SBram Moolenaar 
4254071d4279SBram Moolenaar 		if (VIsual_active)
4255071d4279SBram Moolenaar 		{
4256071d4279SBram Moolenaar 		    char *p;
4257071d4279SBram Moolenaar 
425863d9e730SBram Moolenaar 		    // Don't concatenate separate words to avoid translation
425963d9e730SBram Moolenaar 		    // problems.
4260071d4279SBram Moolenaar 		    switch ((VIsual_select ? 4 : 0)
4261071d4279SBram Moolenaar 			    + (VIsual_mode == Ctrl_V) * 2
4262071d4279SBram Moolenaar 			    + (VIsual_mode == 'V'))
4263071d4279SBram Moolenaar 		    {
4264071d4279SBram Moolenaar 			case 0:	p = N_(" VISUAL"); break;
4265071d4279SBram Moolenaar 			case 1: p = N_(" VISUAL LINE"); break;
4266071d4279SBram Moolenaar 			case 2: p = N_(" VISUAL BLOCK"); break;
4267071d4279SBram Moolenaar 			case 4: p = N_(" SELECT"); break;
4268071d4279SBram Moolenaar 			case 5: p = N_(" SELECT LINE"); break;
4269071d4279SBram Moolenaar 			default: p = N_(" SELECT BLOCK"); break;
4270071d4279SBram Moolenaar 		    }
427132526b3cSBram Moolenaar 		    msg_puts_attr(_(p), attr);
4272071d4279SBram Moolenaar 		}
427332526b3cSBram Moolenaar 		msg_puts_attr(" --", attr);
4274071d4279SBram Moolenaar 	    }
4275d12f5c17SBram Moolenaar 
4276071d4279SBram Moolenaar 	    need_clear = TRUE;
4277071d4279SBram Moolenaar 	}
42780b6d911eSBram Moolenaar 	if (reg_recording != 0
4279e2c453d3SBram Moolenaar 		&& edit_submode == NULL)    // otherwise it gets too long
4280071d4279SBram Moolenaar 	{
4281a0ed84a2SBram Moolenaar 	    recording_mode(attr);
4282071d4279SBram Moolenaar 	    need_clear = TRUE;
4283071d4279SBram Moolenaar 	}
4284d12f5c17SBram Moolenaar 
4285d12f5c17SBram Moolenaar 	mode_displayed = TRUE;
42864c25bd78SBram Moolenaar 	if (need_clear || clear_cmdline || redraw_mode)
4287071d4279SBram Moolenaar 	    msg_clr_eos();
428863d9e730SBram Moolenaar 	msg_didout = FALSE;		// overwrite this message
4289071d4279SBram Moolenaar 	length = msg_col;
4290071d4279SBram Moolenaar 	msg_col = 0;
429163d9e730SBram Moolenaar 	need_wait_return = nwr_save;	// never ask for hit-return for this
4292071d4279SBram Moolenaar     }
4293071d4279SBram Moolenaar     else if (clear_cmdline && msg_silent == 0)
429463d9e730SBram Moolenaar 	// Clear the whole command line.  Will reset "clear_cmdline".
4295071d4279SBram Moolenaar 	msg_clr_cmdline();
42964c25bd78SBram Moolenaar     else if (redraw_mode)
42974c25bd78SBram Moolenaar     {
42984c25bd78SBram Moolenaar 	msg_pos_mode();
42994c25bd78SBram Moolenaar 	msg_clr_eos();
43004c25bd78SBram Moolenaar     }
4301071d4279SBram Moolenaar 
4302071d4279SBram Moolenaar #ifdef FEAT_CMDL_INFO
430363d9e730SBram Moolenaar     // In Visual mode the size of the selected area must be redrawn.
4304071d4279SBram Moolenaar     if (VIsual_active)
4305071d4279SBram Moolenaar 	clear_showcmd();
4306071d4279SBram Moolenaar 
430763d9e730SBram Moolenaar     // If the last window has no status line, the ruler is after the mode
430863d9e730SBram Moolenaar     // message and must be redrawn
43094033c55eSBram Moolenaar     if (redrawing() && lastwin->w_status_height == 0)
4310491ac28dSBram Moolenaar 	win_redr_ruler(lastwin, TRUE, FALSE);
4311071d4279SBram Moolenaar #endif
4312071d4279SBram Moolenaar     redraw_cmdline = FALSE;
43134c25bd78SBram Moolenaar     redraw_mode = FALSE;
4314071d4279SBram Moolenaar     clear_cmdline = FALSE;
4315071d4279SBram Moolenaar 
4316071d4279SBram Moolenaar     return length;
4317071d4279SBram Moolenaar }
4318071d4279SBram Moolenaar 
4319071d4279SBram Moolenaar /*
4320071d4279SBram Moolenaar  * Position for a mode message.
4321071d4279SBram Moolenaar  */
4322071d4279SBram Moolenaar     static void
msg_pos_mode(void)432305540976SBram Moolenaar msg_pos_mode(void)
4324071d4279SBram Moolenaar {
4325071d4279SBram Moolenaar     msg_col = 0;
4326071d4279SBram Moolenaar     msg_row = Rows - 1;
4327071d4279SBram Moolenaar }
4328071d4279SBram Moolenaar 
4329071d4279SBram Moolenaar /*
4330071d4279SBram Moolenaar  * Delete mode message.  Used when ESC is typed which is expected to end
4331071d4279SBram Moolenaar  * Insert mode (but Insert mode didn't end yet!).
4332d12f5c17SBram Moolenaar  * Caller should check "mode_displayed".
4333071d4279SBram Moolenaar  */
4334071d4279SBram Moolenaar     void
unshowmode(int force)433505540976SBram Moolenaar unshowmode(int force)
4336071d4279SBram Moolenaar {
4337071d4279SBram Moolenaar     /*
4338e4ebd29eSBram Moolenaar      * Don't delete it right now, when not redrawing or inside a mapping.
4339071d4279SBram Moolenaar      */
4340071d4279SBram Moolenaar     if (!redrawing() || (!force && char_avail() && !KeyTyped))
434163d9e730SBram Moolenaar 	redraw_cmdline = TRUE;		// delete mode later
4342071d4279SBram Moolenaar     else
4343fd773e9eSBram Moolenaar 	clearmode();
4344fd773e9eSBram Moolenaar }
4345fd773e9eSBram Moolenaar 
4346fd773e9eSBram Moolenaar /*
4347fd773e9eSBram Moolenaar  * Clear the mode message.
4348fd773e9eSBram Moolenaar  */
4349fd773e9eSBram Moolenaar     void
clearmode(void)4350cf089463SBram Moolenaar clearmode(void)
4351071d4279SBram Moolenaar {
43522abad54cSBram Moolenaar     int save_msg_row = msg_row;
43532abad54cSBram Moolenaar     int save_msg_col = msg_col;
43542abad54cSBram Moolenaar 
4355071d4279SBram Moolenaar     msg_pos_mode();
43560b6d911eSBram Moolenaar     if (reg_recording != 0)
43578820b486SBram Moolenaar 	recording_mode(HL_ATTR(HLF_CM));
4358071d4279SBram Moolenaar     msg_clr_eos();
43592abad54cSBram Moolenaar 
43602abad54cSBram Moolenaar     msg_col = save_msg_col;
43612abad54cSBram Moolenaar     msg_row = save_msg_row;
4362071d4279SBram Moolenaar }
4363071d4279SBram Moolenaar 
4364a0ed84a2SBram Moolenaar     static void
recording_mode(int attr)436505540976SBram Moolenaar recording_mode(int attr)
4366a0ed84a2SBram Moolenaar {
436732526b3cSBram Moolenaar     msg_puts_attr(_("recording"), attr);
4368a0ed84a2SBram Moolenaar     if (!shortmess(SHM_RECORDING))
4369a0ed84a2SBram Moolenaar     {
437032526b3cSBram Moolenaar 	char s[4];
437132526b3cSBram Moolenaar 
437232526b3cSBram Moolenaar 	sprintf(s, " @%c", reg_recording);
437332526b3cSBram Moolenaar 	msg_puts_attr(s, attr);
4374a0ed84a2SBram Moolenaar     }
4375a0ed84a2SBram Moolenaar }
4376a0ed84a2SBram Moolenaar 
43771d2ba7faSBram Moolenaar /*
43781d2ba7faSBram Moolenaar  * Draw the tab pages line at the top of the Vim window.
43791d2ba7faSBram Moolenaar  */
4380e12bab31SBram Moolenaar     void
draw_tabline(void)438105540976SBram Moolenaar draw_tabline(void)
43821d2ba7faSBram Moolenaar {
43831d2ba7faSBram Moolenaar     int		tabcount = 0;
43841d2ba7faSBram Moolenaar     tabpage_T	*tp;
43851d2ba7faSBram Moolenaar     int		tabwidth;
43861d2ba7faSBram Moolenaar     int		col = 0;
4387997fb4baSBram Moolenaar     int		scol = 0;
43881d2ba7faSBram Moolenaar     int		attr;
43891d2ba7faSBram Moolenaar     win_T	*wp;
4390f740b29aSBram Moolenaar     win_T	*cwp;
4391f740b29aSBram Moolenaar     int		wincount;
4392f740b29aSBram Moolenaar     int		modified;
43931d2ba7faSBram Moolenaar     int		c;
43941d2ba7faSBram Moolenaar     int		len;
43958820b486SBram Moolenaar     int		attr_sel = HL_ATTR(HLF_TPS);
43968820b486SBram Moolenaar     int		attr_nosel = HL_ATTR(HLF_TP);
43978820b486SBram Moolenaar     int		attr_fill = HL_ATTR(HLF_TPF);
4398997fb4baSBram Moolenaar     char_u	*p;
4399faa959a8SBram Moolenaar     int		room;
4400faa959a8SBram Moolenaar     int		use_sep_chars = (t_colors < 8
4401faa959a8SBram Moolenaar #ifdef FEAT_GUI
4402faa959a8SBram Moolenaar 					    && !gui.in_use
4403faa959a8SBram Moolenaar #endif
440461be73bbSBram Moolenaar #ifdef FEAT_TERMGUICOLORS
440561be73bbSBram Moolenaar 					    && !p_tgc
44068a633e34SBram Moolenaar #endif
4407faa959a8SBram Moolenaar 					    );
44081d2ba7faSBram Moolenaar 
4409c695cec4SBram Moolenaar     if (ScreenLines == NULL)
4410c695cec4SBram Moolenaar 	return;
4411997fb4baSBram Moolenaar     redraw_tabline = FALSE;
44121d2ba7faSBram Moolenaar 
441332466aa2SBram Moolenaar #ifdef FEAT_GUI_TABLINE
441463d9e730SBram Moolenaar     // Take care of a GUI tabline.
441532466aa2SBram Moolenaar     if (gui_use_tabline())
441632466aa2SBram Moolenaar     {
441732466aa2SBram Moolenaar 	gui_update_tabline();
441832466aa2SBram Moolenaar 	return;
441932466aa2SBram Moolenaar     }
442032466aa2SBram Moolenaar #endif
442132466aa2SBram Moolenaar 
442232466aa2SBram Moolenaar     if (tabline_height() < 1)
44231d2ba7faSBram Moolenaar 	return;
44241d2ba7faSBram Moolenaar 
4425faa959a8SBram Moolenaar #if defined(FEAT_STL_OPT)
4426ca57ab54SBram Moolenaar     clear_TabPageIdxs();
4427d1f56e68SBram Moolenaar 
442863d9e730SBram Moolenaar     // Use the 'tabline' option if it's set.
4429faa959a8SBram Moolenaar     if (*p_tal != NUL)
4430faa959a8SBram Moolenaar     {
4431f73d3bc2SBram Moolenaar 	int	saved_did_emsg = did_emsg;
4432faa959a8SBram Moolenaar 
443363d9e730SBram Moolenaar 	// Check for an error.  If there is one we would loop in redrawing the
443463d9e730SBram Moolenaar 	// screen.  Avoid that by making 'tabline' empty.
4435f73d3bc2SBram Moolenaar 	did_emsg = FALSE;
4436238a5649SBram Moolenaar 	win_redr_custom(NULL, FALSE);
4437f73d3bc2SBram Moolenaar 	if (did_emsg)
4438238a5649SBram Moolenaar 	    set_string_option_direct((char_u *)"tabline", -1,
44395e3cb7e8SBram Moolenaar 					   (char_u *)"", OPT_FREE, SID_ERROR);
4440f73d3bc2SBram Moolenaar 	did_emsg |= saved_did_emsg;
4441238a5649SBram Moolenaar     }
4442238a5649SBram Moolenaar     else
4443238a5649SBram Moolenaar #endif
4444238a5649SBram Moolenaar     {
444529323590SBram Moolenaar 	FOR_ALL_TABPAGES(tp)
44461d2ba7faSBram Moolenaar 	    ++tabcount;
44471d2ba7faSBram Moolenaar 
4448f740b29aSBram Moolenaar 	tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
44491d2ba7faSBram Moolenaar 	if (tabwidth < 6)
44501d2ba7faSBram Moolenaar 	    tabwidth = 6;
44511d2ba7faSBram Moolenaar 
44521d2ba7faSBram Moolenaar 	attr = attr_nosel;
4453f740b29aSBram Moolenaar 	tabcount = 0;
4454fd2ac767SBram Moolenaar 	for (tp = first_tabpage; tp != NULL && col < Columns - 4;
4455fd2ac767SBram Moolenaar 							     tp = tp->tp_next)
44561d2ba7faSBram Moolenaar 	{
4457f740b29aSBram Moolenaar 	    scol = col;
4458f740b29aSBram Moolenaar 
44591d2ba7faSBram Moolenaar 	    if (tp->tp_topframe == topframe)
44601d2ba7faSBram Moolenaar 		attr = attr_sel;
4461faa959a8SBram Moolenaar 	    if (use_sep_chars && col > 0)
4462faa959a8SBram Moolenaar 		screen_putchar('|', 0, col++, attr);
44631d2ba7faSBram Moolenaar 
44641d2ba7faSBram Moolenaar 	    if (tp->tp_topframe != topframe)
44651d2ba7faSBram Moolenaar 		attr = attr_nosel;
44661d2ba7faSBram Moolenaar 
44674c7ed462SBram Moolenaar 	    screen_putchar(' ', 0, col++, attr);
44684c7ed462SBram Moolenaar 
4469238a5649SBram Moolenaar 	    if (tp == curtab)
4470f740b29aSBram Moolenaar 	    {
4471f740b29aSBram Moolenaar 		cwp = curwin;
4472f740b29aSBram Moolenaar 		wp = firstwin;
4473f740b29aSBram Moolenaar 	    }
44741d2ba7faSBram Moolenaar 	    else
4475f740b29aSBram Moolenaar 	    {
4476f740b29aSBram Moolenaar 		cwp = tp->tp_curwin;
4477f740b29aSBram Moolenaar 		wp = tp->tp_firstwin;
4478f740b29aSBram Moolenaar 	    }
4479f740b29aSBram Moolenaar 
4480f740b29aSBram Moolenaar 	    modified = FALSE;
4481f740b29aSBram Moolenaar 	    for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
4482f740b29aSBram Moolenaar 		if (bufIsChanged(wp->w_buffer))
4483f740b29aSBram Moolenaar 		    modified = TRUE;
4484f740b29aSBram Moolenaar 	    if (modified || wincount > 1)
4485f740b29aSBram Moolenaar 	    {
4486f740b29aSBram Moolenaar 		if (wincount > 1)
4487f740b29aSBram Moolenaar 		{
4488faa959a8SBram Moolenaar 		    vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
4489a93fa7eeSBram Moolenaar 		    len = (int)STRLEN(NameBuff);
4490fd2ac767SBram Moolenaar 		    if (col + len >= Columns - 3)
4491fd2ac767SBram Moolenaar 			break;
4492faa959a8SBram Moolenaar 		    screen_puts_len(NameBuff, len, 0, col,
4493faa959a8SBram Moolenaar #if defined(FEAT_SYN_HL)
44948820b486SBram Moolenaar 					 hl_combine_attr(attr, HL_ATTR(HLF_T))
4495faa959a8SBram Moolenaar #else
4496faa959a8SBram Moolenaar 					 attr
4497faa959a8SBram Moolenaar #endif
4498faa959a8SBram Moolenaar 					       );
4499f740b29aSBram Moolenaar 		    col += len;
4500f740b29aSBram Moolenaar 		}
4501f740b29aSBram Moolenaar 		if (modified)
4502faa959a8SBram Moolenaar 		    screen_puts_len((char_u *)"+", 1, 0, col++, attr);
4503f740b29aSBram Moolenaar 		screen_putchar(' ', 0, col++, attr);
4504f740b29aSBram Moolenaar 	    }
4505f740b29aSBram Moolenaar 
4506faa959a8SBram Moolenaar 	    room = scol - col + tabwidth - 1;
4507faa959a8SBram Moolenaar 	    if (room > 0)
4508faa959a8SBram Moolenaar 	    {
450963d9e730SBram Moolenaar 		// Get buffer name in NameBuff[]
451032466aa2SBram Moolenaar 		get_trans_bufname(cwp->w_buffer);
4511910f66f9SBram Moolenaar 		shorten_dir(NameBuff);
4512faa959a8SBram Moolenaar 		len = vim_strsize(NameBuff);
4513997fb4baSBram Moolenaar 		p = NameBuff;
4514faa959a8SBram Moolenaar 		if (has_mbyte)
4515faa959a8SBram Moolenaar 		    while (len > room)
4516997fb4baSBram Moolenaar 		    {
4517faa959a8SBram Moolenaar 			len -= ptr2cells(p);
451891acfffcSBram Moolenaar 			MB_PTR_ADV(p);
4519997fb4baSBram Moolenaar 		    }
4520a12a161bSBram Moolenaar 		else if (len > room)
4521f740b29aSBram Moolenaar 		{
4522faa959a8SBram Moolenaar 		    p += len - room;
4523faa959a8SBram Moolenaar 		    len = room;
4524faa959a8SBram Moolenaar 		}
4525fd2ac767SBram Moolenaar 		if (len > Columns - col - 1)
4526fd2ac767SBram Moolenaar 		    len = Columns - col - 1;
4527faa959a8SBram Moolenaar 
4528a93fa7eeSBram Moolenaar 		screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
45291d2ba7faSBram Moolenaar 		col += len;
4530f740b29aSBram Moolenaar 	    }
45314c7ed462SBram Moolenaar 	    screen_putchar(' ', 0, col++, attr);
4532f740b29aSBram Moolenaar 
453363d9e730SBram Moolenaar 	    // Store the tab page number in TabPageIdxs[], so that
453463d9e730SBram Moolenaar 	    // jump_to_mouse() knows where each one is.
4535f740b29aSBram Moolenaar 	    ++tabcount;
4536f740b29aSBram Moolenaar 	    while (scol < col)
4537f740b29aSBram Moolenaar 		TabPageIdxs[scol++] = tabcount;
45381d2ba7faSBram Moolenaar 	}
45391d2ba7faSBram Moolenaar 
4540faa959a8SBram Moolenaar 	if (use_sep_chars)
45414c7ed462SBram Moolenaar 	    c = '_';
45424c7ed462SBram Moolenaar 	else
45434c7ed462SBram Moolenaar 	    c = ' ';
45444c7ed462SBram Moolenaar 	screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
4545f740b29aSBram Moolenaar 
454663d9e730SBram Moolenaar 	// Put an "X" for closing the current tab if there are several.
4547f740b29aSBram Moolenaar 	if (first_tabpage->tp_next != NULL)
4548d1f56e68SBram Moolenaar 	{
4549f740b29aSBram Moolenaar 	    screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
4550d1f56e68SBram Moolenaar 	    TabPageIdxs[Columns - 1] = -999;
4551d1f56e68SBram Moolenaar 	}
4552d1f56e68SBram Moolenaar     }
4553b21e5843SBram Moolenaar 
455463d9e730SBram Moolenaar     // Reset the flag here again, in case evaluating 'tabline' causes it to be
455563d9e730SBram Moolenaar     // set.
4556b21e5843SBram Moolenaar     redraw_tabline = FALSE;
45571d2ba7faSBram Moolenaar }
455832466aa2SBram Moolenaar 
455932466aa2SBram Moolenaar /*
456032466aa2SBram Moolenaar  * Get buffer name for "buf" into NameBuff[].
456132466aa2SBram Moolenaar  * Takes care of special buffer names and translates special characters.
456232466aa2SBram Moolenaar  */
456332466aa2SBram Moolenaar     void
get_trans_bufname(buf_T * buf)456405540976SBram Moolenaar get_trans_bufname(buf_T *buf)
456532466aa2SBram Moolenaar {
456632466aa2SBram Moolenaar     if (buf_spname(buf) != NULL)
4567e1704badSBram Moolenaar 	vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
456832466aa2SBram Moolenaar     else
456932466aa2SBram Moolenaar 	home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
457032466aa2SBram Moolenaar     trans_characters(NameBuff, MAXPATHL);
457132466aa2SBram Moolenaar }
45721d2ba7faSBram Moolenaar 
4573071d4279SBram Moolenaar /*
4574071d4279SBram Moolenaar  * Get the character to use in a status line.  Get its attributes in "*attr".
4575071d4279SBram Moolenaar  */
45767528d1f6SBram Moolenaar     int
fillchar_status(int * attr,win_T * wp)45773633cf52SBram Moolenaar fillchar_status(int *attr, win_T *wp)
4578071d4279SBram Moolenaar {
4579071d4279SBram Moolenaar     int fill;
45803633cf52SBram Moolenaar 
45813633cf52SBram Moolenaar #ifdef FEAT_TERMINAL
45823633cf52SBram Moolenaar     if (bt_terminal(wp->w_buffer))
45833633cf52SBram Moolenaar     {
45843633cf52SBram Moolenaar 	if (wp == curwin)
458505fbfdcdSBram Moolenaar 	{
458605fbfdcdSBram Moolenaar 	    *attr = HL_ATTR(HLF_ST);
45873633cf52SBram Moolenaar 	    fill = fill_stl;
458805fbfdcdSBram Moolenaar 	}
45893633cf52SBram Moolenaar 	else
459005fbfdcdSBram Moolenaar 	{
459105fbfdcdSBram Moolenaar 	    *attr = HL_ATTR(HLF_STNC);
45923633cf52SBram Moolenaar 	    fill = fill_stlnc;
45933633cf52SBram Moolenaar 	}
459405fbfdcdSBram Moolenaar     }
45953633cf52SBram Moolenaar     else
45963633cf52SBram Moolenaar #endif
45973633cf52SBram Moolenaar     if (wp == curwin)
4598071d4279SBram Moolenaar     {
45998820b486SBram Moolenaar 	*attr = HL_ATTR(HLF_S);
4600071d4279SBram Moolenaar 	fill = fill_stl;
4601071d4279SBram Moolenaar     }
4602071d4279SBram Moolenaar     else
4603071d4279SBram Moolenaar     {
46048820b486SBram Moolenaar 	*attr = HL_ATTR(HLF_SNC);
4605071d4279SBram Moolenaar 	fill = fill_stlnc;
4606071d4279SBram Moolenaar     }
460763d9e730SBram Moolenaar     // Use fill when there is highlighting, and highlighting of current
460863d9e730SBram Moolenaar     // window differs, or the fillchars differ, or this is not the
460963d9e730SBram Moolenaar     // current window
46108820b486SBram Moolenaar     if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
46113633cf52SBram Moolenaar 			|| wp != curwin || ONE_WINDOW)
4612071d4279SBram Moolenaar 		    || (fill_stl != fill_stlnc)))
4613071d4279SBram Moolenaar 	return fill;
46143633cf52SBram Moolenaar     if (wp == curwin)
4615071d4279SBram Moolenaar 	return '^';
4616071d4279SBram Moolenaar     return '=';
4617071d4279SBram Moolenaar }
4618071d4279SBram Moolenaar 
4619071d4279SBram Moolenaar /*
4620071d4279SBram Moolenaar  * Get the character to use in a separator between vertically split windows.
4621071d4279SBram Moolenaar  * Get its attributes in "*attr".
4622071d4279SBram Moolenaar  */
46237528d1f6SBram Moolenaar     int
fillchar_vsep(int * attr)462405540976SBram Moolenaar fillchar_vsep(int *attr)
4625071d4279SBram Moolenaar {
46268820b486SBram Moolenaar     *attr = HL_ATTR(HLF_C);
4627071d4279SBram Moolenaar     if (*attr == 0 && fill_vert == ' ')
4628071d4279SBram Moolenaar 	return '|';
4629071d4279SBram Moolenaar     else
4630071d4279SBram Moolenaar 	return fill_vert;
4631071d4279SBram Moolenaar }
4632071d4279SBram Moolenaar 
4633071d4279SBram Moolenaar /*
4634071d4279SBram Moolenaar  * Return TRUE if redrawing should currently be done.
4635071d4279SBram Moolenaar  */
4636071d4279SBram Moolenaar     int
redrawing(void)463705540976SBram Moolenaar redrawing(void)
4638071d4279SBram Moolenaar {
4639eb992cb9SBram Moolenaar #ifdef FEAT_EVAL
4640eb992cb9SBram Moolenaar     if (disable_redraw_for_testing)
4641eb992cb9SBram Moolenaar 	return 0;
4642eb992cb9SBram Moolenaar     else
4643eb992cb9SBram Moolenaar #endif
4644ed5a9d66SBram Moolenaar 	return ((!RedrawingDisabled
4645ed5a9d66SBram Moolenaar #ifdef FEAT_EVAL
4646ed5a9d66SBram Moolenaar 		    || ignore_redraw_flag_for_testing
4647ed5a9d66SBram Moolenaar #endif
4648ed5a9d66SBram Moolenaar 		) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
4649071d4279SBram Moolenaar }
4650071d4279SBram Moolenaar 
4651071d4279SBram Moolenaar /*
4652071d4279SBram Moolenaar  * Return TRUE if printing messages should currently be done.
4653071d4279SBram Moolenaar  */
4654071d4279SBram Moolenaar     int
messaging(void)465505540976SBram Moolenaar messaging(void)
4656071d4279SBram Moolenaar {
4657071d4279SBram Moolenaar     return (!(p_lz && char_avail() && !KeyTyped));
4658071d4279SBram Moolenaar }
4659071d4279SBram Moolenaar 
4660e677df8dSBram Moolenaar /*
4661e677df8dSBram Moolenaar  * Compute columns for ruler and shown command. 'sc_col' is also used to
4662e677df8dSBram Moolenaar  * decide what the maximum length of a message on the status line can be.
4663e677df8dSBram Moolenaar  * If there is a status line for the last window, 'sc_col' is independent
4664e677df8dSBram Moolenaar  * of 'ru_col'.
4665e677df8dSBram Moolenaar  */
4666e677df8dSBram Moolenaar 
4667e677df8dSBram Moolenaar #define COL_RULER 17	    // columns needed by standard ruler
4668e677df8dSBram Moolenaar 
4669e677df8dSBram Moolenaar     void
comp_col(void)4670e677df8dSBram Moolenaar comp_col(void)
4671e677df8dSBram Moolenaar {
4672e677df8dSBram Moolenaar #if defined(FEAT_CMDL_INFO)
4673e677df8dSBram Moolenaar     int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
4674e677df8dSBram Moolenaar 
4675e677df8dSBram Moolenaar     sc_col = 0;
4676e677df8dSBram Moolenaar     ru_col = 0;
4677e677df8dSBram Moolenaar     if (p_ru)
4678e677df8dSBram Moolenaar     {
4679e677df8dSBram Moolenaar # ifdef FEAT_STL_OPT
4680e677df8dSBram Moolenaar 	ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
4681e677df8dSBram Moolenaar # else
4682e677df8dSBram Moolenaar 	ru_col = COL_RULER + 1;
4683e677df8dSBram Moolenaar # endif
4684e677df8dSBram Moolenaar 	// no last status line, adjust sc_col
4685e677df8dSBram Moolenaar 	if (!last_has_status)
4686e677df8dSBram Moolenaar 	    sc_col = ru_col;
4687e677df8dSBram Moolenaar     }
4688e677df8dSBram Moolenaar     if (p_sc)
4689e677df8dSBram Moolenaar     {
4690e677df8dSBram Moolenaar 	sc_col += SHOWCMD_COLS;
4691e677df8dSBram Moolenaar 	if (!p_ru || last_has_status)	    // no need for separating space
4692e677df8dSBram Moolenaar 	    ++sc_col;
4693e677df8dSBram Moolenaar     }
4694e677df8dSBram Moolenaar     sc_col = Columns - sc_col;
4695e677df8dSBram Moolenaar     ru_col = Columns - ru_col;
4696e677df8dSBram Moolenaar     if (sc_col <= 0)		// screen too narrow, will become a mess
4697e677df8dSBram Moolenaar 	sc_col = 1;
4698e677df8dSBram Moolenaar     if (ru_col <= 0)
4699e677df8dSBram Moolenaar 	ru_col = 1;
4700e677df8dSBram Moolenaar #else
4701e677df8dSBram Moolenaar     sc_col = Columns;
4702e677df8dSBram Moolenaar     ru_col = Columns;
4703e677df8dSBram Moolenaar #endif
4704e677df8dSBram Moolenaar #ifdef FEAT_EVAL
4705e677df8dSBram Moolenaar     set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
4706e677df8dSBram Moolenaar #endif
4707e677df8dSBram Moolenaar }
4708e677df8dSBram Moolenaar 
4709592e0a2aSBram Moolenaar #if defined(FEAT_LINEBREAK) || defined(PROTO)
4710592e0a2aSBram Moolenaar /*
471164486671SBram Moolenaar  * Return the width of the 'number' and 'relativenumber' column.
471264486671SBram Moolenaar  * Caller may need to check if 'number' or 'relativenumber' is set.
4713592e0a2aSBram Moolenaar  * Otherwise it depends on 'numberwidth' and the line count.
4714592e0a2aSBram Moolenaar  */
4715592e0a2aSBram Moolenaar     int
number_width(win_T * wp)471605540976SBram Moolenaar number_width(win_T *wp)
4717592e0a2aSBram Moolenaar {
4718592e0a2aSBram Moolenaar     int		n;
4719592e0a2aSBram Moolenaar     linenr_T	lnum;
4720592e0a2aSBram Moolenaar 
47215ebc09b4SBram Moolenaar     if (wp->w_p_rnu && !wp->w_p_nu)
472263d9e730SBram Moolenaar 	// cursor line shows "0"
47235ebc09b4SBram Moolenaar 	lnum = wp->w_height;
47245ebc09b4SBram Moolenaar     else
472563d9e730SBram Moolenaar 	// cursor line shows absolute line number
4726592e0a2aSBram Moolenaar 	lnum = wp->w_buffer->b_ml.ml_line_count;
472764486671SBram Moolenaar 
47286b31467aSBram Moolenaar     if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
4729592e0a2aSBram Moolenaar 	return wp->w_nrwidth_width;
4730592e0a2aSBram Moolenaar     wp->w_nrwidth_line_count = lnum;
4731592e0a2aSBram Moolenaar 
4732592e0a2aSBram Moolenaar     n = 0;
4733592e0a2aSBram Moolenaar     do
4734592e0a2aSBram Moolenaar     {
4735592e0a2aSBram Moolenaar 	lnum /= 10;
4736592e0a2aSBram Moolenaar 	++n;
4737592e0a2aSBram Moolenaar     } while (lnum > 0);
4738592e0a2aSBram Moolenaar 
473963d9e730SBram Moolenaar     // 'numberwidth' gives the minimal width plus one
4740592e0a2aSBram Moolenaar     if (n < wp->w_p_nuw - 1)
4741592e0a2aSBram Moolenaar 	n = wp->w_p_nuw - 1;
4742592e0a2aSBram Moolenaar 
4743e4b407f5SBram Moolenaar # ifdef FEAT_SIGNS
4744e4b407f5SBram Moolenaar     // If 'signcolumn' is set to 'number' and there is a sign to display, then
4745e4b407f5SBram Moolenaar     // the minimal width for the number column is 2.
47464eb7dae2SBram Moolenaar     if (n < 2 && get_first_valid_sign(wp) != NULL
4747e4b407f5SBram Moolenaar 	    && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
4748e4b407f5SBram Moolenaar 	n = 2;
4749e4b407f5SBram Moolenaar # endif
4750e4b407f5SBram Moolenaar 
4751592e0a2aSBram Moolenaar     wp->w_nrwidth_width = n;
47526b31467aSBram Moolenaar     wp->w_nuw_cached = wp->w_p_nuw;
4753592e0a2aSBram Moolenaar     return n;
4754592e0a2aSBram Moolenaar }
4755592e0a2aSBram Moolenaar #endif
47569750bb19SBram Moolenaar 
4757113e1072SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
47589750bb19SBram Moolenaar /*
47599750bb19SBram Moolenaar  * Return the current cursor column. This is the actual position on the
47609750bb19SBram Moolenaar  * screen. First column is 0.
47619750bb19SBram Moolenaar  */
47629750bb19SBram Moolenaar     int
screen_screencol(void)476305540976SBram Moolenaar screen_screencol(void)
47649750bb19SBram Moolenaar {
47659750bb19SBram Moolenaar     return screen_cur_col;
47669750bb19SBram Moolenaar }
47679750bb19SBram Moolenaar 
47689750bb19SBram Moolenaar /*
47699750bb19SBram Moolenaar  * Return the current cursor row. This is the actual position on the screen.
47709750bb19SBram Moolenaar  * First row is 0.
47719750bb19SBram Moolenaar  */
47729750bb19SBram Moolenaar     int
screen_screenrow(void)477305540976SBram Moolenaar screen_screenrow(void)
47749750bb19SBram Moolenaar {
47759750bb19SBram Moolenaar     return screen_cur_row;
47769750bb19SBram Moolenaar }
4777113e1072SBram Moolenaar #endif
4778e677df8dSBram Moolenaar 
4779e677df8dSBram Moolenaar /*
478093ff6720SBram Moolenaar  * Calls mb_ptr2char_adv(p) and returns the character.
478193ff6720SBram Moolenaar  * If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
478293ff6720SBram Moolenaar  */
478393ff6720SBram Moolenaar     static int
get_encoded_char_adv(char_u ** p)478493ff6720SBram Moolenaar get_encoded_char_adv(char_u **p)
478593ff6720SBram Moolenaar {
478693ff6720SBram Moolenaar     char_u *s = *p;
478793ff6720SBram Moolenaar 
478893ff6720SBram Moolenaar     if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
478993ff6720SBram Moolenaar     {
479093ff6720SBram Moolenaar 	varnumber_T num = 0;
479193ff6720SBram Moolenaar 	int	    bytes;
479293ff6720SBram Moolenaar 	int	    n;
479393ff6720SBram Moolenaar 
479493ff6720SBram Moolenaar 	for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
479593ff6720SBram Moolenaar 	{
479693ff6720SBram Moolenaar 	    *p += 2;
479793ff6720SBram Moolenaar 	    n = hexhex2nr(*p);
479893ff6720SBram Moolenaar 	    if (n < 0)
479993ff6720SBram Moolenaar 		return 0;
480093ff6720SBram Moolenaar 	    num = num * 256 + n;
480193ff6720SBram Moolenaar 	}
480293ff6720SBram Moolenaar 	*p += 2;
480393ff6720SBram Moolenaar 	return num;
480493ff6720SBram Moolenaar     }
480593ff6720SBram Moolenaar     return mb_ptr2char_adv(p);
480693ff6720SBram Moolenaar }
480793ff6720SBram Moolenaar 
480893ff6720SBram Moolenaar /*
4809e677df8dSBram Moolenaar  * Handle setting 'listchars' or 'fillchars'.
4810eed9d462SBram Moolenaar  * Assume monocell characters.
4811e677df8dSBram Moolenaar  * Returns error message, NULL if it's OK.
4812e677df8dSBram Moolenaar  */
4813e677df8dSBram Moolenaar     char *
set_chars_option(win_T * wp,char_u ** varp)4814eed9d462SBram Moolenaar set_chars_option(win_T *wp, char_u **varp)
4815e677df8dSBram Moolenaar {
4816e677df8dSBram Moolenaar     int		round, i, len, entries;
4817e677df8dSBram Moolenaar     char_u	*p, *s;
4818e677df8dSBram Moolenaar     int		c1 = 0, c2 = 0, c3 = 0;
481956e14698SBram Moolenaar     char_u	*last_multispace = NULL; // Last occurrence of "multispace:"
4820f14b8ba1Szeertzjq     int		multispace_len = 0;	 // Length of lcs-multispace string
4821e677df8dSBram Moolenaar     struct charstab
4822e677df8dSBram Moolenaar     {
4823e677df8dSBram Moolenaar 	int	*cp;
4824e677df8dSBram Moolenaar 	char	*name;
4825e677df8dSBram Moolenaar     };
4826e677df8dSBram Moolenaar     static struct charstab filltab[] =
4827e677df8dSBram Moolenaar     {
4828e677df8dSBram Moolenaar 	{&fill_stl,		"stl"},
4829e677df8dSBram Moolenaar 	{&fill_stlnc,		"stlnc"},
4830e677df8dSBram Moolenaar 	{&fill_vert,		"vert"},
4831e677df8dSBram Moolenaar 	{&fill_fold,		"fold"},
48323aca5a6fSBram Moolenaar 	{&fill_foldopen,	"foldopen"},
48333aca5a6fSBram Moolenaar 	{&fill_foldclosed,	"foldclose"},
48343aca5a6fSBram Moolenaar 	{&fill_foldsep,		"foldsep"},
4835e677df8dSBram Moolenaar 	{&fill_diff,		"diff"},
4836a98f8a23SBram Moolenaar 	{&fill_eob,		"eob"},
4837e677df8dSBram Moolenaar     };
4838333bd564SBram Moolenaar     static lcs_chars_T lcs_chars;
4839eed9d462SBram Moolenaar     struct charstab lcstab[] =
4840e677df8dSBram Moolenaar     {
4841333bd564SBram Moolenaar 	{&lcs_chars.eol,	"eol"},
4842333bd564SBram Moolenaar 	{&lcs_chars.ext,	"extends"},
4843333bd564SBram Moolenaar 	{&lcs_chars.nbsp,	"nbsp"},
4844333bd564SBram Moolenaar 	{&lcs_chars.prec,	"precedes"},
4845333bd564SBram Moolenaar 	{&lcs_chars.space,	"space"},
4846333bd564SBram Moolenaar 	{&lcs_chars.tab2,	"tab"},
4847333bd564SBram Moolenaar 	{&lcs_chars.trail,	"trail"},
4848333bd564SBram Moolenaar 	{&lcs_chars.lead,	"lead"},
4849e677df8dSBram Moolenaar #ifdef FEAT_CONCEAL
4850333bd564SBram Moolenaar 	{&lcs_chars.conceal,	"conceal"},
4851e677df8dSBram Moolenaar #else
4852e677df8dSBram Moolenaar 	{NULL,			"conceal"},
4853e677df8dSBram Moolenaar #endif
4854e677df8dSBram Moolenaar     };
4855e677df8dSBram Moolenaar     struct charstab *tab;
4856e677df8dSBram Moolenaar 
4857eed9d462SBram Moolenaar     if (varp == &p_lcs || varp == &wp->w_p_lcs)
4858e677df8dSBram Moolenaar     {
4859e677df8dSBram Moolenaar 	tab = lcstab;
4860333bd564SBram Moolenaar 	CLEAR_FIELD(lcs_chars);
4861eeec2548SK.Takata 	entries = ARRAY_LENGTH(lcstab);
4862eed9d462SBram Moolenaar 	if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL)
4863eed9d462SBram Moolenaar 	    varp = &p_lcs;
4864e677df8dSBram Moolenaar     }
4865e677df8dSBram Moolenaar     else
4866e677df8dSBram Moolenaar     {
4867e677df8dSBram Moolenaar 	tab = filltab;
4868eeec2548SK.Takata 	entries = ARRAY_LENGTH(filltab);
4869e677df8dSBram Moolenaar     }
4870e677df8dSBram Moolenaar 
4871e677df8dSBram Moolenaar     // first round: check for valid value, second round: assign values
4872e677df8dSBram Moolenaar     for (round = 0; round <= 1; ++round)
4873e677df8dSBram Moolenaar     {
4874e677df8dSBram Moolenaar 	if (round > 0)
4875e677df8dSBram Moolenaar 	{
4876e677df8dSBram Moolenaar 	    // After checking that the value is valid: set defaults: space for
4877e677df8dSBram Moolenaar 	    // 'fillchars', NUL for 'listchars'
4878e677df8dSBram Moolenaar 	    for (i = 0; i < entries; ++i)
4879e677df8dSBram Moolenaar 		if (tab[i].cp != NULL)
4880eed9d462SBram Moolenaar 		    *(tab[i].cp) =
4881eed9d462SBram Moolenaar 			((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' ');
4882e677df8dSBram Moolenaar 
4883eed9d462SBram Moolenaar 	    if (varp == &p_lcs || varp == &wp->w_p_lcs)
4884e677df8dSBram Moolenaar 	    {
4885333bd564SBram Moolenaar 		lcs_chars.tab1 = NUL;
4886333bd564SBram Moolenaar 		lcs_chars.tab3 = NUL;
4887f5785cf0SMike Williams 		if (multispace_len > 0)
4888f14b8ba1Szeertzjq 		{
4889f14b8ba1Szeertzjq 		    lcs_chars.multispace = ALLOC_MULT(int, multispace_len + 1);
4890f14b8ba1Szeertzjq 		    lcs_chars.multispace[multispace_len] = NUL;
4891f14b8ba1Szeertzjq 		}
4892f14b8ba1Szeertzjq 		else
4893f14b8ba1Szeertzjq 		    lcs_chars.multispace = NULL;
4894e677df8dSBram Moolenaar 	    }
4895e677df8dSBram Moolenaar 	    else
4896a98f8a23SBram Moolenaar 	    {
4897e677df8dSBram Moolenaar 		fill_diff = '-';
48983aca5a6fSBram Moolenaar 		fill_foldopen = '-';
48993aca5a6fSBram Moolenaar 		fill_foldclosed = '+';
49003aca5a6fSBram Moolenaar 		fill_foldsep = '|';
4901a98f8a23SBram Moolenaar 		fill_eob = '~';
4902a98f8a23SBram Moolenaar 	    }
4903e677df8dSBram Moolenaar 	}
4904e677df8dSBram Moolenaar 	p = *varp;
4905e677df8dSBram Moolenaar 	while (*p)
4906e677df8dSBram Moolenaar 	{
4907e677df8dSBram Moolenaar 	    for (i = 0; i < entries; ++i)
4908e677df8dSBram Moolenaar 	    {
4909e677df8dSBram Moolenaar 		len = (int)STRLEN(tab[i].name);
4910e677df8dSBram Moolenaar 		if (STRNCMP(p, tab[i].name, len) == 0
4911e677df8dSBram Moolenaar 			&& p[len] == ':'
4912e677df8dSBram Moolenaar 			&& p[len + 1] != NUL)
4913e677df8dSBram Moolenaar 		{
4914e677df8dSBram Moolenaar 		    c2 = c3 = 0;
4915e677df8dSBram Moolenaar 		    s = p + len + 1;
491693ff6720SBram Moolenaar 		    c1 = get_encoded_char_adv(&s);
4917e677df8dSBram Moolenaar 		    if (mb_char2cells(c1) > 1)
4918f14b8ba1Szeertzjq 			return e_invarg;
4919333bd564SBram Moolenaar 		    if (tab[i].cp == &lcs_chars.tab2)
4920e677df8dSBram Moolenaar 		    {
4921e677df8dSBram Moolenaar 			if (*s == NUL)
4922f14b8ba1Szeertzjq 			    return e_invarg;
492393ff6720SBram Moolenaar 			c2 = get_encoded_char_adv(&s);
4924e677df8dSBram Moolenaar 			if (mb_char2cells(c2) > 1)
4925f14b8ba1Szeertzjq 			    return e_invarg;
4926e677df8dSBram Moolenaar 			if (!(*s == ',' || *s == NUL))
4927e677df8dSBram Moolenaar 			{
492893ff6720SBram Moolenaar 			    c3 = get_encoded_char_adv(&s);
4929e677df8dSBram Moolenaar 			    if (mb_char2cells(c3) > 1)
4930f14b8ba1Szeertzjq 				return e_invarg;
4931e677df8dSBram Moolenaar 			}
4932e677df8dSBram Moolenaar 		    }
4933e677df8dSBram Moolenaar 
4934e677df8dSBram Moolenaar 		    if (*s == ',' || *s == NUL)
4935e677df8dSBram Moolenaar 		    {
4936f5785cf0SMike Williams 			if (round > 0)
4937e677df8dSBram Moolenaar 			{
4938333bd564SBram Moolenaar 			    if (tab[i].cp == &lcs_chars.tab2)
4939e677df8dSBram Moolenaar 			    {
4940333bd564SBram Moolenaar 				lcs_chars.tab1 = c1;
4941333bd564SBram Moolenaar 				lcs_chars.tab2 = c2;
4942333bd564SBram Moolenaar 				lcs_chars.tab3 = c3;
4943e677df8dSBram Moolenaar 			    }
4944e677df8dSBram Moolenaar 			    else if (tab[i].cp != NULL)
4945e677df8dSBram Moolenaar 				*(tab[i].cp) = c1;
4946e677df8dSBram Moolenaar 
4947e677df8dSBram Moolenaar 			}
4948e677df8dSBram Moolenaar 			p = s;
4949e677df8dSBram Moolenaar 			break;
4950e677df8dSBram Moolenaar 		    }
4951e677df8dSBram Moolenaar 		}
4952e677df8dSBram Moolenaar 	    }
4953e677df8dSBram Moolenaar 
4954e677df8dSBram Moolenaar 	    if (i == entries)
4955f14b8ba1Szeertzjq 	    {
4956f5785cf0SMike Williams 		len = (int)STRLEN("multispace");
4957f14b8ba1Szeertzjq 		if ((varp == &p_lcs || varp == &wp->w_p_lcs)
4958f14b8ba1Szeertzjq 			&& STRNCMP(p, "multispace", len) == 0
4959f14b8ba1Szeertzjq 			&& p[len] == ':'
4960f14b8ba1Szeertzjq 			&& p[len + 1] != NUL)
4961f14b8ba1Szeertzjq 		{
4962f14b8ba1Szeertzjq 		    s = p + len + 1;
4963f14b8ba1Szeertzjq 		    if (round == 0)
4964f14b8ba1Szeertzjq 		    {
4965f14b8ba1Szeertzjq 			// Get length of lcs-multispace string in first round
4966f14b8ba1Szeertzjq 			last_multispace = p;
4967f14b8ba1Szeertzjq 			multispace_len = 0;
4968f14b8ba1Szeertzjq 			while (*s != NUL && *s != ',')
4969f14b8ba1Szeertzjq 			{
497093ff6720SBram Moolenaar 			    c1 = get_encoded_char_adv(&s);
4971f14b8ba1Szeertzjq 			    if (mb_char2cells(c1) > 1)
4972e677df8dSBram Moolenaar 				return e_invarg;
4973f14b8ba1Szeertzjq 			    ++multispace_len;
4974f14b8ba1Szeertzjq 			}
4975f14b8ba1Szeertzjq 			if (multispace_len == 0)
4976f14b8ba1Szeertzjq 			    // lcs-multispace cannot be an empty string
4977f14b8ba1Szeertzjq 			    return e_invarg;
4978f14b8ba1Szeertzjq 			p = s;
4979f14b8ba1Szeertzjq 		    }
4980f14b8ba1Szeertzjq 		    else
4981f14b8ba1Szeertzjq 		    {
4982f14b8ba1Szeertzjq 			int multispace_pos = 0;
4983f5785cf0SMike Williams 
4984f14b8ba1Szeertzjq 			while (*s != NUL && *s != ',')
4985f14b8ba1Szeertzjq 			{
498693ff6720SBram Moolenaar 			    c1 = get_encoded_char_adv(&s);
4987f14b8ba1Szeertzjq 			    if (p == last_multispace)
4988f14b8ba1Szeertzjq 				lcs_chars.multispace[multispace_pos++] = c1;
4989f14b8ba1Szeertzjq 			}
4990f14b8ba1Szeertzjq 			p = s;
4991f14b8ba1Szeertzjq 		    }
4992f14b8ba1Szeertzjq 		}
4993f14b8ba1Szeertzjq 		else
4994f14b8ba1Szeertzjq 		    return e_invarg;
4995f14b8ba1Szeertzjq 	    }
4996f14b8ba1Szeertzjq 
4997e677df8dSBram Moolenaar 	    if (*p == ',')
4998e677df8dSBram Moolenaar 		++p;
4999e677df8dSBram Moolenaar 	}
5000e677df8dSBram Moolenaar     }
5001333bd564SBram Moolenaar     if (tab == lcstab)
5002f14b8ba1Szeertzjq     {
5003f14b8ba1Szeertzjq 	if (wp->w_lcs_chars.multispace != NULL)
5004f14b8ba1Szeertzjq 	    vim_free(wp->w_lcs_chars.multispace);
5005333bd564SBram Moolenaar 	wp->w_lcs_chars = lcs_chars;
5006f14b8ba1Szeertzjq     }
5007e677df8dSBram Moolenaar 
5008e677df8dSBram Moolenaar     return NULL;	// no error
5009e677df8dSBram Moolenaar }
5010017ba07fSBram Moolenaar 
5011