1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * screen.c: Lower level code for displaying on the screen.
12  *
13  * Output to the screen (console, terminal emulator or GUI window) is minimized
14  * by remembering what is already on the screen, and only updating the parts
15  * that changed.
16  *
17  * ScreenLines[off]  Contains a copy of the whole screen, as it is currently
18  *		     displayed (excluding text written by external commands).
19  * ScreenAttrs[off]  Contains the associated attributes.
20  * LineOffset[row]   Contains the offset into ScreenLines*[] and ScreenAttrs[]
21  *		     for each line.
22  * LineWraps[row]    Flag for each line whether it wraps to the next line.
23  *
24  * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25  * one character which occupies two display cells.
26  * For UTF-8 a multi-byte character is converted to Unicode and stored in
27  * ScreenLinesUC[].  ScreenLines[] contains the first byte only.  For an ASCII
28  * character without composing chars ScreenLinesUC[] will be 0 and
29  * ScreenLinesC[][] is not used.  When the character occupies two display
30  * cells the next byte in ScreenLines[] is 0.
31  * ScreenLinesC[][] contain up to 'maxcombine' composing characters
32  * (drawn on top of the first character).  There is 0 after the last one used.
33  * ScreenLines2[] is only used for euc-jp to store the second byte if the
34  * first byte is 0x8e (single-width character).
35  *
36  * The screen_*() functions write to the screen and handle updating
37  * ScreenLines[].
38  */
39 
40 #include "vim.h"
41 
42 /*
43  * The attributes that are actually active for writing to the screen.
44  */
45 static int	screen_attr = 0;
46 
47 static void screen_char_2(unsigned off, int row, int col);
48 static void screenclear2(void);
49 static void lineclear(unsigned off, int width, int attr);
50 static void lineinvalid(unsigned off, int width);
51 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
52 static void win_rest_invalid(win_T *wp);
53 static void msg_pos_mode(void);
54 static void recording_mode(int attr);
55 
56 // Ugly global: overrule attribute used by screen_char()
57 static int screen_char_attr = 0;
58 
59 #if defined(FEAT_CONCEAL) || defined(PROTO)
60 /*
61  * Return TRUE if the cursor line in window "wp" may be concealed, according
62  * to the 'concealcursor' option.
63  */
64     int
conceal_cursor_line(win_T * wp)65 conceal_cursor_line(win_T *wp)
66 {
67     int		c;
68 
69     if (*wp->w_p_cocu == NUL)
70 	return FALSE;
71     if (get_real_state() & VISUAL)
72 	c = 'v';
73     else if (State & INSERT)
74 	c = 'i';
75     else if (State & NORMAL)
76 	c = 'n';
77     else if (State & CMDLINE)
78 	c = 'c';
79     else
80 	return FALSE;
81     return vim_strchr(wp->w_p_cocu, c) != NULL;
82 }
83 
84 /*
85  * Check if the cursor line needs to be redrawn because of 'concealcursor'.
86  * To be called after changing the state, "was_concealed" is the value of
87  * "conceal_cursor_line()" before the change.
88  * "
89  */
90     void
conceal_check_cursor_line(int was_concealed)91 conceal_check_cursor_line(int was_concealed)
92 {
93     if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin) != was_concealed)
94     {
95 	int wcol = curwin->w_wcol;
96 
97 	need_cursor_line_redraw = TRUE;
98 	// Need to recompute cursor column, e.g., when starting Visual mode
99 	// without concealing.
100 	curs_columns(TRUE);
101 
102 	// When concealing now w_wcol will be computed wrong, keep the previous
103 	// value, it will be updated in win_line().
104 	if (!was_concealed)
105 	    curwin->w_wcol = wcol;
106     }
107 }
108 #endif
109 
110 /*
111  * Get 'wincolor' attribute for window "wp".  If not set and "wp" is a popup
112  * window then get the "Pmenu" highlight attribute.
113  */
114     int
get_wcr_attr(win_T * wp)115 get_wcr_attr(win_T *wp)
116 {
117     int wcr_attr = 0;
118 
119     if (*wp->w_p_wcr != NUL)
120 	wcr_attr = syn_name2attr(wp->w_p_wcr);
121 #ifdef FEAT_PROP_POPUP
122     else if (WIN_IS_POPUP(wp))
123     {
124 	if (wp->w_popup_flags & POPF_INFO)
125 	    wcr_attr = HL_ATTR(HLF_PSI);    // PmenuSel
126 	else
127 	    wcr_attr = HL_ATTR(HLF_PNI);    // Pmenu
128     }
129 #endif
130     return wcr_attr;
131 }
132 
133 /*
134  * Call screen_fill() with the columns adjusted for 'rightleft' if needed.
135  * Return the new offset.
136  */
137     static int
screen_fill_end(win_T * wp,int c1,int c2,int off,int width,int row,int endrow,int attr)138 screen_fill_end(
139 	win_T *wp,
140 	int	c1,
141 	int	c2,
142 	int	off,
143 	int	width,
144 	int	row,
145 	int	endrow,
146 	int	attr)
147 {
148     int	    nn = off + width;
149 
150     if (nn > wp->w_width)
151 	nn = wp->w_width;
152 #ifdef FEAT_RIGHTLEFT
153     if (wp->w_p_rl)
154     {
155 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
156 		W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
157 		c1, c2, attr);
158     }
159     else
160 #endif
161 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
162 		wp->w_wincol + off, (int)wp->w_wincol + nn,
163 		c1, c2, attr);
164     return nn;
165 }
166 
167 /*
168  * Clear lines near the end the window and mark the unused lines with "c1".
169  * use "c2" as the filler character.
170  * When "draw_margin" is TRUE then draw the sign, fold and number columns.
171  */
172     void
win_draw_end(win_T * wp,int c1,int c2,int draw_margin,int row,int endrow,hlf_T hl)173 win_draw_end(
174     win_T	*wp,
175     int		c1,
176     int		c2,
177     int		draw_margin,
178     int		row,
179     int		endrow,
180     hlf_T	hl)
181 {
182     int		n = 0;
183     int		attr = HL_ATTR(hl);
184     int		wcr_attr = get_wcr_attr(wp);
185 
186     attr = hl_combine_attr(wcr_attr, attr);
187 
188     if (draw_margin)
189     {
190 #ifdef FEAT_FOLDING
191 	int	fdc = compute_foldcolumn(wp, 0);
192 
193 	if (fdc > 0)
194 	    // draw the fold column
195 	    n = screen_fill_end(wp, ' ', ' ', n, fdc,
196 		      row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_FC)));
197 #endif
198 #ifdef FEAT_SIGNS
199 	if (signcolumn_on(wp))
200 	    // draw the sign column
201 	    n = screen_fill_end(wp, ' ', ' ', n, 2,
202 		      row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_SC)));
203 #endif
204 	if ((wp->w_p_nu || wp->w_p_rnu)
205 				  && vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
206 	    // draw the number column
207 	    n = screen_fill_end(wp, ' ', ' ', n, number_width(wp) + 1,
208 		       row, endrow, hl_combine_attr(wcr_attr, HL_ATTR(HLF_N)));
209     }
210 
211 #ifdef FEAT_RIGHTLEFT
212     if (wp->w_p_rl)
213     {
214 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
215 		wp->w_wincol, W_ENDCOL(wp) - 1 - n,
216 		c2, c2, attr);
217 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
218 		W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
219 		c1, c2, attr);
220     }
221     else
222 #endif
223     {
224 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
225 		wp->w_wincol + n, (int)W_ENDCOL(wp),
226 		c1, c2, attr);
227     }
228 
229     set_empty_rows(wp, row);
230 }
231 
232 #if defined(FEAT_FOLDING) || defined(PROTO)
233 /*
234  * Compute the width of the foldcolumn.  Based on 'foldcolumn' and how much
235  * space is available for window "wp", minus "col".
236  */
237     int
compute_foldcolumn(win_T * wp,int col)238 compute_foldcolumn(win_T *wp, int col)
239 {
240     int fdc = wp->w_p_fdc;
241     int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
242     int wwidth = wp->w_width;
243 
244     if (fdc > wwidth - (col + wmw))
245 	fdc = wwidth - (col + wmw);
246     return fdc;
247 }
248 
249 /*
250  * Fill the foldcolumn at "p" for window "wp".
251  * Only to be called when 'foldcolumn' > 0.
252  * Returns the number of bytes stored in 'p'. When non-multibyte characters are
253  * used for the fold column markers, this is equal to 'fdc' setting. Otherwise,
254  * this will be greater than 'fdc'.
255  */
256     size_t
fill_foldcolumn(char_u * p,win_T * wp,int closed,linenr_T lnum)257 fill_foldcolumn(
258     char_u	*p,
259     win_T	*wp,
260     int		closed,		// TRUE of FALSE
261     linenr_T	lnum)		// current line number
262 {
263     int		i = 0;
264     int		level;
265     int		first_level;
266     int		empty;
267     int		fdc = compute_foldcolumn(wp, 0);
268     size_t	byte_counter = 0;
269     int		symbol = 0;
270     int		len = 0;
271 
272     // Init to all spaces.
273     vim_memset(p, ' ', MAX_MCO * fdc + 1);
274 
275     level = win_foldinfo.fi_level;
276     empty = (fdc == 1) ? 0 : 1;
277 
278     // If the column is too narrow, we start at the lowest level that
279     // fits and use numbers to indicate the depth.
280     first_level = level - fdc - closed + 1 + empty;
281     if (first_level < 1)
282 	first_level = 1;
283 
284     for (i = 0; i < MIN(fdc, level); i++)
285     {
286 	if (win_foldinfo.fi_lnum == lnum
287 		&& first_level + i >= win_foldinfo.fi_low_level)
288 	    symbol = fill_foldopen;
289 	else if (first_level == 1)
290 	    symbol = fill_foldsep;
291 	else if (first_level + i <= 9)
292 	    symbol = '0' + first_level + i;
293 	else
294 	    symbol = '>';
295 
296 	len = utf_char2bytes(symbol, &p[byte_counter]);
297 	byte_counter += len;
298 	if (first_level + i >= level)
299 	{
300 	    i++;
301 	    break;
302 	}
303     }
304 
305     if (closed)
306     {
307 	if (symbol != 0)
308 	{
309 	    // rollback length and the character
310 	    byte_counter -= len;
311 	    if (len > 1)
312 		// for a multibyte character, erase all the bytes
313 		vim_memset(p + byte_counter, ' ', len);
314 	}
315 	symbol = fill_foldclosed;
316 	len = utf_char2bytes(symbol, &p[byte_counter]);
317 	byte_counter += len;
318     }
319 
320     return MAX(byte_counter + (fdc - i), (size_t)fdc);
321 }
322 #endif // FEAT_FOLDING
323 
324 /*
325  * Return if the composing characters at "off_from" and "off_to" differ.
326  * Only to be used when ScreenLinesUC[off_from] != 0.
327  */
328     static int
comp_char_differs(int off_from,int off_to)329 comp_char_differs(int off_from, int off_to)
330 {
331     int	    i;
332 
333     for (i = 0; i < Screen_mco; ++i)
334     {
335 	if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
336 	    return TRUE;
337 	if (ScreenLinesC[i][off_from] == 0)
338 	    break;
339     }
340     return FALSE;
341 }
342 
343 /*
344  * Check whether the given character needs redrawing:
345  * - the (first byte of the) character is different
346  * - the attributes are different
347  * - the character is multi-byte and the next byte is different
348  * - the character is two cells wide and the second cell differs.
349  */
350     static int
char_needs_redraw(int off_from,int off_to,int cols)351 char_needs_redraw(int off_from, int off_to, int cols)
352 {
353     if (cols > 0
354 	    && ((ScreenLines[off_from] != ScreenLines[off_to]
355 		    || ScreenAttrs[off_from] != ScreenAttrs[off_to])
356 		|| (enc_dbcs != 0
357 		    && MB_BYTE2LEN(ScreenLines[off_from]) > 1
358 		    && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
359 			? ScreenLines2[off_from] != ScreenLines2[off_to]
360 			: (cols > 1 && ScreenLines[off_from + 1]
361 						 != ScreenLines[off_to + 1])))
362 		|| (enc_utf8
363 		    && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
364 			|| (ScreenLinesUC[off_from] != 0
365 			    && comp_char_differs(off_from, off_to))
366 			|| ((*mb_off2cells)(off_from, off_from + cols) > 1
367 			    && ScreenLines[off_from + 1]
368 						!= ScreenLines[off_to + 1])))))
369 	return TRUE;
370     return FALSE;
371 }
372 
373 #if defined(FEAT_TERMINAL) || defined(PROTO)
374 /*
375  * Return the index in ScreenLines[] for the current screen line.
376  */
377     int
screen_get_current_line_off()378 screen_get_current_line_off()
379 {
380     return (int)(current_ScreenLine - ScreenLines);
381 }
382 #endif
383 
384 #ifdef FEAT_PROP_POPUP
385 /*
386  * Return TRUE if this position has a higher level popup or this cell is
387  * transparent in the current popup.
388  */
389     static int
blocked_by_popup(int row,int col)390 blocked_by_popup(int row, int col)
391 {
392     int off;
393 
394     if (!popup_visible)
395 	return FALSE;
396     off = row * screen_Columns + col;
397     return popup_mask[off] > screen_zindex || popup_transparent[off];
398 }
399 #endif
400 
401 /*
402  * Reset the highlighting.  Used before clearing the screen.
403  */
404     void
reset_screen_attr(void)405 reset_screen_attr(void)
406 {
407 #ifdef FEAT_GUI
408     if (gui.in_use)
409 	// Use a code that will reset gui.highlight_mask in
410 	// gui_stop_highlight().
411 	screen_attr = HL_ALL + 1;
412     else
413 #endif
414 	// Use attributes that is very unlikely to appear in text.
415 	screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE | HL_STRIKETHROUGH;
416 }
417 
418 /*
419  * Move one "cooked" screen line to the screen, but only the characters that
420  * have actually changed.  Handle insert/delete character.
421  * "coloff" gives the first column on the screen for this line.
422  * "endcol" gives the columns where valid characters are.
423  * "clear_width" is the width of the window.  It's > 0 if the rest of the line
424  * needs to be cleared, negative otherwise.
425  * "flags" can have bits:
426  * SLF_POPUP	    popup window
427  * SLF_RIGHTLEFT    rightleft window:
428  *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
429  *    When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
430  */
431     void
screen_line(int row,int coloff,int endcol,int clear_width,int flags UNUSED)432 screen_line(
433     int	    row,
434     int	    coloff,
435     int	    endcol,
436     int	    clear_width,
437     int	    flags UNUSED)
438 {
439     unsigned	    off_from;
440     unsigned	    off_to;
441     unsigned	    max_off_from;
442     unsigned	    max_off_to;
443     int		    col = 0;
444     int		    hl;
445     int		    force = FALSE;	// force update rest of the line
446     int		    redraw_this		// bool: does character need redraw?
447 #ifdef FEAT_GUI
448 				= TRUE	// For GUI when while-loop empty
449 #endif
450 				;
451     int		    redraw_next;	// redraw_this for next character
452     int		    clear_next = FALSE;
453     int		    char_cells;		// 1: normal char
454 					// 2: occupies two display cells
455 # define CHAR_CELLS char_cells
456 
457     // Check for illegal row and col, just in case.
458     if (row >= Rows)
459 	row = Rows - 1;
460     if (endcol > Columns)
461 	endcol = Columns;
462 
463 # ifdef FEAT_CLIPBOARD
464     clip_may_clear_selection(row, row);
465 # endif
466 
467     off_from = (unsigned)(current_ScreenLine - ScreenLines);
468     off_to = LineOffset[row] + coloff;
469     max_off_from = off_from + screen_Columns;
470     max_off_to = LineOffset[row] + screen_Columns;
471 
472 #ifdef FEAT_RIGHTLEFT
473     if (flags & SLF_RIGHTLEFT)
474     {
475 	// Clear rest first, because it's left of the text.
476 	if (clear_width > 0)
477 	{
478 	    while (col <= endcol && ScreenLines[off_to] == ' '
479 		    && ScreenAttrs[off_to] == 0
480 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
481 	    {
482 		++off_to;
483 		++col;
484 	    }
485 	    if (col <= endcol)
486 		screen_fill(row, row + 1, col + coloff,
487 					    endcol + coloff + 1, ' ', ' ', 0);
488 	}
489 	col = endcol + 1;
490 	off_to = LineOffset[row] + col + coloff;
491 	off_from += col;
492 	endcol = (clear_width > 0 ? clear_width : -clear_width);
493     }
494 #endif // FEAT_RIGHTLEFT
495 
496 #ifdef FEAT_PROP_POPUP
497     // First char of a popup window may go on top of the right half of a
498     // double-wide character. Clear the left half to avoid it getting the popup
499     // window background color.
500     if (coloff > 0 && enc_utf8
501 		   && ScreenLines[off_to] == 0
502 		   && ScreenLinesUC[off_to - 1] != 0
503 		   && (*mb_char2cells)(ScreenLinesUC[off_to - 1]) > 1)
504     {
505 	ScreenLines[off_to - 1] = ' ';
506 	ScreenLinesUC[off_to - 1] = 0;
507 	screen_char(off_to - 1, row, col + coloff - 1);
508     }
509 #endif
510 
511     redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
512 
513     while (col < endcol)
514     {
515 	if (has_mbyte && (col + 1 < endcol))
516 	    char_cells = (*mb_off2cells)(off_from, max_off_from);
517 	else
518 	    char_cells = 1;
519 
520 	redraw_this = redraw_next;
521 	redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
522 			      off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
523 
524 #ifdef FEAT_GUI
525 	// If the next character was bold, then redraw the current character to
526 	// remove any pixels that might have spilt over into us.  This only
527 	// happens in the GUI.
528 	if (redraw_next && gui.in_use)
529 	{
530 	    hl = ScreenAttrs[off_to + CHAR_CELLS];
531 	    if (hl > HL_ALL)
532 		hl = syn_attr2attr(hl);
533 	    if (hl & HL_BOLD)
534 		redraw_this = TRUE;
535 	}
536 #endif
537 #ifdef FEAT_PROP_POPUP
538 	if (blocked_by_popup(row, col + coloff))
539 	    redraw_this = FALSE;
540 #endif
541 	if (redraw_this)
542 	{
543 	    /*
544 	     * Special handling when 'xs' termcap flag set (hpterm):
545 	     * Attributes for characters are stored at the position where the
546 	     * cursor is when writing the highlighting code.  The
547 	     * start-highlighting code must be written with the cursor on the
548 	     * first highlighted character.  The stop-highlighting code must
549 	     * be written with the cursor just after the last highlighted
550 	     * character.
551 	     * Overwriting a character doesn't remove its highlighting.  Need
552 	     * to clear the rest of the line, and force redrawing it
553 	     * completely.
554 	     */
555 	    if (       p_wiv
556 		    && !force
557 #ifdef FEAT_GUI
558 		    && !gui.in_use
559 #endif
560 		    && ScreenAttrs[off_to] != 0
561 		    && ScreenAttrs[off_from] != ScreenAttrs[off_to])
562 	    {
563 		/*
564 		 * Need to remove highlighting attributes here.
565 		 */
566 		windgoto(row, col + coloff);
567 		out_str(T_CE);		// clear rest of this screen line
568 		screen_start();		// don't know where cursor is now
569 		force = TRUE;		// force redraw of rest of the line
570 		redraw_next = TRUE;	// or else next char would miss out
571 
572 		/*
573 		 * If the previous character was highlighted, need to stop
574 		 * highlighting at this character.
575 		 */
576 		if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
577 		{
578 		    screen_attr = ScreenAttrs[off_to - 1];
579 		    term_windgoto(row, col + coloff);
580 		    screen_stop_highlight();
581 		}
582 		else
583 		    screen_attr = 0;	    // highlighting has stopped
584 	    }
585 	    if (enc_dbcs != 0)
586 	    {
587 		// Check if overwriting a double-byte with a single-byte or
588 		// the other way around requires another character to be
589 		// redrawn.  For UTF-8 this isn't needed, because comparing
590 		// ScreenLinesUC[] is sufficient.
591 		if (char_cells == 1
592 			&& col + 1 < endcol
593 			&& (*mb_off2cells)(off_to, max_off_to) > 1)
594 		{
595 		    // Writing a single-cell character over a double-cell
596 		    // character: need to redraw the next cell.
597 		    ScreenLines[off_to + 1] = 0;
598 		    redraw_next = TRUE;
599 		}
600 		else if (char_cells == 2
601 			&& col + 2 < endcol
602 			&& (*mb_off2cells)(off_to, max_off_to) == 1
603 			&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)
604 		{
605 		    // Writing the second half of a double-cell character over
606 		    // a double-cell character: need to redraw the second
607 		    // cell.
608 		    ScreenLines[off_to + 2] = 0;
609 		    redraw_next = TRUE;
610 		}
611 
612 		if (enc_dbcs == DBCS_JPNU)
613 		    ScreenLines2[off_to] = ScreenLines2[off_from];
614 	    }
615 	    // When writing a single-width character over a double-width
616 	    // character and at the end of the redrawn text, need to clear out
617 	    // the right halve of the old character.
618 	    // Also required when writing the right halve of a double-width
619 	    // char over the left halve of an existing one.
620 	    if (has_mbyte && col + char_cells == endcol
621 		    && ((char_cells == 1
622 			    && (*mb_off2cells)(off_to, max_off_to) > 1)
623 			|| (char_cells == 2
624 			    && (*mb_off2cells)(off_to, max_off_to) == 1
625 			    && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
626 		clear_next = TRUE;
627 
628 	    ScreenLines[off_to] = ScreenLines[off_from];
629 	    if (enc_utf8)
630 	    {
631 		ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
632 		if (ScreenLinesUC[off_from] != 0)
633 		{
634 		    int	    i;
635 
636 		    for (i = 0; i < Screen_mco; ++i)
637 			ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
638 		}
639 	    }
640 	    if (char_cells == 2)
641 		ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
642 
643 #if defined(FEAT_GUI) || defined(UNIX)
644 	    // The bold trick makes a single column of pixels appear in the
645 	    // next character.  When a bold character is removed, the next
646 	    // character should be redrawn too.  This happens for our own GUI
647 	    // and for some xterms.
648 	    if (
649 # ifdef FEAT_GUI
650 		    gui.in_use
651 # endif
652 # if defined(FEAT_GUI) && defined(UNIX)
653 		    ||
654 # endif
655 # ifdef UNIX
656 		    term_is_xterm
657 # endif
658 		    )
659 	    {
660 		hl = ScreenAttrs[off_to];
661 		if (hl > HL_ALL)
662 		    hl = syn_attr2attr(hl);
663 		if (hl & HL_BOLD)
664 		    redraw_next = TRUE;
665 	    }
666 #endif
667 	    ScreenAttrs[off_to] = ScreenAttrs[off_from];
668 
669 	    // For simplicity set the attributes of second half of a
670 	    // double-wide character equal to the first half.
671 	    if (char_cells == 2)
672 		ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
673 
674 	    if (enc_dbcs != 0 && char_cells == 2)
675 		screen_char_2(off_to, row, col + coloff);
676 	    else
677 		screen_char(off_to, row, col + coloff);
678 	}
679 	else if (  p_wiv
680 #ifdef FEAT_GUI
681 		&& !gui.in_use
682 #endif
683 		&& col + coloff > 0)
684 	{
685 	    if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
686 	    {
687 		/*
688 		 * Don't output stop-highlight when moving the cursor, it will
689 		 * stop the highlighting when it should continue.
690 		 */
691 		screen_attr = 0;
692 	    }
693 	    else if (screen_attr != 0)
694 		screen_stop_highlight();
695 	}
696 
697 	off_to += CHAR_CELLS;
698 	off_from += CHAR_CELLS;
699 	col += CHAR_CELLS;
700     }
701 
702     if (clear_next)
703     {
704 	// Clear the second half of a double-wide character of which the left
705 	// half was overwritten with a single-wide character.
706 	ScreenLines[off_to] = ' ';
707 	if (enc_utf8)
708 	    ScreenLinesUC[off_to] = 0;
709 	screen_char(off_to, row, col + coloff);
710     }
711 
712     if (clear_width > 0
713 #ifdef FEAT_RIGHTLEFT
714 		    && !(flags & SLF_RIGHTLEFT)
715 #endif
716 				   )
717     {
718 #ifdef FEAT_GUI
719 	int startCol = col;
720 #endif
721 
722 	// blank out the rest of the line
723 	while (col < clear_width && ScreenLines[off_to] == ' '
724 						  && ScreenAttrs[off_to] == 0
725 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
726 	{
727 	    ++off_to;
728 	    ++col;
729 	}
730 	if (col < clear_width)
731 	{
732 #ifdef FEAT_GUI
733 	    /*
734 	     * In the GUI, clearing the rest of the line may leave pixels
735 	     * behind if the first character cleared was bold.  Some bold
736 	     * fonts spill over the left.  In this case we redraw the previous
737 	     * character too.  If we didn't skip any blanks above, then we
738 	     * only redraw if the character wasn't already redrawn anyway.
739 	     */
740 	    if (gui.in_use && (col > startCol || !redraw_this))
741 	    {
742 		hl = ScreenAttrs[off_to];
743 		if (hl > HL_ALL || (hl & HL_BOLD))
744 		{
745 		    int prev_cells = 1;
746 
747 		    if (enc_utf8)
748 			// for utf-8, ScreenLines[char_offset + 1] == 0 means
749 			// that its width is 2.
750 			prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
751 		    else if (enc_dbcs != 0)
752 		    {
753 			// find previous character by counting from first
754 			// column and get its width.
755 			unsigned off = LineOffset[row];
756 			unsigned max_off = LineOffset[row] + screen_Columns;
757 
758 			while (off < off_to)
759 			{
760 			    prev_cells = (*mb_off2cells)(off, max_off);
761 			    off += prev_cells;
762 			}
763 		    }
764 
765 		    if (enc_dbcs != 0 && prev_cells > 1)
766 			screen_char_2(off_to - prev_cells, row,
767 						   col + coloff - prev_cells);
768 		    else
769 			screen_char(off_to - prev_cells, row,
770 						   col + coloff - prev_cells);
771 		}
772 	    }
773 #endif
774 	    screen_fill(row, row + 1, col + coloff, clear_width + coloff,
775 								 ' ', ' ', 0);
776 	    off_to += clear_width - col;
777 	    col = clear_width;
778 	}
779     }
780 
781     if (clear_width > 0
782 #ifdef FEAT_PROP_POPUP
783 	    && !(flags & SLF_POPUP)  // no separator for popup window
784 #endif
785 	    )
786     {
787 	// For a window that has a right neighbor, draw the separator char
788 	// right of the window contents.  But not on top of a popup window.
789 	if (coloff + col < Columns)
790 	{
791 #ifdef FEAT_PROP_POPUP
792 	    if (!blocked_by_popup(row, col + coloff))
793 #endif
794 	    {
795 		int c;
796 
797 		c = fillchar_vsep(&hl);
798 		if (ScreenLines[off_to] != (schar_T)c
799 			|| (enc_utf8 && (int)ScreenLinesUC[off_to]
800 							!= (c >= 0x80 ? c : 0))
801 			|| ScreenAttrs[off_to] != hl)
802 		{
803 		    ScreenLines[off_to] = c;
804 		    ScreenAttrs[off_to] = hl;
805 		    if (enc_utf8)
806 		    {
807 			if (c >= 0x80)
808 			{
809 			    ScreenLinesUC[off_to] = c;
810 			    ScreenLinesC[0][off_to] = 0;
811 			}
812 			else
813 			    ScreenLinesUC[off_to] = 0;
814 		    }
815 		    screen_char(off_to, row, col + coloff);
816 		}
817 	    }
818 	}
819 	else
820 	    LineWraps[row] = FALSE;
821     }
822 }
823 
824 #if defined(FEAT_RIGHTLEFT) || defined(PROTO)
825 /*
826  * Mirror text "str" for right-left displaying.
827  * Only works for single-byte characters (e.g., numbers).
828  */
829     void
rl_mirror(char_u * str)830 rl_mirror(char_u *str)
831 {
832     char_u	*p1, *p2;
833     int		t;
834 
835     for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
836     {
837 	t = *p1;
838 	*p1 = *p2;
839 	*p2 = t;
840     }
841 }
842 #endif
843 
844 /*
845  * Draw the verticap separator right of window "wp" starting with line "row".
846  */
847     void
draw_vsep_win(win_T * wp,int row)848 draw_vsep_win(win_T *wp, int row)
849 {
850     int		hl;
851     int		c;
852 
853     if (wp->w_vsep_width)
854     {
855 	// draw the vertical separator right of this window
856 	c = fillchar_vsep(&hl);
857 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
858 		W_ENDCOL(wp), W_ENDCOL(wp) + 1,
859 		c, ' ', hl);
860     }
861 }
862 
863 #ifdef FEAT_WILDMENU
864 static int skip_status_match_char(expand_T *xp, char_u *s);
865 
866 /*
867  * Get the length of an item as it will be shown in the status line.
868  */
869     static int
status_match_len(expand_T * xp,char_u * s)870 status_match_len(expand_T *xp, char_u *s)
871 {
872     int	len = 0;
873 
874 #ifdef FEAT_MENU
875     int emenu = (xp->xp_context == EXPAND_MENUS
876 	    || xp->xp_context == EXPAND_MENUNAMES);
877 
878     // Check for menu separators - replace with '|'.
879     if (emenu && menu_is_separator(s))
880 	return 1;
881 #endif
882 
883     while (*s != NUL)
884     {
885 	s += skip_status_match_char(xp, s);
886 	len += ptr2cells(s);
887 	MB_PTR_ADV(s);
888     }
889 
890     return len;
891 }
892 
893 /*
894  * Return the number of characters that should be skipped in a status match.
895  * These are backslashes used for escaping.  Do show backslashes in help tags.
896  */
897     static int
skip_status_match_char(expand_T * xp,char_u * s)898 skip_status_match_char(expand_T *xp, char_u *s)
899 {
900     if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
901 #ifdef FEAT_MENU
902 	    || ((xp->xp_context == EXPAND_MENUS
903 		    || xp->xp_context == EXPAND_MENUNAMES)
904 			  && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
905 #endif
906 	   )
907     {
908 #ifndef BACKSLASH_IN_FILENAME
909 	if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
910 	    return 2;
911 #endif
912 	return 1;
913     }
914     return 0;
915 }
916 
917 /*
918  * Show wildchar matches in the status line.
919  * Show at least the "match" item.
920  * We start at item 'first_match' in the list and show all matches that fit.
921  *
922  * If inversion is possible we use it. Else '=' characters are used.
923  */
924     void
win_redr_status_matches(expand_T * xp,int num_matches,char_u ** matches,int match,int showtail)925 win_redr_status_matches(
926     expand_T	*xp,
927     int		num_matches,
928     char_u	**matches,	// list of matches
929     int		match,
930     int		showtail)
931 {
932 #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
933     int		row;
934     char_u	*buf;
935     int		len;
936     int		clen;		// length in screen cells
937     int		fillchar;
938     int		attr;
939     int		i;
940     int		highlight = TRUE;
941     char_u	*selstart = NULL;
942     int		selstart_col = 0;
943     char_u	*selend = NULL;
944     static int	first_match = 0;
945     int		add_left = FALSE;
946     char_u	*s;
947 #ifdef FEAT_MENU
948     int		emenu;
949 #endif
950     int		l;
951 
952     if (matches == NULL)	// interrupted completion?
953 	return;
954 
955     if (has_mbyte)
956 	buf = alloc(Columns * MB_MAXBYTES + 1);
957     else
958 	buf = alloc(Columns + 1);
959     if (buf == NULL)
960 	return;
961 
962     if (match == -1)	// don't show match but original text
963     {
964 	match = 0;
965 	highlight = FALSE;
966     }
967     // count 1 for the ending ">"
968     clen = status_match_len(xp, L_MATCH(match)) + 3;
969     if (match == 0)
970 	first_match = 0;
971     else if (match < first_match)
972     {
973 	// jumping left, as far as we can go
974 	first_match = match;
975 	add_left = TRUE;
976     }
977     else
978     {
979 	// check if match fits on the screen
980 	for (i = first_match; i < match; ++i)
981 	    clen += status_match_len(xp, L_MATCH(i)) + 2;
982 	if (first_match > 0)
983 	    clen += 2;
984 	// jumping right, put match at the left
985 	if ((long)clen > Columns)
986 	{
987 	    first_match = match;
988 	    // if showing the last match, we can add some on the left
989 	    clen = 2;
990 	    for (i = match; i < num_matches; ++i)
991 	    {
992 		clen += status_match_len(xp, L_MATCH(i)) + 2;
993 		if ((long)clen >= Columns)
994 		    break;
995 	    }
996 	    if (i == num_matches)
997 		add_left = TRUE;
998 	}
999     }
1000     if (add_left)
1001 	while (first_match > 0)
1002 	{
1003 	    clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
1004 	    if ((long)clen >= Columns)
1005 		break;
1006 	    --first_match;
1007 	}
1008 
1009     fillchar = fillchar_status(&attr, curwin);
1010 
1011     if (first_match == 0)
1012     {
1013 	*buf = NUL;
1014 	len = 0;
1015     }
1016     else
1017     {
1018 	STRCPY(buf, "< ");
1019 	len = 2;
1020     }
1021     clen = len;
1022 
1023     i = first_match;
1024     while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
1025     {
1026 	if (i == match)
1027 	{
1028 	    selstart = buf + len;
1029 	    selstart_col = clen;
1030 	}
1031 
1032 	s = L_MATCH(i);
1033 	// Check for menu separators - replace with '|'
1034 #ifdef FEAT_MENU
1035 	emenu = (xp->xp_context == EXPAND_MENUS
1036 		|| xp->xp_context == EXPAND_MENUNAMES);
1037 	if (emenu && menu_is_separator(s))
1038 	{
1039 	    STRCPY(buf + len, transchar('|'));
1040 	    l = (int)STRLEN(buf + len);
1041 	    len += l;
1042 	    clen += l;
1043 	}
1044 	else
1045 #endif
1046 	    for ( ; *s != NUL; ++s)
1047 	{
1048 	    s += skip_status_match_char(xp, s);
1049 	    clen += ptr2cells(s);
1050 	    if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
1051 	    {
1052 		STRNCPY(buf + len, s, l);
1053 		s += l - 1;
1054 		len += l;
1055 	    }
1056 	    else
1057 	    {
1058 		STRCPY(buf + len, transchar_byte(*s));
1059 		len += (int)STRLEN(buf + len);
1060 	    }
1061 	}
1062 	if (i == match)
1063 	    selend = buf + len;
1064 
1065 	*(buf + len++) = ' ';
1066 	*(buf + len++) = ' ';
1067 	clen += 2;
1068 	if (++i == num_matches)
1069 		break;
1070     }
1071 
1072     if (i != num_matches)
1073     {
1074 	*(buf + len++) = '>';
1075 	++clen;
1076     }
1077 
1078     buf[len] = NUL;
1079 
1080     row = cmdline_row - 1;
1081     if (row >= 0)
1082     {
1083 	if (wild_menu_showing == 0)
1084 	{
1085 	    if (msg_scrolled > 0)
1086 	    {
1087 		// Put the wildmenu just above the command line.  If there is
1088 		// no room, scroll the screen one line up.
1089 		if (cmdline_row == Rows - 1)
1090 		{
1091 		    screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
1092 		    ++msg_scrolled;
1093 		}
1094 		else
1095 		{
1096 		    ++cmdline_row;
1097 		    ++row;
1098 		}
1099 		wild_menu_showing = WM_SCROLLED;
1100 	    }
1101 	    else
1102 	    {
1103 		// Create status line if needed by setting 'laststatus' to 2.
1104 		// Set 'winminheight' to zero to avoid that the window is
1105 		// resized.
1106 		if (lastwin->w_status_height == 0)
1107 		{
1108 		    save_p_ls = p_ls;
1109 		    save_p_wmh = p_wmh;
1110 		    p_ls = 2;
1111 		    p_wmh = 0;
1112 		    last_status(FALSE);
1113 		}
1114 		wild_menu_showing = WM_SHOWN;
1115 	    }
1116 	}
1117 
1118 	screen_puts(buf, row, 0, attr);
1119 	if (selstart != NULL && highlight)
1120 	{
1121 	    *selend = NUL;
1122 	    screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM));
1123 	}
1124 
1125 	screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
1126     }
1127 
1128     win_redraw_last_status(topframe);
1129     vim_free(buf);
1130 }
1131 #endif
1132 
1133 /*
1134  * Return TRUE if the status line of window "wp" is connected to the status
1135  * line of the window right of it.  If not, then it's a vertical separator.
1136  * Only call if (wp->w_vsep_width != 0).
1137  */
1138     int
stl_connected(win_T * wp)1139 stl_connected(win_T *wp)
1140 {
1141     frame_T	*fr;
1142 
1143     fr = wp->w_frame;
1144     while (fr->fr_parent != NULL)
1145     {
1146 	if (fr->fr_parent->fr_layout == FR_COL)
1147 	{
1148 	    if (fr->fr_next != NULL)
1149 		break;
1150 	}
1151 	else
1152 	{
1153 	    if (fr->fr_next != NULL)
1154 		return TRUE;
1155 	}
1156 	fr = fr->fr_parent;
1157     }
1158     return FALSE;
1159 }
1160 
1161 
1162 /*
1163  * Get the value to show for the language mappings, active 'keymap'.
1164  */
1165     int
get_keymap_str(win_T * wp,char_u * fmt,char_u * buf,int len)1166 get_keymap_str(
1167     win_T	*wp,
1168     char_u	*fmt,	    // format string containing one %s item
1169     char_u	*buf,	    // buffer for the result
1170     int		len)	    // length of buffer
1171 {
1172     char_u	*p;
1173 
1174     if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
1175 	return FALSE;
1176 
1177     {
1178 #ifdef FEAT_EVAL
1179 	buf_T	*old_curbuf = curbuf;
1180 	win_T	*old_curwin = curwin;
1181 	char_u	*s;
1182 
1183 	curbuf = wp->w_buffer;
1184 	curwin = wp;
1185 	STRCPY(buf, "b:keymap_name");	// must be writable
1186 	++emsg_skip;
1187 	s = p = eval_to_string(buf, FALSE);
1188 	--emsg_skip;
1189 	curbuf = old_curbuf;
1190 	curwin = old_curwin;
1191 	if (p == NULL || *p == NUL)
1192 #endif
1193 	{
1194 #ifdef FEAT_KEYMAP
1195 	    if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
1196 		p = wp->w_buffer->b_p_keymap;
1197 	    else
1198 #endif
1199 		p = (char_u *)"lang";
1200 	}
1201 	if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
1202 	    buf[0] = NUL;
1203 #ifdef FEAT_EVAL
1204 	vim_free(s);
1205 #endif
1206     }
1207     return buf[0] != NUL;
1208 }
1209 
1210 #if defined(FEAT_STL_OPT) || defined(PROTO)
1211 /*
1212  * Redraw the status line or ruler of window "wp".
1213  * When "wp" is NULL redraw the tab pages line from 'tabline'.
1214  */
1215     void
win_redr_custom(win_T * wp,int draw_ruler)1216 win_redr_custom(
1217     win_T	*wp,
1218     int		draw_ruler)	// TRUE or FALSE
1219 {
1220     static int	entered = FALSE;
1221     int		attr;
1222     int		curattr;
1223     int		row;
1224     int		col = 0;
1225     int		maxwidth;
1226     int		width;
1227     int		n;
1228     int		len;
1229     int		fillchar;
1230     char_u	buf[MAXPATHL];
1231     char_u	*stl;
1232     char_u	*p;
1233     stl_hlrec_T *hltab;
1234     stl_hlrec_T *tabtab;
1235     int		use_sandbox = FALSE;
1236     win_T	*ewp;
1237     int		p_crb_save;
1238 
1239     // There is a tiny chance that this gets called recursively: When
1240     // redrawing a status line triggers redrawing the ruler or tabline.
1241     // Avoid trouble by not allowing recursion.
1242     if (entered)
1243 	return;
1244     entered = TRUE;
1245 
1246     // setup environment for the task at hand
1247     if (wp == NULL)
1248     {
1249 	// Use 'tabline'.  Always at the first line of the screen.
1250 	stl = p_tal;
1251 	row = 0;
1252 	fillchar = ' ';
1253 	attr = HL_ATTR(HLF_TPF);
1254 	maxwidth = Columns;
1255 # ifdef FEAT_EVAL
1256 	use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
1257 # endif
1258     }
1259     else
1260     {
1261 	row = statusline_row(wp);
1262 	fillchar = fillchar_status(&attr, wp);
1263 	maxwidth = wp->w_width;
1264 
1265 	if (draw_ruler)
1266 	{
1267 	    stl = p_ruf;
1268 	    // advance past any leading group spec - implicit in ru_col
1269 	    if (*stl == '%')
1270 	    {
1271 		if (*++stl == '-')
1272 		    stl++;
1273 		if (atoi((char *)stl))
1274 		    while (VIM_ISDIGIT(*stl))
1275 			stl++;
1276 		if (*stl++ != '(')
1277 		    stl = p_ruf;
1278 	    }
1279 	    col = ru_col - (Columns - wp->w_width);
1280 	    if (col < (wp->w_width + 1) / 2)
1281 		col = (wp->w_width + 1) / 2;
1282 	    maxwidth = wp->w_width - col;
1283 	    if (!wp->w_status_height)
1284 	    {
1285 		row = Rows - 1;
1286 		--maxwidth;	// writing in last column may cause scrolling
1287 		fillchar = ' ';
1288 		attr = 0;
1289 	    }
1290 
1291 # ifdef FEAT_EVAL
1292 	    use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
1293 # endif
1294 	}
1295 	else
1296 	{
1297 	    if (*wp->w_p_stl != NUL)
1298 		stl = wp->w_p_stl;
1299 	    else
1300 		stl = p_stl;
1301 # ifdef FEAT_EVAL
1302 	    use_sandbox = was_set_insecurely((char_u *)"statusline",
1303 					 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
1304 # endif
1305 	}
1306 
1307 	col += wp->w_wincol;
1308     }
1309 
1310     if (maxwidth <= 0)
1311 	goto theend;
1312 
1313     // Temporarily reset 'cursorbind', we don't want a side effect from moving
1314     // the cursor away and back.
1315     ewp = wp == NULL ? curwin : wp;
1316     p_crb_save = ewp->w_p_crb;
1317     ewp->w_p_crb = FALSE;
1318 
1319     // Make a copy, because the statusline may include a function call that
1320     // might change the option value and free the memory.
1321     stl = vim_strsave(stl);
1322     width = build_stl_str_hl(ewp, buf, sizeof(buf),
1323 				stl, use_sandbox,
1324 				fillchar, maxwidth, &hltab, &tabtab);
1325     vim_free(stl);
1326     ewp->w_p_crb = p_crb_save;
1327 
1328     // Make all characters printable.
1329     p = transstr(buf);
1330     if (p != NULL)
1331     {
1332 	vim_strncpy(buf, p, sizeof(buf) - 1);
1333 	vim_free(p);
1334     }
1335 
1336     // fill up with "fillchar"
1337     len = (int)STRLEN(buf);
1338     while (width < maxwidth && len < (int)sizeof(buf) - 1)
1339     {
1340 	len += (*mb_char2bytes)(fillchar, buf + len);
1341 	++width;
1342     }
1343     buf[len] = NUL;
1344 
1345     /*
1346      * Draw each snippet with the specified highlighting.
1347      */
1348     curattr = attr;
1349     p = buf;
1350     for (n = 0; hltab[n].start != NULL; n++)
1351     {
1352 	len = (int)(hltab[n].start - p);
1353 	screen_puts_len(p, len, row, col, curattr);
1354 	col += vim_strnsize(p, len);
1355 	p = hltab[n].start;
1356 
1357 	if (hltab[n].userhl == 0)
1358 	    curattr = attr;
1359 	else if (hltab[n].userhl < 0)
1360 	    curattr = syn_id2attr(-hltab[n].userhl);
1361 #ifdef FEAT_TERMINAL
1362 	else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
1363 						   && wp->w_status_height != 0)
1364 	    curattr = highlight_stltermnc[hltab[n].userhl - 1];
1365 	else if (wp != NULL && bt_terminal(wp->w_buffer)
1366 						   && wp->w_status_height != 0)
1367 	    curattr = highlight_stlterm[hltab[n].userhl - 1];
1368 #endif
1369 	else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
1370 	    curattr = highlight_stlnc[hltab[n].userhl - 1];
1371 	else
1372 	    curattr = highlight_user[hltab[n].userhl - 1];
1373     }
1374     screen_puts(p, row, col, curattr);
1375 
1376     if (wp == NULL)
1377     {
1378 	// Fill the TabPageIdxs[] array for clicking in the tab pagesline.
1379 	col = 0;
1380 	len = 0;
1381 	p = buf;
1382 	fillchar = 0;
1383 	for (n = 0; tabtab[n].start != NULL; n++)
1384 	{
1385 	    len += vim_strnsize(p, (int)(tabtab[n].start - p));
1386 	    while (col < len)
1387 		TabPageIdxs[col++] = fillchar;
1388 	    p = tabtab[n].start;
1389 	    fillchar = tabtab[n].userhl;
1390 	}
1391 	while (col < Columns)
1392 	    TabPageIdxs[col++] = fillchar;
1393     }
1394 
1395 theend:
1396     entered = FALSE;
1397 }
1398 
1399 #endif // FEAT_STL_OPT
1400 
1401 /*
1402  * Output a single character directly to the screen and update ScreenLines.
1403  */
1404     void
screen_putchar(int c,int row,int col,int attr)1405 screen_putchar(int c, int row, int col, int attr)
1406 {
1407     char_u	buf[MB_MAXBYTES + 1];
1408 
1409     if (has_mbyte)
1410 	buf[(*mb_char2bytes)(c, buf)] = NUL;
1411     else
1412     {
1413 	buf[0] = c;
1414 	buf[1] = NUL;
1415     }
1416     screen_puts(buf, row, col, attr);
1417 }
1418 
1419 /*
1420  * Get a single character directly from ScreenLines into "bytes[]".
1421  * Also return its attribute in *attrp;
1422  */
1423     void
screen_getbytes(int row,int col,char_u * bytes,int * attrp)1424 screen_getbytes(int row, int col, char_u *bytes, int *attrp)
1425 {
1426     unsigned off;
1427 
1428     // safety check
1429     if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
1430     {
1431 	off = LineOffset[row] + col;
1432 	*attrp = ScreenAttrs[off];
1433 	bytes[0] = ScreenLines[off];
1434 	bytes[1] = NUL;
1435 
1436 	if (enc_utf8 && ScreenLinesUC[off] != 0)
1437 	    bytes[utfc_char2bytes(off, bytes)] = NUL;
1438 	else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
1439 	{
1440 	    bytes[0] = ScreenLines[off];
1441 	    bytes[1] = ScreenLines2[off];
1442 	    bytes[2] = NUL;
1443 	}
1444 	else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
1445 	{
1446 	    bytes[1] = ScreenLines[off + 1];
1447 	    bytes[2] = NUL;
1448 	}
1449     }
1450 }
1451 
1452 /*
1453  * Return TRUE if composing characters for screen posn "off" differs from
1454  * composing characters in "u8cc".
1455  * Only to be used when ScreenLinesUC[off] != 0.
1456  */
1457     static int
screen_comp_differs(int off,int * u8cc)1458 screen_comp_differs(int off, int *u8cc)
1459 {
1460     int	    i;
1461 
1462     for (i = 0; i < Screen_mco; ++i)
1463     {
1464 	if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
1465 	    return TRUE;
1466 	if (u8cc[i] == 0)
1467 	    break;
1468     }
1469     return FALSE;
1470 }
1471 
1472 /*
1473  * Put string '*text' on the screen at position 'row' and 'col', with
1474  * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
1475  * Note: only outputs within one row, message is truncated at screen boundary!
1476  * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
1477  */
1478     void
screen_puts(char_u * text,int row,int col,int attr)1479 screen_puts(
1480     char_u	*text,
1481     int		row,
1482     int		col,
1483     int		attr)
1484 {
1485     screen_puts_len(text, -1, row, col, attr);
1486 }
1487 
1488 /*
1489  * Like screen_puts(), but output "text[len]".  When "len" is -1 output up to
1490  * a NUL.
1491  */
1492     void
screen_puts_len(char_u * text,int textlen,int row,int col,int attr)1493 screen_puts_len(
1494     char_u	*text,
1495     int		textlen,
1496     int		row,
1497     int		col,
1498     int		attr)
1499 {
1500     unsigned	off;
1501     char_u	*ptr = text;
1502     int		len = textlen;
1503     int		c;
1504     unsigned	max_off;
1505     int		mbyte_blen = 1;
1506     int		mbyte_cells = 1;
1507     int		u8c = 0;
1508     int		u8cc[MAX_MCO];
1509     int		clear_next_cell = FALSE;
1510 #ifdef FEAT_ARABIC
1511     int		prev_c = 0;		// previous Arabic character
1512     int		pc, nc, nc1;
1513     int		pcc[MAX_MCO];
1514 #endif
1515     int		force_redraw_this;
1516     int		force_redraw_next = FALSE;
1517     int		need_redraw;
1518 
1519     // Safety check. The check for negative row and column is to fix issue
1520     // #4102. TODO: find out why row/col could be negative.
1521     if (ScreenLines == NULL
1522 	    || row >= screen_Rows || row < 0
1523 	    || col >= screen_Columns || col < 0)
1524 	return;
1525     off = LineOffset[row] + col;
1526 
1527     // When drawing over the right halve of a double-wide char clear out the
1528     // left halve.  Only needed in a terminal.
1529     if (has_mbyte && col > 0 && col < screen_Columns
1530 #ifdef FEAT_GUI
1531 	    && !gui.in_use
1532 #endif
1533 	    && mb_fix_col(col, row) != col)
1534     {
1535 	ScreenLines[off - 1] = ' ';
1536 	ScreenAttrs[off - 1] = 0;
1537 	if (enc_utf8)
1538 	{
1539 	    ScreenLinesUC[off - 1] = 0;
1540 	    ScreenLinesC[0][off - 1] = 0;
1541 	}
1542 	// redraw the previous cell, make it empty
1543 	screen_char(off - 1, row, col - 1);
1544 	// force the cell at "col" to be redrawn
1545 	force_redraw_next = TRUE;
1546     }
1547 
1548     max_off = LineOffset[row] + screen_Columns;
1549     while (col < screen_Columns
1550 	    && (len < 0 || (int)(ptr - text) < len)
1551 	    && *ptr != NUL)
1552     {
1553 	c = *ptr;
1554 	// check if this is the first byte of a multibyte
1555 	if (has_mbyte)
1556 	{
1557 	    if (enc_utf8 && len > 0)
1558 		mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
1559 	    else
1560 		mbyte_blen = (*mb_ptr2len)(ptr);
1561 	    if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1562 		mbyte_cells = 1;
1563 	    else if (enc_dbcs != 0)
1564 		mbyte_cells = mbyte_blen;
1565 	    else	// enc_utf8
1566 	    {
1567 		if (len >= 0)
1568 		    u8c = utfc_ptr2char_len(ptr, u8cc,
1569 						   (int)((text + len) - ptr));
1570 		else
1571 		    u8c = utfc_ptr2char(ptr, u8cc);
1572 		mbyte_cells = utf_char2cells(u8c);
1573 #ifdef FEAT_ARABIC
1574 		if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
1575 		{
1576 		    // Do Arabic shaping.
1577 		    if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
1578 		    {
1579 			// Past end of string to be displayed.
1580 			nc = NUL;
1581 			nc1 = NUL;
1582 		    }
1583 		    else
1584 		    {
1585 			nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
1586 				      (int)((text + len) - ptr - mbyte_blen));
1587 			nc1 = pcc[0];
1588 		    }
1589 		    pc = prev_c;
1590 		    prev_c = u8c;
1591 		    u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
1592 		}
1593 		else
1594 		    prev_c = u8c;
1595 #endif
1596 		if (col + mbyte_cells > screen_Columns)
1597 		{
1598 		    // Only 1 cell left, but character requires 2 cells:
1599 		    // display a '>' in the last column to avoid wrapping.
1600 		    c = '>';
1601 		    mbyte_cells = 1;
1602 		}
1603 	    }
1604 	}
1605 
1606 	force_redraw_this = force_redraw_next;
1607 	force_redraw_next = FALSE;
1608 
1609 	need_redraw = ScreenLines[off] != c
1610 		|| (mbyte_cells == 2
1611 		    && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
1612 		|| (enc_dbcs == DBCS_JPNU
1613 		    && c == 0x8e
1614 		    && ScreenLines2[off] != ptr[1])
1615 		|| (enc_utf8
1616 		    && (ScreenLinesUC[off] !=
1617 				(u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
1618 			|| (ScreenLinesUC[off] != 0
1619 					  && screen_comp_differs(off, u8cc))))
1620 		|| ScreenAttrs[off] != attr
1621 		|| exmode_active;
1622 
1623 	if ((need_redraw || force_redraw_this)
1624 #ifdef FEAT_PROP_POPUP
1625 		&& !blocked_by_popup(row, col)
1626 #endif
1627 	   )
1628 	{
1629 #if defined(FEAT_GUI) || defined(UNIX)
1630 	    // The bold trick makes a single row of pixels appear in the next
1631 	    // character.  When a bold character is removed, the next
1632 	    // character should be redrawn too.  This happens for our own GUI
1633 	    // and for some xterms.
1634 	    if (need_redraw && ScreenLines[off] != ' ' && (
1635 # ifdef FEAT_GUI
1636 		    gui.in_use
1637 # endif
1638 # if defined(FEAT_GUI) && defined(UNIX)
1639 		    ||
1640 # endif
1641 # ifdef UNIX
1642 		    term_is_xterm
1643 # endif
1644 		    ))
1645 	    {
1646 		int	n = ScreenAttrs[off];
1647 
1648 		if (n > HL_ALL)
1649 		    n = syn_attr2attr(n);
1650 		if (n & HL_BOLD)
1651 		    force_redraw_next = TRUE;
1652 	    }
1653 #endif
1654 	    // When at the end of the text and overwriting a two-cell
1655 	    // character with a one-cell character, need to clear the next
1656 	    // cell.  Also when overwriting the left halve of a two-cell char
1657 	    // with the right halve of a two-cell char.  Do this only once
1658 	    // (mb_off2cells() may return 2 on the right halve).
1659 	    if (clear_next_cell)
1660 		clear_next_cell = FALSE;
1661 	    else if (has_mbyte
1662 		    && (len < 0 ? ptr[mbyte_blen] == NUL
1663 					     : ptr + mbyte_blen >= text + len)
1664 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1665 			|| (mbyte_cells == 2
1666 			    && (*mb_off2cells)(off, max_off) == 1
1667 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
1668 		clear_next_cell = TRUE;
1669 
1670 	    // Make sure we never leave a second byte of a double-byte behind,
1671 	    // it confuses mb_off2cells().
1672 	    if (enc_dbcs
1673 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
1674 			|| (mbyte_cells == 2
1675 			    && (*mb_off2cells)(off, max_off) == 1
1676 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
1677 		ScreenLines[off + mbyte_blen] = 0;
1678 	    ScreenLines[off] = c;
1679 	    ScreenAttrs[off] = attr;
1680 	    if (enc_utf8)
1681 	    {
1682 		if (c < 0x80 && u8cc[0] == 0)
1683 		    ScreenLinesUC[off] = 0;
1684 		else
1685 		{
1686 		    int	    i;
1687 
1688 		    ScreenLinesUC[off] = u8c;
1689 		    for (i = 0; i < Screen_mco; ++i)
1690 		    {
1691 			ScreenLinesC[i][off] = u8cc[i];
1692 			if (u8cc[i] == 0)
1693 			    break;
1694 		    }
1695 		}
1696 		if (mbyte_cells == 2)
1697 		{
1698 		    ScreenLines[off + 1] = 0;
1699 		    ScreenAttrs[off + 1] = attr;
1700 		}
1701 		screen_char(off, row, col);
1702 	    }
1703 	    else if (mbyte_cells == 2)
1704 	    {
1705 		ScreenLines[off + 1] = ptr[1];
1706 		ScreenAttrs[off + 1] = attr;
1707 		screen_char_2(off, row, col);
1708 	    }
1709 	    else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
1710 	    {
1711 		ScreenLines2[off] = ptr[1];
1712 		screen_char(off, row, col);
1713 	    }
1714 	    else
1715 		screen_char(off, row, col);
1716 	}
1717 	if (has_mbyte)
1718 	{
1719 	    off += mbyte_cells;
1720 	    col += mbyte_cells;
1721 	    ptr += mbyte_blen;
1722 	    if (clear_next_cell)
1723 	    {
1724 		// This only happens at the end, display one space next.
1725 		ptr = (char_u *)" ";
1726 		len = -1;
1727 	    }
1728 	}
1729 	else
1730 	{
1731 	    ++off;
1732 	    ++col;
1733 	    ++ptr;
1734 	}
1735     }
1736 
1737     // If we detected the next character needs to be redrawn, but the text
1738     // doesn't extend up to there, update the character here.
1739     if (force_redraw_next && col < screen_Columns)
1740     {
1741 	if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
1742 	    screen_char_2(off, row, col);
1743 	else
1744 	    screen_char(off, row, col);
1745     }
1746 }
1747 
1748 #if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
1749 /*
1750  * Prepare for 'hlsearch' highlighting.
1751  */
1752     void
start_search_hl(void)1753 start_search_hl(void)
1754 {
1755     if (p_hls && !no_hlsearch)
1756     {
1757 	end_search_hl();  // just in case it wasn't called before
1758 	last_pat_prog(&screen_search_hl.rm);
1759 	screen_search_hl.attr = HL_ATTR(HLF_L);
1760 # ifdef FEAT_RELTIME
1761 	// Set the time limit to 'redrawtime'.
1762 	profile_setlimit(p_rdt, &screen_search_hl.tm);
1763 # endif
1764     }
1765 }
1766 
1767 /*
1768  * Clean up for 'hlsearch' highlighting.
1769  */
1770     void
end_search_hl(void)1771 end_search_hl(void)
1772 {
1773     if (screen_search_hl.rm.regprog != NULL)
1774     {
1775 	vim_regfree(screen_search_hl.rm.regprog);
1776 	screen_search_hl.rm.regprog = NULL;
1777     }
1778 }
1779 #endif
1780 
1781       static void
screen_start_highlight(int attr)1782 screen_start_highlight(int attr)
1783 {
1784     attrentry_T *aep = NULL;
1785 
1786     screen_attr = attr;
1787     if (full_screen
1788 #ifdef MSWIN
1789 		    && termcap_active
1790 #endif
1791 				       )
1792     {
1793 #ifdef FEAT_GUI
1794 	if (gui.in_use)
1795 	{
1796 	    char	buf[20];
1797 
1798 	    // The GUI handles this internally.
1799 	    sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
1800 	    OUT_STR(buf);
1801 	}
1802 	else
1803 #endif
1804 	{
1805 	    if (attr > HL_ALL)				// special HL attr.
1806 	    {
1807 		if (IS_CTERM)
1808 		    aep = syn_cterm_attr2entry(attr);
1809 		else
1810 		    aep = syn_term_attr2entry(attr);
1811 		if (aep == NULL)	    // did ":syntax clear"
1812 		    attr = 0;
1813 		else
1814 		    attr = aep->ae_attr;
1815 	    }
1816 #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1817 	    if (use_vtp())
1818 	    {
1819 		guicolor_T  defguifg, defguibg;
1820 		int	    defctermfg, defctermbg;
1821 
1822 		// If FG and BG are unset, the color is undefined when
1823 		// BOLD+INVERSE. Use Normal as the default value.
1824 		get_default_console_color(&defctermfg, &defctermbg, &defguifg,
1825 								    &defguibg);
1826 
1827 		if (p_tgc)
1828 		{
1829 		    if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.fg_rgb))
1830 			term_fg_rgb_color(defguifg);
1831 		    if (aep == NULL || COLOR_INVALID(aep->ae_u.cterm.bg_rgb))
1832 			term_bg_rgb_color(defguibg);
1833 		}
1834 		else if (t_colors >= 256)
1835 		{
1836 		    if (aep == NULL || aep->ae_u.cterm.fg_color == 0)
1837 			term_fg_color(defctermfg);
1838 		    if (aep == NULL || aep->ae_u.cterm.bg_color == 0)
1839 			term_bg_color(defctermbg);
1840 		}
1841 	    }
1842 #endif
1843 	    if ((attr & HL_BOLD) && *T_MD != NUL)	// bold
1844 		out_str(T_MD);
1845 	    else if (aep != NULL && cterm_normal_fg_bold && (
1846 #ifdef FEAT_TERMGUICOLORS
1847 			p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1848 			  ? aep->ae_u.cterm.fg_rgb != INVALCOLOR
1849 			  :
1850 #endif
1851 			    t_colors > 1 && aep->ae_u.cterm.fg_color))
1852 		// If the Normal FG color has BOLD attribute and the new HL
1853 		// has a FG color defined, clear BOLD.
1854 		out_str(T_ME);
1855 	    if ((attr & HL_STANDOUT) && *T_SO != NUL)	// standout
1856 		out_str(T_SO);
1857 	    if ((attr & HL_UNDERCURL) && *T_UCS != NUL) // undercurl
1858 		out_str(T_UCS);
1859 	    if (((attr & HL_UNDERLINE)	    // underline or undercurl
1860 			|| ((attr & HL_UNDERCURL) && *T_UCS == NUL))
1861 		    && *T_US != NUL)
1862 		out_str(T_US);
1863 	    if ((attr & HL_ITALIC) && *T_CZH != NUL)	// italic
1864 		out_str(T_CZH);
1865 	    if ((attr & HL_INVERSE) && *T_MR != NUL)	// inverse (reverse)
1866 		out_str(T_MR);
1867 	    if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL)	// strike
1868 		out_str(T_STS);
1869 
1870 	    /*
1871 	     * Output the color or start string after bold etc., in case the
1872 	     * bold etc. override the color setting.
1873 	     */
1874 	    if (aep != NULL)
1875 	    {
1876 #ifdef FEAT_TERMGUICOLORS
1877 		// When 'termguicolors' is set but fg or bg is unset,
1878 		// fall back to the cterm colors.   This helps for SpellBad,
1879 		// where the GUI uses a red undercurl.
1880 		if (p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR)
1881 		{
1882 		    if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
1883 			term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
1884 		}
1885 		else
1886 #endif
1887 		if (t_colors > 1)
1888 		{
1889 		    if (aep->ae_u.cterm.fg_color)
1890 			term_fg_color(aep->ae_u.cterm.fg_color - 1);
1891 		}
1892 #ifdef FEAT_TERMGUICOLORS
1893 		if (p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR)
1894 		{
1895 		    if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
1896 			term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
1897 		}
1898 		else
1899 #endif
1900 		if (t_colors > 1)
1901 		{
1902 		    if (aep->ae_u.cterm.bg_color)
1903 			term_bg_color(aep->ae_u.cterm.bg_color - 1);
1904 		}
1905 #ifdef FEAT_TERMGUICOLORS
1906 		if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
1907 		{
1908 		    if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
1909 			term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
1910 		}
1911 		else
1912 #endif
1913 		if (t_colors > 1)
1914 		{
1915 		    if (aep->ae_u.cterm.ul_color)
1916 			term_ul_color(aep->ae_u.cterm.ul_color - 1);
1917 		}
1918 
1919 		if (!IS_CTERM)
1920 		{
1921 		    if (aep->ae_u.term.start != NULL)
1922 			out_str(aep->ae_u.term.start);
1923 		}
1924 	    }
1925 	}
1926     }
1927 }
1928 
1929       void
screen_stop_highlight(void)1930 screen_stop_highlight(void)
1931 {
1932     int	    do_ME = FALSE;	    // output T_ME code
1933 #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1934     int	    do_ME_fg = FALSE, do_ME_bg = FALSE;
1935 #endif
1936 
1937     if (screen_attr != 0
1938 #ifdef MSWIN
1939 			&& termcap_active
1940 #endif
1941 					   )
1942     {
1943 #ifdef FEAT_GUI
1944 	if (gui.in_use)
1945 	{
1946 	    char	buf[20];
1947 
1948 	    // use internal GUI code
1949 	    sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
1950 	    OUT_STR(buf);
1951 	}
1952 	else
1953 #endif
1954 	{
1955 	    if (screen_attr > HL_ALL)			// special HL attr.
1956 	    {
1957 		attrentry_T *aep;
1958 
1959 		if (IS_CTERM)
1960 		{
1961 		    /*
1962 		     * Assume that t_me restores the original colors!
1963 		     */
1964 		    aep = syn_cterm_attr2entry(screen_attr);
1965 		    if (aep != NULL && ((
1966 #ifdef FEAT_TERMGUICOLORS
1967 			    p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
1968 				? aep->ae_u.cterm.fg_rgb != INVALCOLOR
1969 # ifdef FEAT_VTP
1970 				    ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
1971 # endif
1972 				:
1973 #endif
1974 				aep->ae_u.cterm.fg_color) || (
1975 #ifdef FEAT_TERMGUICOLORS
1976 			    p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
1977 				? aep->ae_u.cterm.bg_rgb != INVALCOLOR
1978 # ifdef FEAT_VTP
1979 				    ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
1980 # endif
1981 				:
1982 #endif
1983 				aep->ae_u.cterm.bg_color)))
1984 			do_ME = TRUE;
1985 #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
1986 		    if (use_vtp())
1987 		    {
1988 			if (do_ME_fg && do_ME_bg)
1989 			    do_ME = TRUE;
1990 
1991 			// FG and BG cannot be separated in T_ME, which is not
1992 			// efficient.
1993 			if (!do_ME && do_ME_fg)
1994 			    out_str((char_u *)"\033|39m"); // restore FG
1995 			if (!do_ME && do_ME_bg)
1996 			    out_str((char_u *)"\033|49m"); // restore BG
1997 		    }
1998 		    else
1999 		    {
2000 			// Process FG and BG at once.
2001 			if (!do_ME)
2002 			    do_ME = do_ME_fg | do_ME_bg;
2003 		    }
2004 #endif
2005 		}
2006 		else
2007 		{
2008 		    aep = syn_term_attr2entry(screen_attr);
2009 		    if (aep != NULL && aep->ae_u.term.stop != NULL)
2010 		    {
2011 			if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
2012 			    do_ME = TRUE;
2013 			else
2014 			    out_str(aep->ae_u.term.stop);
2015 		    }
2016 		}
2017 		if (aep == NULL)	    // did ":syntax clear"
2018 		    screen_attr = 0;
2019 		else
2020 		    screen_attr = aep->ae_attr;
2021 	    }
2022 
2023 	    /*
2024 	     * Often all ending-codes are equal to T_ME.  Avoid outputting the
2025 	     * same sequence several times.
2026 	     */
2027 	    if (screen_attr & HL_STANDOUT)
2028 	    {
2029 		if (STRCMP(T_SE, T_ME) == 0)
2030 		    do_ME = TRUE;
2031 		else
2032 		    out_str(T_SE);
2033 	    }
2034 	    if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
2035 	    {
2036 		if (STRCMP(T_UCE, T_ME) == 0)
2037 		    do_ME = TRUE;
2038 		else
2039 		    out_str(T_UCE);
2040 	    }
2041 	    if ((screen_attr & HL_UNDERLINE)
2042 			    || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
2043 	    {
2044 		if (STRCMP(T_UE, T_ME) == 0)
2045 		    do_ME = TRUE;
2046 		else
2047 		    out_str(T_UE);
2048 	    }
2049 	    if (screen_attr & HL_ITALIC)
2050 	    {
2051 		if (STRCMP(T_CZR, T_ME) == 0)
2052 		    do_ME = TRUE;
2053 		else
2054 		    out_str(T_CZR);
2055 	    }
2056 	    if (screen_attr & HL_STRIKETHROUGH)
2057 	    {
2058 		if (STRCMP(T_STE, T_ME) == 0)
2059 		    do_ME = TRUE;
2060 		else
2061 		    out_str(T_STE);
2062 	    }
2063 	    if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
2064 		out_str(T_ME);
2065 
2066 #ifdef FEAT_TERMGUICOLORS
2067 	    if (p_tgc)
2068 	    {
2069 		if (cterm_normal_fg_gui_color != INVALCOLOR)
2070 		    term_fg_rgb_color(cterm_normal_fg_gui_color);
2071 		if (cterm_normal_bg_gui_color != INVALCOLOR)
2072 		    term_bg_rgb_color(cterm_normal_bg_gui_color);
2073 		if (cterm_normal_ul_gui_color != INVALCOLOR)
2074 		    term_ul_rgb_color(cterm_normal_ul_gui_color);
2075 	    }
2076 	    else
2077 #endif
2078 	    {
2079 		if (t_colors > 1)
2080 		{
2081 		    // set Normal cterm colors
2082 		    if (cterm_normal_fg_color != 0)
2083 			term_fg_color(cterm_normal_fg_color - 1);
2084 		    if (cterm_normal_bg_color != 0)
2085 			term_bg_color(cterm_normal_bg_color - 1);
2086 		    if (cterm_normal_ul_color != 0)
2087 			term_ul_color(cterm_normal_ul_color - 1);
2088 		    if (cterm_normal_fg_bold)
2089 			out_str(T_MD);
2090 		}
2091 	    }
2092 	}
2093     }
2094     screen_attr = 0;
2095 }
2096 
2097 /*
2098  * Reset the colors for a cterm.  Used when leaving Vim.
2099  * The machine specific code may override this again.
2100  */
2101     void
reset_cterm_colors(void)2102 reset_cterm_colors(void)
2103 {
2104     if (IS_CTERM)
2105     {
2106 	// set Normal cterm colors
2107 #ifdef FEAT_TERMGUICOLORS
2108 	if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
2109 		 || cterm_normal_bg_gui_color != INVALCOLOR)
2110 		: (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
2111 #else
2112 	if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
2113 #endif
2114 	{
2115 	    out_str(T_OP);
2116 	    screen_attr = -1;
2117 	}
2118 	if (cterm_normal_fg_bold)
2119 	{
2120 	    out_str(T_ME);
2121 	    screen_attr = -1;
2122 	}
2123     }
2124 }
2125 
2126 /*
2127  * Put character ScreenLines["off"] on the screen at position "row" and "col",
2128  * using the attributes from ScreenAttrs["off"].
2129  */
2130     void
screen_char(unsigned off,int row,int col)2131 screen_char(unsigned off, int row, int col)
2132 {
2133     int		attr;
2134 
2135     // Check for illegal values, just in case (could happen just after
2136     // resizing).
2137     if (row >= screen_Rows || col >= screen_Columns)
2138 	return;
2139 
2140     // Skip if under the popup menu.
2141     // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top.
2142     if (pum_under_menu(row, col, TRUE)
2143 #ifdef FEAT_PROP_POPUP
2144 	    && screen_zindex <= POPUPMENU_ZINDEX
2145 #endif
2146 	    )
2147 	return;
2148 #ifdef FEAT_PROP_POPUP
2149     if (blocked_by_popup(row, col))
2150 	return;
2151 #endif
2152 
2153     // Outputting a character in the last cell on the screen may scroll the
2154     // screen up.  Only do it when the "xn" termcap property is set, otherwise
2155     // mark the character invalid (update it when scrolled up).
2156     if (*T_XN == NUL
2157 	    && row == screen_Rows - 1 && col == screen_Columns - 1
2158 #ifdef FEAT_RIGHTLEFT
2159 	    // account for first command-line character in rightleft mode
2160 	    && !cmdmsg_rl
2161 #endif
2162        )
2163     {
2164 	ScreenAttrs[off] = (sattr_T)-1;
2165 	return;
2166     }
2167 
2168     /*
2169      * Stop highlighting first, so it's easier to move the cursor.
2170      */
2171     if (screen_char_attr != 0)
2172 	attr = screen_char_attr;
2173     else
2174 	attr = ScreenAttrs[off];
2175     if (screen_attr != attr)
2176 	screen_stop_highlight();
2177 
2178     windgoto(row, col);
2179 
2180     if (screen_attr != attr)
2181 	screen_start_highlight(attr);
2182 
2183     if (enc_utf8 && ScreenLinesUC[off] != 0)
2184     {
2185 	char_u	    buf[MB_MAXBYTES + 1];
2186 
2187 	if (utf_ambiguous_width(ScreenLinesUC[off]))
2188 	{
2189 	    if (*p_ambw == 'd'
2190 #ifdef FEAT_GUI
2191 		    && !gui.in_use
2192 #endif
2193 		    )
2194 	    {
2195 		// Clear the two screen cells. If the character is actually
2196 		// single width it won't change the second cell.
2197 		out_str((char_u *)"  ");
2198 		term_windgoto(row, col);
2199 	    }
2200 	    // not sure where the cursor is after drawing the ambiguous width
2201 	    // character
2202 	    screen_cur_col = 9999;
2203 	}
2204 	else if (utf_char2cells(ScreenLinesUC[off]) > 1)
2205 	    ++screen_cur_col;
2206 
2207 	// Convert the UTF-8 character to bytes and write it.
2208 	buf[utfc_char2bytes(off, buf)] = NUL;
2209 	out_str(buf);
2210     }
2211     else
2212     {
2213 	out_flush_check();
2214 	out_char(ScreenLines[off]);
2215 	// double-byte character in single-width cell
2216 	if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
2217 	    out_char(ScreenLines2[off]);
2218     }
2219 
2220     screen_cur_col++;
2221 }
2222 
2223 /*
2224  * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
2225  * on the screen at position 'row' and 'col'.
2226  * The attributes of the first byte is used for all.  This is required to
2227  * output the two bytes of a double-byte character with nothing in between.
2228  */
2229     static void
screen_char_2(unsigned off,int row,int col)2230 screen_char_2(unsigned off, int row, int col)
2231 {
2232     // Check for illegal values (could be wrong when screen was resized).
2233     if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
2234 	return;
2235 
2236     // Outputting the last character on the screen may scrollup the screen.
2237     // Don't to it!  Mark the character invalid (update it when scrolled up)
2238     if (row == screen_Rows - 1 && col >= screen_Columns - 2)
2239     {
2240 	ScreenAttrs[off] = (sattr_T)-1;
2241 	return;
2242     }
2243 
2244     // Output the first byte normally (positions the cursor), then write the
2245     // second byte directly.
2246     screen_char(off, row, col);
2247     out_char(ScreenLines[off + 1]);
2248     ++screen_cur_col;
2249 }
2250 
2251 /*
2252  * Draw a rectangle of the screen, inverted when "invert" is TRUE.
2253  * This uses the contents of ScreenLines[] and doesn't change it.
2254  */
2255     void
screen_draw_rectangle(int row,int col,int height,int width,int invert)2256 screen_draw_rectangle(
2257     int		row,
2258     int		col,
2259     int		height,
2260     int		width,
2261     int		invert)
2262 {
2263     int		r, c;
2264     int		off;
2265     int		max_off;
2266 
2267     // Can't use ScreenLines unless initialized
2268     if (ScreenLines == NULL)
2269 	return;
2270 
2271     if (invert)
2272 	screen_char_attr = HL_INVERSE;
2273     for (r = row; r < row + height; ++r)
2274     {
2275 	off = LineOffset[r];
2276 	max_off = off + screen_Columns;
2277 	for (c = col; c < col + width; ++c)
2278 	{
2279 	    if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
2280 	    {
2281 		screen_char_2(off + c, r, c);
2282 		++c;
2283 	    }
2284 	    else
2285 	    {
2286 		screen_char(off + c, r, c);
2287 		if (utf_off2cells(off + c, max_off) > 1)
2288 		    ++c;
2289 	    }
2290 	}
2291     }
2292     screen_char_attr = 0;
2293 }
2294 
2295 /*
2296  * Redraw the characters for a vertically split window.
2297  */
2298     static void
redraw_block(int row,int end,win_T * wp)2299 redraw_block(int row, int end, win_T *wp)
2300 {
2301     int		col;
2302     int		width;
2303 
2304 # ifdef FEAT_CLIPBOARD
2305     clip_may_clear_selection(row, end - 1);
2306 # endif
2307 
2308     if (wp == NULL)
2309     {
2310 	col = 0;
2311 	width = Columns;
2312     }
2313     else
2314     {
2315 	col = wp->w_wincol;
2316 	width = wp->w_width;
2317     }
2318     screen_draw_rectangle(row, col, end - row, width, FALSE);
2319 }
2320 
2321     void
space_to_screenline(int off,int attr)2322 space_to_screenline(int off, int attr)
2323 {
2324     ScreenLines[off] = ' ';
2325     ScreenAttrs[off] = attr;
2326     if (enc_utf8)
2327 	ScreenLinesUC[off] = 0;
2328 }
2329 
2330 /*
2331  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
2332  * with character 'c1' in first column followed by 'c2' in the other columns.
2333  * Use attributes 'attr'.
2334  */
2335     void
screen_fill(int start_row,int end_row,int start_col,int end_col,int c1,int c2,int attr)2336 screen_fill(
2337 	int	start_row,
2338 	int	end_row,
2339 	int	start_col,
2340 	int	end_col,
2341 	int	c1,
2342 	int	c2,
2343 	int	attr)
2344 {
2345     int	    row;
2346     int	    col;
2347     int	    off;
2348     int	    end_off;
2349     int	    did_delete;
2350     int	    c;
2351     int	    norm_term;
2352 #if defined(FEAT_GUI) || defined(UNIX)
2353     int	    force_next = FALSE;
2354 #endif
2355 
2356     if (end_row > screen_Rows)		// safety check
2357 	end_row = screen_Rows;
2358     if (end_col > screen_Columns)	// safety check
2359 	end_col = screen_Columns;
2360     if (ScreenLines == NULL
2361 	    || start_row >= end_row
2362 	    || start_col >= end_col)	// nothing to do
2363 	return;
2364 
2365     // it's a "normal" terminal when not in a GUI or cterm
2366     norm_term = (
2367 #ifdef FEAT_GUI
2368 	    !gui.in_use &&
2369 #endif
2370 	    !IS_CTERM);
2371     for (row = start_row; row < end_row; ++row)
2372     {
2373 	if (has_mbyte
2374 #ifdef FEAT_GUI
2375 		&& !gui.in_use
2376 #endif
2377 	   )
2378 	{
2379 	    // When drawing over the right halve of a double-wide char clear
2380 	    // out the left halve.  When drawing over the left halve of a
2381 	    // double wide-char clear out the right halve.  Only needed in a
2382 	    // terminal.
2383 	    if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
2384 		screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
2385 	    if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
2386 		screen_puts_len((char_u *)" ", 1, row, end_col, 0);
2387 	}
2388 	/*
2389 	 * Try to use delete-line termcap code, when no attributes or in a
2390 	 * "normal" terminal, where a bold/italic space is just a
2391 	 * space.
2392 	 */
2393 	did_delete = FALSE;
2394 	if (c2 == ' '
2395 		&& end_col == Columns
2396 		&& can_clear(T_CE)
2397 		&& (attr == 0
2398 		    || (norm_term
2399 			&& attr <= HL_ALL
2400 			&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
2401 	{
2402 	    /*
2403 	     * check if we really need to clear something
2404 	     */
2405 	    col = start_col;
2406 	    if (c1 != ' ')			// don't clear first char
2407 		++col;
2408 
2409 	    off = LineOffset[row] + col;
2410 	    end_off = LineOffset[row] + end_col;
2411 
2412 	    // skip blanks (used often, keep it fast!)
2413 	    if (enc_utf8)
2414 		while (off < end_off && ScreenLines[off] == ' '
2415 			  && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
2416 		    ++off;
2417 	    else
2418 		while (off < end_off && ScreenLines[off] == ' '
2419 						     && ScreenAttrs[off] == 0)
2420 		    ++off;
2421 	    if (off < end_off)		// something to be cleared
2422 	    {
2423 		col = off - LineOffset[row];
2424 		screen_stop_highlight();
2425 		term_windgoto(row, col);// clear rest of this screen line
2426 		out_str(T_CE);
2427 		screen_start();		// don't know where cursor is now
2428 		col = end_col - col;
2429 		while (col--)		// clear chars in ScreenLines
2430 		{
2431 		    space_to_screenline(off, 0);
2432 		    ++off;
2433 		}
2434 	    }
2435 	    did_delete = TRUE;		// the chars are cleared now
2436 	}
2437 
2438 	off = LineOffset[row] + start_col;
2439 	c = c1;
2440 	for (col = start_col; col < end_col; ++col)
2441 	{
2442 	    if ((ScreenLines[off] != c
2443 		    || (enc_utf8 && (int)ScreenLinesUC[off]
2444 						       != (c >= 0x80 ? c : 0))
2445 		    || ScreenAttrs[off] != attr
2446 #if defined(FEAT_GUI) || defined(UNIX)
2447 		    || force_next
2448 #endif
2449 		    )
2450 #ifdef FEAT_PROP_POPUP
2451 		    // Skip if under a(nother) popup.
2452 		    && !blocked_by_popup(row, col)
2453 #endif
2454 	       )
2455 	    {
2456 #if defined(FEAT_GUI) || defined(UNIX)
2457 		// The bold trick may make a single row of pixels appear in
2458 		// the next character.  When a bold character is removed, the
2459 		// next character should be redrawn too.  This happens for our
2460 		// own GUI and for some xterms.
2461 		if (
2462 # ifdef FEAT_GUI
2463 			gui.in_use
2464 # endif
2465 # if defined(FEAT_GUI) && defined(UNIX)
2466 			||
2467 # endif
2468 # ifdef UNIX
2469 			term_is_xterm
2470 # endif
2471 		   )
2472 		{
2473 		    if (ScreenLines[off] != ' '
2474 			    && (ScreenAttrs[off] > HL_ALL
2475 				|| ScreenAttrs[off] & HL_BOLD))
2476 			force_next = TRUE;
2477 		    else
2478 			force_next = FALSE;
2479 		}
2480 #endif
2481 		ScreenLines[off] = c;
2482 		if (enc_utf8)
2483 		{
2484 		    if (c >= 0x80)
2485 		    {
2486 			ScreenLinesUC[off] = c;
2487 			ScreenLinesC[0][off] = 0;
2488 		    }
2489 		    else
2490 			ScreenLinesUC[off] = 0;
2491 		}
2492 		ScreenAttrs[off] = attr;
2493 		if (!did_delete || c != ' ')
2494 		    screen_char(off, row, col);
2495 	    }
2496 	    ++off;
2497 	    if (col == start_col)
2498 	    {
2499 		if (did_delete)
2500 		    break;
2501 		c = c2;
2502 	    }
2503 	}
2504 	if (end_col == Columns)
2505 	    LineWraps[row] = FALSE;
2506 	if (row == Rows - 1)		// overwritten the command line
2507 	{
2508 	    redraw_cmdline = TRUE;
2509 	    if (start_col == 0 && end_col == Columns
2510 		    && c1 == ' ' && c2 == ' ' && attr == 0)
2511 		clear_cmdline = FALSE;	// command line has been cleared
2512 	    if (start_col == 0)
2513 		mode_displayed = FALSE; // mode cleared or overwritten
2514 	}
2515     }
2516 }
2517 
2518 /*
2519  * Check if there should be a delay.  Used before clearing or redrawing the
2520  * screen or the command line.
2521  */
2522     void
check_for_delay(int check_msg_scroll)2523 check_for_delay(int check_msg_scroll)
2524 {
2525     if ((emsg_on_display || (check_msg_scroll && msg_scroll))
2526 	    && !did_wait_return
2527 	    && emsg_silent == 0
2528 	    && !in_assert_fails)
2529     {
2530 	out_flush();
2531 	ui_delay(1006L, TRUE);
2532 	emsg_on_display = FALSE;
2533 	if (check_msg_scroll)
2534 	    msg_scroll = FALSE;
2535     }
2536 }
2537 
2538 /*
2539  * Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
2540  */
2541     static void
clear_TabPageIdxs(void)2542 clear_TabPageIdxs(void)
2543 {
2544     int		scol;
2545 
2546     for (scol = 0; scol < Columns; ++scol)
2547 	TabPageIdxs[scol] = 0;
2548 }
2549 
2550 /*
2551  * screen_valid -  allocate screen buffers if size changed
2552  *   If "doclear" is TRUE: clear screen if it has been resized.
2553  *	Returns TRUE if there is a valid screen to write to.
2554  *	Returns FALSE when starting up and screen not initialized yet.
2555  */
2556     int
screen_valid(int doclear)2557 screen_valid(int doclear)
2558 {
2559     screenalloc(doclear);	   // allocate screen buffers if size changed
2560     return (ScreenLines != NULL);
2561 }
2562 
2563 /*
2564  * Resize the shell to Rows and Columns.
2565  * Allocate ScreenLines[] and associated items.
2566  *
2567  * There may be some time between setting Rows and Columns and (re)allocating
2568  * ScreenLines[].  This happens when starting up and when (manually) changing
2569  * the shell size.  Always use screen_Rows and screen_Columns to access items
2570  * in ScreenLines[].  Use Rows and Columns for positioning text etc. where the
2571  * final size of the shell is needed.
2572  */
2573     void
screenalloc(int doclear)2574 screenalloc(int doclear)
2575 {
2576     int		    new_row, old_row;
2577 #ifdef FEAT_GUI
2578     int		    old_Rows;
2579 #endif
2580     win_T	    *wp;
2581     int		    outofmem = FALSE;
2582     int		    len;
2583     schar_T	    *new_ScreenLines;
2584     u8char_T	    *new_ScreenLinesUC = NULL;
2585     u8char_T	    *new_ScreenLinesC[MAX_MCO];
2586     schar_T	    *new_ScreenLines2 = NULL;
2587     int		    i;
2588     sattr_T	    *new_ScreenAttrs;
2589     unsigned	    *new_LineOffset;
2590     char_u	    *new_LineWraps;
2591     short	    *new_TabPageIdxs;
2592 #ifdef FEAT_PROP_POPUP
2593     short	    *new_popup_mask;
2594     short	    *new_popup_mask_next;
2595     char	    *new_popup_transparent;
2596 #endif
2597     tabpage_T	    *tp;
2598     static int	    entered = FALSE;		// avoid recursiveness
2599     static int	    done_outofmem_msg = FALSE;	// did outofmem message
2600     int		    retry_count = 0;
2601 
2602 retry:
2603     /*
2604      * Allocation of the screen buffers is done only when the size changes and
2605      * when Rows and Columns have been set and we have started doing full
2606      * screen stuff.
2607      */
2608     if ((ScreenLines != NULL
2609 		&& Rows == screen_Rows
2610 		&& Columns == screen_Columns
2611 		&& enc_utf8 == (ScreenLinesUC != NULL)
2612 		&& (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
2613 		&& p_mco == Screen_mco)
2614 	    || Rows == 0
2615 	    || Columns == 0
2616 	    || (!full_screen && ScreenLines == NULL))
2617 	return;
2618 
2619     /*
2620      * It's possible that we produce an out-of-memory message below, which
2621      * will cause this function to be called again.  To break the loop, just
2622      * return here.
2623      */
2624     if (entered)
2625 	return;
2626     entered = TRUE;
2627 
2628     /*
2629      * Note that the window sizes are updated before reallocating the arrays,
2630      * thus we must not redraw here!
2631      */
2632     ++RedrawingDisabled;
2633 
2634     win_new_shellsize();    // fit the windows in the new sized shell
2635 
2636 #ifdef FEAT_GUI_HAIKU
2637     vim_lock_screen();  // be safe, put it here
2638 #endif
2639 
2640     comp_col();		// recompute columns for shown command and ruler
2641 
2642     /*
2643      * We're changing the size of the screen.
2644      * - Allocate new arrays for ScreenLines and ScreenAttrs.
2645      * - Move lines from the old arrays into the new arrays, clear extra
2646      *	 lines (unless the screen is going to be cleared).
2647      * - Free the old arrays.
2648      *
2649      * If anything fails, make ScreenLines NULL, so we don't do anything!
2650      * Continuing with the old ScreenLines may result in a crash, because the
2651      * size is wrong.
2652      */
2653     FOR_ALL_TAB_WINDOWS(tp, wp)
2654 	win_free_lsize(wp);
2655     if (aucmd_win != NULL)
2656 	win_free_lsize(aucmd_win);
2657 #ifdef FEAT_PROP_POPUP
2658     // global popup windows
2659     FOR_ALL_POPUPWINS(wp)
2660 	win_free_lsize(wp);
2661     // tab-local popup windows
2662     FOR_ALL_TABPAGES(tp)
2663 	FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
2664 	    win_free_lsize(wp);
2665 #endif
2666 
2667     new_ScreenLines = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2668     vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
2669     if (enc_utf8)
2670     {
2671 	new_ScreenLinesUC = LALLOC_MULT(u8char_T, (Rows + 1) * Columns);
2672 	for (i = 0; i < p_mco; ++i)
2673 	    new_ScreenLinesC[i] = LALLOC_CLEAR_MULT(u8char_T,
2674 							 (Rows + 1) * Columns);
2675     }
2676     if (enc_dbcs == DBCS_JPNU)
2677 	new_ScreenLines2 = LALLOC_MULT(schar_T, (Rows + 1) * Columns);
2678     new_ScreenAttrs = LALLOC_MULT(sattr_T, (Rows + 1) * Columns);
2679     new_LineOffset = LALLOC_MULT(unsigned, Rows);
2680     new_LineWraps = LALLOC_MULT(char_u, Rows);
2681     new_TabPageIdxs = LALLOC_MULT(short, Columns);
2682 #ifdef FEAT_PROP_POPUP
2683     new_popup_mask = LALLOC_MULT(short, Rows * Columns);
2684     new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
2685     new_popup_transparent = LALLOC_MULT(char, Rows * Columns);
2686 #endif
2687 
2688     FOR_ALL_TAB_WINDOWS(tp, wp)
2689     {
2690 	if (win_alloc_lines(wp) == FAIL)
2691 	{
2692 	    outofmem = TRUE;
2693 	    goto give_up;
2694 	}
2695     }
2696     if (aucmd_win != NULL && aucmd_win->w_lines == NULL
2697 					&& win_alloc_lines(aucmd_win) == FAIL)
2698 	outofmem = TRUE;
2699 #ifdef FEAT_PROP_POPUP
2700     // global popup windows
2701     FOR_ALL_POPUPWINS(wp)
2702 	if (win_alloc_lines(wp) == FAIL)
2703 	{
2704 	    outofmem = TRUE;
2705 	    goto give_up;
2706 	}
2707     // tab-local popup windows
2708     FOR_ALL_TABPAGES(tp)
2709 	FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
2710 	    if (win_alloc_lines(wp) == FAIL)
2711 	    {
2712 		outofmem = TRUE;
2713 		goto give_up;
2714 	    }
2715 #endif
2716 
2717 give_up:
2718 
2719     for (i = 0; i < p_mco; ++i)
2720 	if (new_ScreenLinesC[i] == NULL)
2721 	    break;
2722     if (new_ScreenLines == NULL
2723 	    || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
2724 	    || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
2725 	    || new_ScreenAttrs == NULL
2726 	    || new_LineOffset == NULL
2727 	    || new_LineWraps == NULL
2728 	    || new_TabPageIdxs == NULL
2729 #ifdef FEAT_PROP_POPUP
2730 	    || new_popup_mask == NULL
2731 	    || new_popup_mask_next == NULL
2732 	    || new_popup_transparent == NULL
2733 #endif
2734 	    || outofmem)
2735     {
2736 	if (ScreenLines != NULL || !done_outofmem_msg)
2737 	{
2738 	    // guess the size
2739 	    do_outofmem_msg((long_u)((Rows + 1) * Columns));
2740 
2741 	    // Remember we did this to avoid getting outofmem messages over
2742 	    // and over again.
2743 	    done_outofmem_msg = TRUE;
2744 	}
2745 	VIM_CLEAR(new_ScreenLines);
2746 	VIM_CLEAR(new_ScreenLinesUC);
2747 	for (i = 0; i < p_mco; ++i)
2748 	    VIM_CLEAR(new_ScreenLinesC[i]);
2749 	VIM_CLEAR(new_ScreenLines2);
2750 	VIM_CLEAR(new_ScreenAttrs);
2751 	VIM_CLEAR(new_LineOffset);
2752 	VIM_CLEAR(new_LineWraps);
2753 	VIM_CLEAR(new_TabPageIdxs);
2754 #ifdef FEAT_PROP_POPUP
2755 	VIM_CLEAR(new_popup_mask);
2756 	VIM_CLEAR(new_popup_mask_next);
2757 	VIM_CLEAR(new_popup_transparent);
2758 #endif
2759     }
2760     else
2761     {
2762 	done_outofmem_msg = FALSE;
2763 
2764 	for (new_row = 0; new_row < Rows; ++new_row)
2765 	{
2766 	    new_LineOffset[new_row] = new_row * Columns;
2767 	    new_LineWraps[new_row] = FALSE;
2768 
2769 	    /*
2770 	     * If the screen is not going to be cleared, copy as much as
2771 	     * possible from the old screen to the new one and clear the rest
2772 	     * (used when resizing the window at the "--more--" prompt or when
2773 	     * executing an external command, for the GUI).
2774 	     */
2775 	    if (!doclear)
2776 	    {
2777 		(void)vim_memset(new_ScreenLines + new_row * Columns,
2778 				      ' ', (size_t)Columns * sizeof(schar_T));
2779 		if (enc_utf8)
2780 		{
2781 		    (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
2782 				       0, (size_t)Columns * sizeof(u8char_T));
2783 		    for (i = 0; i < p_mco; ++i)
2784 			(void)vim_memset(new_ScreenLinesC[i]
2785 							  + new_row * Columns,
2786 				       0, (size_t)Columns * sizeof(u8char_T));
2787 		}
2788 		if (enc_dbcs == DBCS_JPNU)
2789 		    (void)vim_memset(new_ScreenLines2 + new_row * Columns,
2790 				       0, (size_t)Columns * sizeof(schar_T));
2791 		(void)vim_memset(new_ScreenAttrs + new_row * Columns,
2792 					0, (size_t)Columns * sizeof(sattr_T));
2793 		old_row = new_row + (screen_Rows - Rows);
2794 		if (old_row >= 0 && ScreenLines != NULL)
2795 		{
2796 		    if (screen_Columns < Columns)
2797 			len = screen_Columns;
2798 		    else
2799 			len = Columns;
2800 		    // When switching to utf-8 don't copy characters, they
2801 		    // may be invalid now.  Also when p_mco changes.
2802 		    if (!(enc_utf8 && ScreenLinesUC == NULL)
2803 						       && p_mco == Screen_mco)
2804 			mch_memmove(new_ScreenLines + new_LineOffset[new_row],
2805 				ScreenLines + LineOffset[old_row],
2806 				(size_t)len * sizeof(schar_T));
2807 		    if (enc_utf8 && ScreenLinesUC != NULL
2808 						       && p_mco == Screen_mco)
2809 		    {
2810 			mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
2811 				ScreenLinesUC + LineOffset[old_row],
2812 				(size_t)len * sizeof(u8char_T));
2813 			for (i = 0; i < p_mco; ++i)
2814 			    mch_memmove(new_ScreenLinesC[i]
2815 						    + new_LineOffset[new_row],
2816 				ScreenLinesC[i] + LineOffset[old_row],
2817 				(size_t)len * sizeof(u8char_T));
2818 		    }
2819 		    if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
2820 			mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
2821 				ScreenLines2 + LineOffset[old_row],
2822 				(size_t)len * sizeof(schar_T));
2823 		    mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
2824 			    ScreenAttrs + LineOffset[old_row],
2825 			    (size_t)len * sizeof(sattr_T));
2826 		}
2827 	    }
2828 	}
2829 	// Use the last line of the screen for the current line.
2830 	current_ScreenLine = new_ScreenLines + Rows * Columns;
2831 
2832 #ifdef FEAT_PROP_POPUP
2833 	vim_memset(new_popup_mask, 0, Rows * Columns * sizeof(short));
2834 	vim_memset(new_popup_transparent, 0, Rows * Columns * sizeof(char));
2835 #endif
2836     }
2837 
2838     free_screenlines();
2839 
2840     // NOTE: this may result in all pointers to become NULL.
2841     ScreenLines = new_ScreenLines;
2842     ScreenLinesUC = new_ScreenLinesUC;
2843     for (i = 0; i < p_mco; ++i)
2844 	ScreenLinesC[i] = new_ScreenLinesC[i];
2845     Screen_mco = p_mco;
2846     ScreenLines2 = new_ScreenLines2;
2847     ScreenAttrs = new_ScreenAttrs;
2848     LineOffset = new_LineOffset;
2849     LineWraps = new_LineWraps;
2850     TabPageIdxs = new_TabPageIdxs;
2851 #ifdef FEAT_PROP_POPUP
2852     popup_mask = new_popup_mask;
2853     popup_mask_next = new_popup_mask_next;
2854     popup_transparent = new_popup_transparent;
2855     popup_mask_refresh = TRUE;
2856 #endif
2857 
2858     // It's important that screen_Rows and screen_Columns reflect the actual
2859     // size of ScreenLines[].  Set them before calling anything.
2860 #ifdef FEAT_GUI
2861     old_Rows = screen_Rows;
2862 #endif
2863     screen_Rows = Rows;
2864     screen_Columns = Columns;
2865 
2866     must_redraw = CLEAR;	// need to clear the screen later
2867     if (doclear)
2868 	screenclear2();
2869 #ifdef FEAT_GUI
2870     else if (gui.in_use
2871 	    && !gui.starting
2872 	    && ScreenLines != NULL
2873 	    && old_Rows != Rows)
2874     {
2875 	gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
2876 
2877 	// Adjust the position of the cursor, for when executing an external
2878 	// command.
2879 	if (msg_row >= Rows)		// Rows got smaller
2880 	    msg_row = Rows - 1;		// put cursor at last row
2881 	else if (Rows > old_Rows)	// Rows got bigger
2882 	    msg_row += Rows - old_Rows; // put cursor in same place
2883 	if (msg_col >= Columns)		// Columns got smaller
2884 	    msg_col = Columns - 1;	// put cursor at last column
2885     }
2886 #endif
2887     clear_TabPageIdxs();
2888 
2889 #ifdef FEAT_GUI_HAIKU
2890     vim_unlock_screen();
2891 #endif
2892 
2893     entered = FALSE;
2894     --RedrawingDisabled;
2895 
2896     /*
2897      * Do not apply autocommands more than 3 times to avoid an endless loop
2898      * in case applying autocommands always changes Rows or Columns.
2899      */
2900     if (starting == 0 && ++retry_count <= 3)
2901     {
2902 	apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
2903 	// In rare cases, autocommands may have altered Rows or Columns,
2904 	// jump back to check if we need to allocate the screen again.
2905 	goto retry;
2906     }
2907 }
2908 
2909     void
free_screenlines(void)2910 free_screenlines(void)
2911 {
2912     int		i;
2913 
2914     VIM_CLEAR(ScreenLinesUC);
2915     for (i = 0; i < Screen_mco; ++i)
2916 	VIM_CLEAR(ScreenLinesC[i]);
2917     VIM_CLEAR(ScreenLines2);
2918     VIM_CLEAR(ScreenLines);
2919     VIM_CLEAR(ScreenAttrs);
2920     VIM_CLEAR(LineOffset);
2921     VIM_CLEAR(LineWraps);
2922     VIM_CLEAR(TabPageIdxs);
2923 #ifdef FEAT_PROP_POPUP
2924     VIM_CLEAR(popup_mask);
2925     VIM_CLEAR(popup_mask_next);
2926     VIM_CLEAR(popup_transparent);
2927 #endif
2928 }
2929 
2930     void
screenclear(void)2931 screenclear(void)
2932 {
2933     check_for_delay(FALSE);
2934     screenalloc(FALSE);	    // allocate screen buffers if size changed
2935     screenclear2();	    // clear the screen
2936 }
2937 
2938     static void
screenclear2(void)2939 screenclear2(void)
2940 {
2941     int	    i;
2942 
2943     if (starting == NO_SCREEN || ScreenLines == NULL
2944 #ifdef FEAT_GUI
2945 	    || (gui.in_use && gui.starting)
2946 #endif
2947 	    )
2948 	return;
2949 
2950 #ifdef FEAT_GUI
2951     if (!gui.in_use)
2952 #endif
2953 	screen_attr = -1;	// force setting the Normal colors
2954     screen_stop_highlight();	// don't want highlighting here
2955 
2956 #ifdef FEAT_CLIPBOARD
2957     // disable selection without redrawing it
2958     clip_scroll_selection(9999);
2959 #endif
2960 
2961     // blank out ScreenLines
2962     for (i = 0; i < Rows; ++i)
2963     {
2964 	lineclear(LineOffset[i], (int)Columns, 0);
2965 	LineWraps[i] = FALSE;
2966     }
2967 
2968     if (can_clear(T_CL))
2969     {
2970 	out_str(T_CL);		// clear the display
2971 	clear_cmdline = FALSE;
2972 	mode_displayed = FALSE;
2973     }
2974     else
2975     {
2976 	// can't clear the screen, mark all chars with invalid attributes
2977 	for (i = 0; i < Rows; ++i)
2978 	    lineinvalid(LineOffset[i], (int)Columns);
2979 	clear_cmdline = TRUE;
2980     }
2981 
2982     screen_cleared = TRUE;	// can use contents of ScreenLines now
2983 
2984     win_rest_invalid(firstwin);
2985     redraw_cmdline = TRUE;
2986     redraw_tabline = TRUE;
2987     if (must_redraw == CLEAR)	// no need to clear again
2988 	must_redraw = NOT_VALID;
2989     compute_cmdrow();
2990     msg_row = cmdline_row;	// put cursor on last line for messages
2991     msg_col = 0;
2992     screen_start();		// don't know where cursor is now
2993     msg_scrolled = 0;		// can't scroll back
2994     msg_didany = FALSE;
2995     msg_didout = FALSE;
2996 }
2997 
2998 /*
2999  * Clear one line in ScreenLines.
3000  */
3001     static void
lineclear(unsigned off,int width,int attr)3002 lineclear(unsigned off, int width, int attr)
3003 {
3004     (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
3005     if (enc_utf8)
3006 	(void)vim_memset(ScreenLinesUC + off, 0,
3007 					  (size_t)width * sizeof(u8char_T));
3008     (void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
3009 }
3010 
3011 /*
3012  * Mark one line in ScreenLines invalid by setting the attributes to an
3013  * invalid value.
3014  */
3015     static void
lineinvalid(unsigned off,int width)3016 lineinvalid(unsigned off, int width)
3017 {
3018     (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
3019 }
3020 
3021 /*
3022  * To be called when characters were sent to the terminal directly, outputting
3023  * test on "screen_lnum".
3024  */
3025     void
line_was_clobbered(int screen_lnum)3026 line_was_clobbered(int screen_lnum)
3027 {
3028     lineinvalid(LineOffset[screen_lnum], (int)Columns);
3029 }
3030 
3031 /*
3032  * Copy part of a Screenline for vertically split window "wp".
3033  */
3034     static void
linecopy(int to,int from,win_T * wp)3035 linecopy(int to, int from, win_T *wp)
3036 {
3037     unsigned	off_to = LineOffset[to] + wp->w_wincol;
3038     unsigned	off_from = LineOffset[from] + wp->w_wincol;
3039 
3040     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
3041 	    wp->w_width * sizeof(schar_T));
3042     if (enc_utf8)
3043     {
3044 	int	i;
3045 
3046 	mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
3047 		wp->w_width * sizeof(u8char_T));
3048 	for (i = 0; i < p_mco; ++i)
3049 	    mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
3050 		    wp->w_width * sizeof(u8char_T));
3051     }
3052     if (enc_dbcs == DBCS_JPNU)
3053 	mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
3054 		wp->w_width * sizeof(schar_T));
3055     mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
3056 	    wp->w_width * sizeof(sattr_T));
3057 }
3058 
3059 /*
3060  * Return TRUE if clearing with term string "p" would work.
3061  * It can't work when the string is empty or it won't set the right background.
3062  * Don't clear to end-of-line when there are popups, it may cause flicker.
3063  */
3064     int
can_clear(char_u * p)3065 can_clear(char_u *p)
3066 {
3067     return (*p != NUL && (t_colors <= 1
3068 #ifdef FEAT_GUI
3069 		|| gui.in_use
3070 #endif
3071 #ifdef FEAT_TERMGUICOLORS
3072 		|| (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
3073 		|| (!p_tgc && cterm_normal_bg_color == 0)
3074 #else
3075 		|| cterm_normal_bg_color == 0
3076 #endif
3077 		|| *T_UT != NUL)
3078 #ifdef FEAT_PROP_POPUP
3079 	    && !(p == T_CE && popup_visible)
3080 #endif
3081 	    );
3082 }
3083 
3084 /*
3085  * Reset cursor position. Use whenever cursor was moved because of outputting
3086  * something directly to the screen (shell commands) or a terminal control
3087  * code.
3088  */
3089     void
screen_start(void)3090 screen_start(void)
3091 {
3092     screen_cur_row = screen_cur_col = 9999;
3093 }
3094 
3095 /*
3096  * Move the cursor to position "row","col" in the screen.
3097  * This tries to find the most efficient way to move, minimizing the number of
3098  * characters sent to the terminal.
3099  */
3100     void
windgoto(int row,int col)3101 windgoto(int row, int col)
3102 {
3103     sattr_T	    *p;
3104     int		    i;
3105     int		    plan;
3106     int		    cost;
3107     int		    wouldbe_col;
3108     int		    noinvcurs;
3109     char_u	    *bs;
3110     int		    goto_cost;
3111     int		    attr;
3112 
3113 #define GOTO_COST   7	// assume a term_windgoto() takes about 7 chars
3114 #define HIGHL_COST  5	// assume unhighlight takes 5 chars
3115 
3116 #define PLAN_LE	    1
3117 #define PLAN_CR	    2
3118 #define PLAN_NL	    3
3119 #define PLAN_WRITE  4
3120     // Can't use ScreenLines unless initialized
3121     if (ScreenLines == NULL)
3122 	return;
3123     if (col != screen_cur_col || row != screen_cur_row)
3124     {
3125 	// Check for valid position.
3126 	if (row < 0)	// window without text lines?
3127 	    row = 0;
3128 	if (row >= screen_Rows)
3129 	    row = screen_Rows - 1;
3130 	if (col >= screen_Columns)
3131 	    col = screen_Columns - 1;
3132 
3133 	// check if no cursor movement is allowed in highlight mode
3134 	if (screen_attr && *T_MS == NUL)
3135 	    noinvcurs = HIGHL_COST;
3136 	else
3137 	    noinvcurs = 0;
3138 	goto_cost = GOTO_COST + noinvcurs;
3139 
3140 	/*
3141 	 * Plan how to do the positioning:
3142 	 * 1. Use CR to move it to column 0, same row.
3143 	 * 2. Use T_LE to move it a few columns to the left.
3144 	 * 3. Use NL to move a few lines down, column 0.
3145 	 * 4. Move a few columns to the right with T_ND or by writing chars.
3146 	 *
3147 	 * Don't do this if the cursor went beyond the last column, the cursor
3148 	 * position is unknown then (some terminals wrap, some don't )
3149 	 *
3150 	 * First check if the highlighting attributes allow us to write
3151 	 * characters to move the cursor to the right.
3152 	 */
3153 	if (row >= screen_cur_row && screen_cur_col < Columns)
3154 	{
3155 	    /*
3156 	     * If the cursor is in the same row, bigger col, we can use CR
3157 	     * or T_LE.
3158 	     */
3159 	    bs = NULL;			    // init for GCC
3160 	    attr = screen_attr;
3161 	    if (row == screen_cur_row && col < screen_cur_col)
3162 	    {
3163 		// "le" is preferred over "bc", because "bc" is obsolete
3164 		if (*T_LE)
3165 		    bs = T_LE;		    // "cursor left"
3166 		else
3167 		    bs = T_BC;		    // "backspace character (old)
3168 		if (*bs)
3169 		    cost = (screen_cur_col - col) * (int)STRLEN(bs);
3170 		else
3171 		    cost = 999;
3172 		if (col + 1 < cost)	    // using CR is less characters
3173 		{
3174 		    plan = PLAN_CR;
3175 		    wouldbe_col = 0;
3176 		    cost = 1;		    // CR is just one character
3177 		}
3178 		else
3179 		{
3180 		    plan = PLAN_LE;
3181 		    wouldbe_col = col;
3182 		}
3183 		if (noinvcurs)		    // will stop highlighting
3184 		{
3185 		    cost += noinvcurs;
3186 		    attr = 0;
3187 		}
3188 	    }
3189 
3190 	    /*
3191 	     * If the cursor is above where we want to be, we can use CR LF.
3192 	     */
3193 	    else if (row > screen_cur_row)
3194 	    {
3195 		plan = PLAN_NL;
3196 		wouldbe_col = 0;
3197 		cost = (row - screen_cur_row) * 2;  // CR LF
3198 		if (noinvcurs)		    // will stop highlighting
3199 		{
3200 		    cost += noinvcurs;
3201 		    attr = 0;
3202 		}
3203 	    }
3204 
3205 	    /*
3206 	     * If the cursor is in the same row, smaller col, just use write.
3207 	     */
3208 	    else
3209 	    {
3210 		plan = PLAN_WRITE;
3211 		wouldbe_col = screen_cur_col;
3212 		cost = 0;
3213 	    }
3214 
3215 	    /*
3216 	     * Check if any characters that need to be written have the
3217 	     * correct attributes.  Also avoid UTF-8 characters.
3218 	     */
3219 	    i = col - wouldbe_col;
3220 	    if (i > 0)
3221 		cost += i;
3222 	    if (cost < goto_cost && i > 0)
3223 	    {
3224 		/*
3225 		 * Check if the attributes are correct without additionally
3226 		 * stopping highlighting.
3227 		 */
3228 		p = ScreenAttrs + LineOffset[row] + wouldbe_col;
3229 		while (i && *p++ == attr)
3230 		    --i;
3231 		if (i != 0)
3232 		{
3233 		    /*
3234 		     * Try if it works when highlighting is stopped here.
3235 		     */
3236 		    if (*--p == 0)
3237 		    {
3238 			cost += noinvcurs;
3239 			while (i && *p++ == 0)
3240 			    --i;
3241 		    }
3242 		    if (i != 0)
3243 			cost = 999;	// different attributes, don't do it
3244 		}
3245 		if (enc_utf8)
3246 		{
3247 		    // Don't use an UTF-8 char for positioning, it's slow.
3248 		    for (i = wouldbe_col; i < col; ++i)
3249 			if (ScreenLinesUC[LineOffset[row] + i] != 0)
3250 			{
3251 			    cost = 999;
3252 			    break;
3253 			}
3254 		}
3255 	    }
3256 
3257 	    /*
3258 	     * We can do it without term_windgoto()!
3259 	     */
3260 	    if (cost < goto_cost)
3261 	    {
3262 		if (plan == PLAN_LE)
3263 		{
3264 		    if (noinvcurs)
3265 			screen_stop_highlight();
3266 		    while (screen_cur_col > col)
3267 		    {
3268 			out_str(bs);
3269 			--screen_cur_col;
3270 		    }
3271 		}
3272 		else if (plan == PLAN_CR)
3273 		{
3274 		    if (noinvcurs)
3275 			screen_stop_highlight();
3276 		    out_char('\r');
3277 		    screen_cur_col = 0;
3278 		}
3279 		else if (plan == PLAN_NL)
3280 		{
3281 		    if (noinvcurs)
3282 			screen_stop_highlight();
3283 		    while (screen_cur_row < row)
3284 		    {
3285 			out_char('\n');
3286 			++screen_cur_row;
3287 		    }
3288 		    screen_cur_col = 0;
3289 		}
3290 
3291 		i = col - screen_cur_col;
3292 		if (i > 0)
3293 		{
3294 		    /*
3295 		     * Use cursor-right if it's one character only.  Avoids
3296 		     * removing a line of pixels from the last bold char, when
3297 		     * using the bold trick in the GUI.
3298 		     */
3299 		    if (T_ND[0] != NUL && T_ND[1] == NUL)
3300 		    {
3301 			while (i-- > 0)
3302 			    out_char(*T_ND);
3303 		    }
3304 		    else
3305 		    {
3306 			int	off;
3307 
3308 			off = LineOffset[row] + screen_cur_col;
3309 			while (i-- > 0)
3310 			{
3311 			    if (ScreenAttrs[off] != screen_attr)
3312 				screen_stop_highlight();
3313 			    out_flush_check();
3314 			    out_char(ScreenLines[off]);
3315 			    if (enc_dbcs == DBCS_JPNU
3316 						  && ScreenLines[off] == 0x8e)
3317 				out_char(ScreenLines2[off]);
3318 			    ++off;
3319 			}
3320 		    }
3321 		}
3322 	    }
3323 	}
3324 	else
3325 	    cost = 999;
3326 
3327 	if (cost >= goto_cost)
3328 	{
3329 	    if (noinvcurs)
3330 		screen_stop_highlight();
3331 	    if (row == screen_cur_row && (col > screen_cur_col)
3332 							     && *T_CRI != NUL)
3333 		term_cursor_right(col - screen_cur_col);
3334 	    else
3335 		term_windgoto(row, col);
3336 	}
3337 	screen_cur_row = row;
3338 	screen_cur_col = col;
3339     }
3340 }
3341 
3342 /*
3343  * Set cursor to its position in the current window.
3344  */
3345     void
setcursor(void)3346 setcursor(void)
3347 {
3348     setcursor_mayforce(FALSE);
3349 }
3350 
3351 /*
3352  * Set cursor to its position in the current window.
3353  * When "force" is TRUE also when not redrawing.
3354  */
3355     void
setcursor_mayforce(int force)3356 setcursor_mayforce(int force)
3357 {
3358     if (force || redrawing())
3359     {
3360 	validate_cursor();
3361 	windgoto(W_WINROW(curwin) + curwin->w_wrow,
3362 		curwin->w_wincol + (
3363 #ifdef FEAT_RIGHTLEFT
3364 		// With 'rightleft' set and the cursor on a double-wide
3365 		// character, position it on the leftmost column.
3366 		curwin->w_p_rl ? ((int)curwin->w_width - curwin->w_wcol
3367 		    - ((has_mbyte
3368 			   && (*mb_ptr2cells)(ml_get_cursor()) == 2
3369 			   && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
3370 #endif
3371 							    curwin->w_wcol));
3372     }
3373 }
3374 
3375 
3376 /*
3377  * Insert 'line_count' lines at 'row' in window 'wp'.
3378  * If 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
3379  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
3380  * scrolling.
3381  * Returns FAIL if the lines are not inserted, OK for success.
3382  */
3383     int
win_ins_lines(win_T * wp,int row,int line_count,int invalid,int mayclear)3384 win_ins_lines(
3385     win_T	*wp,
3386     int		row,
3387     int		line_count,
3388     int		invalid,
3389     int		mayclear)
3390 {
3391     int		did_delete;
3392     int		nextrow;
3393     int		lastrow;
3394     int		retval;
3395 
3396     if (invalid)
3397 	wp->w_lines_valid = 0;
3398 
3399     if (wp->w_height < 5)
3400 	return FAIL;
3401 
3402     if (line_count > wp->w_height - row)
3403 	line_count = wp->w_height - row;
3404 
3405     retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
3406     if (retval != MAYBE)
3407 	return retval;
3408 
3409     /*
3410      * If there is a next window or a status line, we first try to delete the
3411      * lines at the bottom to avoid messing what is after the window.
3412      * If this fails and there are following windows, don't do anything to
3413      * avoid messing up those windows, better just redraw.
3414      */
3415     did_delete = FALSE;
3416     if (wp->w_next != NULL || wp->w_status_height)
3417     {
3418 	if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3419 				  line_count, (int)Rows, FALSE, 0, NULL) == OK)
3420 	    did_delete = TRUE;
3421 	else if (wp->w_next)
3422 	    return FAIL;
3423     }
3424     /*
3425      * if no lines deleted, blank the lines that will end up below the window
3426      */
3427     if (!did_delete)
3428     {
3429 	wp->w_redr_status = TRUE;
3430 	redraw_cmdline = TRUE;
3431 	nextrow = W_WINROW(wp) + wp->w_height + wp->w_status_height;
3432 	lastrow = nextrow + line_count;
3433 	if (lastrow > Rows)
3434 	    lastrow = Rows;
3435 	screen_fill(nextrow - line_count, lastrow - line_count,
3436 		  wp->w_wincol, (int)W_ENDCOL(wp),
3437 		  ' ', ' ', 0);
3438     }
3439 
3440     if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
3441 								      == FAIL)
3442     {
3443 	// deletion will have messed up other windows
3444 	if (did_delete)
3445 	{
3446 	    wp->w_redr_status = TRUE;
3447 	    win_rest_invalid(W_NEXT(wp));
3448 	}
3449 	return FAIL;
3450     }
3451 
3452     return OK;
3453 }
3454 
3455 /*
3456  * Delete "line_count" window lines at "row" in window "wp".
3457  * If "invalid" is TRUE curwin->w_lines[] is invalidated.
3458  * If "mayclear" is TRUE the screen will be cleared if it is faster than
3459  * scrolling
3460  * Return OK for success, FAIL if the lines are not deleted.
3461  */
3462     int
win_del_lines(win_T * wp,int row,int line_count,int invalid,int mayclear,int clear_attr)3463 win_del_lines(
3464     win_T	*wp,
3465     int		row,
3466     int		line_count,
3467     int		invalid,
3468     int		mayclear,
3469     int		clear_attr)	    // for clearing lines
3470 {
3471     int		retval;
3472 
3473     if (invalid)
3474 	wp->w_lines_valid = 0;
3475 
3476     if (line_count > wp->w_height - row)
3477 	line_count = wp->w_height - row;
3478 
3479     retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
3480     if (retval != MAYBE)
3481 	return retval;
3482 
3483     if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
3484 				   (int)Rows, FALSE, clear_attr, NULL) == FAIL)
3485 	return FAIL;
3486 
3487     /*
3488      * If there are windows or status lines below, try to put them at the
3489      * correct place. If we can't do that, they have to be redrawn.
3490      */
3491     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
3492     {
3493 	if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
3494 			      line_count, (int)Rows, clear_attr, NULL) == FAIL)
3495 	{
3496 	    wp->w_redr_status = TRUE;
3497 	    win_rest_invalid(wp->w_next);
3498 	}
3499     }
3500     /*
3501      * If this is the last window and there is no status line, redraw the
3502      * command line later.
3503      */
3504     else
3505 	redraw_cmdline = TRUE;
3506     return OK;
3507 }
3508 
3509 /*
3510  * Common code for win_ins_lines() and win_del_lines().
3511  * Returns OK or FAIL when the work has been done.
3512  * Returns MAYBE when not finished yet.
3513  */
3514     static int
win_do_lines(win_T * wp,int row,int line_count,int mayclear,int del,int clear_attr)3515 win_do_lines(
3516     win_T	*wp,
3517     int		row,
3518     int		line_count,
3519     int		mayclear,
3520     int		del,
3521     int		clear_attr)
3522 {
3523     int		retval;
3524 
3525     if (!redrawing() || line_count <= 0)
3526 	return FAIL;
3527 
3528     // When inserting lines would result in loss of command output, just redraw
3529     // the lines.
3530     if (no_win_do_lines_ins && !del)
3531 	return FAIL;
3532 
3533     // only a few lines left: redraw is faster
3534     if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
3535     {
3536 	if (!no_win_do_lines_ins)
3537 	    screenclear();	    // will set wp->w_lines_valid to 0
3538 	return FAIL;
3539     }
3540 
3541 #ifdef FEAT_PROP_POPUP
3542     // this doesn't work when there are popups visible
3543     if (popup_visible)
3544 	return FAIL;
3545 #endif
3546 
3547     // Delete all remaining lines
3548     if (row + line_count >= wp->w_height)
3549     {
3550 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
3551 		wp->w_wincol, (int)W_ENDCOL(wp),
3552 		' ', ' ', 0);
3553 	return OK;
3554     }
3555 
3556     /*
3557      * When scrolling, the message on the command line should be cleared,
3558      * otherwise it will stay there forever.
3559      * Don't do this when avoiding to insert lines.
3560      */
3561     if (!no_win_do_lines_ins)
3562 	clear_cmdline = TRUE;
3563 
3564     /*
3565      * If the terminal can set a scroll region, use that.
3566      * Always do this in a vertically split window.  This will redraw from
3567      * ScreenLines[] when t_CV isn't defined.  That's faster than using
3568      * win_line().
3569      * Don't use a scroll region when we are going to redraw the text, writing
3570      * a character in the lower right corner of the scroll region may cause a
3571      * scroll-up .
3572      */
3573     if (scroll_region || wp->w_width != Columns)
3574     {
3575 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3576 	    scroll_region_set(wp, row);
3577 	if (del)
3578 	    retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
3579 				    wp->w_height - row, FALSE, clear_attr, wp);
3580 	else
3581 	    retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
3582 					   wp->w_height - row, clear_attr, wp);
3583 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
3584 	    scroll_region_reset();
3585 	return retval;
3586     }
3587 
3588     if (wp->w_next != NULL && p_tf) // don't delete/insert on fast terminal
3589 	return FAIL;
3590 
3591     return MAYBE;
3592 }
3593 
3594 /*
3595  * window 'wp' and everything after it is messed up, mark it for redraw
3596  */
3597     static void
win_rest_invalid(win_T * wp)3598 win_rest_invalid(win_T *wp)
3599 {
3600     while (wp != NULL)
3601     {
3602 	redraw_win_later(wp, NOT_VALID);
3603 	wp->w_redr_status = TRUE;
3604 	wp = wp->w_next;
3605     }
3606     redraw_cmdline = TRUE;
3607 }
3608 
3609 /*
3610  * The rest of the routines in this file perform screen manipulations. The
3611  * given operation is performed physically on the screen. The corresponding
3612  * change is also made to the internal screen image. In this way, the editor
3613  * anticipates the effect of editing changes on the appearance of the screen.
3614  * That way, when we call screenupdate a complete redraw isn't usually
3615  * necessary. Another advantage is that we can keep adding code to anticipate
3616  * screen changes, and in the meantime, everything still works.
3617  */
3618 
3619 /*
3620  * types for inserting or deleting lines
3621  */
3622 #define USE_T_CAL   1
3623 #define USE_T_CDL   2
3624 #define USE_T_AL    3
3625 #define USE_T_CE    4
3626 #define USE_T_DL    5
3627 #define USE_T_SR    6
3628 #define USE_NL	    7
3629 #define USE_T_CD    8
3630 #define USE_REDRAW  9
3631 
3632 /*
3633  * insert lines on the screen and update ScreenLines[]
3634  * 'end' is the line after the scrolled part. Normally it is Rows.
3635  * When scrolling region used 'off' is the offset from the top for the region.
3636  * 'row' and 'end' are relative to the start of the region.
3637  *
3638  * return FAIL for failure, OK for success.
3639  */
3640     int
screen_ins_lines(int off,int row,int line_count,int end,int clear_attr,win_T * wp)3641 screen_ins_lines(
3642     int		off,
3643     int		row,
3644     int		line_count,
3645     int		end,
3646     int		clear_attr,
3647     win_T	*wp)	    // NULL or window to use width from
3648 {
3649     int		i;
3650     int		j;
3651     unsigned	temp;
3652     int		cursor_row;
3653     int		cursor_col = 0;
3654     int		type;
3655     int		result_empty;
3656     int		can_ce = can_clear(T_CE);
3657 
3658     /*
3659      * FAIL if
3660      * - there is no valid screen
3661      * - the screen has to be redrawn completely
3662      * - the line count is less than one
3663      * - the line count is more than 'ttyscroll'
3664      * - redrawing for a callback and there is a modeless selection
3665      * - there is a popup window
3666      */
3667      if (!screen_valid(TRUE)
3668 	     || line_count <= 0 || line_count > p_ttyscroll
3669 #ifdef FEAT_CLIPBOARD
3670 	     || (clip_star.state != SELECT_CLEARED
3671 						 && redrawing_for_callback > 0)
3672 #endif
3673 #ifdef FEAT_PROP_POPUP
3674 	     || popup_visible
3675 #endif
3676 	     )
3677 	return FAIL;
3678 
3679     /*
3680      * There are seven ways to insert lines:
3681      * 0. When in a vertically split window and t_CV isn't set, redraw the
3682      *    characters from ScreenLines[].
3683      * 1. Use T_CD (clear to end of display) if it exists and the result of
3684      *	  the insert is just empty lines
3685      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
3686      *	  present or line_count > 1. It looks better if we do all the inserts
3687      *	  at once.
3688      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
3689      *	  insert is just empty lines and T_CE is not present or line_count >
3690      *	  1.
3691      * 4. Use T_AL (insert line) if it exists.
3692      * 5. Use T_CE (erase line) if it exists and the result of the insert is
3693      *	  just empty lines.
3694      * 6. Use T_DL (delete line) if it exists and the result of the insert is
3695      *	  just empty lines.
3696      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
3697      *	  the 'da' flag is not set or we have clear line capability.
3698      * 8. redraw the characters from ScreenLines[].
3699      *
3700      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
3701      * the scrollbar for the window. It does have insert line, use that if it
3702      * exists.
3703      */
3704     result_empty = (row + line_count >= end);
3705     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3706 	type = USE_REDRAW;
3707     else if (can_clear(T_CD) && result_empty)
3708 	type = USE_T_CD;
3709     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
3710 	type = USE_T_CAL;
3711     else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
3712 	type = USE_T_CDL;
3713     else if (*T_AL != NUL)
3714 	type = USE_T_AL;
3715     else if (can_ce && result_empty)
3716 	type = USE_T_CE;
3717     else if (*T_DL != NUL && result_empty)
3718 	type = USE_T_DL;
3719     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
3720 	type = USE_T_SR;
3721     else
3722 	return FAIL;
3723 
3724     /*
3725      * For clearing the lines screen_del_lines() is used. This will also take
3726      * care of t_db if necessary.
3727      */
3728     if (type == USE_T_CD || type == USE_T_CDL ||
3729 					 type == USE_T_CE || type == USE_T_DL)
3730 	return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
3731 
3732     /*
3733      * If text is retained below the screen, first clear or delete as many
3734      * lines at the bottom of the window as are about to be inserted so that
3735      * the deleted lines won't later surface during a screen_del_lines.
3736      */
3737     if (*T_DB)
3738 	screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
3739 
3740 #ifdef FEAT_CLIPBOARD
3741     // Remove a modeless selection when inserting lines halfway the screen
3742     // or not the full width of the screen.
3743     if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3744 	clip_clear_selection(&clip_star);
3745     else
3746 	clip_scroll_selection(-line_count);
3747 #endif
3748 
3749 #ifdef FEAT_GUI_HAIKU
3750     vim_lock_screen();
3751 #endif
3752 
3753 #ifdef FEAT_GUI
3754     // Don't update the GUI cursor here, ScreenLines[] is invalid until the
3755     // scrolling is actually carried out.
3756     gui_dont_update_cursor(row + off <= gui.cursor_row);
3757 #endif
3758 
3759     if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3760 	cursor_col = wp->w_wincol;
3761 
3762     if (*T_CCS != NUL)	   // cursor relative to region
3763 	cursor_row = row;
3764     else
3765 	cursor_row = row + off;
3766 
3767     /*
3768      * Shift LineOffset[] line_count down to reflect the inserted lines.
3769      * Clear the inserted lines in ScreenLines[].
3770      */
3771     row += off;
3772     end += off;
3773     for (i = 0; i < line_count; ++i)
3774     {
3775 	if (wp != NULL && wp->w_width != Columns)
3776 	{
3777 	    // need to copy part of a line
3778 	    j = end - 1 - i;
3779 	    while ((j -= line_count) >= row)
3780 		linecopy(j + line_count, j, wp);
3781 	    j += line_count;
3782 	    if (can_clear((char_u *)" "))
3783 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
3784 								   clear_attr);
3785 	    else
3786 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
3787 	    LineWraps[j] = FALSE;
3788 	}
3789 	else
3790 	{
3791 	    j = end - 1 - i;
3792 	    temp = LineOffset[j];
3793 	    while ((j -= line_count) >= row)
3794 	    {
3795 		LineOffset[j + line_count] = LineOffset[j];
3796 		LineWraps[j + line_count] = LineWraps[j];
3797 	    }
3798 	    LineOffset[j + line_count] = temp;
3799 	    LineWraps[j + line_count] = FALSE;
3800 	    if (can_clear((char_u *)" "))
3801 		lineclear(temp, (int)Columns, clear_attr);
3802 	    else
3803 		lineinvalid(temp, (int)Columns);
3804 	}
3805     }
3806 
3807 #ifdef FEAT_GUI_HAIKU
3808     vim_unlock_screen();
3809 #endif
3810 
3811     screen_stop_highlight();
3812     windgoto(cursor_row, cursor_col);
3813     if (clear_attr != 0)
3814 	screen_start_highlight(clear_attr);
3815 
3816     // redraw the characters
3817     if (type == USE_REDRAW)
3818 	redraw_block(row, end, wp);
3819     else if (type == USE_T_CAL)
3820     {
3821 	term_append_lines(line_count);
3822 	screen_start();		// don't know where cursor is now
3823     }
3824     else
3825     {
3826 	for (i = 0; i < line_count; i++)
3827 	{
3828 	    if (type == USE_T_AL)
3829 	    {
3830 		if (i && cursor_row != 0)
3831 		    windgoto(cursor_row, cursor_col);
3832 		out_str(T_AL);
3833 	    }
3834 	    else  // type == USE_T_SR
3835 		out_str(T_SR);
3836 	    screen_start();	    // don't know where cursor is now
3837 	}
3838     }
3839 
3840     /*
3841      * With scroll-reverse and 'da' flag set we need to clear the lines that
3842      * have been scrolled down into the region.
3843      */
3844     if (type == USE_T_SR && *T_DA)
3845     {
3846 	for (i = 0; i < line_count; ++i)
3847 	{
3848 	    windgoto(off + i, cursor_col);
3849 	    out_str(T_CE);
3850 	    screen_start();	    // don't know where cursor is now
3851 	}
3852     }
3853 
3854 #ifdef FEAT_GUI
3855     gui_can_update_cursor();
3856     if (gui.in_use)
3857 	out_flush();	// always flush after a scroll
3858 #endif
3859     return OK;
3860 }
3861 
3862 /*
3863  * Delete lines on the screen and update ScreenLines[].
3864  * "end" is the line after the scrolled part. Normally it is Rows.
3865  * When scrolling region used "off" is the offset from the top for the region.
3866  * "row" and "end" are relative to the start of the region.
3867  *
3868  * Return OK for success, FAIL if the lines are not deleted.
3869  */
3870     int
screen_del_lines(int off,int row,int line_count,int end,int force,int clear_attr,win_T * wp UNUSED)3871 screen_del_lines(
3872     int		off,
3873     int		row,
3874     int		line_count,
3875     int		end,
3876     int		force,		// even when line_count > p_ttyscroll
3877     int		clear_attr,	// used for clearing lines
3878     win_T	*wp UNUSED)	// NULL or window to use width from
3879 {
3880     int		j;
3881     int		i;
3882     unsigned	temp;
3883     int		cursor_row;
3884     int		cursor_col = 0;
3885     int		cursor_end;
3886     int		result_empty;	// result is empty until end of region
3887     int		can_delete;	// deleting line codes can be used
3888     int		type;
3889 
3890     /*
3891      * FAIL if
3892      * - there is no valid screen
3893      * - the screen has to be redrawn completely
3894      * - the line count is less than one
3895      * - the line count is more than 'ttyscroll'
3896      * - redrawing for a callback and there is a modeless selection
3897      */
3898     if (!screen_valid(TRUE) || line_count <= 0
3899 					|| (!force && line_count > p_ttyscroll)
3900 #ifdef FEAT_CLIPBOARD
3901 	     || (clip_star.state != SELECT_CLEARED
3902 						 && redrawing_for_callback > 0)
3903 #endif
3904        )
3905 	return FAIL;
3906 
3907     /*
3908      * Check if the rest of the current region will become empty.
3909      */
3910     result_empty = row + line_count >= end;
3911 
3912     /*
3913      * We can delete lines only when 'db' flag not set or when 'ce' option
3914      * available.
3915      */
3916     can_delete = (*T_DB == NUL || can_clear(T_CE));
3917 
3918     /*
3919      * There are six ways to delete lines:
3920      * 0. When in a vertically split window and t_CV isn't set, redraw the
3921      *    characters from ScreenLines[].
3922      * 1. Use T_CD if it exists and the result is empty.
3923      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
3924      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
3925      *	  none of the other ways work.
3926      * 4. Use T_CE (erase line) if the result is empty.
3927      * 5. Use T_DL (delete line) if it exists.
3928      * 6. redraw the characters from ScreenLines[].
3929      */
3930     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
3931 	type = USE_REDRAW;
3932     else if (can_clear(T_CD) && result_empty)
3933 	type = USE_T_CD;
3934     else if (row == 0 && (
3935 #ifndef AMIGA
3936 	// On the Amiga, somehow '\n' on the last line doesn't always scroll
3937 	// up, so use delete-line command
3938 			    line_count == 1 ||
3939 #endif
3940 						*T_CDL == NUL))
3941 	type = USE_NL;
3942     else if (*T_CDL != NUL && line_count > 1 && can_delete)
3943 	type = USE_T_CDL;
3944     else if (can_clear(T_CE) && result_empty
3945 	    && (wp == NULL || wp->w_width == Columns))
3946 	type = USE_T_CE;
3947     else if (*T_DL != NUL && can_delete)
3948 	type = USE_T_DL;
3949     else if (*T_CDL != NUL && can_delete)
3950 	type = USE_T_CDL;
3951     else
3952 	return FAIL;
3953 
3954 #ifdef FEAT_CLIPBOARD
3955     // Remove a modeless selection when deleting lines halfway the screen or
3956     // not the full width of the screen.
3957     if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
3958 	clip_clear_selection(&clip_star);
3959     else
3960 	clip_scroll_selection(line_count);
3961 #endif
3962 
3963 #ifdef FEAT_GUI_HAIKU
3964     vim_lock_screen();
3965 #endif
3966 
3967 #ifdef FEAT_GUI
3968     // Don't update the GUI cursor here, ScreenLines[] is invalid until the
3969     // scrolling is actually carried out.
3970     gui_dont_update_cursor(gui.cursor_row >= row + off
3971 						&& gui.cursor_row < end + off);
3972 #endif
3973 
3974     if (wp != NULL && wp->w_wincol != 0 && *T_CSV != NUL && *T_CCS == NUL)
3975 	cursor_col = wp->w_wincol;
3976 
3977     if (*T_CCS != NUL)	    // cursor relative to region
3978     {
3979 	cursor_row = row;
3980 	cursor_end = end;
3981     }
3982     else
3983     {
3984 	cursor_row = row + off;
3985 	cursor_end = end + off;
3986     }
3987 
3988     /*
3989      * Now shift LineOffset[] line_count up to reflect the deleted lines.
3990      * Clear the inserted lines in ScreenLines[].
3991      */
3992     row += off;
3993     end += off;
3994     for (i = 0; i < line_count; ++i)
3995     {
3996 	if (wp != NULL && wp->w_width != Columns)
3997 	{
3998 	    // need to copy part of a line
3999 	    j = row + i;
4000 	    while ((j += line_count) <= end - 1)
4001 		linecopy(j - line_count, j, wp);
4002 	    j -= line_count;
4003 	    if (can_clear((char_u *)" "))
4004 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
4005 								   clear_attr);
4006 	    else
4007 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
4008 	    LineWraps[j] = FALSE;
4009 	}
4010 	else
4011 	{
4012 	    // whole width, moving the line pointers is faster
4013 	    j = row + i;
4014 	    temp = LineOffset[j];
4015 	    while ((j += line_count) <= end - 1)
4016 	    {
4017 		LineOffset[j - line_count] = LineOffset[j];
4018 		LineWraps[j - line_count] = LineWraps[j];
4019 	    }
4020 	    LineOffset[j - line_count] = temp;
4021 	    LineWraps[j - line_count] = FALSE;
4022 	    if (can_clear((char_u *)" "))
4023 		lineclear(temp, (int)Columns, clear_attr);
4024 	    else
4025 		lineinvalid(temp, (int)Columns);
4026 	}
4027     }
4028 
4029 #ifdef FEAT_GUI_HAIKU
4030     vim_unlock_screen();
4031 #endif
4032 
4033     if (screen_attr != clear_attr)
4034 	screen_stop_highlight();
4035     if (clear_attr != 0)
4036 	screen_start_highlight(clear_attr);
4037 
4038     // redraw the characters
4039     if (type == USE_REDRAW)
4040 	redraw_block(row, end, wp);
4041     else if (type == USE_T_CD)	// delete the lines
4042     {
4043 	windgoto(cursor_row, cursor_col);
4044 	out_str(T_CD);
4045 	screen_start();			// don't know where cursor is now
4046     }
4047     else if (type == USE_T_CDL)
4048     {
4049 	windgoto(cursor_row, cursor_col);
4050 	term_delete_lines(line_count);
4051 	screen_start();			// don't know where cursor is now
4052     }
4053     /*
4054      * Deleting lines at top of the screen or scroll region: Just scroll
4055      * the whole screen (scroll region) up by outputting newlines on the
4056      * last line.
4057      */
4058     else if (type == USE_NL)
4059     {
4060 	windgoto(cursor_end - 1, cursor_col);
4061 	for (i = line_count; --i >= 0; )
4062 	    out_char('\n');		// cursor will remain on same line
4063     }
4064     else
4065     {
4066 	for (i = line_count; --i >= 0; )
4067 	{
4068 	    if (type == USE_T_DL)
4069 	    {
4070 		windgoto(cursor_row, cursor_col);
4071 		out_str(T_DL);		// delete a line
4072 	    }
4073 	    else // type == USE_T_CE
4074 	    {
4075 		windgoto(cursor_row + i, cursor_col);
4076 		out_str(T_CE);		// erase a line
4077 	    }
4078 	    screen_start();		// don't know where cursor is now
4079 	}
4080     }
4081 
4082     /*
4083      * If the 'db' flag is set, we need to clear the lines that have been
4084      * scrolled up at the bottom of the region.
4085      */
4086     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
4087     {
4088 	for (i = line_count; i > 0; --i)
4089 	{
4090 	    windgoto(cursor_end - i, cursor_col);
4091 	    out_str(T_CE);		// erase a line
4092 	    screen_start();		// don't know where cursor is now
4093 	}
4094     }
4095 
4096 #ifdef FEAT_GUI
4097     gui_can_update_cursor();
4098     if (gui.in_use)
4099 	out_flush();	// always flush after a scroll
4100 #endif
4101 
4102     return OK;
4103 }
4104 
4105 /*
4106  * Return TRUE when postponing displaying the mode message: when not redrawing
4107  * or inside a mapping.
4108  */
4109     int
skip_showmode()4110 skip_showmode()
4111 {
4112     // Call char_avail() only when we are going to show something, because it
4113     // takes a bit of time.  redrawing() may also call char_avail_avail().
4114     if (global_busy
4115 	    || msg_silent != 0
4116 	    || !redrawing()
4117 	    || (char_avail() && !KeyTyped))
4118     {
4119 	redraw_mode = TRUE;		// show mode later
4120 	return TRUE;
4121     }
4122     return FALSE;
4123 }
4124 
4125 /*
4126  * Show the current mode and ruler.
4127  *
4128  * If clear_cmdline is TRUE, clear the rest of the cmdline.
4129  * If clear_cmdline is FALSE there may be a message there that needs to be
4130  * cleared only if a mode is shown.
4131  * If redraw_mode is TRUE show or clear the mode.
4132  * Return the length of the message (0 if no message).
4133  */
4134     int
showmode(void)4135 showmode(void)
4136 {
4137     int		need_clear;
4138     int		length = 0;
4139     int		do_mode;
4140     int		attr;
4141     int		nwr_save;
4142     int		sub_attr;
4143 
4144     do_mode = ((p_smd && msg_silent == 0)
4145 	    && ((State & INSERT)
4146 		|| restart_edit != NUL
4147 		|| VIsual_active));
4148     if (do_mode || reg_recording != 0)
4149     {
4150 	if (skip_showmode())
4151 	    return 0;		// show mode later
4152 
4153 	nwr_save = need_wait_return;
4154 
4155 	// wait a bit before overwriting an important message
4156 	check_for_delay(FALSE);
4157 
4158 	// if the cmdline is more than one line high, erase top lines
4159 	need_clear = clear_cmdline;
4160 	if (clear_cmdline && cmdline_row < Rows - 1)
4161 	    msg_clr_cmdline();			// will reset clear_cmdline
4162 
4163 	// Position on the last line in the window, column 0
4164 	msg_pos_mode();
4165 	cursor_off();
4166 	attr = HL_ATTR(HLF_CM);			// Highlight mode
4167 	if (do_mode)
4168 	{
4169 	    msg_puts_attr("--", attr);
4170 #if defined(FEAT_XIM)
4171 	    if (
4172 # ifdef FEAT_GUI_GTK
4173 		    preedit_get_status()
4174 # else
4175 		    im_get_status()
4176 # endif
4177 	       )
4178 # ifdef FEAT_GUI_GTK // most of the time, it's not XIM being used
4179 		msg_puts_attr(" IM", attr);
4180 # else
4181 		msg_puts_attr(" XIM", attr);
4182 # endif
4183 #endif
4184 	    // CTRL-X in Insert mode
4185 	    if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
4186 	    {
4187 		// These messages can get long, avoid a wrap in a narrow
4188 		// window.  Prefer showing edit_submode_extra.
4189 		length = (Rows - msg_row) * Columns - 3;
4190 		if (edit_submode_extra != NULL)
4191 		    length -= vim_strsize(edit_submode_extra);
4192 		if (length > 0)
4193 		{
4194 		    if (edit_submode_pre != NULL)
4195 			length -= vim_strsize(edit_submode_pre);
4196 		    if (length - vim_strsize(edit_submode) > 0)
4197 		    {
4198 			if (edit_submode_pre != NULL)
4199 			    msg_puts_attr((char *)edit_submode_pre, attr);
4200 			msg_puts_attr((char *)edit_submode, attr);
4201 		    }
4202 		    if (edit_submode_extra != NULL)
4203 		    {
4204 			msg_puts_attr(" ", attr);  // add a space in between
4205 			if ((int)edit_submode_highl < (int)HLF_COUNT)
4206 			    sub_attr = HL_ATTR(edit_submode_highl);
4207 			else
4208 			    sub_attr = attr;
4209 			msg_puts_attr((char *)edit_submode_extra, sub_attr);
4210 		    }
4211 		}
4212 	    }
4213 	    else
4214 	    {
4215 		if (State & VREPLACE_FLAG)
4216 		    msg_puts_attr(_(" VREPLACE"), attr);
4217 		else if (State & REPLACE_FLAG)
4218 		    msg_puts_attr(_(" REPLACE"), attr);
4219 		else if (State & INSERT)
4220 		{
4221 #ifdef FEAT_RIGHTLEFT
4222 		    if (p_ri)
4223 			msg_puts_attr(_(" REVERSE"), attr);
4224 #endif
4225 		    msg_puts_attr(_(" INSERT"), attr);
4226 		}
4227 		else if (restart_edit == 'I' || restart_edit == 'i' ||
4228 			restart_edit == 'a' || restart_edit == 'A')
4229 		    msg_puts_attr(_(" (insert)"), attr);
4230 		else if (restart_edit == 'R')
4231 		    msg_puts_attr(_(" (replace)"), attr);
4232 		else if (restart_edit == 'V')
4233 		    msg_puts_attr(_(" (vreplace)"), attr);
4234 #ifdef FEAT_RIGHTLEFT
4235 		if (p_hkmap)
4236 		    msg_puts_attr(_(" Hebrew"), attr);
4237 #endif
4238 #ifdef FEAT_KEYMAP
4239 		if (State & LANGMAP)
4240 		{
4241 # ifdef FEAT_ARABIC
4242 		    if (curwin->w_p_arab)
4243 			msg_puts_attr(_(" Arabic"), attr);
4244 		    else
4245 # endif
4246 			if (get_keymap_str(curwin, (char_u *)" (%s)",
4247 							   NameBuff, MAXPATHL))
4248 			    msg_puts_attr((char *)NameBuff, attr);
4249 		}
4250 #endif
4251 		if ((State & INSERT) && p_paste)
4252 		    msg_puts_attr(_(" (paste)"), attr);
4253 
4254 		if (VIsual_active)
4255 		{
4256 		    char *p;
4257 
4258 		    // Don't concatenate separate words to avoid translation
4259 		    // problems.
4260 		    switch ((VIsual_select ? 4 : 0)
4261 			    + (VIsual_mode == Ctrl_V) * 2
4262 			    + (VIsual_mode == 'V'))
4263 		    {
4264 			case 0:	p = N_(" VISUAL"); break;
4265 			case 1: p = N_(" VISUAL LINE"); break;
4266 			case 2: p = N_(" VISUAL BLOCK"); break;
4267 			case 4: p = N_(" SELECT"); break;
4268 			case 5: p = N_(" SELECT LINE"); break;
4269 			default: p = N_(" SELECT BLOCK"); break;
4270 		    }
4271 		    msg_puts_attr(_(p), attr);
4272 		}
4273 		msg_puts_attr(" --", attr);
4274 	    }
4275 
4276 	    need_clear = TRUE;
4277 	}
4278 	if (reg_recording != 0
4279 		&& edit_submode == NULL)    // otherwise it gets too long
4280 	{
4281 	    recording_mode(attr);
4282 	    need_clear = TRUE;
4283 	}
4284 
4285 	mode_displayed = TRUE;
4286 	if (need_clear || clear_cmdline || redraw_mode)
4287 	    msg_clr_eos();
4288 	msg_didout = FALSE;		// overwrite this message
4289 	length = msg_col;
4290 	msg_col = 0;
4291 	need_wait_return = nwr_save;	// never ask for hit-return for this
4292     }
4293     else if (clear_cmdline && msg_silent == 0)
4294 	// Clear the whole command line.  Will reset "clear_cmdline".
4295 	msg_clr_cmdline();
4296     else if (redraw_mode)
4297     {
4298 	msg_pos_mode();
4299 	msg_clr_eos();
4300     }
4301 
4302 #ifdef FEAT_CMDL_INFO
4303     // In Visual mode the size of the selected area must be redrawn.
4304     if (VIsual_active)
4305 	clear_showcmd();
4306 
4307     // If the last window has no status line, the ruler is after the mode
4308     // message and must be redrawn
4309     if (redrawing() && lastwin->w_status_height == 0)
4310 	win_redr_ruler(lastwin, TRUE, FALSE);
4311 #endif
4312     redraw_cmdline = FALSE;
4313     redraw_mode = FALSE;
4314     clear_cmdline = FALSE;
4315 
4316     return length;
4317 }
4318 
4319 /*
4320  * Position for a mode message.
4321  */
4322     static void
msg_pos_mode(void)4323 msg_pos_mode(void)
4324 {
4325     msg_col = 0;
4326     msg_row = Rows - 1;
4327 }
4328 
4329 /*
4330  * Delete mode message.  Used when ESC is typed which is expected to end
4331  * Insert mode (but Insert mode didn't end yet!).
4332  * Caller should check "mode_displayed".
4333  */
4334     void
unshowmode(int force)4335 unshowmode(int force)
4336 {
4337     /*
4338      * Don't delete it right now, when not redrawing or inside a mapping.
4339      */
4340     if (!redrawing() || (!force && char_avail() && !KeyTyped))
4341 	redraw_cmdline = TRUE;		// delete mode later
4342     else
4343 	clearmode();
4344 }
4345 
4346 /*
4347  * Clear the mode message.
4348  */
4349     void
clearmode(void)4350 clearmode(void)
4351 {
4352     int save_msg_row = msg_row;
4353     int save_msg_col = msg_col;
4354 
4355     msg_pos_mode();
4356     if (reg_recording != 0)
4357 	recording_mode(HL_ATTR(HLF_CM));
4358     msg_clr_eos();
4359 
4360     msg_col = save_msg_col;
4361     msg_row = save_msg_row;
4362 }
4363 
4364     static void
recording_mode(int attr)4365 recording_mode(int attr)
4366 {
4367     msg_puts_attr(_("recording"), attr);
4368     if (!shortmess(SHM_RECORDING))
4369     {
4370 	char s[4];
4371 
4372 	sprintf(s, " @%c", reg_recording);
4373 	msg_puts_attr(s, attr);
4374     }
4375 }
4376 
4377 /*
4378  * Draw the tab pages line at the top of the Vim window.
4379  */
4380     void
draw_tabline(void)4381 draw_tabline(void)
4382 {
4383     int		tabcount = 0;
4384     tabpage_T	*tp;
4385     int		tabwidth;
4386     int		col = 0;
4387     int		scol = 0;
4388     int		attr;
4389     win_T	*wp;
4390     win_T	*cwp;
4391     int		wincount;
4392     int		modified;
4393     int		c;
4394     int		len;
4395     int		attr_sel = HL_ATTR(HLF_TPS);
4396     int		attr_nosel = HL_ATTR(HLF_TP);
4397     int		attr_fill = HL_ATTR(HLF_TPF);
4398     char_u	*p;
4399     int		room;
4400     int		use_sep_chars = (t_colors < 8
4401 #ifdef FEAT_GUI
4402 					    && !gui.in_use
4403 #endif
4404 #ifdef FEAT_TERMGUICOLORS
4405 					    && !p_tgc
4406 #endif
4407 					    );
4408 
4409     if (ScreenLines == NULL)
4410 	return;
4411     redraw_tabline = FALSE;
4412 
4413 #ifdef FEAT_GUI_TABLINE
4414     // Take care of a GUI tabline.
4415     if (gui_use_tabline())
4416     {
4417 	gui_update_tabline();
4418 	return;
4419     }
4420 #endif
4421 
4422     if (tabline_height() < 1)
4423 	return;
4424 
4425 #if defined(FEAT_STL_OPT)
4426     clear_TabPageIdxs();
4427 
4428     // Use the 'tabline' option if it's set.
4429     if (*p_tal != NUL)
4430     {
4431 	int	saved_did_emsg = did_emsg;
4432 
4433 	// Check for an error.  If there is one we would loop in redrawing the
4434 	// screen.  Avoid that by making 'tabline' empty.
4435 	did_emsg = FALSE;
4436 	win_redr_custom(NULL, FALSE);
4437 	if (did_emsg)
4438 	    set_string_option_direct((char_u *)"tabline", -1,
4439 					   (char_u *)"", OPT_FREE, SID_ERROR);
4440 	did_emsg |= saved_did_emsg;
4441     }
4442     else
4443 #endif
4444     {
4445 	FOR_ALL_TABPAGES(tp)
4446 	    ++tabcount;
4447 
4448 	tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
4449 	if (tabwidth < 6)
4450 	    tabwidth = 6;
4451 
4452 	attr = attr_nosel;
4453 	tabcount = 0;
4454 	for (tp = first_tabpage; tp != NULL && col < Columns - 4;
4455 							     tp = tp->tp_next)
4456 	{
4457 	    scol = col;
4458 
4459 	    if (tp->tp_topframe == topframe)
4460 		attr = attr_sel;
4461 	    if (use_sep_chars && col > 0)
4462 		screen_putchar('|', 0, col++, attr);
4463 
4464 	    if (tp->tp_topframe != topframe)
4465 		attr = attr_nosel;
4466 
4467 	    screen_putchar(' ', 0, col++, attr);
4468 
4469 	    if (tp == curtab)
4470 	    {
4471 		cwp = curwin;
4472 		wp = firstwin;
4473 	    }
4474 	    else
4475 	    {
4476 		cwp = tp->tp_curwin;
4477 		wp = tp->tp_firstwin;
4478 	    }
4479 
4480 	    modified = FALSE;
4481 	    for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
4482 		if (bufIsChanged(wp->w_buffer))
4483 		    modified = TRUE;
4484 	    if (modified || wincount > 1)
4485 	    {
4486 		if (wincount > 1)
4487 		{
4488 		    vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
4489 		    len = (int)STRLEN(NameBuff);
4490 		    if (col + len >= Columns - 3)
4491 			break;
4492 		    screen_puts_len(NameBuff, len, 0, col,
4493 #if defined(FEAT_SYN_HL)
4494 					 hl_combine_attr(attr, HL_ATTR(HLF_T))
4495 #else
4496 					 attr
4497 #endif
4498 					       );
4499 		    col += len;
4500 		}
4501 		if (modified)
4502 		    screen_puts_len((char_u *)"+", 1, 0, col++, attr);
4503 		screen_putchar(' ', 0, col++, attr);
4504 	    }
4505 
4506 	    room = scol - col + tabwidth - 1;
4507 	    if (room > 0)
4508 	    {
4509 		// Get buffer name in NameBuff[]
4510 		get_trans_bufname(cwp->w_buffer);
4511 		shorten_dir(NameBuff);
4512 		len = vim_strsize(NameBuff);
4513 		p = NameBuff;
4514 		if (has_mbyte)
4515 		    while (len > room)
4516 		    {
4517 			len -= ptr2cells(p);
4518 			MB_PTR_ADV(p);
4519 		    }
4520 		else if (len > room)
4521 		{
4522 		    p += len - room;
4523 		    len = room;
4524 		}
4525 		if (len > Columns - col - 1)
4526 		    len = Columns - col - 1;
4527 
4528 		screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
4529 		col += len;
4530 	    }
4531 	    screen_putchar(' ', 0, col++, attr);
4532 
4533 	    // Store the tab page number in TabPageIdxs[], so that
4534 	    // jump_to_mouse() knows where each one is.
4535 	    ++tabcount;
4536 	    while (scol < col)
4537 		TabPageIdxs[scol++] = tabcount;
4538 	}
4539 
4540 	if (use_sep_chars)
4541 	    c = '_';
4542 	else
4543 	    c = ' ';
4544 	screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
4545 
4546 	// Put an "X" for closing the current tab if there are several.
4547 	if (first_tabpage->tp_next != NULL)
4548 	{
4549 	    screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
4550 	    TabPageIdxs[Columns - 1] = -999;
4551 	}
4552     }
4553 
4554     // Reset the flag here again, in case evaluating 'tabline' causes it to be
4555     // set.
4556     redraw_tabline = FALSE;
4557 }
4558 
4559 /*
4560  * Get buffer name for "buf" into NameBuff[].
4561  * Takes care of special buffer names and translates special characters.
4562  */
4563     void
get_trans_bufname(buf_T * buf)4564 get_trans_bufname(buf_T *buf)
4565 {
4566     if (buf_spname(buf) != NULL)
4567 	vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
4568     else
4569 	home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
4570     trans_characters(NameBuff, MAXPATHL);
4571 }
4572 
4573 /*
4574  * Get the character to use in a status line.  Get its attributes in "*attr".
4575  */
4576     int
fillchar_status(int * attr,win_T * wp)4577 fillchar_status(int *attr, win_T *wp)
4578 {
4579     int fill;
4580 
4581 #ifdef FEAT_TERMINAL
4582     if (bt_terminal(wp->w_buffer))
4583     {
4584 	if (wp == curwin)
4585 	{
4586 	    *attr = HL_ATTR(HLF_ST);
4587 	    fill = fill_stl;
4588 	}
4589 	else
4590 	{
4591 	    *attr = HL_ATTR(HLF_STNC);
4592 	    fill = fill_stlnc;
4593 	}
4594     }
4595     else
4596 #endif
4597     if (wp == curwin)
4598     {
4599 	*attr = HL_ATTR(HLF_S);
4600 	fill = fill_stl;
4601     }
4602     else
4603     {
4604 	*attr = HL_ATTR(HLF_SNC);
4605 	fill = fill_stlnc;
4606     }
4607     // Use fill when there is highlighting, and highlighting of current
4608     // window differs, or the fillchars differ, or this is not the
4609     // current window
4610     if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC)
4611 			|| wp != curwin || ONE_WINDOW)
4612 		    || (fill_stl != fill_stlnc)))
4613 	return fill;
4614     if (wp == curwin)
4615 	return '^';
4616     return '=';
4617 }
4618 
4619 /*
4620  * Get the character to use in a separator between vertically split windows.
4621  * Get its attributes in "*attr".
4622  */
4623     int
fillchar_vsep(int * attr)4624 fillchar_vsep(int *attr)
4625 {
4626     *attr = HL_ATTR(HLF_C);
4627     if (*attr == 0 && fill_vert == ' ')
4628 	return '|';
4629     else
4630 	return fill_vert;
4631 }
4632 
4633 /*
4634  * Return TRUE if redrawing should currently be done.
4635  */
4636     int
redrawing(void)4637 redrawing(void)
4638 {
4639 #ifdef FEAT_EVAL
4640     if (disable_redraw_for_testing)
4641 	return 0;
4642     else
4643 #endif
4644 	return ((!RedrawingDisabled
4645 #ifdef FEAT_EVAL
4646 		    || ignore_redraw_flag_for_testing
4647 #endif
4648 		) && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
4649 }
4650 
4651 /*
4652  * Return TRUE if printing messages should currently be done.
4653  */
4654     int
messaging(void)4655 messaging(void)
4656 {
4657     return (!(p_lz && char_avail() && !KeyTyped));
4658 }
4659 
4660 /*
4661  * Compute columns for ruler and shown command. 'sc_col' is also used to
4662  * decide what the maximum length of a message on the status line can be.
4663  * If there is a status line for the last window, 'sc_col' is independent
4664  * of 'ru_col'.
4665  */
4666 
4667 #define COL_RULER 17	    // columns needed by standard ruler
4668 
4669     void
comp_col(void)4670 comp_col(void)
4671 {
4672 #if defined(FEAT_CMDL_INFO)
4673     int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
4674 
4675     sc_col = 0;
4676     ru_col = 0;
4677     if (p_ru)
4678     {
4679 # ifdef FEAT_STL_OPT
4680 	ru_col = (ru_wid ? ru_wid : COL_RULER) + 1;
4681 # else
4682 	ru_col = COL_RULER + 1;
4683 # endif
4684 	// no last status line, adjust sc_col
4685 	if (!last_has_status)
4686 	    sc_col = ru_col;
4687     }
4688     if (p_sc)
4689     {
4690 	sc_col += SHOWCMD_COLS;
4691 	if (!p_ru || last_has_status)	    // no need for separating space
4692 	    ++sc_col;
4693     }
4694     sc_col = Columns - sc_col;
4695     ru_col = Columns - ru_col;
4696     if (sc_col <= 0)		// screen too narrow, will become a mess
4697 	sc_col = 1;
4698     if (ru_col <= 0)
4699 	ru_col = 1;
4700 #else
4701     sc_col = Columns;
4702     ru_col = Columns;
4703 #endif
4704 #ifdef FEAT_EVAL
4705     set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
4706 #endif
4707 }
4708 
4709 #if defined(FEAT_LINEBREAK) || defined(PROTO)
4710 /*
4711  * Return the width of the 'number' and 'relativenumber' column.
4712  * Caller may need to check if 'number' or 'relativenumber' is set.
4713  * Otherwise it depends on 'numberwidth' and the line count.
4714  */
4715     int
number_width(win_T * wp)4716 number_width(win_T *wp)
4717 {
4718     int		n;
4719     linenr_T	lnum;
4720 
4721     if (wp->w_p_rnu && !wp->w_p_nu)
4722 	// cursor line shows "0"
4723 	lnum = wp->w_height;
4724     else
4725 	// cursor line shows absolute line number
4726 	lnum = wp->w_buffer->b_ml.ml_line_count;
4727 
4728     if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
4729 	return wp->w_nrwidth_width;
4730     wp->w_nrwidth_line_count = lnum;
4731 
4732     n = 0;
4733     do
4734     {
4735 	lnum /= 10;
4736 	++n;
4737     } while (lnum > 0);
4738 
4739     // 'numberwidth' gives the minimal width plus one
4740     if (n < wp->w_p_nuw - 1)
4741 	n = wp->w_p_nuw - 1;
4742 
4743 # ifdef FEAT_SIGNS
4744     // If 'signcolumn' is set to 'number' and there is a sign to display, then
4745     // the minimal width for the number column is 2.
4746     if (n < 2 && get_first_valid_sign(wp) != NULL
4747 	    && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'))
4748 	n = 2;
4749 # endif
4750 
4751     wp->w_nrwidth_width = n;
4752     wp->w_nuw_cached = wp->w_p_nuw;
4753     return n;
4754 }
4755 #endif
4756 
4757 #if defined(FEAT_EVAL) || defined(PROTO)
4758 /*
4759  * Return the current cursor column. This is the actual position on the
4760  * screen. First column is 0.
4761  */
4762     int
screen_screencol(void)4763 screen_screencol(void)
4764 {
4765     return screen_cur_col;
4766 }
4767 
4768 /*
4769  * Return the current cursor row. This is the actual position on the screen.
4770  * First row is 0.
4771  */
4772     int
screen_screenrow(void)4773 screen_screenrow(void)
4774 {
4775     return screen_cur_row;
4776 }
4777 #endif
4778 
4779 /*
4780  * Calls mb_ptr2char_adv(p) and returns the character.
4781  * If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
4782  */
4783     static int
get_encoded_char_adv(char_u ** p)4784 get_encoded_char_adv(char_u **p)
4785 {
4786     char_u *s = *p;
4787 
4788     if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U'))
4789     {
4790 	varnumber_T num = 0;
4791 	int	    bytes;
4792 	int	    n;
4793 
4794 	for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; --bytes)
4795 	{
4796 	    *p += 2;
4797 	    n = hexhex2nr(*p);
4798 	    if (n < 0)
4799 		return 0;
4800 	    num = num * 256 + n;
4801 	}
4802 	*p += 2;
4803 	return num;
4804     }
4805     return mb_ptr2char_adv(p);
4806 }
4807 
4808 /*
4809  * Handle setting 'listchars' or 'fillchars'.
4810  * Assume monocell characters.
4811  * Returns error message, NULL if it's OK.
4812  */
4813     char *
set_chars_option(win_T * wp,char_u ** varp)4814 set_chars_option(win_T *wp, char_u **varp)
4815 {
4816     int		round, i, len, entries;
4817     char_u	*p, *s;
4818     int		c1 = 0, c2 = 0, c3 = 0;
4819     char_u	*last_multispace = NULL; // Last occurrence of "multispace:"
4820     int		multispace_len = 0;	 // Length of lcs-multispace string
4821     struct charstab
4822     {
4823 	int	*cp;
4824 	char	*name;
4825     };
4826     static struct charstab filltab[] =
4827     {
4828 	{&fill_stl,		"stl"},
4829 	{&fill_stlnc,		"stlnc"},
4830 	{&fill_vert,		"vert"},
4831 	{&fill_fold,		"fold"},
4832 	{&fill_foldopen,	"foldopen"},
4833 	{&fill_foldclosed,	"foldclose"},
4834 	{&fill_foldsep,		"foldsep"},
4835 	{&fill_diff,		"diff"},
4836 	{&fill_eob,		"eob"},
4837     };
4838     static lcs_chars_T lcs_chars;
4839     struct charstab lcstab[] =
4840     {
4841 	{&lcs_chars.eol,	"eol"},
4842 	{&lcs_chars.ext,	"extends"},
4843 	{&lcs_chars.nbsp,	"nbsp"},
4844 	{&lcs_chars.prec,	"precedes"},
4845 	{&lcs_chars.space,	"space"},
4846 	{&lcs_chars.tab2,	"tab"},
4847 	{&lcs_chars.trail,	"trail"},
4848 	{&lcs_chars.lead,	"lead"},
4849 #ifdef FEAT_CONCEAL
4850 	{&lcs_chars.conceal,	"conceal"},
4851 #else
4852 	{NULL,			"conceal"},
4853 #endif
4854     };
4855     struct charstab *tab;
4856 
4857     if (varp == &p_lcs || varp == &wp->w_p_lcs)
4858     {
4859 	tab = lcstab;
4860 	CLEAR_FIELD(lcs_chars);
4861 	entries = ARRAY_LENGTH(lcstab);
4862 	if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL)
4863 	    varp = &p_lcs;
4864     }
4865     else
4866     {
4867 	tab = filltab;
4868 	entries = ARRAY_LENGTH(filltab);
4869     }
4870 
4871     // first round: check for valid value, second round: assign values
4872     for (round = 0; round <= 1; ++round)
4873     {
4874 	if (round > 0)
4875 	{
4876 	    // After checking that the value is valid: set defaults: space for
4877 	    // 'fillchars', NUL for 'listchars'
4878 	    for (i = 0; i < entries; ++i)
4879 		if (tab[i].cp != NULL)
4880 		    *(tab[i].cp) =
4881 			((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' ');
4882 
4883 	    if (varp == &p_lcs || varp == &wp->w_p_lcs)
4884 	    {
4885 		lcs_chars.tab1 = NUL;
4886 		lcs_chars.tab3 = NUL;
4887 		if (multispace_len > 0)
4888 		{
4889 		    lcs_chars.multispace = ALLOC_MULT(int, multispace_len + 1);
4890 		    lcs_chars.multispace[multispace_len] = NUL;
4891 		}
4892 		else
4893 		    lcs_chars.multispace = NULL;
4894 	    }
4895 	    else
4896 	    {
4897 		fill_diff = '-';
4898 		fill_foldopen = '-';
4899 		fill_foldclosed = '+';
4900 		fill_foldsep = '|';
4901 		fill_eob = '~';
4902 	    }
4903 	}
4904 	p = *varp;
4905 	while (*p)
4906 	{
4907 	    for (i = 0; i < entries; ++i)
4908 	    {
4909 		len = (int)STRLEN(tab[i].name);
4910 		if (STRNCMP(p, tab[i].name, len) == 0
4911 			&& p[len] == ':'
4912 			&& p[len + 1] != NUL)
4913 		{
4914 		    c2 = c3 = 0;
4915 		    s = p + len + 1;
4916 		    c1 = get_encoded_char_adv(&s);
4917 		    if (mb_char2cells(c1) > 1)
4918 			return e_invarg;
4919 		    if (tab[i].cp == &lcs_chars.tab2)
4920 		    {
4921 			if (*s == NUL)
4922 			    return e_invarg;
4923 			c2 = get_encoded_char_adv(&s);
4924 			if (mb_char2cells(c2) > 1)
4925 			    return e_invarg;
4926 			if (!(*s == ',' || *s == NUL))
4927 			{
4928 			    c3 = get_encoded_char_adv(&s);
4929 			    if (mb_char2cells(c3) > 1)
4930 				return e_invarg;
4931 			}
4932 		    }
4933 
4934 		    if (*s == ',' || *s == NUL)
4935 		    {
4936 			if (round > 0)
4937 			{
4938 			    if (tab[i].cp == &lcs_chars.tab2)
4939 			    {
4940 				lcs_chars.tab1 = c1;
4941 				lcs_chars.tab2 = c2;
4942 				lcs_chars.tab3 = c3;
4943 			    }
4944 			    else if (tab[i].cp != NULL)
4945 				*(tab[i].cp) = c1;
4946 
4947 			}
4948 			p = s;
4949 			break;
4950 		    }
4951 		}
4952 	    }
4953 
4954 	    if (i == entries)
4955 	    {
4956 		len = (int)STRLEN("multispace");
4957 		if ((varp == &p_lcs || varp == &wp->w_p_lcs)
4958 			&& STRNCMP(p, "multispace", len) == 0
4959 			&& p[len] == ':'
4960 			&& p[len + 1] != NUL)
4961 		{
4962 		    s = p + len + 1;
4963 		    if (round == 0)
4964 		    {
4965 			// Get length of lcs-multispace string in first round
4966 			last_multispace = p;
4967 			multispace_len = 0;
4968 			while (*s != NUL && *s != ',')
4969 			{
4970 			    c1 = get_encoded_char_adv(&s);
4971 			    if (mb_char2cells(c1) > 1)
4972 				return e_invarg;
4973 			    ++multispace_len;
4974 			}
4975 			if (multispace_len == 0)
4976 			    // lcs-multispace cannot be an empty string
4977 			    return e_invarg;
4978 			p = s;
4979 		    }
4980 		    else
4981 		    {
4982 			int multispace_pos = 0;
4983 
4984 			while (*s != NUL && *s != ',')
4985 			{
4986 			    c1 = get_encoded_char_adv(&s);
4987 			    if (p == last_multispace)
4988 				lcs_chars.multispace[multispace_pos++] = c1;
4989 			}
4990 			p = s;
4991 		    }
4992 		}
4993 		else
4994 		    return e_invarg;
4995 	    }
4996 
4997 	    if (*p == ',')
4998 		++p;
4999 	}
5000     }
5001     if (tab == lcstab)
5002     {
5003 	if (wp->w_lcs_chars.multispace != NULL)
5004 	    vim_free(wp->w_lcs_chars.multispace);
5005 	wp->w_lcs_chars = lcs_chars;
5006     }
5007 
5008     return NULL;	// no error
5009 }
5010 
5011