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