xref: /vim-8.2.3635/src/drawscreen.c (revision f3caeb63)
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  * drawscreen.c: Code for updating all the windows on the screen.
12  * This is the top level, drawline.c is the middle and screen.c the lower
13  * level.
14  *
15  * update_screen() is the function that updates all windows and status lines.
16  * It is called form the main loop when must_redraw is non-zero.  It may be
17  * called from other places when an immediate screen update is needed.
18  *
19  * The part of the buffer that is displayed in a window is set with:
20  * - w_topline (first buffer line in window)
21  * - w_topfill (filler lines above the first line)
22  * - w_leftcol (leftmost window cell in window),
23  * - w_skipcol (skipped window cells of first line)
24  *
25  * Commands that only move the cursor around in a window, do not need to take
26  * action to update the display.  The main loop will check if w_topline is
27  * valid and update it (scroll the window) when needed.
28  *
29  * Commands that scroll a window change w_topline and must call
30  * check_cursor() to move the cursor into the visible part of the window, and
31  * call redraw_later(VALID) to have the window displayed by update_screen()
32  * later.
33  *
34  * Commands that change text in the buffer must call changed_bytes() or
35  * changed_lines() to mark the area that changed and will require updating
36  * later.  The main loop will call update_screen(), which will update each
37  * window that shows the changed buffer.  This assumes text above the change
38  * can remain displayed as it is.  Text after the change may need updating for
39  * scrolling, folding and syntax highlighting.
40  *
41  * Commands that change how a window is displayed (e.g., setting 'list') or
42  * invalidate the contents of a window in another way (e.g., change fold
43  * settings), must call redraw_later(NOT_VALID) to have the whole window
44  * redisplayed by update_screen() later.
45  *
46  * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
47  * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
48  * buffer redisplayed by update_screen() later.
49  *
50  * Commands that change highlighting and possibly cause a scroll too must call
51  * redraw_later(SOME_VALID) to update the whole window but still use scrolling
52  * to avoid redrawing everything.  But the length of displayed lines must not
53  * change, use NOT_VALID then.
54  *
55  * Commands that move the window position must call redraw_later(NOT_VALID).
56  * TODO: should minimize redrawing by scrolling when possible.
57  *
58  * Commands that change everything (e.g., resizing the screen) must call
59  * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
60  *
61  * Things that are handled indirectly:
62  * - When messages scroll the screen up, msg_scrolled will be set and
63  *   update_screen() called to redraw.
64  */
65 
66 #include "vim.h"
67 
68 static void win_update(win_T *wp);
69 #ifdef FEAT_STL_OPT
70 static void redraw_custom_statusline(win_T *wp);
71 #endif
72 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
73 static int  did_update_one_window;
74 #endif
75 
76 static void win_redr_status(win_T *wp, int ignore_pum);
77 
78 /*
79  * Based on the current value of curwin->w_topline, transfer a screenfull
80  * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
81  * Return OK when the screen was updated, FAIL if it was not done.
82  */
83     int
84 update_screen(int type_arg)
85 {
86     int		type = type_arg;
87     win_T	*wp;
88     static int	did_intro = FALSE;
89 #ifdef FEAT_GUI
90     int		did_one = FALSE;
91     int		did_undraw = FALSE;
92     int		gui_cursor_col = 0;
93     int		gui_cursor_row = 0;
94 #endif
95     int		no_update = FALSE;
96     int		save_pum_will_redraw = pum_will_redraw;
97 
98     // Don't do anything if the screen structures are (not yet) valid.
99     if (!screen_valid(TRUE))
100 	return FAIL;
101 
102     if (type == VALID_NO_UPDATE)
103     {
104 	no_update = TRUE;
105 	type = 0;
106     }
107 
108 #ifdef FEAT_EVAL
109     {
110 	buf_T *buf;
111 
112 	// Before updating the screen, notify any listeners of changed text.
113 	FOR_ALL_BUFFERS(buf)
114 	    invoke_listeners(buf);
115     }
116 #endif
117 
118 #ifdef FEAT_DIFF
119     // May have postponed updating diffs.
120     if (need_diff_redraw)
121 	diff_redraw(TRUE);
122 #endif
123 
124     if (must_redraw)
125     {
126 	if (type < must_redraw)	    // use maximal type
127 	    type = must_redraw;
128 
129 	// must_redraw is reset here, so that when we run into some weird
130 	// reason to redraw while busy redrawing (e.g., asynchronous
131 	// scrolling), or update_topline() in win_update() will cause a
132 	// scroll, the screen will be redrawn later or in win_update().
133 	must_redraw = 0;
134     }
135 
136     // May need to update w_lines[].
137     if (curwin->w_lines_valid == 0 && type < NOT_VALID
138 #ifdef FEAT_TERMINAL
139 	    && !term_do_update_window(curwin)
140 #endif
141 		)
142 	type = NOT_VALID;
143 
144     // Postpone the redrawing when it's not needed and when being called
145     // recursively.
146     if (!redrawing() || updating_screen)
147     {
148 	redraw_later(type);		// remember type for next time
149 	must_redraw = type;
150 	if (type > INVERTED_ALL)
151 	    curwin->w_lines_valid = 0;	// don't use w_lines[].wl_size now
152 	return FAIL;
153     }
154     updating_screen = TRUE;
155 
156 #ifdef FEAT_PROP_POPUP
157     // Update popup_mask if needed.  This may set w_redraw_top and w_redraw_bot
158     // in some windows.
159     may_update_popup_mask(type);
160 #endif
161 
162 #ifdef FEAT_SYN_HL
163     ++display_tick;	    // let syntax code know we're in a next round of
164 			    // display updating
165 #endif
166     if (no_update)
167 	++no_win_do_lines_ins;
168 
169     // if the screen was scrolled up when displaying a message, scroll it down
170     if (msg_scrolled)
171     {
172 	clear_cmdline = TRUE;
173 	if (msg_scrolled > Rows - 5)	    // clearing is faster
174 	    type = CLEAR;
175 	else if (type != CLEAR)
176 	{
177 	    check_for_delay(FALSE);
178 	    if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
179 								       == FAIL)
180 		type = CLEAR;
181 	    FOR_ALL_WINDOWS(wp)
182 	    {
183 		if (wp->w_winrow < msg_scrolled)
184 		{
185 		    if (W_WINROW(wp) + wp->w_height > msg_scrolled
186 			    && wp->w_redr_type < REDRAW_TOP
187 			    && wp->w_lines_valid > 0
188 			    && wp->w_topline == wp->w_lines[0].wl_lnum)
189 		    {
190 			wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
191 			wp->w_redr_type = REDRAW_TOP;
192 		    }
193 		    else
194 		    {
195 			wp->w_redr_type = NOT_VALID;
196 			if (W_WINROW(wp) + wp->w_height + wp->w_status_height
197 							       <= msg_scrolled)
198 			    wp->w_redr_status = TRUE;
199 		    }
200 		}
201 	    }
202 	    if (!no_update)
203 		redraw_cmdline = TRUE;
204 	    redraw_tabline = TRUE;
205 	}
206 	msg_scrolled = 0;
207 	need_wait_return = FALSE;
208     }
209 
210     // reset cmdline_row now (may have been changed temporarily)
211     compute_cmdrow();
212 
213     // Check for changed highlighting
214     if (need_highlight_changed)
215 	highlight_changed();
216 
217     if (type == CLEAR)		// first clear screen
218     {
219 	screenclear();		// will reset clear_cmdline
220 	type = NOT_VALID;
221 	// must_redraw may be set indirectly, avoid another redraw later
222 	must_redraw = 0;
223     }
224 
225     if (clear_cmdline)		// going to clear cmdline (done below)
226 	check_for_delay(FALSE);
227 
228 #ifdef FEAT_LINEBREAK
229     // Force redraw when width of 'number' or 'relativenumber' column
230     // changes.
231     if (curwin->w_redr_type < NOT_VALID
232 	   && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
233 				    ? number_width(curwin) : 0))
234 	curwin->w_redr_type = NOT_VALID;
235 #endif
236 
237     // Only start redrawing if there is really something to do.
238     if (type == INVERTED)
239 	update_curswant();
240     if (curwin->w_redr_type < type
241 	    && !((type == VALID
242 		    && curwin->w_lines[0].wl_valid
243 #ifdef FEAT_DIFF
244 		    && curwin->w_topfill == curwin->w_old_topfill
245 		    && curwin->w_botfill == curwin->w_old_botfill
246 #endif
247 		    && curwin->w_topline == curwin->w_lines[0].wl_lnum)
248 		|| (type == INVERTED
249 		    && VIsual_active
250 		    && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
251 		    && curwin->w_old_visual_mode == VIsual_mode
252 		    && (curwin->w_valid & VALID_VIRTCOL)
253 		    && curwin->w_old_curswant == curwin->w_curswant)
254 		))
255 	curwin->w_redr_type = type;
256 
257     // Redraw the tab pages line if needed.
258     if (redraw_tabline || type >= NOT_VALID)
259 	draw_tabline();
260 
261 #ifdef FEAT_SYN_HL
262     // Correct stored syntax highlighting info for changes in each displayed
263     // buffer.  Each buffer must only be done once.
264     FOR_ALL_WINDOWS(wp)
265     {
266 	if (wp->w_buffer->b_mod_set)
267 	{
268 	    win_T	*wwp;
269 
270 	    // Check if we already did this buffer.
271 	    for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
272 		if (wwp->w_buffer == wp->w_buffer)
273 		    break;
274 	    if (wwp == wp && syntax_present(wp))
275 		syn_stack_apply_changes(wp->w_buffer);
276 	}
277     }
278 #endif
279 
280     if (pum_redraw_in_same_position())
281 	// Avoid flicker if the popup menu is going to be redrawn in the same
282 	// position.
283 	pum_will_redraw = TRUE;
284 
285     // Go from top to bottom through the windows, redrawing the ones that need
286     // it.
287 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
288     did_update_one_window = FALSE;
289 #endif
290 #ifdef FEAT_SEARCH_EXTRA
291     screen_search_hl.rm.regprog = NULL;
292 #endif
293     FOR_ALL_WINDOWS(wp)
294     {
295 	if (wp->w_redr_type != 0)
296 	{
297 	    cursor_off();
298 #ifdef FEAT_GUI
299 	    if (!did_one)
300 	    {
301 		did_one = TRUE;
302 
303 		// Remove the cursor before starting to do anything, because
304 		// scrolling may make it difficult to redraw the text under
305 		// it.
306 		// Also remove the cursor if it needs to be hidden due to an
307 		// ongoing cursor-less sleep.
308 		if (gui.in_use && (wp == curwin || cursor_is_sleeping()))
309 		{
310 		    gui_cursor_col = gui.cursor_col;
311 		    gui_cursor_row = gui.cursor_row;
312 		    gui_undraw_cursor();
313 		    did_undraw = TRUE;
314 		}
315 	    }
316 #endif
317 	    win_update(wp);
318 	}
319 
320 	// redraw status line after the window to minimize cursor movement
321 	if (wp->w_redr_status)
322 	{
323 	    cursor_off();
324 	    win_redr_status(wp, TRUE); // any popup menu will be redrawn below
325 	}
326     }
327 #if defined(FEAT_SEARCH_EXTRA)
328     end_search_hl();
329 #endif
330 
331     // May need to redraw the popup menu.
332     pum_will_redraw = save_pum_will_redraw;
333     pum_may_redraw();
334 
335     // Reset b_mod_set flags.  Going through all windows is probably faster
336     // than going through all buffers (there could be many buffers).
337     FOR_ALL_WINDOWS(wp)
338 	wp->w_buffer->b_mod_set = FALSE;
339 
340 #ifdef FEAT_PROP_POPUP
341     // Display popup windows on top of the windows and command line.
342     update_popups(win_update);
343 #endif
344 
345     after_updating_screen(TRUE);
346 
347     // Clear or redraw the command line.  Done last, because scrolling may
348     // mess up the command line.
349     if (clear_cmdline || redraw_cmdline || redraw_mode)
350 	showmode();
351 
352     if (no_update)
353 	--no_win_do_lines_ins;
354 
355     // May put up an introductory message when not editing a file
356     if (!did_intro)
357 	maybe_intro_message();
358     did_intro = TRUE;
359 
360 #ifdef FEAT_GUI
361     // Redraw the cursor and update the scrollbars when all screen updating is
362     // done.
363     if (gui.in_use)
364     {
365 	if (did_undraw && !gui_mch_is_blink_off())
366 	{
367 	    mch_disable_flush();
368 	    out_flush();	// required before updating the cursor
369 	    mch_enable_flush();
370 
371 	    // Put the GUI position where the cursor was, gui_update_cursor()
372 	    // uses that.
373 	    gui.col = gui_cursor_col;
374 	    gui.row = gui_cursor_row;
375 	    gui.col = mb_fix_col(gui.col, gui.row);
376 	    gui_update_cursor(FALSE, FALSE);
377 	    gui_may_flush();
378 	    screen_cur_col = gui.col;
379 	    screen_cur_row = gui.row;
380 	}
381 	else
382 	    out_flush();
383 	gui_update_scrollbars(FALSE);
384     }
385 #endif
386     return OK;
387 }
388 
389 /*
390  * Return the row for drawing the statusline and the ruler of window "wp".
391  */
392     int
393 statusline_row(win_T *wp)
394 {
395 #if defined(FEAT_PROP_POPUP)
396     // If the window is really zero height the winbar isn't displayed.
397     if (wp->w_frame->fr_height == wp->w_status_height && !popup_is_popup(wp))
398 	return wp->w_winrow;
399 #endif
400     return W_WINROW(wp) + wp->w_height;
401 }
402 
403 /*
404  * Redraw the status line of window wp.
405  *
406  * If inversion is possible we use it. Else '=' characters are used.
407  * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is
408  * displayed.
409  */
410     static void
411 win_redr_status(win_T *wp, int ignore_pum UNUSED)
412 {
413     int		row;
414     char_u	*p;
415     int		len;
416     int		fillchar;
417     int		attr;
418     int		this_ru_col;
419     static int  busy = FALSE;
420 
421     // It's possible to get here recursively when 'statusline' (indirectly)
422     // invokes ":redrawstatus".  Simply ignore the call then.
423     if (busy)
424 	return;
425     busy = TRUE;
426 
427     row = statusline_row(wp);
428 
429     wp->w_redr_status = FALSE;
430     if (wp->w_status_height == 0)
431     {
432 	// no status line, can only be last window
433 	redraw_cmdline = TRUE;
434     }
435     else if (!redrawing()
436 	    // don't update status line when popup menu is visible and may be
437 	    // drawn over it, unless it will be redrawn later
438 	    || (!ignore_pum && pum_visible()))
439     {
440 	// Don't redraw right now, do it later.
441 	wp->w_redr_status = TRUE;
442     }
443 #ifdef FEAT_STL_OPT
444     else if (*p_stl != NUL || *wp->w_p_stl != NUL)
445     {
446 	// redraw custom status line
447 	redraw_custom_statusline(wp);
448     }
449 #endif
450     else
451     {
452 	fillchar = fillchar_status(&attr, wp);
453 
454 	get_trans_bufname(wp->w_buffer);
455 	p = NameBuff;
456 	len = (int)STRLEN(p);
457 
458 	if (bt_help(wp->w_buffer)
459 #ifdef FEAT_QUICKFIX
460 		|| wp->w_p_pvw
461 #endif
462 		|| bufIsChanged(wp->w_buffer)
463 		|| wp->w_buffer->b_p_ro)
464 	    *(p + len++) = ' ';
465 	if (bt_help(wp->w_buffer))
466 	{
467 	    STRCPY(p + len, _("[Help]"));
468 	    len += (int)STRLEN(p + len);
469 	}
470 #ifdef FEAT_QUICKFIX
471 	if (wp->w_p_pvw)
472 	{
473 	    STRCPY(p + len, _("[Preview]"));
474 	    len += (int)STRLEN(p + len);
475 	}
476 #endif
477 	if (bufIsChanged(wp->w_buffer)
478 #ifdef FEAT_TERMINAL
479 		&& !bt_terminal(wp->w_buffer)
480 #endif
481 		)
482 	{
483 	    STRCPY(p + len, "[+]");
484 	    len += 3;
485 	}
486 	if (wp->w_buffer->b_p_ro)
487 	{
488 	    STRCPY(p + len, _("[RO]"));
489 	    len += (int)STRLEN(p + len);
490 	}
491 
492 	this_ru_col = ru_col - (Columns - wp->w_width);
493 	if (this_ru_col < (wp->w_width + 1) / 2)
494 	    this_ru_col = (wp->w_width + 1) / 2;
495 	if (this_ru_col <= 1)
496 	{
497 	    p = (char_u *)"<";		// No room for file name!
498 	    len = 1;
499 	}
500 	else if (has_mbyte)
501 	{
502 	    int	clen = 0, i;
503 
504 	    // Count total number of display cells.
505 	    clen = mb_string2cells(p, -1);
506 
507 	    // Find first character that will fit.
508 	    // Going from start to end is much faster for DBCS.
509 	    for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
510 		    i += (*mb_ptr2len)(p + i))
511 		clen -= (*mb_ptr2cells)(p + i);
512 	    len = clen;
513 	    if (i > 0)
514 	    {
515 		p = p + i - 1;
516 		*p = '<';
517 		++len;
518 	    }
519 
520 	}
521 	else if (len > this_ru_col - 1)
522 	{
523 	    p += len - (this_ru_col - 1);
524 	    *p = '<';
525 	    len = this_ru_col - 1;
526 	}
527 
528 	screen_puts(p, row, wp->w_wincol, attr);
529 	screen_fill(row, row + 1, len + wp->w_wincol,
530 			this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
531 
532 	if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
533 		&& (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
534 	    screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
535 						   - 1 + wp->w_wincol), attr);
536 
537 #ifdef FEAT_CMDL_INFO
538 	win_redr_ruler(wp, TRUE, ignore_pum);
539 #endif
540     }
541 
542     /*
543      * May need to draw the character below the vertical separator.
544      */
545     if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
546     {
547 	if (stl_connected(wp))
548 	    fillchar = fillchar_status(&attr, wp);
549 	else
550 	    fillchar = fillchar_vsep(&attr);
551 	screen_putchar(fillchar, row, W_ENDCOL(wp), attr);
552     }
553     busy = FALSE;
554 }
555 
556 #ifdef FEAT_STL_OPT
557 /*
558  * Redraw the status line according to 'statusline' and take care of any
559  * errors encountered.
560  */
561     static void
562 redraw_custom_statusline(win_T *wp)
563 {
564     static int	    entered = FALSE;
565     int		    saved_did_emsg = did_emsg;
566 
567     // When called recursively return.  This can happen when the statusline
568     // contains an expression that triggers a redraw.
569     if (entered)
570 	return;
571     entered = TRUE;
572 
573     did_emsg = FALSE;
574     win_redr_custom(wp, FALSE);
575     if (did_emsg)
576     {
577 	// When there is an error disable the statusline, otherwise the
578 	// display is messed up with errors and a redraw triggers the problem
579 	// again and again.
580 	set_string_option_direct((char_u *)"statusline", -1,
581 		(char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
582 					? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
583     }
584     did_emsg |= saved_did_emsg;
585     entered = FALSE;
586 }
587 #endif
588 
589 /*
590  * Show current status info in ruler and various other places
591  * If always is FALSE, only show ruler if position has changed.
592  */
593     void
594 showruler(int always)
595 {
596     if (!always && !redrawing())
597 	return;
598     if (pum_visible())
599     {
600 	// Don't redraw right now, do it later.
601 	curwin->w_redr_status = TRUE;
602 	return;
603     }
604 #if defined(FEAT_STL_OPT)
605     if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
606 	redraw_custom_statusline(curwin);
607     else
608 #endif
609 #ifdef FEAT_CMDL_INFO
610 	win_redr_ruler(curwin, always, FALSE);
611 #endif
612 
613 #ifdef FEAT_TITLE
614     if (need_maketitle
615 # ifdef FEAT_STL_OPT
616 	    || (p_icon && (stl_syntax & STL_IN_ICON))
617 	    || (p_title && (stl_syntax & STL_IN_TITLE))
618 # endif
619        )
620 	maketitle();
621 #endif
622     // Redraw the tab pages line if needed.
623     if (redraw_tabline)
624 	draw_tabline();
625 }
626 
627 #if defined(FEAT_CMDL_INFO) || defined(PROTO)
628     void
629 win_redr_ruler(win_T *wp, int always, int ignore_pum)
630 {
631 #define RULER_BUF_LEN 70
632     char_u	buffer[RULER_BUF_LEN];
633     int		row;
634     int		fillchar;
635     int		attr;
636     int		empty_line = FALSE;
637     colnr_T	virtcol;
638     int		i;
639     size_t	len;
640     int		o;
641     int		this_ru_col;
642     int		off = 0;
643     int		width;
644 
645     // If 'ruler' off or redrawing disabled, don't do anything
646     if (!p_ru)
647 	return;
648 
649     /*
650      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
651      * after deleting lines, before cursor.lnum is corrected.
652      */
653     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
654 	return;
655 
656     // Don't draw the ruler while doing insert-completion, it might overwrite
657     // the (long) mode message.
658     if (wp == lastwin && lastwin->w_status_height == 0)
659 	if (edit_submode != NULL)
660 	    return;
661     // Don't draw the ruler when the popup menu is visible, it may overlap.
662     // Except when the popup menu will be redrawn anyway.
663     if (!ignore_pum && pum_visible())
664 	return;
665 
666 #ifdef FEAT_STL_OPT
667     if (*p_ruf)
668     {
669 	int	called_emsg_before = called_emsg;
670 
671 	win_redr_custom(wp, TRUE);
672 	if (called_emsg > called_emsg_before)
673 	    set_string_option_direct((char_u *)"rulerformat", -1,
674 					   (char_u *)"", OPT_FREE, SID_ERROR);
675 	return;
676     }
677 #endif
678 
679     /*
680      * Check if not in Insert mode and the line is empty (will show "0-1").
681      */
682     if (!(State & INSERT)
683 		&& *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
684 	empty_line = TRUE;
685 
686     /*
687      * Only draw the ruler when something changed.
688      */
689     validate_virtcol_win(wp);
690     if (       redraw_cmdline
691 	    || always
692 	    || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
693 	    || wp->w_cursor.col != wp->w_ru_cursor.col
694 	    || wp->w_virtcol != wp->w_ru_virtcol
695 	    || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
696 	    || wp->w_topline != wp->w_ru_topline
697 	    || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
698 #ifdef FEAT_DIFF
699 	    || wp->w_topfill != wp->w_ru_topfill
700 #endif
701 	    || empty_line != wp->w_ru_empty)
702     {
703 	cursor_off();
704 	if (wp->w_status_height)
705 	{
706 	    row = statusline_row(wp);
707 	    fillchar = fillchar_status(&attr, wp);
708 	    off = wp->w_wincol;
709 	    width = wp->w_width;
710 	}
711 	else
712 	{
713 	    row = Rows - 1;
714 	    fillchar = ' ';
715 	    attr = 0;
716 	    width = Columns;
717 	    off = 0;
718 	}
719 
720 	// In list mode virtcol needs to be recomputed
721 	virtcol = wp->w_virtcol;
722 	if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL)
723 	{
724 	    wp->w_p_list = FALSE;
725 	    getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
726 	    wp->w_p_list = TRUE;
727 	}
728 
729 	/*
730 	 * Some sprintfs return the length, some return a pointer.
731 	 * To avoid portability problems we use strlen() here.
732 	 */
733 	vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
734 		(wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
735 		    ? 0L
736 		    : (long)(wp->w_cursor.lnum));
737 	len = STRLEN(buffer);
738 	col_print(buffer + len, RULER_BUF_LEN - len,
739 			empty_line ? 0 : (int)wp->w_cursor.col + 1,
740 			(int)virtcol + 1);
741 
742 	/*
743 	 * Add a "50%" if there is room for it.
744 	 * On the last line, don't print in the last column (scrolls the
745 	 * screen up on some terminals).
746 	 */
747 	i = (int)STRLEN(buffer);
748 	get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
749 	o = i + vim_strsize(buffer + i + 1);
750 	if (wp->w_status_height == 0)	// can't use last char of screen
751 	    ++o;
752 	this_ru_col = ru_col - (Columns - width);
753 	if (this_ru_col < 0)
754 	    this_ru_col = 0;
755 	// Never use more than half the window/screen width, leave the other
756 	// half for the filename.
757 	if (this_ru_col < (width + 1) / 2)
758 	    this_ru_col = (width + 1) / 2;
759 	if (this_ru_col + o < width)
760 	{
761 	    // need at least 3 chars left for get_rel_pos() + NUL
762 	    while (this_ru_col + o < width && RULER_BUF_LEN > i + 4)
763 	    {
764 		if (has_mbyte)
765 		    i += (*mb_char2bytes)(fillchar, buffer + i);
766 		else
767 		    buffer[i++] = fillchar;
768 		++o;
769 	    }
770 	    get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
771 	}
772 	// Truncate at window boundary.
773 	if (has_mbyte)
774 	{
775 	    o = 0;
776 	    for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
777 	    {
778 		o += (*mb_ptr2cells)(buffer + i);
779 		if (this_ru_col + o > width)
780 		{
781 		    buffer[i] = NUL;
782 		    break;
783 		}
784 	    }
785 	}
786 	else if (this_ru_col + (int)STRLEN(buffer) > width)
787 	    buffer[width - this_ru_col] = NUL;
788 
789 	screen_puts(buffer, row, this_ru_col + off, attr);
790 	i = redraw_cmdline;
791 	screen_fill(row, row + 1,
792 		this_ru_col + off + (int)STRLEN(buffer),
793 		(int)(off + width),
794 		fillchar, fillchar, attr);
795 	// don't redraw the cmdline because of showing the ruler
796 	redraw_cmdline = i;
797 	wp->w_ru_cursor = wp->w_cursor;
798 	wp->w_ru_virtcol = wp->w_virtcol;
799 	wp->w_ru_empty = empty_line;
800 	wp->w_ru_topline = wp->w_topline;
801 	wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
802 #ifdef FEAT_DIFF
803 	wp->w_ru_topfill = wp->w_topfill;
804 #endif
805     }
806 }
807 #endif
808 
809 /*
810  * To be called when "updating_screen" was set before and now the postponed
811  * side effects may take place.
812  */
813     void
814 after_updating_screen(int may_resize_shell UNUSED)
815 {
816     updating_screen = FALSE;
817 #ifdef FEAT_GUI
818     if (may_resize_shell)
819 	gui_may_resize_shell();
820 #endif
821 #ifdef FEAT_TERMINAL
822     term_check_channel_closed_recently();
823 #endif
824 
825 #ifdef HAVE_DROP_FILE
826     // If handle_drop() was called while updating_screen was TRUE need to
827     // handle the drop now.
828     handle_any_postponed_drop();
829 #endif
830 }
831 
832 /*
833  * Update all windows that are editing the current buffer.
834  */
835     void
836 update_curbuf(int type)
837 {
838     redraw_curbuf_later(type);
839     update_screen(type);
840 }
841 
842 #if defined(FEAT_MENU) || defined(FEAT_FOLDING)
843 /*
844  * Copy "text" to ScreenLines using "attr".
845  * Returns the next screen column.
846  */
847     static int
848 text_to_screenline(win_T *wp, char_u *text, int col)
849 {
850     int		off = (int)(current_ScreenLine - ScreenLines);
851 
852     if (has_mbyte)
853     {
854 	int	cells;
855 	int	u8c, u8cc[MAX_MCO];
856 	int	i;
857 	int	idx;
858 	int	c_len;
859 	char_u	*p;
860 # ifdef FEAT_ARABIC
861 	int	prev_c = 0;		// previous Arabic character
862 	int	prev_c1 = 0;		// first composing char for prev_c
863 # endif
864 
865 # ifdef FEAT_RIGHTLEFT
866 	if (wp->w_p_rl)
867 	    idx = off;
868 	else
869 # endif
870 	    idx = off + col;
871 
872 	// Store multibyte characters in ScreenLines[] et al. correctly.
873 	for (p = text; *p != NUL; )
874 	{
875 	    cells = (*mb_ptr2cells)(p);
876 	    c_len = (*mb_ptr2len)(p);
877 	    if (col + cells > wp->w_width
878 # ifdef FEAT_RIGHTLEFT
879 		    - (wp->w_p_rl ? col : 0)
880 # endif
881 		    )
882 		break;
883 	    ScreenLines[idx] = *p;
884 	    if (enc_utf8)
885 	    {
886 		u8c = utfc_ptr2char(p, u8cc);
887 		if (*p < 0x80 && u8cc[0] == 0)
888 		{
889 		    ScreenLinesUC[idx] = 0;
890 #ifdef FEAT_ARABIC
891 		    prev_c = u8c;
892 #endif
893 		}
894 		else
895 		{
896 #ifdef FEAT_ARABIC
897 		    if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
898 		    {
899 			// Do Arabic shaping.
900 			int	pc, pc1, nc;
901 			int	pcc[MAX_MCO];
902 			int	firstbyte = *p;
903 
904 			// The idea of what is the previous and next
905 			// character depends on 'rightleft'.
906 			if (wp->w_p_rl)
907 			{
908 			    pc = prev_c;
909 			    pc1 = prev_c1;
910 			    nc = utf_ptr2char(p + c_len);
911 			    prev_c1 = u8cc[0];
912 			}
913 			else
914 			{
915 			    pc = utfc_ptr2char(p + c_len, pcc);
916 			    nc = prev_c;
917 			    pc1 = pcc[0];
918 			}
919 			prev_c = u8c;
920 
921 			u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
922 								 pc, pc1, nc);
923 			ScreenLines[idx] = firstbyte;
924 		    }
925 		    else
926 			prev_c = u8c;
927 #endif
928 		    // Non-BMP character: display as ? or fullwidth ?.
929 		    ScreenLinesUC[idx] = u8c;
930 		    for (i = 0; i < Screen_mco; ++i)
931 		    {
932 			ScreenLinesC[i][idx] = u8cc[i];
933 			if (u8cc[i] == 0)
934 			    break;
935 		    }
936 		}
937 		if (cells > 1)
938 		    ScreenLines[idx + 1] = 0;
939 	    }
940 	    else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
941 		// double-byte single width character
942 		ScreenLines2[idx] = p[1];
943 	    else if (cells > 1)
944 		// double-width character
945 		ScreenLines[idx + 1] = p[1];
946 	    col += cells;
947 	    idx += cells;
948 	    p += c_len;
949 	}
950     }
951     else
952     {
953 	int len = (int)STRLEN(text);
954 
955 	if (len > wp->w_width - col)
956 	    len = wp->w_width - col;
957 	if (len > 0)
958 	{
959 #ifdef FEAT_RIGHTLEFT
960 	    if (wp->w_p_rl)
961 		mch_memmove(current_ScreenLine, text, len);
962 	    else
963 #endif
964 		mch_memmove(current_ScreenLine + col, text, len);
965 	    col += len;
966 	}
967     }
968     return col;
969 }
970 #endif
971 
972 #ifdef FEAT_MENU
973 /*
974  * Draw the window toolbar.
975  */
976     static void
977 redraw_win_toolbar(win_T *wp)
978 {
979     vimmenu_T	*menu;
980     int		item_idx = 0;
981     int		item_count = 0;
982     int		col = 0;
983     int		next_col;
984     int		off = (int)(current_ScreenLine - ScreenLines);
985     int		fill_attr = syn_name2attr((char_u *)"ToolbarLine");
986     int		button_attr = syn_name2attr((char_u *)"ToolbarButton");
987 
988     vim_free(wp->w_winbar_items);
989     FOR_ALL_CHILD_MENUS(wp->w_winbar, menu)
990 	++item_count;
991     wp->w_winbar_items = ALLOC_CLEAR_MULT(winbar_item_T, item_count + 1);
992 
993     // TODO: use fewer spaces if there is not enough room
994     for (menu = wp->w_winbar->children;
995 			  menu != NULL && col < wp->w_width; menu = menu->next)
996     {
997 	space_to_screenline(off + col, fill_attr);
998 	if (++col >= wp->w_width)
999 	    break;
1000 	if (col > 1)
1001 	{
1002 	    space_to_screenline(off + col, fill_attr);
1003 	    if (++col >= wp->w_width)
1004 		break;
1005 	}
1006 
1007 	wp->w_winbar_items[item_idx].wb_startcol = col;
1008 	space_to_screenline(off + col, button_attr);
1009 	if (++col >= wp->w_width)
1010 	    break;
1011 
1012 	next_col = text_to_screenline(wp, menu->name, col);
1013 	while (col < next_col)
1014 	{
1015 	    ScreenAttrs[off + col] = button_attr;
1016 	    ++col;
1017 	}
1018 	wp->w_winbar_items[item_idx].wb_endcol = col;
1019 	wp->w_winbar_items[item_idx].wb_menu = menu;
1020 	++item_idx;
1021 
1022 	if (col >= wp->w_width)
1023 	    break;
1024 	space_to_screenline(off + col, button_attr);
1025 	++col;
1026     }
1027     while (col < wp->w_width)
1028     {
1029 	space_to_screenline(off + col, fill_attr);
1030 	++col;
1031     }
1032     wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker
1033 
1034     screen_line(wp->w_winrow, wp->w_wincol, (int)wp->w_width,
1035 							  (int)wp->w_width, 0);
1036 }
1037 #endif
1038 
1039 #if defined(FEAT_FOLDING) || defined(PROTO)
1040 /*
1041  * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
1042  */
1043     static void
1044 copy_text_attr(
1045     int		off,
1046     char_u	*buf,
1047     int		len,
1048     int		attr)
1049 {
1050     int		i;
1051 
1052     mch_memmove(ScreenLines + off, buf, (size_t)len);
1053     if (enc_utf8)
1054 	vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
1055     for (i = 0; i < len; ++i)
1056 	ScreenAttrs[off + i] = attr;
1057 }
1058 
1059 /*
1060  * Display one folded line.
1061  */
1062     static void
1063 fold_line(
1064     win_T	*wp,
1065     long	fold_count,
1066     foldinfo_T	*foldinfo,
1067     linenr_T	lnum,
1068     int		row)
1069 {
1070     // Max value of 'foldcolumn' is 12 and maximum number of bytes in a
1071     // multi-byte character is MAX_MCO.
1072     char_u	buf[MAX_MCO * 12 + 1];
1073     pos_T	*top, *bot;
1074     linenr_T	lnume = lnum + fold_count - 1;
1075     int		len;
1076     char_u	*text;
1077     int		fdc;
1078     int		col;
1079     int		txtcol;
1080     int		off = (int)(current_ScreenLine - ScreenLines);
1081     int		ri;
1082 
1083     // Build the fold line:
1084     // 1. Add the cmdwin_type for the command-line window
1085     // 2. Add the 'foldcolumn'
1086     // 3. Add the 'number' or 'relativenumber' column
1087     // 4. Compose the text
1088     // 5. Add the text
1089     // 6. set highlighting for the Visual area an other text
1090     col = 0;
1091 
1092     // 1. Add the cmdwin_type for the command-line window
1093     // Ignores 'rightleft', this window is never right-left.
1094 #ifdef FEAT_CMDWIN
1095     if (cmdwin_type != 0 && wp == curwin)
1096     {
1097 	ScreenLines[off] = cmdwin_type;
1098 	ScreenAttrs[off] = HL_ATTR(HLF_AT);
1099 	if (enc_utf8)
1100 	    ScreenLinesUC[off] = 0;
1101 	++col;
1102     }
1103 #endif
1104 
1105 #ifdef FEAT_RIGHTLEFT
1106 # define RL_MEMSET(p, v, l) \
1107     do { \
1108 	if (wp->w_p_rl) \
1109 	    for (ri = 0; ri < l; ++ri) \
1110 	       ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \
1111 	 else \
1112 	    for (ri = 0; ri < l; ++ri) \
1113 	       ScreenAttrs[off + (p) + ri] = v; \
1114     } while (0)
1115 #else
1116 # define RL_MEMSET(p, v, l) \
1117     do { \
1118 	for (ri = 0; ri < l; ++ri) \
1119 	    ScreenAttrs[off + (p) + ri] = v; \
1120     } while (0)
1121 #endif
1122 
1123     // 2. Add the 'foldcolumn'
1124     //    Reduce the width when there is not enough space.
1125     fdc = compute_foldcolumn(wp, col);
1126     if (fdc > 0)
1127     {
1128 	char_u	*p;
1129 	int	i;
1130 	int	idx;
1131 
1132 	fill_foldcolumn(buf, wp, TRUE, lnum);
1133 	p = buf;
1134 	for (i = 0; i < fdc; i++)
1135 	{
1136 	    int		ch;
1137 
1138 	    if (has_mbyte)
1139 		ch = mb_ptr2char_adv(&p);
1140 	    else
1141 		ch = *p++;
1142 #ifdef FEAT_RIGHTLEFT
1143 	    if (wp->w_p_rl)
1144 		idx = off + wp->w_width - i - 1 - col;
1145 	    else
1146 #endif
1147 		idx = off + col + i;
1148 	    if (enc_utf8)
1149 	    {
1150 		if (ch >= 0x80)
1151 		{
1152 		    ScreenLinesUC[idx] = ch;
1153 		    ScreenLinesC[0][idx] = 0;
1154 		    ScreenLines[idx] = 0x80;
1155 		}
1156 		else
1157 		{
1158 		    ScreenLines[idx] = ch;
1159 		    ScreenLinesUC[idx] = 0;
1160 		}
1161 	    }
1162 	    else
1163 		ScreenLines[idx] = ch;
1164 	}
1165 
1166 	RL_MEMSET(col, HL_ATTR(HLF_FC), fdc);
1167 	col += fdc;
1168     }
1169 
1170     // Set all attributes of the 'number' or 'relativenumber' column and the
1171     // text
1172     RL_MEMSET(col, HL_ATTR(HLF_FL), wp->w_width - col);
1173 
1174 #ifdef FEAT_SIGNS
1175     // If signs are being displayed, add two spaces.
1176     if (signcolumn_on(wp))
1177     {
1178 	len = wp->w_width - col;
1179 	if (len > 0)
1180 	{
1181 	    if (len > 2)
1182 		len = 2;
1183 # ifdef FEAT_RIGHTLEFT
1184 	    if (wp->w_p_rl)
1185 		// the line number isn't reversed
1186 		copy_text_attr(off + wp->w_width - len - col,
1187 					(char_u *)"  ", len, HL_ATTR(HLF_FL));
1188 	    else
1189 # endif
1190 		copy_text_attr(off + col, (char_u *)"  ", len, HL_ATTR(HLF_FL));
1191 	    col += len;
1192 	}
1193     }
1194 #endif
1195 
1196     // 3. Add the 'number' or 'relativenumber' column
1197     if (wp->w_p_nu || wp->w_p_rnu)
1198     {
1199 	len = wp->w_width - col;
1200 	if (len > 0)
1201 	{
1202 	    int	    w = number_width(wp);
1203 	    long    num;
1204 	    char    *fmt = "%*ld ";
1205 
1206 	    if (len > w + 1)
1207 		len = w + 1;
1208 
1209 	    if (wp->w_p_nu && !wp->w_p_rnu)
1210 		// 'number' + 'norelativenumber'
1211 		num = (long)lnum;
1212 	    else
1213 	    {
1214 		// 'relativenumber', don't use negative numbers
1215 		num = labs((long)get_cursor_rel_lnum(wp, lnum));
1216 		if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
1217 		{
1218 		    // 'number' + 'relativenumber': cursor line shows absolute
1219 		    // line number
1220 		    num = lnum;
1221 		    fmt = "%-*ld ";
1222 		}
1223 	    }
1224 
1225 	    sprintf((char *)buf, fmt, w, num);
1226 #ifdef FEAT_RIGHTLEFT
1227 	    if (wp->w_p_rl)
1228 		// the line number isn't reversed
1229 		copy_text_attr(off + wp->w_width - len - col, buf, len,
1230 							     HL_ATTR(HLF_FL));
1231 	    else
1232 #endif
1233 		copy_text_attr(off + col, buf, len, HL_ATTR(HLF_FL));
1234 	    col += len;
1235 	}
1236     }
1237 
1238     // 4. Compose the folded-line string with 'foldtext', if set.
1239     text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
1240 
1241     txtcol = col;	// remember where text starts
1242 
1243     // 5. move the text to current_ScreenLine.  Fill up with "fill_fold".
1244     //    Right-left text is put in columns 0 - number-col, normal text is put
1245     //    in columns number-col - window-width.
1246     col = text_to_screenline(wp, text, col);
1247 
1248     // Fill the rest of the line with the fold filler
1249 #ifdef FEAT_RIGHTLEFT
1250     if (wp->w_p_rl)
1251 	col -= txtcol;
1252 #endif
1253     while (col < wp->w_width
1254 #ifdef FEAT_RIGHTLEFT
1255 		    - (wp->w_p_rl ? txtcol : 0)
1256 #endif
1257 	    )
1258     {
1259 	if (enc_utf8)
1260 	{
1261 	    if (fill_fold >= 0x80)
1262 	    {
1263 		ScreenLinesUC[off + col] = fill_fold;
1264 		ScreenLinesC[0][off + col] = 0;
1265 		ScreenLines[off + col] = 0x80; // avoid storing zero
1266 	    }
1267 	    else
1268 	    {
1269 		ScreenLinesUC[off + col] = 0;
1270 		ScreenLines[off + col] = fill_fold;
1271 	    }
1272 	    col++;
1273 	}
1274 	else
1275 	    ScreenLines[off + col++] = fill_fold;
1276     }
1277 
1278     if (text != buf)
1279 	vim_free(text);
1280 
1281     // 6. set highlighting for the Visual area an other text.
1282     // If all folded lines are in the Visual area, highlight the line.
1283     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
1284     {
1285 	if (LTOREQ_POS(curwin->w_cursor, VIsual))
1286 	{
1287 	    // Visual is after curwin->w_cursor
1288 	    top = &curwin->w_cursor;
1289 	    bot = &VIsual;
1290 	}
1291 	else
1292 	{
1293 	    // Visual is before curwin->w_cursor
1294 	    top = &VIsual;
1295 	    bot = &curwin->w_cursor;
1296 	}
1297 	if (lnum >= top->lnum
1298 		&& lnume <= bot->lnum
1299 		&& (VIsual_mode != 'v'
1300 		    || ((lnum > top->lnum
1301 			    || (lnum == top->lnum
1302 				&& top->col == 0))
1303 			&& (lnume < bot->lnum
1304 			    || (lnume == bot->lnum
1305 				&& (bot->col - (*p_sel == 'e'))
1306 		>= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
1307 	{
1308 	    if (VIsual_mode == Ctrl_V)
1309 	    {
1310 		// Visual block mode: highlight the chars part of the block
1311 		if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_width)
1312 		{
1313 		    if (wp->w_old_cursor_lcol != MAXCOL
1314 			     && wp->w_old_cursor_lcol + txtcol
1315 						       < (colnr_T)wp->w_width)
1316 			len = wp->w_old_cursor_lcol;
1317 		    else
1318 			len = wp->w_width - txtcol;
1319 		    RL_MEMSET(wp->w_old_cursor_fcol + txtcol, HL_ATTR(HLF_V),
1320 					    len - (int)wp->w_old_cursor_fcol);
1321 		}
1322 	    }
1323 	    else
1324 	    {
1325 		// Set all attributes of the text
1326 		RL_MEMSET(txtcol, HL_ATTR(HLF_V), wp->w_width - txtcol);
1327 	    }
1328 	}
1329     }
1330 
1331 #ifdef FEAT_SYN_HL
1332     // Show colorcolumn in the fold line, but let cursorcolumn override it.
1333     if (wp->w_p_cc_cols)
1334     {
1335 	int i = 0;
1336 	int j = wp->w_p_cc_cols[i];
1337 	int old_txtcol = txtcol;
1338 
1339 	while (j > -1)
1340 	{
1341 	    txtcol += j;
1342 	    if (wp->w_p_wrap)
1343 		txtcol -= wp->w_skipcol;
1344 	    else
1345 		txtcol -= wp->w_leftcol;
1346 	    if (txtcol >= 0 && txtcol < wp->w_width)
1347 		ScreenAttrs[off + txtcol] = hl_combine_attr(
1348 				    ScreenAttrs[off + txtcol], HL_ATTR(HLF_MC));
1349 	    txtcol = old_txtcol;
1350 	    j = wp->w_p_cc_cols[++i];
1351 	}
1352     }
1353 
1354     // Show 'cursorcolumn' in the fold line.
1355     if (wp->w_p_cuc)
1356     {
1357 	txtcol += wp->w_virtcol;
1358 	if (wp->w_p_wrap)
1359 	    txtcol -= wp->w_skipcol;
1360 	else
1361 	    txtcol -= wp->w_leftcol;
1362 	if (txtcol >= 0 && txtcol < wp->w_width)
1363 	    ScreenAttrs[off + txtcol] = hl_combine_attr(
1364 				 ScreenAttrs[off + txtcol], HL_ATTR(HLF_CUC));
1365     }
1366 #endif
1367 
1368     screen_line(row + W_WINROW(wp), wp->w_wincol, (int)wp->w_width,
1369 						     (int)wp->w_width, 0);
1370 
1371     // Update w_cline_height and w_cline_folded if the cursor line was
1372     // updated (saves a call to plines() later).
1373     if (wp == curwin
1374 	    && lnum <= curwin->w_cursor.lnum
1375 	    && lnume >= curwin->w_cursor.lnum)
1376     {
1377 	curwin->w_cline_row = row;
1378 	curwin->w_cline_height = 1;
1379 	curwin->w_cline_folded = TRUE;
1380 	curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
1381     }
1382 }
1383 #endif
1384 
1385 /*
1386  * Update a single window.
1387  *
1388  * This may cause the windows below it also to be redrawn (when clearing the
1389  * screen or scrolling lines).
1390  *
1391  * How the window is redrawn depends on wp->w_redr_type.  Each type also
1392  * implies the one below it.
1393  * NOT_VALID	redraw the whole window
1394  * SOME_VALID	redraw the whole window but do scroll when possible
1395  * REDRAW_TOP	redraw the top w_upd_rows window lines, otherwise like VALID
1396  * INVERTED	redraw the changed part of the Visual area
1397  * INVERTED_ALL	redraw the whole Visual area
1398  * VALID	1. scroll up/down to adjust for a changed w_topline
1399  *		2. update lines at the top when scrolled down
1400  *		3. redraw changed text:
1401  *		   - if wp->w_buffer->b_mod_set set, update lines between
1402  *		     b_mod_top and b_mod_bot.
1403  *		   - if wp->w_redraw_top non-zero, redraw lines between
1404  *		     wp->w_redraw_top and wp->w_redr_bot.
1405  *		   - continue redrawing when syntax status is invalid.
1406  *		4. if scrolled up, update lines at the bottom.
1407  * This results in three areas that may need updating:
1408  * top:	from first row to top_end (when scrolled down)
1409  * mid: from mid_start to mid_end (update inversion or changed text)
1410  * bot: from bot_start to last row (when scrolled up)
1411  */
1412     static void
1413 win_update(win_T *wp)
1414 {
1415     buf_T	*buf = wp->w_buffer;
1416     int		type;
1417     int		top_end = 0;	// Below last row of the top area that needs
1418 				// updating.  0 when no top area updating.
1419     int		mid_start = 999;// first row of the mid area that needs
1420 				// updating.  999 when no mid area updating.
1421     int		mid_end = 0;	// Below last row of the mid area that needs
1422 				// updating.  0 when no mid area updating.
1423     int		bot_start = 999;// first row of the bot area that needs
1424 				// updating.  999 when no bot area updating
1425     int		scrolled_down = FALSE;	// TRUE when scrolled down when
1426 					// w_topline got smaller a bit
1427 #ifdef FEAT_SEARCH_EXTRA
1428     int		top_to_mod = FALSE;    // redraw above mod_top
1429 #endif
1430 
1431     int		row;		// current window row to display
1432     linenr_T	lnum;		// current buffer lnum to display
1433     int		idx;		// current index in w_lines[]
1434     int		srow;		// starting row of the current line
1435 
1436     int		eof = FALSE;	// if TRUE, we hit the end of the file
1437     int		didline = FALSE; // if TRUE, we finished the last line
1438     int		i;
1439     long	j;
1440     static int	recursive = FALSE;	// being called recursively
1441     linenr_T	old_botline = wp->w_botline;
1442 #ifdef FEAT_CONCEAL
1443     int		old_wrow = wp->w_wrow;
1444     int		old_wcol = wp->w_wcol;
1445 #endif
1446 #ifdef FEAT_FOLDING
1447     long	fold_count;
1448 #endif
1449 #ifdef FEAT_SYN_HL
1450     // remember what happened to the previous line, to know if
1451     // check_visual_highlight() can be used
1452 #define DID_NONE 1	// didn't update a line
1453 #define DID_LINE 2	// updated a normal line
1454 #define DID_FOLD 3	// updated a folded line
1455     int		did_update = DID_NONE;
1456     linenr_T	syntax_last_parsed = 0;		// last parsed text line
1457 #endif
1458     linenr_T	mod_top = 0;
1459     linenr_T	mod_bot = 0;
1460 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1461     int		save_got_int;
1462 #endif
1463 #ifdef SYN_TIME_LIMIT
1464     proftime_T	syntax_tm;
1465 #endif
1466 
1467 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
1468     // This needs to be done only for the first window when update_screen() is
1469     // called.
1470     if (!did_update_one_window)
1471     {
1472 	did_update_one_window = TRUE;
1473 # ifdef FEAT_SEARCH_EXTRA
1474 	start_search_hl();
1475 # endif
1476 # ifdef FEAT_CLIPBOARD
1477 	// When Visual area changed, may have to update selection.
1478 	if (clip_star.available && clip_isautosel_star())
1479 	    clip_update_selection(&clip_star);
1480 	if (clip_plus.available && clip_isautosel_plus())
1481 	    clip_update_selection(&clip_plus);
1482 # endif
1483     }
1484 #endif
1485 
1486     type = wp->w_redr_type;
1487 
1488     if (type == NOT_VALID)
1489     {
1490 	wp->w_redr_status = TRUE;
1491 	wp->w_lines_valid = 0;
1492     }
1493 
1494     // Window frame is zero-height: nothing to draw.
1495     if (wp->w_height + WINBAR_HEIGHT(wp) == 0
1496 	    || (wp->w_frame->fr_height == wp->w_status_height
1497 #if defined(FEAT_PROP_POPUP)
1498 		&& !popup_is_popup(wp)
1499 #endif
1500 	       ))
1501     {
1502 	wp->w_redr_type = 0;
1503 	return;
1504     }
1505 
1506     // Window is zero-width: Only need to draw the separator.
1507     if (wp->w_width == 0)
1508     {
1509 	// draw the vertical separator right of this window
1510 	draw_vsep_win(wp, 0);
1511 	wp->w_redr_type = 0;
1512 	return;
1513     }
1514 
1515 #ifdef FEAT_TERMINAL
1516     // If this window contains a terminal, redraw works completely differently.
1517     if (term_do_update_window(wp))
1518     {
1519 	term_update_window(wp);
1520 # ifdef FEAT_MENU
1521 	// Draw the window toolbar, if there is one.
1522 	if (winbar_height(wp) > 0)
1523 	    redraw_win_toolbar(wp);
1524 # endif
1525 	wp->w_redr_type = 0;
1526 	return;
1527     }
1528 #endif
1529 
1530 #ifdef FEAT_SEARCH_EXTRA
1531     init_search_hl(wp, &screen_search_hl);
1532 #endif
1533 
1534 #ifdef FEAT_LINEBREAK
1535     // Force redraw when width of 'number' or 'relativenumber' column
1536     // changes.
1537     i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
1538     if (wp->w_nrwidth != i)
1539     {
1540 	type = NOT_VALID;
1541 	wp->w_nrwidth = i;
1542     }
1543     else
1544 #endif
1545 
1546     if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1547     {
1548 	// When there are both inserted/deleted lines and specific lines to be
1549 	// redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1550 	// everything (only happens when redrawing is off for while).
1551 	type = NOT_VALID;
1552     }
1553     else
1554     {
1555 	// Set mod_top to the first line that needs displaying because of
1556 	// changes.  Set mod_bot to the first line after the changes.
1557 	mod_top = wp->w_redraw_top;
1558 	if (wp->w_redraw_bot != 0)
1559 	    mod_bot = wp->w_redraw_bot + 1;
1560 	else
1561 	    mod_bot = 0;
1562 	if (buf->b_mod_set)
1563 	{
1564 	    if (mod_top == 0 || mod_top > buf->b_mod_top)
1565 	    {
1566 		mod_top = buf->b_mod_top;
1567 #ifdef FEAT_SYN_HL
1568 		// Need to redraw lines above the change that may be included
1569 		// in a pattern match.
1570 		if (syntax_present(wp))
1571 		{
1572 		    mod_top -= buf->b_s.b_syn_sync_linebreaks;
1573 		    if (mod_top < 1)
1574 			mod_top = 1;
1575 		}
1576 #endif
1577 	    }
1578 	    if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1579 		mod_bot = buf->b_mod_bot;
1580 
1581 #ifdef FEAT_SEARCH_EXTRA
1582 	    // When 'hlsearch' is on and using a multi-line search pattern, a
1583 	    // change in one line may make the Search highlighting in a
1584 	    // previous line invalid.  Simple solution: redraw all visible
1585 	    // lines above the change.
1586 	    // Same for a match pattern.
1587 	    if (screen_search_hl.rm.regprog != NULL
1588 		    && re_multiline(screen_search_hl.rm.regprog))
1589 		top_to_mod = TRUE;
1590 	    else
1591 	    {
1592 		matchitem_T *cur = wp->w_match_head;
1593 
1594 		while (cur != NULL)
1595 		{
1596 		    if (cur->match.regprog != NULL
1597 					   && re_multiline(cur->match.regprog))
1598 		    {
1599 			top_to_mod = TRUE;
1600 			break;
1601 		    }
1602 		    cur = cur->next;
1603 		}
1604 	    }
1605 #endif
1606 	}
1607 #ifdef FEAT_FOLDING
1608 	if (mod_top != 0 && hasAnyFolding(wp))
1609 	{
1610 	    linenr_T	lnumt, lnumb;
1611 
1612 	    // A change in a line can cause lines above it to become folded or
1613 	    // unfolded.  Find the top most buffer line that may be affected.
1614 	    // If the line was previously folded and displayed, get the first
1615 	    // line of that fold.  If the line is folded now, get the first
1616 	    // folded line.  Use the minimum of these two.
1617 
1618 	    // Find last valid w_lines[] entry above mod_top.  Set lnumt to
1619 	    // the line below it.  If there is no valid entry, use w_topline.
1620 	    // Find the first valid w_lines[] entry below mod_bot.  Set lnumb
1621 	    // to this line.  If there is no valid entry, use MAXLNUM.
1622 	    lnumt = wp->w_topline;
1623 	    lnumb = MAXLNUM;
1624 	    for (i = 0; i < wp->w_lines_valid; ++i)
1625 		if (wp->w_lines[i].wl_valid)
1626 		{
1627 		    if (wp->w_lines[i].wl_lastlnum < mod_top)
1628 			lnumt = wp->w_lines[i].wl_lastlnum + 1;
1629 		    if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1630 		    {
1631 			lnumb = wp->w_lines[i].wl_lnum;
1632 			// When there is a fold column it might need updating
1633 			// in the next line ("J" just above an open fold).
1634 			if (compute_foldcolumn(wp, 0) > 0)
1635 			    ++lnumb;
1636 		    }
1637 		}
1638 
1639 	    (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1640 	    if (mod_top > lnumt)
1641 		mod_top = lnumt;
1642 
1643 	    // Now do the same for the bottom line (one above mod_bot).
1644 	    --mod_bot;
1645 	    (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1646 	    ++mod_bot;
1647 	    if (mod_bot < lnumb)
1648 		mod_bot = lnumb;
1649 	}
1650 #endif
1651 
1652 	// When a change starts above w_topline and the end is below
1653 	// w_topline, start redrawing at w_topline.
1654 	// If the end of the change is above w_topline: do like no change was
1655 	// made, but redraw the first line to find changes in syntax.
1656 	if (mod_top != 0 && mod_top < wp->w_topline)
1657 	{
1658 	    if (mod_bot > wp->w_topline)
1659 		mod_top = wp->w_topline;
1660 #ifdef FEAT_SYN_HL
1661 	    else if (syntax_present(wp))
1662 		top_end = 1;
1663 #endif
1664 	}
1665 
1666 	// When line numbers are displayed need to redraw all lines below
1667 	// inserted/deleted lines.
1668 	if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1669 	    mod_bot = MAXLNUM;
1670     }
1671     wp->w_redraw_top = 0;	// reset for next time
1672     wp->w_redraw_bot = 0;
1673 
1674     // When only displaying the lines at the top, set top_end.  Used when
1675     // window has scrolled down for msg_scrolled.
1676     if (type == REDRAW_TOP)
1677     {
1678 	j = 0;
1679 	for (i = 0; i < wp->w_lines_valid; ++i)
1680 	{
1681 	    j += wp->w_lines[i].wl_size;
1682 	    if (j >= wp->w_upd_rows)
1683 	    {
1684 		top_end = j;
1685 		break;
1686 	    }
1687 	}
1688 	if (top_end == 0)
1689 	    // not found (cannot happen?): redraw everything
1690 	    type = NOT_VALID;
1691 	else
1692 	    // top area defined, the rest is VALID
1693 	    type = VALID;
1694     }
1695 
1696     // Trick: we want to avoid clearing the screen twice.  screenclear() will
1697     // set "screen_cleared" to TRUE.  The special value MAYBE (which is still
1698     // non-zero and thus not FALSE) will indicate that screenclear() was not
1699     // called.
1700     if (screen_cleared)
1701 	screen_cleared = MAYBE;
1702 
1703     // If there are no changes on the screen that require a complete redraw,
1704     // handle three cases:
1705     // 1: we are off the top of the screen by a few lines: scroll down
1706     // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1707     // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1708     //    w_lines[] that needs updating.
1709     if ((type == VALID || type == SOME_VALID
1710 				  || type == INVERTED || type == INVERTED_ALL)
1711 #ifdef FEAT_DIFF
1712 	    && !wp->w_botfill && !wp->w_old_botfill
1713 #endif
1714 	    )
1715     {
1716 	if (mod_top != 0
1717 		&& wp->w_topline == mod_top
1718 		&& (!wp->w_lines[0].wl_valid
1719 		    || wp->w_topline <= wp->w_lines[0].wl_lnum))
1720 	{
1721 	    // w_topline is the first changed line and window is not scrolled,
1722 	    // the scrolling from changed lines will be done further down.
1723 	}
1724 	else if (wp->w_lines[0].wl_valid
1725 		&& (wp->w_topline < wp->w_lines[0].wl_lnum
1726 #ifdef FEAT_DIFF
1727 		    || (wp->w_topline == wp->w_lines[0].wl_lnum
1728 			&& wp->w_topfill > wp->w_old_topfill)
1729 #endif
1730 		   ))
1731 	{
1732 	    // New topline is above old topline: May scroll down.
1733 #ifdef FEAT_FOLDING
1734 	    if (hasAnyFolding(wp))
1735 	    {
1736 		linenr_T ln;
1737 
1738 		// count the number of lines we are off, counting a sequence
1739 		// of folded lines as one
1740 		j = 0;
1741 		for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1742 		{
1743 		    ++j;
1744 		    if (j >= wp->w_height - 2)
1745 			break;
1746 		    (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1747 		}
1748 	    }
1749 	    else
1750 #endif
1751 		j = wp->w_lines[0].wl_lnum - wp->w_topline;
1752 	    if (j < wp->w_height - 2)		// not too far off
1753 	    {
1754 		i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1755 #ifdef FEAT_DIFF
1756 		// insert extra lines for previously invisible filler lines
1757 		if (wp->w_lines[0].wl_lnum != wp->w_topline)
1758 		    i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1759 							  - wp->w_old_topfill;
1760 #endif
1761 		if (i < wp->w_height - 2)	// less than a screen off
1762 		{
1763 		    // Try to insert the correct number of lines.
1764 		    // If not the last window, delete the lines at the bottom.
1765 		    // win_ins_lines may fail when the terminal can't do it.
1766 		    if (i > 0)
1767 			check_for_delay(FALSE);
1768 		    if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1769 		    {
1770 			if (wp->w_lines_valid != 0)
1771 			{
1772 			    // Need to update rows that are new, stop at the
1773 			    // first one that scrolled down.
1774 			    top_end = i;
1775 			    scrolled_down = TRUE;
1776 
1777 			    // Move the entries that were scrolled, disable
1778 			    // the entries for the lines to be redrawn.
1779 			    if ((wp->w_lines_valid += j) > wp->w_height)
1780 				wp->w_lines_valid = wp->w_height;
1781 			    for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1782 				wp->w_lines[idx] = wp->w_lines[idx - j];
1783 			    while (idx >= 0)
1784 				wp->w_lines[idx--].wl_valid = FALSE;
1785 			}
1786 		    }
1787 		    else
1788 			mid_start = 0;		// redraw all lines
1789 		}
1790 		else
1791 		    mid_start = 0;		// redraw all lines
1792 	    }
1793 	    else
1794 		mid_start = 0;		// redraw all lines
1795 	}
1796 	else
1797 	{
1798 	    // New topline is at or below old topline: May scroll up.
1799 	    // When topline didn't change, find first entry in w_lines[] that
1800 	    // needs updating.
1801 
1802 	    // try to find wp->w_topline in wp->w_lines[].wl_lnum
1803 	    j = -1;
1804 	    row = 0;
1805 	    for (i = 0; i < wp->w_lines_valid; i++)
1806 	    {
1807 		if (wp->w_lines[i].wl_valid
1808 			&& wp->w_lines[i].wl_lnum == wp->w_topline)
1809 		{
1810 		    j = i;
1811 		    break;
1812 		}
1813 		row += wp->w_lines[i].wl_size;
1814 	    }
1815 	    if (j == -1)
1816 	    {
1817 		// if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1818 		// lines
1819 		mid_start = 0;
1820 	    }
1821 	    else
1822 	    {
1823 		// Try to delete the correct number of lines.
1824 		// wp->w_topline is at wp->w_lines[i].wl_lnum.
1825 #ifdef FEAT_DIFF
1826 		// If the topline didn't change, delete old filler lines,
1827 		// otherwise delete filler lines of the new topline...
1828 		if (wp->w_lines[0].wl_lnum == wp->w_topline)
1829 		    row += wp->w_old_topfill;
1830 		else
1831 		    row += diff_check_fill(wp, wp->w_topline);
1832 		// ... but don't delete new filler lines.
1833 		row -= wp->w_topfill;
1834 #endif
1835 		if (row > 0)
1836 		{
1837 		    check_for_delay(FALSE);
1838 		    if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
1839 									 == OK)
1840 			bot_start = wp->w_height - row;
1841 		    else
1842 			mid_start = 0;		// redraw all lines
1843 		}
1844 		if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1845 		{
1846 		    // Skip the lines (below the deleted lines) that are still
1847 		    // valid and don't need redrawing.	Copy their info
1848 		    // upwards, to compensate for the deleted lines.  Set
1849 		    // bot_start to the first row that needs redrawing.
1850 		    bot_start = 0;
1851 		    idx = 0;
1852 		    for (;;)
1853 		    {
1854 			wp->w_lines[idx] = wp->w_lines[j];
1855 			// stop at line that didn't fit, unless it is still
1856 			// valid (no lines deleted)
1857 			if (row > 0 && bot_start + row
1858 				 + (int)wp->w_lines[j].wl_size > wp->w_height)
1859 			{
1860 			    wp->w_lines_valid = idx + 1;
1861 			    break;
1862 			}
1863 			bot_start += wp->w_lines[idx++].wl_size;
1864 
1865 			// stop at the last valid entry in w_lines[].wl_size
1866 			if (++j >= wp->w_lines_valid)
1867 			{
1868 			    wp->w_lines_valid = idx;
1869 			    break;
1870 			}
1871 		    }
1872 #ifdef FEAT_DIFF
1873 		    // Correct the first entry for filler lines at the top
1874 		    // when it won't get updated below.
1875 		    if (wp->w_p_diff && bot_start > 0)
1876 			wp->w_lines[0].wl_size =
1877 			    plines_win_nofill(wp, wp->w_topline, TRUE)
1878 							      + wp->w_topfill;
1879 #endif
1880 		}
1881 	    }
1882 	}
1883 
1884 	// When starting redraw in the first line, redraw all lines.  When
1885 	// there is only one window it's probably faster to clear the screen
1886 	// first.
1887 	if (mid_start == 0)
1888 	{
1889 	    mid_end = wp->w_height;
1890 	    if (ONE_WINDOW && !WIN_IS_POPUP(wp))
1891 	    {
1892 		// Clear the screen when it was not done by win_del_lines() or
1893 		// win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1894 		// then.
1895 		if (screen_cleared != TRUE)
1896 		    screenclear();
1897 		// The screen was cleared, redraw the tab pages line.
1898 		if (redraw_tabline)
1899 		    draw_tabline();
1900 	    }
1901 	}
1902 
1903 	// When win_del_lines() or win_ins_lines() caused the screen to be
1904 	// cleared (only happens for the first window) or when screenclear()
1905 	// was called directly above, "must_redraw" will have been set to
1906 	// NOT_VALID, need to reset it here to avoid redrawing twice.
1907 	if (screen_cleared == TRUE)
1908 	    must_redraw = 0;
1909     }
1910     else
1911     {
1912 	// Not VALID or INVERTED: redraw all lines.
1913 	mid_start = 0;
1914 	mid_end = wp->w_height;
1915     }
1916 
1917     if (type == SOME_VALID)
1918     {
1919 	// SOME_VALID: redraw all lines.
1920 	mid_start = 0;
1921 	mid_end = wp->w_height;
1922 	type = NOT_VALID;
1923     }
1924 
1925     // check if we are updating or removing the inverted part
1926     if ((VIsual_active && buf == curwin->w_buffer)
1927 	    || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1928     {
1929 	linenr_T    from, to;
1930 
1931 	if (VIsual_active)
1932 	{
1933 	    if (VIsual_active
1934 		    && (VIsual_mode != wp->w_old_visual_mode
1935 			|| type == INVERTED_ALL))
1936 	    {
1937 		// If the type of Visual selection changed, redraw the whole
1938 		// selection.  Also when the ownership of the X selection is
1939 		// gained or lost.
1940 		if (curwin->w_cursor.lnum < VIsual.lnum)
1941 		{
1942 		    from = curwin->w_cursor.lnum;
1943 		    to = VIsual.lnum;
1944 		}
1945 		else
1946 		{
1947 		    from = VIsual.lnum;
1948 		    to = curwin->w_cursor.lnum;
1949 		}
1950 		// redraw more when the cursor moved as well
1951 		if (wp->w_old_cursor_lnum < from)
1952 		    from = wp->w_old_cursor_lnum;
1953 		if (wp->w_old_cursor_lnum > to)
1954 		    to = wp->w_old_cursor_lnum;
1955 		if (wp->w_old_visual_lnum < from)
1956 		    from = wp->w_old_visual_lnum;
1957 		if (wp->w_old_visual_lnum > to)
1958 		    to = wp->w_old_visual_lnum;
1959 	    }
1960 	    else
1961 	    {
1962 		// Find the line numbers that need to be updated: The lines
1963 		// between the old cursor position and the current cursor
1964 		// position.  Also check if the Visual position changed.
1965 		if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1966 		{
1967 		    from = curwin->w_cursor.lnum;
1968 		    to = wp->w_old_cursor_lnum;
1969 		}
1970 		else
1971 		{
1972 		    from = wp->w_old_cursor_lnum;
1973 		    to = curwin->w_cursor.lnum;
1974 		    if (from == 0)	// Visual mode just started
1975 			from = to;
1976 		}
1977 
1978 		if (VIsual.lnum != wp->w_old_visual_lnum
1979 					|| VIsual.col != wp->w_old_visual_col)
1980 		{
1981 		    if (wp->w_old_visual_lnum < from
1982 						&& wp->w_old_visual_lnum != 0)
1983 			from = wp->w_old_visual_lnum;
1984 		    if (wp->w_old_visual_lnum > to)
1985 			to = wp->w_old_visual_lnum;
1986 		    if (VIsual.lnum < from)
1987 			from = VIsual.lnum;
1988 		    if (VIsual.lnum > to)
1989 			to = VIsual.lnum;
1990 		}
1991 	    }
1992 
1993 	    // If in block mode and changed column or curwin->w_curswant:
1994 	    // update all lines.
1995 	    // First compute the actual start and end column.
1996 	    if (VIsual_mode == Ctrl_V)
1997 	    {
1998 		colnr_T	    fromc, toc;
1999 #if defined(FEAT_LINEBREAK)
2000 		int	    save_ve_flags = ve_flags;
2001 
2002 		if (curwin->w_p_lbr)
2003 		    ve_flags = VE_ALL;
2004 #endif
2005 		getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
2006 #if defined(FEAT_LINEBREAK)
2007 		ve_flags = save_ve_flags;
2008 #endif
2009 		++toc;
2010 		if (curwin->w_curswant == MAXCOL)
2011 		    toc = MAXCOL;
2012 
2013 		if (fromc != wp->w_old_cursor_fcol
2014 			|| toc != wp->w_old_cursor_lcol)
2015 		{
2016 		    if (from > VIsual.lnum)
2017 			from = VIsual.lnum;
2018 		    if (to < VIsual.lnum)
2019 			to = VIsual.lnum;
2020 		}
2021 		wp->w_old_cursor_fcol = fromc;
2022 		wp->w_old_cursor_lcol = toc;
2023 	    }
2024 	}
2025 	else
2026 	{
2027 	    // Use the line numbers of the old Visual area.
2028 	    if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
2029 	    {
2030 		from = wp->w_old_cursor_lnum;
2031 		to = wp->w_old_visual_lnum;
2032 	    }
2033 	    else
2034 	    {
2035 		from = wp->w_old_visual_lnum;
2036 		to = wp->w_old_cursor_lnum;
2037 	    }
2038 	}
2039 
2040 	// There is no need to update lines above the top of the window.
2041 	if (from < wp->w_topline)
2042 	    from = wp->w_topline;
2043 
2044 	// If we know the value of w_botline, use it to restrict the update to
2045 	// the lines that are visible in the window.
2046 	if (wp->w_valid & VALID_BOTLINE)
2047 	{
2048 	    if (from >= wp->w_botline)
2049 		from = wp->w_botline - 1;
2050 	    if (to >= wp->w_botline)
2051 		to = wp->w_botline - 1;
2052 	}
2053 
2054 	// Find the minimal part to be updated.
2055 	// Watch out for scrolling that made entries in w_lines[] invalid.
2056 	// E.g., CTRL-U makes the first half of w_lines[] invalid and sets
2057 	// top_end; need to redraw from top_end to the "to" line.
2058 	// A middle mouse click with a Visual selection may change the text
2059 	// above the Visual area and reset wl_valid, do count these for
2060 	// mid_end (in srow).
2061 	if (mid_start > 0)
2062 	{
2063 	    lnum = wp->w_topline;
2064 	    idx = 0;
2065 	    srow = 0;
2066 	    if (scrolled_down)
2067 		mid_start = top_end;
2068 	    else
2069 		mid_start = 0;
2070 	    while (lnum < from && idx < wp->w_lines_valid)	// find start
2071 	    {
2072 		if (wp->w_lines[idx].wl_valid)
2073 		    mid_start += wp->w_lines[idx].wl_size;
2074 		else if (!scrolled_down)
2075 		    srow += wp->w_lines[idx].wl_size;
2076 		++idx;
2077 # ifdef FEAT_FOLDING
2078 		if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
2079 		    lnum = wp->w_lines[idx].wl_lnum;
2080 		else
2081 # endif
2082 		    ++lnum;
2083 	    }
2084 	    srow += mid_start;
2085 	    mid_end = wp->w_height;
2086 	    for ( ; idx < wp->w_lines_valid; ++idx)		// find end
2087 	    {
2088 		if (wp->w_lines[idx].wl_valid
2089 			&& wp->w_lines[idx].wl_lnum >= to + 1)
2090 		{
2091 		    // Only update until first row of this line
2092 		    mid_end = srow;
2093 		    break;
2094 		}
2095 		srow += wp->w_lines[idx].wl_size;
2096 	    }
2097 	}
2098     }
2099 
2100     if (VIsual_active && buf == curwin->w_buffer)
2101     {
2102 	wp->w_old_visual_mode = VIsual_mode;
2103 	wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
2104 	wp->w_old_visual_lnum = VIsual.lnum;
2105 	wp->w_old_visual_col = VIsual.col;
2106 	wp->w_old_curswant = curwin->w_curswant;
2107     }
2108     else
2109     {
2110 	wp->w_old_visual_mode = 0;
2111 	wp->w_old_cursor_lnum = 0;
2112 	wp->w_old_visual_lnum = 0;
2113 	wp->w_old_visual_col = 0;
2114     }
2115 
2116 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2117     // reset got_int, otherwise regexp won't work
2118     save_got_int = got_int;
2119     got_int = 0;
2120 #endif
2121 #ifdef SYN_TIME_LIMIT
2122     // Set the time limit to 'redrawtime'.
2123     profile_setlimit(p_rdt, &syntax_tm);
2124     syn_set_timeout(&syntax_tm);
2125 #endif
2126 #ifdef FEAT_FOLDING
2127     win_foldinfo.fi_level = 0;
2128 #endif
2129 
2130 #ifdef FEAT_MENU
2131     // Draw the window toolbar, if there is one.
2132     // TODO: only when needed.
2133     if (winbar_height(wp) > 0)
2134 	redraw_win_toolbar(wp);
2135 #endif
2136 
2137     // Update all the window rows.
2138     idx = 0;		// first entry in w_lines[].wl_size
2139     row = 0;
2140     srow = 0;
2141     lnum = wp->w_topline;	// first line shown in window
2142     for (;;)
2143     {
2144 	// stop updating when reached the end of the window (check for _past_
2145 	// the end of the window is at the end of the loop)
2146 	if (row == wp->w_height)
2147 	{
2148 	    didline = TRUE;
2149 	    break;
2150 	}
2151 
2152 	// stop updating when hit the end of the file
2153 	if (lnum > buf->b_ml.ml_line_count)
2154 	{
2155 	    eof = TRUE;
2156 	    break;
2157 	}
2158 
2159 	// Remember the starting row of the line that is going to be dealt
2160 	// with.  It is used further down when the line doesn't fit.
2161 	srow = row;
2162 
2163 	// Update a line when it is in an area that needs updating, when it
2164 	// has changes or w_lines[idx] is invalid.
2165 	// "bot_start" may be halfway a wrapped line after using
2166 	// win_del_lines(), check if the current line includes it.
2167 	// When syntax folding is being used, the saved syntax states will
2168 	// already have been updated, we can't see where the syntax state is
2169 	// the same again, just update until the end of the window.
2170 	if (row < top_end
2171 		|| (row >= mid_start && row < mid_end)
2172 #ifdef FEAT_SEARCH_EXTRA
2173 		|| top_to_mod
2174 #endif
2175 		|| idx >= wp->w_lines_valid
2176 		|| (row + wp->w_lines[idx].wl_size > bot_start)
2177 		|| (mod_top != 0
2178 		    && (lnum == mod_top
2179 			|| (lnum >= mod_top
2180 			    && (lnum < mod_bot
2181 #ifdef FEAT_SYN_HL
2182 				|| did_update == DID_FOLD
2183 				|| (did_update == DID_LINE
2184 				    && syntax_present(wp)
2185 				    && (
2186 # ifdef FEAT_FOLDING
2187 					(foldmethodIsSyntax(wp)
2188 						      && hasAnyFolding(wp)) ||
2189 # endif
2190 					syntax_check_changed(lnum)))
2191 #endif
2192 #ifdef FEAT_SEARCH_EXTRA
2193 				// match in fixed position might need redraw
2194 				// if lines were inserted or deleted
2195 				|| (wp->w_match_head != NULL
2196 						    && buf->b_mod_xlines != 0)
2197 #endif
2198 				))))
2199 #ifdef FEAT_SYN_HL
2200 		|| (wp->w_p_cul && (lnum == wp->w_cursor.lnum
2201 					     || lnum == wp->w_last_cursorline))
2202 #endif
2203 				)
2204 	{
2205 #ifdef FEAT_SEARCH_EXTRA
2206 	    if (lnum == mod_top)
2207 		top_to_mod = FALSE;
2208 #endif
2209 
2210 	    // When at start of changed lines: May scroll following lines
2211 	    // up or down to minimize redrawing.
2212 	    // Don't do this when the change continues until the end.
2213 	    // Don't scroll when dollar_vcol >= 0, keep the "$".
2214 	    if (lnum == mod_top
2215 		    && mod_bot != MAXLNUM
2216 		    && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
2217 	    {
2218 		int		old_rows = 0;
2219 		int		new_rows = 0;
2220 		int		xtra_rows;
2221 		linenr_T	l;
2222 
2223 		// Count the old number of window rows, using w_lines[], which
2224 		// should still contain the sizes for the lines as they are
2225 		// currently displayed.
2226 		for (i = idx; i < wp->w_lines_valid; ++i)
2227 		{
2228 		    // Only valid lines have a meaningful wl_lnum.  Invalid
2229 		    // lines are part of the changed area.
2230 		    if (wp->w_lines[i].wl_valid
2231 			    && wp->w_lines[i].wl_lnum == mod_bot)
2232 			break;
2233 		    old_rows += wp->w_lines[i].wl_size;
2234 #ifdef FEAT_FOLDING
2235 		    if (wp->w_lines[i].wl_valid
2236 			    && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
2237 		    {
2238 			// Must have found the last valid entry above mod_bot.
2239 			// Add following invalid entries.
2240 			++i;
2241 			while (i < wp->w_lines_valid
2242 						  && !wp->w_lines[i].wl_valid)
2243 			    old_rows += wp->w_lines[i++].wl_size;
2244 			break;
2245 		    }
2246 #endif
2247 		}
2248 
2249 		if (i >= wp->w_lines_valid)
2250 		{
2251 		    // We can't find a valid line below the changed lines,
2252 		    // need to redraw until the end of the window.
2253 		    // Inserting/deleting lines has no use.
2254 		    bot_start = 0;
2255 		}
2256 		else
2257 		{
2258 		    // Able to count old number of rows: Count new window
2259 		    // rows, and may insert/delete lines
2260 		    j = idx;
2261 		    for (l = lnum; l < mod_bot; ++l)
2262 		    {
2263 #ifdef FEAT_FOLDING
2264 			if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
2265 			    ++new_rows;
2266 			else
2267 #endif
2268 #ifdef FEAT_DIFF
2269 			    if (l == wp->w_topline)
2270 			    new_rows += plines_win_nofill(wp, l, TRUE)
2271 							      + wp->w_topfill;
2272 			else
2273 #endif
2274 			    new_rows += plines_win(wp, l, TRUE);
2275 			++j;
2276 			if (new_rows > wp->w_height - row - 2)
2277 			{
2278 			    // it's getting too much, must redraw the rest
2279 			    new_rows = 9999;
2280 			    break;
2281 			}
2282 		    }
2283 		    xtra_rows = new_rows - old_rows;
2284 		    if (xtra_rows < 0)
2285 		    {
2286 			// May scroll text up.  If there is not enough
2287 			// remaining text or scrolling fails, must redraw the
2288 			// rest.  If scrolling works, must redraw the text
2289 			// below the scrolled text.
2290 			if (row - xtra_rows >= wp->w_height - 2)
2291 			    mod_bot = MAXLNUM;
2292 			else
2293 			{
2294 			    check_for_delay(FALSE);
2295 			    if (win_del_lines(wp, row,
2296 					  -xtra_rows, FALSE, FALSE, 0) == FAIL)
2297 				mod_bot = MAXLNUM;
2298 			    else
2299 				bot_start = wp->w_height + xtra_rows;
2300 			}
2301 		    }
2302 		    else if (xtra_rows > 0)
2303 		    {
2304 			// May scroll text down.  If there is not enough
2305 			// remaining text of scrolling fails, must redraw the
2306 			// rest.
2307 			if (row + xtra_rows >= wp->w_height - 2)
2308 			    mod_bot = MAXLNUM;
2309 			else
2310 			{
2311 			    check_for_delay(FALSE);
2312 			    if (win_ins_lines(wp, row + old_rows,
2313 					     xtra_rows, FALSE, FALSE) == FAIL)
2314 				mod_bot = MAXLNUM;
2315 			    else if (top_end > row + old_rows)
2316 				// Scrolled the part at the top that requires
2317 				// updating down.
2318 				top_end += xtra_rows;
2319 			}
2320 		    }
2321 
2322 		    // When not updating the rest, may need to move w_lines[]
2323 		    // entries.
2324 		    if (mod_bot != MAXLNUM && i != j)
2325 		    {
2326 			if (j < i)
2327 			{
2328 			    int x = row + new_rows;
2329 
2330 			    // move entries in w_lines[] upwards
2331 			    for (;;)
2332 			    {
2333 				// stop at last valid entry in w_lines[]
2334 				if (i >= wp->w_lines_valid)
2335 				{
2336 				    wp->w_lines_valid = j;
2337 				    break;
2338 				}
2339 				wp->w_lines[j] = wp->w_lines[i];
2340 				// stop at a line that won't fit
2341 				if (x + (int)wp->w_lines[j].wl_size
2342 							   > wp->w_height)
2343 				{
2344 				    wp->w_lines_valid = j + 1;
2345 				    break;
2346 				}
2347 				x += wp->w_lines[j++].wl_size;
2348 				++i;
2349 			    }
2350 			    if (bot_start > x)
2351 				bot_start = x;
2352 			}
2353 			else // j > i
2354 			{
2355 			    // move entries in w_lines[] downwards
2356 			    j -= i;
2357 			    wp->w_lines_valid += j;
2358 			    if (wp->w_lines_valid > wp->w_height)
2359 				wp->w_lines_valid = wp->w_height;
2360 			    for (i = wp->w_lines_valid; i - j >= idx; --i)
2361 				wp->w_lines[i] = wp->w_lines[i - j];
2362 
2363 			    // The w_lines[] entries for inserted lines are
2364 			    // now invalid, but wl_size may be used above.
2365 			    // Reset to zero.
2366 			    while (i >= idx)
2367 			    {
2368 				wp->w_lines[i].wl_size = 0;
2369 				wp->w_lines[i--].wl_valid = FALSE;
2370 			    }
2371 			}
2372 		    }
2373 		}
2374 	    }
2375 
2376 #ifdef FEAT_FOLDING
2377 	    // When lines are folded, display one line for all of them.
2378 	    // Otherwise, display normally (can be several display lines when
2379 	    // 'wrap' is on).
2380 	    fold_count = foldedCount(wp, lnum, &win_foldinfo);
2381 	    if (fold_count != 0)
2382 	    {
2383 		fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2384 		++row;
2385 		--fold_count;
2386 		wp->w_lines[idx].wl_folded = TRUE;
2387 		wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2388 # ifdef FEAT_SYN_HL
2389 		did_update = DID_FOLD;
2390 # endif
2391 	    }
2392 	    else
2393 #endif
2394 	    if (idx < wp->w_lines_valid
2395 		    && wp->w_lines[idx].wl_valid
2396 		    && wp->w_lines[idx].wl_lnum == lnum
2397 		    && lnum > wp->w_topline
2398 		    && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
2399 		    && !WIN_IS_POPUP(wp)
2400 		    && srow + wp->w_lines[idx].wl_size > wp->w_height
2401 #ifdef FEAT_DIFF
2402 		    && diff_check_fill(wp, lnum) == 0
2403 #endif
2404 		    )
2405 	    {
2406 		// This line is not going to fit.  Don't draw anything here,
2407 		// will draw "@  " lines below.
2408 		row = wp->w_height + 1;
2409 	    }
2410 	    else
2411 	    {
2412 #ifdef FEAT_SEARCH_EXTRA
2413 		prepare_search_hl(wp, &screen_search_hl, lnum);
2414 #endif
2415 #ifdef FEAT_SYN_HL
2416 		// Let the syntax stuff know we skipped a few lines.
2417 		if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
2418 						       && syntax_present(wp))
2419 		    syntax_end_parsing(syntax_last_parsed + 1);
2420 #endif
2421 
2422 		// Display one line.
2423 		row = win_line(wp, lnum, srow, wp->w_height,
2424 							  mod_top == 0, FALSE);
2425 
2426 #ifdef FEAT_FOLDING
2427 		wp->w_lines[idx].wl_folded = FALSE;
2428 		wp->w_lines[idx].wl_lastlnum = lnum;
2429 #endif
2430 #ifdef FEAT_SYN_HL
2431 		did_update = DID_LINE;
2432 		syntax_last_parsed = lnum;
2433 #endif
2434 	    }
2435 
2436 	    wp->w_lines[idx].wl_lnum = lnum;
2437 	    wp->w_lines[idx].wl_valid = TRUE;
2438 
2439 	    // Past end of the window or end of the screen. Note that after
2440 	    // resizing wp->w_height may be end up too big. That's a problem
2441 	    // elsewhere, but prevent a crash here.
2442 	    if (row > wp->w_height || row + wp->w_winrow >= Rows)
2443 	    {
2444 		// we may need the size of that too long line later on
2445 		if (dollar_vcol == -1)
2446 		    wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2447 		++idx;
2448 		break;
2449 	    }
2450 	    if (dollar_vcol == -1)
2451 		wp->w_lines[idx].wl_size = row - srow;
2452 	    ++idx;
2453 #ifdef FEAT_FOLDING
2454 	    lnum += fold_count + 1;
2455 #else
2456 	    ++lnum;
2457 #endif
2458 	}
2459 	else
2460 	{
2461 	    if (wp->w_p_rnu)
2462 	    {
2463 #ifdef FEAT_FOLDING
2464 		// 'relativenumber' set: The text doesn't need to be drawn, but
2465 		// the number column nearly always does.
2466 		fold_count = foldedCount(wp, lnum, &win_foldinfo);
2467 		if (fold_count != 0)
2468 		    fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2469 		else
2470 #endif
2471 		    (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE);
2472 	    }
2473 
2474 	    // This line does not need to be drawn, advance to the next one.
2475 	    row += wp->w_lines[idx++].wl_size;
2476 	    if (row > wp->w_height)	// past end of screen
2477 		break;
2478 #ifdef FEAT_FOLDING
2479 	    lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2480 #else
2481 	    ++lnum;
2482 #endif
2483 #ifdef FEAT_SYN_HL
2484 	    did_update = DID_NONE;
2485 #endif
2486 	}
2487 
2488 	if (lnum > buf->b_ml.ml_line_count)
2489 	{
2490 	    eof = TRUE;
2491 	    break;
2492 	}
2493     }
2494 
2495     // End of loop over all window lines.
2496 
2497 #ifdef FEAT_VTP
2498     // Rewrite the character at the end of the screen line.
2499     // See the version that was fixed.
2500     if (use_vtp() && get_conpty_fix_type() < 1)
2501     {
2502 	int i;
2503 
2504 	for (i = 0; i < Rows; ++i)
2505 	    if (enc_utf8)
2506 		if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
2507 					   LineOffset[i] + screen_Columns) > 1)
2508 		    screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
2509 		else
2510 		    screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
2511 	    else
2512 		screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
2513     }
2514 #endif
2515 
2516     if (idx > wp->w_lines_valid)
2517 	wp->w_lines_valid = idx;
2518 
2519 #ifdef FEAT_SYN_HL
2520     // Let the syntax stuff know we stop parsing here.
2521     if (syntax_last_parsed != 0 && syntax_present(wp))
2522 	syntax_end_parsing(syntax_last_parsed + 1);
2523 #endif
2524 
2525     // If we didn't hit the end of the file, and we didn't finish the last
2526     // line we were working on, then the line didn't fit.
2527     wp->w_empty_rows = 0;
2528 #ifdef FEAT_DIFF
2529     wp->w_filler_rows = 0;
2530 #endif
2531     if (!eof && !didline)
2532     {
2533 	if (lnum == wp->w_topline)
2534 	{
2535 	    // Single line that does not fit!
2536 	    // Don't overwrite it, it can be edited.
2537 	    wp->w_botline = lnum + 1;
2538 	}
2539 #ifdef FEAT_DIFF
2540 	else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2541 	{
2542 	    // Window ends in filler lines.
2543 	    wp->w_botline = lnum;
2544 	    wp->w_filler_rows = wp->w_height - srow;
2545 	}
2546 #endif
2547 #ifdef FEAT_PROP_POPUP
2548 	else if (WIN_IS_POPUP(wp))
2549 	{
2550 	    // popup line that doesn't fit is left as-is
2551 	    wp->w_botline = lnum;
2552 	}
2553 #endif
2554 	else if (dy_flags & DY_TRUNCATE)	// 'display' has "truncate"
2555 	{
2556 	    int scr_row = W_WINROW(wp) + wp->w_height - 1;
2557 
2558 	    // Last line isn't finished: Display "@@@" in the last screen line.
2559 	    screen_puts_len((char_u *)"@@", 2, scr_row, wp->w_wincol,
2560 							      HL_ATTR(HLF_AT));
2561 	    screen_fill(scr_row, scr_row + 1,
2562 		    (int)wp->w_wincol + 2, (int)W_ENDCOL(wp),
2563 		    '@', ' ', HL_ATTR(HLF_AT));
2564 	    set_empty_rows(wp, srow);
2565 	    wp->w_botline = lnum;
2566 	}
2567 	else if (dy_flags & DY_LASTLINE)	// 'display' has "lastline"
2568 	{
2569 	    // Last line isn't finished: Display "@@@" at the end.
2570 	    screen_fill(W_WINROW(wp) + wp->w_height - 1,
2571 		    W_WINROW(wp) + wp->w_height,
2572 		    (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
2573 		    '@', '@', HL_ATTR(HLF_AT));
2574 	    set_empty_rows(wp, srow);
2575 	    wp->w_botline = lnum;
2576 	}
2577 	else
2578 	{
2579 	    win_draw_end(wp, '@', ' ', TRUE, srow, wp->w_height, HLF_AT);
2580 	    wp->w_botline = lnum;
2581 	}
2582     }
2583     else
2584     {
2585 	draw_vsep_win(wp, row);
2586 	if (eof)		// we hit the end of the file
2587 	{
2588 	    wp->w_botline = buf->b_ml.ml_line_count + 1;
2589 #ifdef FEAT_DIFF
2590 	    j = diff_check_fill(wp, wp->w_botline);
2591 	    if (j > 0 && !wp->w_botfill)
2592 	    {
2593 		// Display filler lines at the end of the file.
2594 		if (char2cells(fill_diff) > 1)
2595 		    i = '-';
2596 		else
2597 		    i = fill_diff;
2598 		if (row + j > wp->w_height)
2599 		    j = wp->w_height - row;
2600 		win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED);
2601 		row += j;
2602 	    }
2603 #endif
2604 	}
2605 	else if (dollar_vcol == -1)
2606 	    wp->w_botline = lnum;
2607 
2608 	// Make sure the rest of the screen is blank
2609 	// write the 'fill_eob' character to rows that aren't part of the file
2610 	if (WIN_IS_POPUP(wp))
2611 	    win_draw_end(wp, ' ', ' ', FALSE, row, wp->w_height, HLF_AT);
2612 	else
2613 	    win_draw_end(wp, fill_eob, ' ', FALSE, row, wp->w_height, HLF_EOB);
2614     }
2615 
2616 #ifdef SYN_TIME_LIMIT
2617     syn_set_timeout(NULL);
2618 #endif
2619 
2620     // Reset the type of redrawing required, the window has been updated.
2621     wp->w_redr_type = 0;
2622 #ifdef FEAT_DIFF
2623     wp->w_old_topfill = wp->w_topfill;
2624     wp->w_old_botfill = wp->w_botfill;
2625 #endif
2626 
2627     if (dollar_vcol == -1)
2628     {
2629 	// There is a trick with w_botline.  If we invalidate it on each
2630 	// change that might modify it, this will cause a lot of expensive
2631 	// calls to plines() in update_topline() each time.  Therefore the
2632 	// value of w_botline is often approximated, and this value is used to
2633 	// compute the value of w_topline.  If the value of w_botline was
2634 	// wrong, check that the value of w_topline is correct (cursor is on
2635 	// the visible part of the text).  If it's not, we need to redraw
2636 	// again.  Mostly this just means scrolling up a few lines, so it
2637 	// doesn't look too bad.  Only do this for the current window (where
2638 	// changes are relevant).
2639 	wp->w_valid |= VALID_BOTLINE;
2640 	if (wp == curwin && wp->w_botline != old_botline && !recursive)
2641 	{
2642 	    win_T	*wwp;
2643 #if defined(FEAT_CONCEAL)
2644 	    linenr_T	old_topline = wp->w_topline;
2645 	    int		new_wcol = wp->w_wcol;
2646 #endif
2647 	    recursive = TRUE;
2648 	    curwin->w_valid &= ~VALID_TOPLINE;
2649 	    update_topline();	// may invalidate w_botline again
2650 
2651 #if defined(FEAT_CONCEAL)
2652 	    if (old_wcol != new_wcol && (wp->w_valid & (VALID_WCOL|VALID_WROW))
2653 						    != (VALID_WCOL|VALID_WROW))
2654 	    {
2655 		// A win_line() call applied a fix to screen cursor column to
2656 		// accommodate concealment of cursor line, but in this call to
2657 		// update_topline() the cursor's row or column got invalidated.
2658 		// If they are left invalid, setcursor() will recompute them
2659 		// but there won't be any further win_line() call to re-fix the
2660 		// column and the cursor will end up misplaced.  So we call
2661 		// cursor validation now and reapply the fix again (or call
2662 		// win_line() to do it for us).
2663 		validate_cursor();
2664 		if (wp->w_wcol == old_wcol && wp->w_wrow == old_wrow
2665 					       && old_topline == wp->w_topline)
2666 		    wp->w_wcol = new_wcol;
2667 		else
2668 		    redrawWinline(wp, wp->w_cursor.lnum);
2669 	    }
2670 #endif
2671 	    // New redraw either due to updated topline or due to wcol fix.
2672 	    if (wp->w_redr_type != 0)
2673 	    {
2674 		// Don't update for changes in buffer again.
2675 		i = curbuf->b_mod_set;
2676 		curbuf->b_mod_set = FALSE;
2677 		j = curbuf->b_mod_xlines;
2678 		curbuf->b_mod_xlines = 0;
2679 		win_update(curwin);
2680 		curbuf->b_mod_set = i;
2681 		curbuf->b_mod_xlines = j;
2682 	    }
2683 	    // Other windows might have w_redr_type raised in update_topline().
2684 	    must_redraw = 0;
2685 	    FOR_ALL_WINDOWS(wwp)
2686 		if (wwp->w_redr_type > must_redraw)
2687 		    must_redraw = wwp->w_redr_type;
2688 	    recursive = FALSE;
2689 	}
2690     }
2691 
2692 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2693     // restore got_int, unless CTRL-C was hit while redrawing
2694     if (!got_int)
2695 	got_int = save_got_int;
2696 #endif
2697 }
2698 
2699 #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_GUI)
2700 /*
2701  * Prepare for updating one or more windows.
2702  * Caller must check for "updating_screen" already set to avoid recursiveness.
2703  */
2704     static void
2705 update_prepare(void)
2706 {
2707     cursor_off();
2708     updating_screen = TRUE;
2709 #ifdef FEAT_GUI
2710     // Remove the cursor before starting to do anything, because scrolling may
2711     // make it difficult to redraw the text under it.
2712     if (gui.in_use)
2713 	gui_undraw_cursor();
2714 #endif
2715 #ifdef FEAT_SEARCH_EXTRA
2716     start_search_hl();
2717 #endif
2718 #ifdef FEAT_PROP_POPUP
2719     // Update popup_mask if needed.
2720     may_update_popup_mask(must_redraw);
2721 #endif
2722 }
2723 
2724 /*
2725  * Finish updating one or more windows.
2726  */
2727     static void
2728 update_finish(void)
2729 {
2730     if (redraw_cmdline || redraw_mode)
2731 	showmode();
2732 
2733 # ifdef FEAT_SEARCH_EXTRA
2734     end_search_hl();
2735 # endif
2736 
2737     after_updating_screen(TRUE);
2738 
2739 # ifdef FEAT_GUI
2740     // Redraw the cursor and update the scrollbars when all screen updating is
2741     // done.
2742     if (gui.in_use)
2743     {
2744 	out_flush_cursor(FALSE, FALSE);
2745 	gui_update_scrollbars(FALSE);
2746     }
2747 # endif
2748 }
2749 #endif
2750 
2751 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
2752     void
2753 update_debug_sign(buf_T *buf, linenr_T lnum)
2754 {
2755     win_T	*wp;
2756     int		doit = FALSE;
2757 
2758 # ifdef FEAT_FOLDING
2759     win_foldinfo.fi_level = 0;
2760 # endif
2761 
2762     // update/delete a specific sign
2763     redraw_buf_line_later(buf, lnum);
2764 
2765     // check if it resulted in the need to redraw a window
2766     FOR_ALL_WINDOWS(wp)
2767 	if (wp->w_redr_type != 0)
2768 	    doit = TRUE;
2769 
2770     // Return when there is nothing to do, screen updating is already
2771     // happening (recursive call), messages on the screen or still starting up.
2772     if (!doit || updating_screen
2773 	    || State == ASKMORE || State == HITRETURN
2774 	    || msg_scrolled
2775 #ifdef FEAT_GUI
2776 	    || gui.starting
2777 #endif
2778 	    || starting)
2779 	return;
2780 
2781     // update all windows that need updating
2782     update_prepare();
2783 
2784     FOR_ALL_WINDOWS(wp)
2785     {
2786 	if (wp->w_redr_type != 0)
2787 	    win_update(wp);
2788 	if (wp->w_redr_status)
2789 	    win_redr_status(wp, FALSE);
2790     }
2791 
2792     update_finish();
2793 }
2794 #endif
2795 
2796 #if defined(FEAT_GUI) || defined(PROTO)
2797 /*
2798  * Update a single window, its status line and maybe the command line msg.
2799  * Used for the GUI scrollbar.
2800  */
2801     void
2802 updateWindow(win_T *wp)
2803 {
2804     // return if already busy updating
2805     if (updating_screen)
2806 	return;
2807 
2808     update_prepare();
2809 
2810 #ifdef FEAT_CLIPBOARD
2811     // When Visual area changed, may have to update selection.
2812     if (clip_star.available && clip_isautosel_star())
2813 	clip_update_selection(&clip_star);
2814     if (clip_plus.available && clip_isautosel_plus())
2815 	clip_update_selection(&clip_plus);
2816 #endif
2817 
2818     win_update(wp);
2819 
2820     // When the screen was cleared redraw the tab pages line.
2821     if (redraw_tabline)
2822 	draw_tabline();
2823 
2824     if (wp->w_redr_status
2825 # ifdef FEAT_CMDL_INFO
2826 	    || p_ru
2827 # endif
2828 # ifdef FEAT_STL_OPT
2829 	    || *p_stl != NUL || *wp->w_p_stl != NUL
2830 # endif
2831 	    )
2832 	win_redr_status(wp, FALSE);
2833 
2834 #ifdef FEAT_PROP_POPUP
2835     // Display popup windows on top of everything.
2836     update_popups(win_update);
2837 #endif
2838 
2839     update_finish();
2840 }
2841 #endif
2842 
2843 #if defined(FEAT_TERMRESPONSE) || defined(PROTO)
2844 /*
2845  * Redraw as soon as possible.  When the command line is not scrolled redraw
2846  * right away and restore what was on the command line.
2847  * Return a code indicating what happened.
2848  */
2849     int
2850 redraw_asap(int type)
2851 {
2852     int		rows;
2853     int		cols = screen_Columns;
2854     int		r;
2855     int		ret = 0;
2856     schar_T	*screenline;	// copy from ScreenLines[]
2857     sattr_T	*screenattr;	// copy from ScreenAttrs[]
2858     int		i;
2859     u8char_T	*screenlineUC = NULL;	// copy from ScreenLinesUC[]
2860     u8char_T	*screenlineC[MAX_MCO];	// copy from ScreenLinesC[][]
2861     schar_T	*screenline2 = NULL;	// copy from ScreenLines2[]
2862 
2863     redraw_later(type);
2864     if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
2865 	return ret;
2866 
2867     // Allocate space to save the text displayed in the command line area.
2868     rows = screen_Rows - cmdline_row;
2869     screenline = LALLOC_MULT(schar_T, rows * cols);
2870     screenattr = LALLOC_MULT(sattr_T, rows * cols);
2871     if (screenline == NULL || screenattr == NULL)
2872 	ret = 2;
2873     if (enc_utf8)
2874     {
2875 	screenlineUC = LALLOC_MULT(u8char_T, rows * cols);
2876 	if (screenlineUC == NULL)
2877 	    ret = 2;
2878 	for (i = 0; i < p_mco; ++i)
2879 	{
2880 	    screenlineC[i] = LALLOC_MULT(u8char_T, rows * cols);
2881 	    if (screenlineC[i] == NULL)
2882 		ret = 2;
2883 	}
2884     }
2885     if (enc_dbcs == DBCS_JPNU)
2886     {
2887 	screenline2 = LALLOC_MULT(schar_T, rows * cols);
2888 	if (screenline2 == NULL)
2889 	    ret = 2;
2890     }
2891 
2892     if (ret != 2)
2893     {
2894 	// Save the text displayed in the command line area.
2895 	for (r = 0; r < rows; ++r)
2896 	{
2897 	    mch_memmove(screenline + r * cols,
2898 			ScreenLines + LineOffset[cmdline_row + r],
2899 			(size_t)cols * sizeof(schar_T));
2900 	    mch_memmove(screenattr + r * cols,
2901 			ScreenAttrs + LineOffset[cmdline_row + r],
2902 			(size_t)cols * sizeof(sattr_T));
2903 	    if (enc_utf8)
2904 	    {
2905 		mch_memmove(screenlineUC + r * cols,
2906 			    ScreenLinesUC + LineOffset[cmdline_row + r],
2907 			    (size_t)cols * sizeof(u8char_T));
2908 		for (i = 0; i < p_mco; ++i)
2909 		    mch_memmove(screenlineC[i] + r * cols,
2910 				ScreenLinesC[i] + LineOffset[cmdline_row + r],
2911 				(size_t)cols * sizeof(u8char_T));
2912 	    }
2913 	    if (enc_dbcs == DBCS_JPNU)
2914 		mch_memmove(screenline2 + r * cols,
2915 			    ScreenLines2 + LineOffset[cmdline_row + r],
2916 			    (size_t)cols * sizeof(schar_T));
2917 	}
2918 
2919 	update_screen(0);
2920 	ret = 3;
2921 
2922 	if (must_redraw == 0)
2923 	{
2924 	    int	off = (int)(current_ScreenLine - ScreenLines);
2925 
2926 	    // Restore the text displayed in the command line area.
2927 	    for (r = 0; r < rows; ++r)
2928 	    {
2929 		mch_memmove(current_ScreenLine,
2930 			    screenline + r * cols,
2931 			    (size_t)cols * sizeof(schar_T));
2932 		mch_memmove(ScreenAttrs + off,
2933 			    screenattr + r * cols,
2934 			    (size_t)cols * sizeof(sattr_T));
2935 		if (enc_utf8)
2936 		{
2937 		    mch_memmove(ScreenLinesUC + off,
2938 				screenlineUC + r * cols,
2939 				(size_t)cols * sizeof(u8char_T));
2940 		    for (i = 0; i < p_mco; ++i)
2941 			mch_memmove(ScreenLinesC[i] + off,
2942 				    screenlineC[i] + r * cols,
2943 				    (size_t)cols * sizeof(u8char_T));
2944 		}
2945 		if (enc_dbcs == DBCS_JPNU)
2946 		    mch_memmove(ScreenLines2 + off,
2947 				screenline2 + r * cols,
2948 				(size_t)cols * sizeof(schar_T));
2949 		screen_line(cmdline_row + r, 0, cols, cols, 0);
2950 	    }
2951 	    ret = 4;
2952 	}
2953     }
2954 
2955     vim_free(screenline);
2956     vim_free(screenattr);
2957     if (enc_utf8)
2958     {
2959 	vim_free(screenlineUC);
2960 	for (i = 0; i < p_mco; ++i)
2961 	    vim_free(screenlineC[i]);
2962     }
2963     if (enc_dbcs == DBCS_JPNU)
2964 	vim_free(screenline2);
2965 
2966     // Show the intro message when appropriate.
2967     maybe_intro_message();
2968 
2969     setcursor();
2970 
2971     return ret;
2972 }
2973 #endif
2974 
2975 /*
2976  * Invoked after an asynchronous callback is called.
2977  * If an echo command was used the cursor needs to be put back where
2978  * it belongs. If highlighting was changed a redraw is needed.
2979  * If "call_update_screen" is FALSE don't call update_screen() when at the
2980  * command line.
2981  */
2982     void
2983 redraw_after_callback(int call_update_screen)
2984 {
2985     ++redrawing_for_callback;
2986 
2987     if (State == HITRETURN || State == ASKMORE)
2988 	; // do nothing
2989     else if (State & CMDLINE)
2990     {
2991 	// Don't redraw when in prompt_for_number().
2992 	if (cmdline_row > 0)
2993 	{
2994 	    // Redrawing only works when the screen didn't scroll. Don't clear
2995 	    // wildmenu entries.
2996 	    if (msg_scrolled == 0
2997 #ifdef FEAT_WILDMENU
2998 		    && wild_menu_showing == 0
2999 #endif
3000 		    && call_update_screen)
3001 		update_screen(0);
3002 
3003 	    // Redraw in the same position, so that the user can continue
3004 	    // editing the command.
3005 	    redrawcmdline_ex(FALSE);
3006 	}
3007     }
3008     else if (State & (NORMAL | INSERT | TERMINAL))
3009     {
3010 	// keep the command line if possible
3011 	update_screen(VALID_NO_UPDATE);
3012 	setcursor();
3013 
3014 	if (msg_scrolled == 0)
3015 	{
3016 	    // don't want a hit-enter prompt when something else is displayed
3017 	    msg_didany = FALSE;
3018 	    need_wait_return = FALSE;
3019 	}
3020     }
3021     cursor_on();
3022 #ifdef FEAT_GUI
3023     if (gui.in_use && !gui_mch_is_blink_off())
3024 	// Don't update the cursor when it is blinking and off to avoid
3025 	// flicker.
3026 	out_flush_cursor(FALSE, FALSE);
3027     else
3028 #endif
3029 	out_flush();
3030 
3031     --redrawing_for_callback;
3032 }
3033 
3034 /*
3035  * Redraw the current window later, with update_screen(type).
3036  * Set must_redraw only if not already set to a higher value.
3037  * E.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
3038  */
3039     void
3040 redraw_later(int type)
3041 {
3042     redraw_win_later(curwin, type);
3043 }
3044 
3045     void
3046 redraw_win_later(
3047     win_T	*wp,
3048     int		type)
3049 {
3050     if (!exiting && wp->w_redr_type < type)
3051     {
3052 	wp->w_redr_type = type;
3053 	if (type >= NOT_VALID)
3054 	    wp->w_lines_valid = 0;
3055 	if (must_redraw < type)	// must_redraw is the maximum of all windows
3056 	    must_redraw = type;
3057     }
3058 }
3059 
3060 /*
3061  * Force a complete redraw later.  Also resets the highlighting.  To be used
3062  * after executing a shell command that messes up the screen.
3063  */
3064     void
3065 redraw_later_clear(void)
3066 {
3067     redraw_all_later(CLEAR);
3068     reset_screen_attr();
3069 }
3070 
3071 /*
3072  * Mark all windows to be redrawn later.
3073  */
3074     void
3075 redraw_all_later(int type)
3076 {
3077     win_T	*wp;
3078 
3079     FOR_ALL_WINDOWS(wp)
3080 	redraw_win_later(wp, type);
3081     // This may be needed when switching tabs.
3082     if (must_redraw < type)
3083 	must_redraw = type;
3084 }
3085 
3086 /*
3087  * Mark all windows that are editing the current buffer to be updated later.
3088  */
3089     void
3090 redraw_curbuf_later(int type)
3091 {
3092     redraw_buf_later(curbuf, type);
3093 }
3094 
3095     void
3096 redraw_buf_later(buf_T *buf, int type)
3097 {
3098     win_T	*wp;
3099 
3100     FOR_ALL_WINDOWS(wp)
3101     {
3102 	if (wp->w_buffer == buf)
3103 	    redraw_win_later(wp, type);
3104     }
3105 #if defined(FEAT_TERMINAL) && defined(FEAT_PROP_POPUP)
3106     // terminal in popup window is not in list of windows
3107     if (curwin->w_buffer == buf)
3108 	redraw_win_later(curwin, type);
3109 #endif
3110 }
3111 
3112 #if defined(FEAT_SIGNS) || defined(PROTO)
3113     void
3114 redraw_buf_line_later(buf_T *buf, linenr_T lnum)
3115 {
3116     win_T	*wp;
3117 
3118     FOR_ALL_WINDOWS(wp)
3119 	if (wp->w_buffer == buf && lnum >= wp->w_topline
3120 						  && lnum < wp->w_botline)
3121 	    redrawWinline(wp, lnum);
3122 }
3123 #endif
3124 
3125 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
3126     void
3127 redraw_buf_and_status_later(buf_T *buf, int type)
3128 {
3129     win_T	*wp;
3130 
3131 #ifdef FEAT_WILDMENU
3132     if (wild_menu_showing != 0)
3133 	// Don't redraw while the command line completion is displayed, it
3134 	// would disappear.
3135 	return;
3136 #endif
3137     FOR_ALL_WINDOWS(wp)
3138     {
3139 	if (wp->w_buffer == buf)
3140 	{
3141 	    redraw_win_later(wp, type);
3142 	    wp->w_redr_status = TRUE;
3143 	}
3144     }
3145 }
3146 #endif
3147 
3148 /*
3149  * mark all status lines for redraw; used after first :cd
3150  */
3151     void
3152 status_redraw_all(void)
3153 {
3154     win_T	*wp;
3155 
3156     FOR_ALL_WINDOWS(wp)
3157 	if (wp->w_status_height)
3158 	{
3159 	    wp->w_redr_status = TRUE;
3160 	    redraw_later(VALID);
3161 	}
3162 }
3163 
3164 /*
3165  * mark all status lines of the current buffer for redraw
3166  */
3167     void
3168 status_redraw_curbuf(void)
3169 {
3170     win_T	*wp;
3171 
3172     FOR_ALL_WINDOWS(wp)
3173 	if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
3174 	{
3175 	    wp->w_redr_status = TRUE;
3176 	    redraw_later(VALID);
3177 	}
3178 }
3179 
3180 /*
3181  * Redraw all status lines that need to be redrawn.
3182  */
3183     void
3184 redraw_statuslines(void)
3185 {
3186     win_T	*wp;
3187 
3188     FOR_ALL_WINDOWS(wp)
3189 	if (wp->w_redr_status)
3190 	    win_redr_status(wp, FALSE);
3191     if (redraw_tabline)
3192 	draw_tabline();
3193 }
3194 
3195 #if defined(FEAT_WILDMENU) || defined(PROTO)
3196 /*
3197  * Redraw all status lines at the bottom of frame "frp".
3198  */
3199     void
3200 win_redraw_last_status(frame_T *frp)
3201 {
3202     if (frp->fr_layout == FR_LEAF)
3203 	frp->fr_win->w_redr_status = TRUE;
3204     else if (frp->fr_layout == FR_ROW)
3205     {
3206 	FOR_ALL_FRAMES(frp, frp->fr_child)
3207 	    win_redraw_last_status(frp);
3208     }
3209     else // frp->fr_layout == FR_COL
3210     {
3211 	frp = frp->fr_child;
3212 	while (frp->fr_next != NULL)
3213 	    frp = frp->fr_next;
3214 	win_redraw_last_status(frp);
3215     }
3216 }
3217 #endif
3218 
3219 /*
3220  * Changed something in the current window, at buffer line "lnum", that
3221  * requires that line and possibly other lines to be redrawn.
3222  * Used when entering/leaving Insert mode with the cursor on a folded line.
3223  * Used to remove the "$" from a change command.
3224  * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
3225  * may become invalid and the whole window will have to be redrawn.
3226  */
3227     void
3228 redrawWinline(
3229     win_T	*wp,
3230     linenr_T	lnum)
3231 {
3232     if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
3233 	wp->w_redraw_top = lnum;
3234     if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
3235 	wp->w_redraw_bot = lnum;
3236     redraw_win_later(wp, VALID);
3237 }
3238