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