xref: /vim-8.2.3635/src/screen.c (revision bc2eada5)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * screen.c: code for displaying on the screen
12  *
13  * Output to the screen (console, terminal emulator or GUI window) is minimized
14  * by remembering what is already on the screen, and only updating the parts
15  * that changed.
16  *
17  * ScreenLines[off]  Contains a copy of the whole screen, as it is currently
18  *		     displayed (excluding text written by external commands).
19  * ScreenAttrs[off]  Contains the associated attributes.
20  * LineOffset[row]   Contains the offset into ScreenLines*[] and ScreenAttrs[]
21  *		     for each line.
22  * LineWraps[row]    Flag for each line whether it wraps to the next line.
23  *
24  * For double-byte characters, two consecutive bytes in ScreenLines[] can form
25  * one character which occupies two display cells.
26  * For UTF-8 a multi-byte character is converted to Unicode and stored in
27  * ScreenLinesUC[].  ScreenLines[] contains the first byte only.  For an ASCII
28  * character without composing chars ScreenLinesUC[] will be 0 and
29  * ScreenLinesC[][] is not used.  When the character occupies two display
30  * cells the next byte in ScreenLines[] is 0.
31  * ScreenLinesC[][] contain up to 'maxcombine' composing characters
32  * (drawn on top of the first character).  There is 0 after the last one used.
33  * ScreenLines2[] is only used for euc-jp to store the second byte if the
34  * first byte is 0x8e (single-width character).
35  *
36  * The screen_*() functions write to the screen and handle updating
37  * ScreenLines[].
38  *
39  * update_screen() is the function that updates all windows and status lines.
40  * It is called form the main loop when must_redraw is non-zero.  It may be
41  * called from other places when an immediate screen update is needed.
42  *
43  * The part of the buffer that is displayed in a window is set with:
44  * - w_topline (first buffer line in window)
45  * - w_topfill (filler lines above the first line)
46  * - w_leftcol (leftmost window cell in window),
47  * - w_skipcol (skipped window cells of first line)
48  *
49  * Commands that only move the cursor around in a window, do not need to take
50  * action to update the display.  The main loop will check if w_topline is
51  * valid and update it (scroll the window) when needed.
52  *
53  * Commands that scroll a window change w_topline and must call
54  * check_cursor() to move the cursor into the visible part of the window, and
55  * call redraw_later(VALID) to have the window displayed by update_screen()
56  * later.
57  *
58  * Commands that change text in the buffer must call changed_bytes() or
59  * changed_lines() to mark the area that changed and will require updating
60  * later.  The main loop will call update_screen(), which will update each
61  * window that shows the changed buffer.  This assumes text above the change
62  * can remain displayed as it is.  Text after the change may need updating for
63  * scrolling, folding and syntax highlighting.
64  *
65  * Commands that change how a window is displayed (e.g., setting 'list') or
66  * invalidate the contents of a window in another way (e.g., change fold
67  * settings), must call redraw_later(NOT_VALID) to have the whole window
68  * redisplayed by update_screen() later.
69  *
70  * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
71  * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
72  * buffer redisplayed by update_screen() later.
73  *
74  * Commands that change highlighting and possibly cause a scroll too must call
75  * redraw_later(SOME_VALID) to update the whole window but still use scrolling
76  * to avoid redrawing everything.  But the length of displayed lines must not
77  * change, use NOT_VALID then.
78  *
79  * Commands that move the window position must call redraw_later(NOT_VALID).
80  * TODO: should minimize redrawing by scrolling when possible.
81  *
82  * Commands that change everything (e.g., resizing the screen) must call
83  * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
84  *
85  * Things that are handled indirectly:
86  * - When messages scroll the screen up, msg_scrolled will be set and
87  *   update_screen() called to redraw.
88  */
89 
90 #include "vim.h"
91 
92 #define MB_FILLER_CHAR '<'  /* character used when a double-width character
93 			     * doesn't fit. */
94 
95 /*
96  * The attributes that are actually active for writing to the screen.
97  */
98 static int	screen_attr = 0;
99 
100 /*
101  * Positioning the cursor is reduced by remembering the last position.
102  * Mostly used by windgoto() and screen_char().
103  */
104 static int	screen_cur_row, screen_cur_col;	/* last known cursor position */
105 
106 #ifdef FEAT_SEARCH_EXTRA
107 static match_T search_hl;	/* used for 'hlsearch' highlight matching */
108 #endif
109 
110 #ifdef FEAT_FOLDING
111 static foldinfo_T win_foldinfo;	/* info for 'foldcolumn' */
112 static int compute_foldcolumn(win_T *wp, int col);
113 #endif
114 
115 /*
116  * Buffer for one screen line (characters and attributes).
117  */
118 static schar_T	*current_ScreenLine;
119 
120 static void win_update(win_T *wp);
121 static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl);
122 #ifdef FEAT_FOLDING
123 static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row);
124 static void fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
125 static void copy_text_attr(int off, char_u *buf, int len, int attr);
126 #endif
127 static int win_line(win_T *, linenr_T, int, int, int nochange);
128 static int char_needs_redraw(int off_from, int off_to, int cols);
129 #ifdef FEAT_RIGHTLEFT
130 static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag);
131 # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c), (rl))
132 #else
133 static void screen_line(int row, int coloff, int endcol, int clear_width);
134 # define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c))
135 #endif
136 #ifdef FEAT_WINDOWS
137 static void draw_vsep_win(win_T *wp, int row);
138 #endif
139 #ifdef FEAT_STL_OPT
140 static void redraw_custom_statusline(win_T *wp);
141 #endif
142 #ifdef FEAT_SEARCH_EXTRA
143 # define SEARCH_HL_PRIORITY 0
144 static void start_search_hl(void);
145 static void end_search_hl(void);
146 static void init_search_hl(win_T *wp);
147 static void prepare_search_hl(win_T *wp, linenr_T lnum);
148 static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol, matchitem_T *cur);
149 static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *pos, colnr_T mincol);
150 #endif
151 static void screen_start_highlight(int attr);
152 static void screen_char(unsigned off, int row, int col);
153 #ifdef FEAT_MBYTE
154 static void screen_char_2(unsigned off, int row, int col);
155 #endif
156 static void screenclear2(void);
157 static void lineclear(unsigned off, int width);
158 static void lineinvalid(unsigned off, int width);
159 #ifdef FEAT_WINDOWS
160 static void linecopy(int to, int from, win_T *wp);
161 static void redraw_block(int row, int end, win_T *wp);
162 #endif
163 static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del);
164 static void win_rest_invalid(win_T *wp);
165 static void msg_pos_mode(void);
166 static void recording_mode(int attr);
167 #if defined(FEAT_WINDOWS)
168 static void draw_tabline(void);
169 #endif
170 #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
171 static int fillchar_status(int *attr, int is_curwin);
172 #endif
173 #ifdef FEAT_WINDOWS
174 static int fillchar_vsep(int *attr);
175 #endif
176 #ifdef FEAT_STL_OPT
177 static void win_redr_custom(win_T *wp, int draw_ruler);
178 #endif
179 #ifdef FEAT_CMDL_INFO
180 static void win_redr_ruler(win_T *wp, int always);
181 #endif
182 
183 #if defined(FEAT_CLIPBOARD) || defined(FEAT_WINDOWS)
184 /* Ugly global: overrule attribute used by screen_char() */
185 static int screen_char_attr = 0;
186 #endif
187 
188 /*
189  * Redraw the current window later, with update_screen(type).
190  * Set must_redraw only if not already set to a higher value.
191  * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing.
192  */
193     void
194 redraw_later(int type)
195 {
196     redraw_win_later(curwin, type);
197 }
198 
199     void
200 redraw_win_later(
201     win_T	*wp,
202     int		type)
203 {
204     if (wp->w_redr_type < type)
205     {
206 	wp->w_redr_type = type;
207 	if (type >= NOT_VALID)
208 	    wp->w_lines_valid = 0;
209 	if (must_redraw < type)	/* must_redraw is the maximum of all windows */
210 	    must_redraw = type;
211     }
212 }
213 
214 /*
215  * Force a complete redraw later.  Also resets the highlighting.  To be used
216  * after executing a shell command that messes up the screen.
217  */
218     void
219 redraw_later_clear(void)
220 {
221     redraw_all_later(CLEAR);
222 #ifdef FEAT_GUI
223     if (gui.in_use)
224 	/* Use a code that will reset gui.highlight_mask in
225 	 * gui_stop_highlight(). */
226 	screen_attr = HL_ALL + 1;
227     else
228 #endif
229 	/* Use attributes that is very unlikely to appear in text. */
230 	screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE;
231 }
232 
233 /*
234  * Mark all windows to be redrawn later.
235  */
236     void
237 redraw_all_later(int type)
238 {
239     win_T	*wp;
240 
241     FOR_ALL_WINDOWS(wp)
242     {
243 	redraw_win_later(wp, type);
244     }
245 }
246 
247 /*
248  * Mark all windows that are editing the current buffer to be updated later.
249  */
250     void
251 redraw_curbuf_later(int type)
252 {
253     redraw_buf_later(curbuf, type);
254 }
255 
256     void
257 redraw_buf_later(buf_T *buf, int type)
258 {
259     win_T	*wp;
260 
261     FOR_ALL_WINDOWS(wp)
262     {
263 	if (wp->w_buffer == buf)
264 	    redraw_win_later(wp, type);
265     }
266 }
267 
268 /*
269  * Redraw as soon as possible.  When the command line is not scrolled redraw
270  * right away and restore what was on the command line.
271  * Return a code indicating what happened.
272  */
273     int
274 redraw_asap(int type)
275 {
276     int		rows;
277     int		cols = screen_Columns;
278     int		r;
279     int		ret = 0;
280     schar_T	*screenline;	/* copy from ScreenLines[] */
281     sattr_T	*screenattr;	/* copy from ScreenAttrs[] */
282 #ifdef FEAT_MBYTE
283     int		i;
284     u8char_T	*screenlineUC = NULL;	/* copy from ScreenLinesUC[] */
285     u8char_T	*screenlineC[MAX_MCO];	/* copy from ScreenLinesC[][] */
286     schar_T	*screenline2 = NULL;	/* copy from ScreenLines2[] */
287 #endif
288 
289     redraw_later(type);
290     if (msg_scrolled || (State != NORMAL && State != NORMAL_BUSY) || exiting)
291 	return ret;
292 
293     /* Allocate space to save the text displayed in the command line area. */
294     rows = screen_Rows - cmdline_row;
295     screenline = (schar_T *)lalloc(
296 			   (long_u)(rows * cols * sizeof(schar_T)), FALSE);
297     screenattr = (sattr_T *)lalloc(
298 			   (long_u)(rows * cols * sizeof(sattr_T)), FALSE);
299     if (screenline == NULL || screenattr == NULL)
300 	ret = 2;
301 #ifdef FEAT_MBYTE
302     if (enc_utf8)
303     {
304 	screenlineUC = (u8char_T *)lalloc(
305 			  (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
306 	if (screenlineUC == NULL)
307 	    ret = 2;
308 	for (i = 0; i < p_mco; ++i)
309 	{
310 	    screenlineC[i] = (u8char_T *)lalloc(
311 			  (long_u)(rows * cols * sizeof(u8char_T)), FALSE);
312 	    if (screenlineC[i] == NULL)
313 		ret = 2;
314 	}
315     }
316     if (enc_dbcs == DBCS_JPNU)
317     {
318 	screenline2 = (schar_T *)lalloc(
319 			   (long_u)(rows * cols * sizeof(schar_T)), FALSE);
320 	if (screenline2 == NULL)
321 	    ret = 2;
322     }
323 #endif
324 
325     if (ret != 2)
326     {
327 	/* Save the text displayed in the command line area. */
328 	for (r = 0; r < rows; ++r)
329 	{
330 	    mch_memmove(screenline + r * cols,
331 			ScreenLines + LineOffset[cmdline_row + r],
332 			(size_t)cols * sizeof(schar_T));
333 	    mch_memmove(screenattr + r * cols,
334 			ScreenAttrs + LineOffset[cmdline_row + r],
335 			(size_t)cols * sizeof(sattr_T));
336 #ifdef FEAT_MBYTE
337 	    if (enc_utf8)
338 	    {
339 		mch_memmove(screenlineUC + r * cols,
340 			    ScreenLinesUC + LineOffset[cmdline_row + r],
341 			    (size_t)cols * sizeof(u8char_T));
342 		for (i = 0; i < p_mco; ++i)
343 		    mch_memmove(screenlineC[i] + r * cols,
344 				ScreenLinesC[i] + LineOffset[cmdline_row + r],
345 				(size_t)cols * sizeof(u8char_T));
346 	    }
347 	    if (enc_dbcs == DBCS_JPNU)
348 		mch_memmove(screenline2 + r * cols,
349 			    ScreenLines2 + LineOffset[cmdline_row + r],
350 			    (size_t)cols * sizeof(schar_T));
351 #endif
352 	}
353 
354 	update_screen(0);
355 	ret = 3;
356 
357 	if (must_redraw == 0)
358 	{
359 	    int	off = (int)(current_ScreenLine - ScreenLines);
360 
361 	    /* Restore the text displayed in the command line area. */
362 	    for (r = 0; r < rows; ++r)
363 	    {
364 		mch_memmove(current_ScreenLine,
365 			    screenline + r * cols,
366 			    (size_t)cols * sizeof(schar_T));
367 		mch_memmove(ScreenAttrs + off,
368 			    screenattr + r * cols,
369 			    (size_t)cols * sizeof(sattr_T));
370 #ifdef FEAT_MBYTE
371 		if (enc_utf8)
372 		{
373 		    mch_memmove(ScreenLinesUC + off,
374 				screenlineUC + r * cols,
375 				(size_t)cols * sizeof(u8char_T));
376 		    for (i = 0; i < p_mco; ++i)
377 			mch_memmove(ScreenLinesC[i] + off,
378 				    screenlineC[i] + r * cols,
379 				    (size_t)cols * sizeof(u8char_T));
380 		}
381 		if (enc_dbcs == DBCS_JPNU)
382 		    mch_memmove(ScreenLines2 + off,
383 				screenline2 + r * cols,
384 				(size_t)cols * sizeof(schar_T));
385 #endif
386 		SCREEN_LINE(cmdline_row + r, 0, cols, cols, FALSE);
387 	    }
388 	    ret = 4;
389 	}
390     }
391 
392     vim_free(screenline);
393     vim_free(screenattr);
394 #ifdef FEAT_MBYTE
395     if (enc_utf8)
396     {
397 	vim_free(screenlineUC);
398 	for (i = 0; i < p_mco; ++i)
399 	    vim_free(screenlineC[i]);
400     }
401     if (enc_dbcs == DBCS_JPNU)
402 	vim_free(screenline2);
403 #endif
404 
405     /* Show the intro message when appropriate. */
406     maybe_intro_message();
407 
408     setcursor();
409 
410     return ret;
411 }
412 
413 /*
414  * Invoked after an asynchronous callback is called.
415  * If an echo command was used the cursor needs to be put back where
416  * it belongs. If highlighting was changed a redraw is needed.
417  */
418     void
419 redraw_after_callback(void)
420 {
421     if (State == HITRETURN || State == ASKMORE)
422 	; /* do nothing */
423     else if (State & CMDLINE)
424 	redrawcmdline();
425     else if (State & (NORMAL | INSERT))
426     {
427 	update_screen(0);
428 	setcursor();
429     }
430     cursor_on();
431     out_flush();
432 #ifdef FEAT_GUI
433     if (gui.in_use)
434     {
435 	/* Don't update the cursor when it is blinking and off to avoid
436 	 * flicker. */
437 	if (!gui_mch_is_blink_off())
438 	    gui_update_cursor(FALSE, FALSE);
439 	gui_mch_flush();
440     }
441 #endif
442 }
443 
444 /*
445  * Changed something in the current window, at buffer line "lnum", that
446  * requires that line and possibly other lines to be redrawn.
447  * Used when entering/leaving Insert mode with the cursor on a folded line.
448  * Used to remove the "$" from a change command.
449  * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
450  * may become invalid and the whole window will have to be redrawn.
451  */
452     void
453 redrawWinline(
454     linenr_T	lnum,
455     int		invalid UNUSED)	/* window line height is invalid now */
456 {
457 #ifdef FEAT_FOLDING
458     int		i;
459 #endif
460 
461     if (curwin->w_redraw_top == 0 || curwin->w_redraw_top > lnum)
462 	curwin->w_redraw_top = lnum;
463     if (curwin->w_redraw_bot == 0 || curwin->w_redraw_bot < lnum)
464 	curwin->w_redraw_bot = lnum;
465     redraw_later(VALID);
466 
467 #ifdef FEAT_FOLDING
468     if (invalid)
469     {
470 	/* A w_lines[] entry for this lnum has become invalid. */
471 	i = find_wl_entry(curwin, lnum);
472 	if (i >= 0)
473 	    curwin->w_lines[i].wl_valid = FALSE;
474     }
475 #endif
476 }
477 
478 /*
479  * update all windows that are editing the current buffer
480  */
481     void
482 update_curbuf(int type)
483 {
484     redraw_curbuf_later(type);
485     update_screen(type);
486 }
487 
488 /*
489  * Based on the current value of curwin->w_topline, transfer a screenfull
490  * of stuff from Filemem to ScreenLines[], and update curwin->w_botline.
491  */
492     void
493 update_screen(int type)
494 {
495     win_T	*wp;
496     static int	did_intro = FALSE;
497 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
498     int		did_one;
499 #endif
500 #ifdef FEAT_GUI
501     int		did_undraw = FALSE;
502     int		gui_cursor_col;
503     int		gui_cursor_row;
504 #endif
505 
506     /* Don't do anything if the screen structures are (not yet) valid. */
507     if (!screen_valid(TRUE))
508 	return;
509 
510     if (must_redraw)
511     {
512 	if (type < must_redraw)	    /* use maximal type */
513 	    type = must_redraw;
514 
515 	/* must_redraw is reset here, so that when we run into some weird
516 	 * reason to redraw while busy redrawing (e.g., asynchronous
517 	 * scrolling), or update_topline() in win_update() will cause a
518 	 * scroll, the screen will be redrawn later or in win_update(). */
519 	must_redraw = 0;
520     }
521 
522     /* Need to update w_lines[]. */
523     if (curwin->w_lines_valid == 0 && type < NOT_VALID)
524 	type = NOT_VALID;
525 
526     /* Postpone the redrawing when it's not needed and when being called
527      * recursively. */
528     if (!redrawing() || updating_screen)
529     {
530 	redraw_later(type);		/* remember type for next time */
531 	must_redraw = type;
532 	if (type > INVERTED_ALL)
533 	    curwin->w_lines_valid = 0;	/* don't use w_lines[].wl_size now */
534 	return;
535     }
536 
537     updating_screen = TRUE;
538 #ifdef FEAT_SYN_HL
539     ++display_tick;	    /* let syntax code know we're in a next round of
540 			     * display updating */
541 #endif
542 
543     /*
544      * if the screen was scrolled up when displaying a message, scroll it down
545      */
546     if (msg_scrolled)
547     {
548 	clear_cmdline = TRUE;
549 	if (msg_scrolled > Rows - 5)	    /* clearing is faster */
550 	    type = CLEAR;
551 	else if (type != CLEAR)
552 	{
553 	    check_for_delay(FALSE);
554 	    if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
555 		type = CLEAR;
556 	    FOR_ALL_WINDOWS(wp)
557 	    {
558 		if (W_WINROW(wp) < msg_scrolled)
559 		{
560 		    if (W_WINROW(wp) + wp->w_height > msg_scrolled
561 			    && wp->w_redr_type < REDRAW_TOP
562 			    && wp->w_lines_valid > 0
563 			    && wp->w_topline == wp->w_lines[0].wl_lnum)
564 		    {
565 			wp->w_upd_rows = msg_scrolled - W_WINROW(wp);
566 			wp->w_redr_type = REDRAW_TOP;
567 		    }
568 		    else
569 		    {
570 			wp->w_redr_type = NOT_VALID;
571 #ifdef FEAT_WINDOWS
572 			if (W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp)
573 				<= msg_scrolled)
574 			    wp->w_redr_status = TRUE;
575 #endif
576 		    }
577 		}
578 	    }
579 	    redraw_cmdline = TRUE;
580 #ifdef FEAT_WINDOWS
581 	    redraw_tabline = TRUE;
582 #endif
583 	}
584 	msg_scrolled = 0;
585 	need_wait_return = FALSE;
586     }
587 
588     /* reset cmdline_row now (may have been changed temporarily) */
589     compute_cmdrow();
590 
591     /* Check for changed highlighting */
592     if (need_highlight_changed)
593 	highlight_changed();
594 
595     if (type == CLEAR)		/* first clear screen */
596     {
597 	screenclear();		/* will reset clear_cmdline */
598 	type = NOT_VALID;
599     }
600 
601     if (clear_cmdline)		/* going to clear cmdline (done below) */
602 	check_for_delay(FALSE);
603 
604 #ifdef FEAT_LINEBREAK
605     /* Force redraw when width of 'number' or 'relativenumber' column
606      * changes. */
607     if (curwin->w_redr_type < NOT_VALID
608 	   && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
609 				    ? number_width(curwin) : 0))
610 	curwin->w_redr_type = NOT_VALID;
611 #endif
612 
613     /*
614      * Only start redrawing if there is really something to do.
615      */
616     if (type == INVERTED)
617 	update_curswant();
618     if (curwin->w_redr_type < type
619 	    && !((type == VALID
620 		    && curwin->w_lines[0].wl_valid
621 #ifdef FEAT_DIFF
622 		    && curwin->w_topfill == curwin->w_old_topfill
623 		    && curwin->w_botfill == curwin->w_old_botfill
624 #endif
625 		    && curwin->w_topline == curwin->w_lines[0].wl_lnum)
626 		|| (type == INVERTED
627 		    && VIsual_active
628 		    && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
629 		    && curwin->w_old_visual_mode == VIsual_mode
630 		    && (curwin->w_valid & VALID_VIRTCOL)
631 		    && curwin->w_old_curswant == curwin->w_curswant)
632 		))
633 	curwin->w_redr_type = type;
634 
635 #ifdef FEAT_WINDOWS
636     /* Redraw the tab pages line if needed. */
637     if (redraw_tabline || type >= NOT_VALID)
638 	draw_tabline();
639 #endif
640 
641 #ifdef FEAT_SYN_HL
642     /*
643      * Correct stored syntax highlighting info for changes in each displayed
644      * buffer.  Each buffer must only be done once.
645      */
646     FOR_ALL_WINDOWS(wp)
647     {
648 	if (wp->w_buffer->b_mod_set)
649 	{
650 # ifdef FEAT_WINDOWS
651 	    win_T	*wwp;
652 
653 	    /* Check if we already did this buffer. */
654 	    for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
655 		if (wwp->w_buffer == wp->w_buffer)
656 		    break;
657 # endif
658 	    if (
659 # ifdef FEAT_WINDOWS
660 		    wwp == wp &&
661 # endif
662 		    syntax_present(wp))
663 		syn_stack_apply_changes(wp->w_buffer);
664 	}
665     }
666 #endif
667 
668     /*
669      * Go from top to bottom through the windows, redrawing the ones that need
670      * it.
671      */
672 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
673     did_one = FALSE;
674 #endif
675 #ifdef FEAT_SEARCH_EXTRA
676     search_hl.rm.regprog = NULL;
677 #endif
678     FOR_ALL_WINDOWS(wp)
679     {
680 	if (wp->w_redr_type != 0)
681 	{
682 	    cursor_off();
683 #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
684 	    if (!did_one)
685 	    {
686 		did_one = TRUE;
687 # ifdef FEAT_SEARCH_EXTRA
688 		start_search_hl();
689 # endif
690 # ifdef FEAT_CLIPBOARD
691 		/* When Visual area changed, may have to update selection. */
692 		if (clip_star.available && clip_isautosel_star())
693 		    clip_update_selection(&clip_star);
694 		if (clip_plus.available && clip_isautosel_plus())
695 		    clip_update_selection(&clip_plus);
696 # endif
697 #ifdef FEAT_GUI
698 		/* Remove the cursor before starting to do anything, because
699 		 * scrolling may make it difficult to redraw the text under
700 		 * it. */
701 		if (gui.in_use && wp == curwin)
702 		{
703 		    gui_cursor_col = gui.cursor_col;
704 		    gui_cursor_row = gui.cursor_row;
705 		    gui_undraw_cursor();
706 		    did_undraw = TRUE;
707 		}
708 #endif
709 	    }
710 #endif
711 	    win_update(wp);
712 	}
713 
714 #ifdef FEAT_WINDOWS
715 	/* redraw status line after the window to minimize cursor movement */
716 	if (wp->w_redr_status)
717 	{
718 	    cursor_off();
719 	    win_redr_status(wp);
720 	}
721 #endif
722     }
723 #if defined(FEAT_SEARCH_EXTRA)
724     end_search_hl();
725 #endif
726 #ifdef FEAT_INS_EXPAND
727     /* May need to redraw the popup menu. */
728     if (pum_visible())
729 	pum_redraw();
730 #endif
731 
732 #ifdef FEAT_WINDOWS
733     /* Reset b_mod_set flags.  Going through all windows is probably faster
734      * than going through all buffers (there could be many buffers). */
735     FOR_ALL_WINDOWS(wp)
736 	wp->w_buffer->b_mod_set = FALSE;
737 #else
738 	curbuf->b_mod_set = FALSE;
739 #endif
740 
741     updating_screen = FALSE;
742 #ifdef FEAT_GUI
743     gui_may_resize_shell();
744 #endif
745 
746     /* Clear or redraw the command line.  Done last, because scrolling may
747      * mess up the command line. */
748     if (clear_cmdline || redraw_cmdline)
749 	showmode();
750 
751     /* May put up an introductory message when not editing a file */
752     if (!did_intro)
753 	maybe_intro_message();
754     did_intro = TRUE;
755 
756 #ifdef FEAT_GUI
757     /* Redraw the cursor and update the scrollbars when all screen updating is
758      * done. */
759     if (gui.in_use)
760     {
761 	out_flush();	/* required before updating the cursor */
762 	if (did_undraw && !gui_mch_is_blink_off())
763 	{
764 	    /* Put the GUI position where the cursor was, gui_update_cursor()
765 	     * uses that. */
766 	    gui.col = gui_cursor_col;
767 	    gui.row = gui_cursor_row;
768 # ifdef FEAT_MBYTE
769 	    gui.col = mb_fix_col(gui.col, gui.row);
770 # endif
771 	    gui_update_cursor(FALSE, FALSE);
772 	    screen_cur_col = gui.col;
773 	    screen_cur_row = gui.row;
774 	}
775 	gui_update_scrollbars(FALSE);
776     }
777 #endif
778 }
779 
780 #if defined(FEAT_CONCEAL) || defined(PROTO)
781 /*
782  * Return TRUE if the cursor line in window "wp" may be concealed, according
783  * to the 'concealcursor' option.
784  */
785     int
786 conceal_cursor_line(win_T *wp)
787 {
788     int		c;
789 
790     if (*wp->w_p_cocu == NUL)
791 	return FALSE;
792     if (get_real_state() & VISUAL)
793 	c = 'v';
794     else if (State & INSERT)
795 	c = 'i';
796     else if (State & NORMAL)
797 	c = 'n';
798     else if (State & CMDLINE)
799 	c = 'c';
800     else
801 	return FALSE;
802     return vim_strchr(wp->w_p_cocu, c) != NULL;
803 }
804 
805 /*
806  * Check if the cursor line needs to be redrawn because of 'concealcursor'.
807  */
808     void
809 conceal_check_cursur_line(void)
810 {
811     if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin))
812     {
813 	need_cursor_line_redraw = TRUE;
814 	/* Need to recompute cursor column, e.g., when starting Visual mode
815 	 * without concealing. */
816 	curs_columns(TRUE);
817     }
818 }
819 
820     void
821 update_single_line(win_T *wp, linenr_T lnum)
822 {
823     int		row;
824     int		j;
825 
826     /* Don't do anything if the screen structures are (not yet) valid. */
827     if (!screen_valid(TRUE))
828 	return;
829 
830     if (lnum >= wp->w_topline && lnum < wp->w_botline
831 				 && foldedCount(wp, lnum, &win_foldinfo) == 0)
832     {
833 # ifdef FEAT_GUI
834 	/* Remove the cursor before starting to do anything, because scrolling
835 	 * may make it difficult to redraw the text under it. */
836 	if (gui.in_use)
837 	    gui_undraw_cursor();
838 # endif
839 	row = 0;
840 	for (j = 0; j < wp->w_lines_valid; ++j)
841 	{
842 	    if (lnum == wp->w_lines[j].wl_lnum)
843 	    {
844 		screen_start();	/* not sure of screen cursor */
845 # ifdef FEAT_SEARCH_EXTRA
846 		init_search_hl(wp);
847 		start_search_hl();
848 		prepare_search_hl(wp, lnum);
849 # endif
850 		win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, FALSE);
851 # if defined(FEAT_SEARCH_EXTRA)
852 		end_search_hl();
853 # endif
854 		break;
855 	    }
856 	    row += wp->w_lines[j].wl_size;
857 	}
858 # ifdef FEAT_GUI
859 	/* Redraw the cursor */
860 	if (gui.in_use)
861 	{
862 	    out_flush();	/* required before updating the cursor */
863 	    gui_update_cursor(FALSE, FALSE);
864 	}
865 # endif
866     }
867     need_cursor_line_redraw = FALSE;
868 }
869 #endif
870 
871 #if defined(FEAT_SIGNS) || defined(FEAT_GUI)
872 static void update_prepare(void);
873 static void update_finish(void);
874 
875 /*
876  * Prepare for updating one or more windows.
877  * Caller must check for "updating_screen" already set to avoid recursiveness.
878  */
879     static void
880 update_prepare(void)
881 {
882     cursor_off();
883     updating_screen = TRUE;
884 #ifdef FEAT_GUI
885     /* Remove the cursor before starting to do anything, because scrolling may
886      * make it difficult to redraw the text under it. */
887     if (gui.in_use)
888 	gui_undraw_cursor();
889 #endif
890 #ifdef FEAT_SEARCH_EXTRA
891     start_search_hl();
892 #endif
893 }
894 
895 /*
896  * Finish updating one or more windows.
897  */
898     static void
899 update_finish(void)
900 {
901     if (redraw_cmdline)
902 	showmode();
903 
904 # ifdef FEAT_SEARCH_EXTRA
905     end_search_hl();
906 # endif
907 
908     updating_screen = FALSE;
909 
910 # ifdef FEAT_GUI
911     gui_may_resize_shell();
912 
913     /* Redraw the cursor and update the scrollbars when all screen updating is
914      * done. */
915     if (gui.in_use)
916     {
917 	out_flush();	/* required before updating the cursor */
918 	gui_update_cursor(FALSE, FALSE);
919 	gui_update_scrollbars(FALSE);
920     }
921 # endif
922 }
923 #endif
924 
925 #if defined(FEAT_SIGNS) || defined(PROTO)
926     void
927 update_debug_sign(buf_T *buf, linenr_T lnum)
928 {
929     win_T	*wp;
930     int		doit = FALSE;
931 
932 # ifdef FEAT_FOLDING
933     win_foldinfo.fi_level = 0;
934 # endif
935 
936     /* update/delete a specific mark */
937     FOR_ALL_WINDOWS(wp)
938     {
939 	if (buf != NULL && lnum > 0)
940 	{
941 	    if (wp->w_buffer == buf && lnum >= wp->w_topline
942 						      && lnum < wp->w_botline)
943 	    {
944 		if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum)
945 		    wp->w_redraw_top = lnum;
946 		if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum)
947 		    wp->w_redraw_bot = lnum;
948 		redraw_win_later(wp, VALID);
949 	    }
950 	}
951 	else
952 	    redraw_win_later(wp, VALID);
953 	if (wp->w_redr_type != 0)
954 	    doit = TRUE;
955     }
956 
957     /* Return when there is nothing to do, screen updating is already
958      * happening (recursive call) or still starting up. */
959     if (!doit || updating_screen
960 #ifdef FEAT_GUI
961 	    || gui.starting
962 #endif
963 	    || starting)
964 	return;
965 
966     /* update all windows that need updating */
967     update_prepare();
968 
969 # ifdef FEAT_WINDOWS
970     FOR_ALL_WINDOWS(wp)
971     {
972 	if (wp->w_redr_type != 0)
973 	    win_update(wp);
974 	if (wp->w_redr_status)
975 	    win_redr_status(wp);
976     }
977 # else
978     if (curwin->w_redr_type != 0)
979 	win_update(curwin);
980 # endif
981 
982     update_finish();
983 }
984 #endif
985 
986 
987 #if defined(FEAT_GUI) || defined(PROTO)
988 /*
989  * Update a single window, its status line and maybe the command line msg.
990  * Used for the GUI scrollbar.
991  */
992     void
993 updateWindow(win_T *wp)
994 {
995     /* return if already busy updating */
996     if (updating_screen)
997 	return;
998 
999     update_prepare();
1000 
1001 #ifdef FEAT_CLIPBOARD
1002     /* When Visual area changed, may have to update selection. */
1003     if (clip_star.available && clip_isautosel_star())
1004 	clip_update_selection(&clip_star);
1005     if (clip_plus.available && clip_isautosel_plus())
1006 	clip_update_selection(&clip_plus);
1007 #endif
1008 
1009     win_update(wp);
1010 
1011 #ifdef FEAT_WINDOWS
1012     /* When the screen was cleared redraw the tab pages line. */
1013     if (redraw_tabline)
1014 	draw_tabline();
1015 
1016     if (wp->w_redr_status
1017 # ifdef FEAT_CMDL_INFO
1018 	    || p_ru
1019 # endif
1020 # ifdef FEAT_STL_OPT
1021 	    || *p_stl != NUL || *wp->w_p_stl != NUL
1022 # endif
1023 	    )
1024 	win_redr_status(wp);
1025 #endif
1026 
1027     update_finish();
1028 }
1029 #endif
1030 
1031 /*
1032  * Update a single window.
1033  *
1034  * This may cause the windows below it also to be redrawn (when clearing the
1035  * screen or scrolling lines).
1036  *
1037  * How the window is redrawn depends on wp->w_redr_type.  Each type also
1038  * implies the one below it.
1039  * NOT_VALID	redraw the whole window
1040  * SOME_VALID	redraw the whole window but do scroll when possible
1041  * REDRAW_TOP	redraw the top w_upd_rows window lines, otherwise like VALID
1042  * INVERTED	redraw the changed part of the Visual area
1043  * INVERTED_ALL	redraw the whole Visual area
1044  * VALID	1. scroll up/down to adjust for a changed w_topline
1045  *		2. update lines at the top when scrolled down
1046  *		3. redraw changed text:
1047  *		   - if wp->w_buffer->b_mod_set set, update lines between
1048  *		     b_mod_top and b_mod_bot.
1049  *		   - if wp->w_redraw_top non-zero, redraw lines between
1050  *		     wp->w_redraw_top and wp->w_redr_bot.
1051  *		   - continue redrawing when syntax status is invalid.
1052  *		4. if scrolled up, update lines at the bottom.
1053  * This results in three areas that may need updating:
1054  * top:	from first row to top_end (when scrolled down)
1055  * mid: from mid_start to mid_end (update inversion or changed text)
1056  * bot: from bot_start to last row (when scrolled up)
1057  */
1058     static void
1059 win_update(win_T *wp)
1060 {
1061     buf_T	*buf = wp->w_buffer;
1062     int		type;
1063     int		top_end = 0;	/* Below last row of the top area that needs
1064 				   updating.  0 when no top area updating. */
1065     int		mid_start = 999;/* first row of the mid area that needs
1066 				   updating.  999 when no mid area updating. */
1067     int		mid_end = 0;	/* Below last row of the mid area that needs
1068 				   updating.  0 when no mid area updating. */
1069     int		bot_start = 999;/* first row of the bot area that needs
1070 				   updating.  999 when no bot area updating */
1071     int		scrolled_down = FALSE;	/* TRUE when scrolled down when
1072 					   w_topline got smaller a bit */
1073 #ifdef FEAT_SEARCH_EXTRA
1074     matchitem_T *cur;		/* points to the match list */
1075     int		top_to_mod = FALSE;    /* redraw above mod_top */
1076 #endif
1077 
1078     int		row;		/* current window row to display */
1079     linenr_T	lnum;		/* current buffer lnum to display */
1080     int		idx;		/* current index in w_lines[] */
1081     int		srow;		/* starting row of the current line */
1082 
1083     int		eof = FALSE;	/* if TRUE, we hit the end of the file */
1084     int		didline = FALSE; /* if TRUE, we finished the last line */
1085     int		i;
1086     long	j;
1087     static int	recursive = FALSE;	/* being called recursively */
1088     int		old_botline = wp->w_botline;
1089 #ifdef FEAT_FOLDING
1090     long	fold_count;
1091 #endif
1092 #ifdef FEAT_SYN_HL
1093     /* remember what happened to the previous line, to know if
1094      * check_visual_highlight() can be used */
1095 #define DID_NONE 1	/* didn't update a line */
1096 #define DID_LINE 2	/* updated a normal line */
1097 #define DID_FOLD 3	/* updated a folded line */
1098     int		did_update = DID_NONE;
1099     linenr_T	syntax_last_parsed = 0;		/* last parsed text line */
1100 #endif
1101     linenr_T	mod_top = 0;
1102     linenr_T	mod_bot = 0;
1103 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1104     int		save_got_int;
1105 #endif
1106 
1107     type = wp->w_redr_type;
1108 
1109     if (type == NOT_VALID)
1110     {
1111 #ifdef FEAT_WINDOWS
1112 	wp->w_redr_status = TRUE;
1113 #endif
1114 	wp->w_lines_valid = 0;
1115     }
1116 
1117     /* Window is zero-height: nothing to draw. */
1118     if (wp->w_height == 0)
1119     {
1120 	wp->w_redr_type = 0;
1121 	return;
1122     }
1123 
1124 #ifdef FEAT_WINDOWS
1125     /* Window is zero-width: Only need to draw the separator. */
1126     if (wp->w_width == 0)
1127     {
1128 	/* draw the vertical separator right of this window */
1129 	draw_vsep_win(wp, 0);
1130 	wp->w_redr_type = 0;
1131 	return;
1132     }
1133 #endif
1134 
1135 #ifdef FEAT_SEARCH_EXTRA
1136     init_search_hl(wp);
1137 #endif
1138 
1139 #ifdef FEAT_LINEBREAK
1140     /* Force redraw when width of 'number' or 'relativenumber' column
1141      * changes. */
1142     i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
1143     if (wp->w_nrwidth != i)
1144     {
1145 	type = NOT_VALID;
1146 	wp->w_nrwidth = i;
1147     }
1148     else
1149 #endif
1150 
1151     if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0)
1152     {
1153 	/*
1154 	 * When there are both inserted/deleted lines and specific lines to be
1155 	 * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
1156 	 * everything (only happens when redrawing is off for while).
1157 	 */
1158 	type = NOT_VALID;
1159     }
1160     else
1161     {
1162 	/*
1163 	 * Set mod_top to the first line that needs displaying because of
1164 	 * changes.  Set mod_bot to the first line after the changes.
1165 	 */
1166 	mod_top = wp->w_redraw_top;
1167 	if (wp->w_redraw_bot != 0)
1168 	    mod_bot = wp->w_redraw_bot + 1;
1169 	else
1170 	    mod_bot = 0;
1171 	wp->w_redraw_top = 0;	/* reset for next time */
1172 	wp->w_redraw_bot = 0;
1173 	if (buf->b_mod_set)
1174 	{
1175 	    if (mod_top == 0 || mod_top > buf->b_mod_top)
1176 	    {
1177 		mod_top = buf->b_mod_top;
1178 #ifdef FEAT_SYN_HL
1179 		/* Need to redraw lines above the change that may be included
1180 		 * in a pattern match. */
1181 		if (syntax_present(wp))
1182 		{
1183 		    mod_top -= buf->b_s.b_syn_sync_linebreaks;
1184 		    if (mod_top < 1)
1185 			mod_top = 1;
1186 		}
1187 #endif
1188 	    }
1189 	    if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
1190 		mod_bot = buf->b_mod_bot;
1191 
1192 #ifdef FEAT_SEARCH_EXTRA
1193 	    /* When 'hlsearch' is on and using a multi-line search pattern, a
1194 	     * change in one line may make the Search highlighting in a
1195 	     * previous line invalid.  Simple solution: redraw all visible
1196 	     * lines above the change.
1197 	     * Same for a match pattern.
1198 	     */
1199 	    if (search_hl.rm.regprog != NULL
1200 					&& re_multiline(search_hl.rm.regprog))
1201 		top_to_mod = TRUE;
1202 	    else
1203 	    {
1204 		cur = wp->w_match_head;
1205 		while (cur != NULL)
1206 		{
1207 		    if (cur->match.regprog != NULL
1208 					   && re_multiline(cur->match.regprog))
1209 		    {
1210 			top_to_mod = TRUE;
1211 			break;
1212 		    }
1213 		    cur = cur->next;
1214 		}
1215 	    }
1216 #endif
1217 	}
1218 #ifdef FEAT_FOLDING
1219 	if (mod_top != 0 && hasAnyFolding(wp))
1220 	{
1221 	    linenr_T	lnumt, lnumb;
1222 
1223 	    /*
1224 	     * A change in a line can cause lines above it to become folded or
1225 	     * unfolded.  Find the top most buffer line that may be affected.
1226 	     * If the line was previously folded and displayed, get the first
1227 	     * line of that fold.  If the line is folded now, get the first
1228 	     * folded line.  Use the minimum of these two.
1229 	     */
1230 
1231 	    /* Find last valid w_lines[] entry above mod_top.  Set lnumt to
1232 	     * the line below it.  If there is no valid entry, use w_topline.
1233 	     * Find the first valid w_lines[] entry below mod_bot.  Set lnumb
1234 	     * to this line.  If there is no valid entry, use MAXLNUM. */
1235 	    lnumt = wp->w_topline;
1236 	    lnumb = MAXLNUM;
1237 	    for (i = 0; i < wp->w_lines_valid; ++i)
1238 		if (wp->w_lines[i].wl_valid)
1239 		{
1240 		    if (wp->w_lines[i].wl_lastlnum < mod_top)
1241 			lnumt = wp->w_lines[i].wl_lastlnum + 1;
1242 		    if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot)
1243 		    {
1244 			lnumb = wp->w_lines[i].wl_lnum;
1245 			/* When there is a fold column it might need updating
1246 			 * in the next line ("J" just above an open fold). */
1247 			if (compute_foldcolumn(wp, 0) > 0)
1248 			    ++lnumb;
1249 		    }
1250 		}
1251 
1252 	    (void)hasFoldingWin(wp, mod_top, &mod_top, NULL, TRUE, NULL);
1253 	    if (mod_top > lnumt)
1254 		mod_top = lnumt;
1255 
1256 	    /* Now do the same for the bottom line (one above mod_bot). */
1257 	    --mod_bot;
1258 	    (void)hasFoldingWin(wp, mod_bot, NULL, &mod_bot, TRUE, NULL);
1259 	    ++mod_bot;
1260 	    if (mod_bot < lnumb)
1261 		mod_bot = lnumb;
1262 	}
1263 #endif
1264 
1265 	/* When a change starts above w_topline and the end is below
1266 	 * w_topline, start redrawing at w_topline.
1267 	 * If the end of the change is above w_topline: do like no change was
1268 	 * made, but redraw the first line to find changes in syntax. */
1269 	if (mod_top != 0 && mod_top < wp->w_topline)
1270 	{
1271 	    if (mod_bot > wp->w_topline)
1272 		mod_top = wp->w_topline;
1273 #ifdef FEAT_SYN_HL
1274 	    else if (syntax_present(wp))
1275 		top_end = 1;
1276 #endif
1277 	}
1278 
1279 	/* When line numbers are displayed need to redraw all lines below
1280 	 * inserted/deleted lines. */
1281 	if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
1282 	    mod_bot = MAXLNUM;
1283     }
1284 
1285     /*
1286      * When only displaying the lines at the top, set top_end.  Used when
1287      * window has scrolled down for msg_scrolled.
1288      */
1289     if (type == REDRAW_TOP)
1290     {
1291 	j = 0;
1292 	for (i = 0; i < wp->w_lines_valid; ++i)
1293 	{
1294 	    j += wp->w_lines[i].wl_size;
1295 	    if (j >= wp->w_upd_rows)
1296 	    {
1297 		top_end = j;
1298 		break;
1299 	    }
1300 	}
1301 	if (top_end == 0)
1302 	    /* not found (cannot happen?): redraw everything */
1303 	    type = NOT_VALID;
1304 	else
1305 	    /* top area defined, the rest is VALID */
1306 	    type = VALID;
1307     }
1308 
1309     /* Trick: we want to avoid clearing the screen twice.  screenclear() will
1310      * set "screen_cleared" to TRUE.  The special value MAYBE (which is still
1311      * non-zero and thus not FALSE) will indicate that screenclear() was not
1312      * called. */
1313     if (screen_cleared)
1314 	screen_cleared = MAYBE;
1315 
1316     /*
1317      * If there are no changes on the screen that require a complete redraw,
1318      * handle three cases:
1319      * 1: we are off the top of the screen by a few lines: scroll down
1320      * 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up
1321      * 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in
1322      *    w_lines[] that needs updating.
1323      */
1324     if ((type == VALID || type == SOME_VALID
1325 				  || type == INVERTED || type == INVERTED_ALL)
1326 #ifdef FEAT_DIFF
1327 	    && !wp->w_botfill && !wp->w_old_botfill
1328 #endif
1329 	    )
1330     {
1331 	if (mod_top != 0 && wp->w_topline == mod_top)
1332 	{
1333 	    /*
1334 	     * w_topline is the first changed line, the scrolling will be done
1335 	     * further down.
1336 	     */
1337 	}
1338 	else if (wp->w_lines[0].wl_valid
1339 		&& (wp->w_topline < wp->w_lines[0].wl_lnum
1340 #ifdef FEAT_DIFF
1341 		    || (wp->w_topline == wp->w_lines[0].wl_lnum
1342 			&& wp->w_topfill > wp->w_old_topfill)
1343 #endif
1344 		   ))
1345 	{
1346 	    /*
1347 	     * New topline is above old topline: May scroll down.
1348 	     */
1349 #ifdef FEAT_FOLDING
1350 	    if (hasAnyFolding(wp))
1351 	    {
1352 		linenr_T ln;
1353 
1354 		/* count the number of lines we are off, counting a sequence
1355 		 * of folded lines as one */
1356 		j = 0;
1357 		for (ln = wp->w_topline; ln < wp->w_lines[0].wl_lnum; ++ln)
1358 		{
1359 		    ++j;
1360 		    if (j >= wp->w_height - 2)
1361 			break;
1362 		    (void)hasFoldingWin(wp, ln, NULL, &ln, TRUE, NULL);
1363 		}
1364 	    }
1365 	    else
1366 #endif
1367 		j = wp->w_lines[0].wl_lnum - wp->w_topline;
1368 	    if (j < wp->w_height - 2)		/* not too far off */
1369 	    {
1370 		i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
1371 #ifdef FEAT_DIFF
1372 		/* insert extra lines for previously invisible filler lines */
1373 		if (wp->w_lines[0].wl_lnum != wp->w_topline)
1374 		    i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
1375 							  - wp->w_old_topfill;
1376 #endif
1377 		if (i < wp->w_height - 2)	/* less than a screen off */
1378 		{
1379 		    /*
1380 		     * Try to insert the correct number of lines.
1381 		     * If not the last window, delete the lines at the bottom.
1382 		     * win_ins_lines may fail when the terminal can't do it.
1383 		     */
1384 		    if (i > 0)
1385 			check_for_delay(FALSE);
1386 		    if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK)
1387 		    {
1388 			if (wp->w_lines_valid != 0)
1389 			{
1390 			    /* Need to update rows that are new, stop at the
1391 			     * first one that scrolled down. */
1392 			    top_end = i;
1393 			    scrolled_down = TRUE;
1394 
1395 			    /* Move the entries that were scrolled, disable
1396 			     * the entries for the lines to be redrawn. */
1397 			    if ((wp->w_lines_valid += j) > wp->w_height)
1398 				wp->w_lines_valid = wp->w_height;
1399 			    for (idx = wp->w_lines_valid; idx - j >= 0; idx--)
1400 				wp->w_lines[idx] = wp->w_lines[idx - j];
1401 			    while (idx >= 0)
1402 				wp->w_lines[idx--].wl_valid = FALSE;
1403 			}
1404 		    }
1405 		    else
1406 			mid_start = 0;		/* redraw all lines */
1407 		}
1408 		else
1409 		    mid_start = 0;		/* redraw all lines */
1410 	    }
1411 	    else
1412 		mid_start = 0;		/* redraw all lines */
1413 	}
1414 	else
1415 	{
1416 	    /*
1417 	     * New topline is at or below old topline: May scroll up.
1418 	     * When topline didn't change, find first entry in w_lines[] that
1419 	     * needs updating.
1420 	     */
1421 
1422 	    /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
1423 	    j = -1;
1424 	    row = 0;
1425 	    for (i = 0; i < wp->w_lines_valid; i++)
1426 	    {
1427 		if (wp->w_lines[i].wl_valid
1428 			&& wp->w_lines[i].wl_lnum == wp->w_topline)
1429 		{
1430 		    j = i;
1431 		    break;
1432 		}
1433 		row += wp->w_lines[i].wl_size;
1434 	    }
1435 	    if (j == -1)
1436 	    {
1437 		/* if wp->w_topline is not in wp->w_lines[].wl_lnum redraw all
1438 		 * lines */
1439 		mid_start = 0;
1440 	    }
1441 	    else
1442 	    {
1443 		/*
1444 		 * Try to delete the correct number of lines.
1445 		 * wp->w_topline is at wp->w_lines[i].wl_lnum.
1446 		 */
1447 #ifdef FEAT_DIFF
1448 		/* If the topline didn't change, delete old filler lines,
1449 		 * otherwise delete filler lines of the new topline... */
1450 		if (wp->w_lines[0].wl_lnum == wp->w_topline)
1451 		    row += wp->w_old_topfill;
1452 		else
1453 		    row += diff_check_fill(wp, wp->w_topline);
1454 		/* ... but don't delete new filler lines. */
1455 		row -= wp->w_topfill;
1456 #endif
1457 		if (row > 0)
1458 		{
1459 		    check_for_delay(FALSE);
1460 		    if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
1461 			bot_start = wp->w_height - row;
1462 		    else
1463 			mid_start = 0;		/* redraw all lines */
1464 		}
1465 		if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0)
1466 		{
1467 		    /*
1468 		     * Skip the lines (below the deleted lines) that are still
1469 		     * valid and don't need redrawing.	Copy their info
1470 		     * upwards, to compensate for the deleted lines.  Set
1471 		     * bot_start to the first row that needs redrawing.
1472 		     */
1473 		    bot_start = 0;
1474 		    idx = 0;
1475 		    for (;;)
1476 		    {
1477 			wp->w_lines[idx] = wp->w_lines[j];
1478 			/* stop at line that didn't fit, unless it is still
1479 			 * valid (no lines deleted) */
1480 			if (row > 0 && bot_start + row
1481 				 + (int)wp->w_lines[j].wl_size > wp->w_height)
1482 			{
1483 			    wp->w_lines_valid = idx + 1;
1484 			    break;
1485 			}
1486 			bot_start += wp->w_lines[idx++].wl_size;
1487 
1488 			/* stop at the last valid entry in w_lines[].wl_size */
1489 			if (++j >= wp->w_lines_valid)
1490 			{
1491 			    wp->w_lines_valid = idx;
1492 			    break;
1493 			}
1494 		    }
1495 #ifdef FEAT_DIFF
1496 		    /* Correct the first entry for filler lines at the top
1497 		     * when it won't get updated below. */
1498 		    if (wp->w_p_diff && bot_start > 0)
1499 			wp->w_lines[0].wl_size =
1500 			    plines_win_nofill(wp, wp->w_topline, TRUE)
1501 							      + wp->w_topfill;
1502 #endif
1503 		}
1504 	    }
1505 	}
1506 
1507 	/* When starting redraw in the first line, redraw all lines.  When
1508 	 * there is only one window it's probably faster to clear the screen
1509 	 * first. */
1510 	if (mid_start == 0)
1511 	{
1512 	    mid_end = wp->w_height;
1513 	    if (ONE_WINDOW)
1514 	    {
1515 		/* Clear the screen when it was not done by win_del_lines() or
1516 		 * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
1517 		 * then. */
1518 		if (screen_cleared != TRUE)
1519 		    screenclear();
1520 #ifdef FEAT_WINDOWS
1521 		/* The screen was cleared, redraw the tab pages line. */
1522 		if (redraw_tabline)
1523 		    draw_tabline();
1524 #endif
1525 	    }
1526 	}
1527 
1528 	/* When win_del_lines() or win_ins_lines() caused the screen to be
1529 	 * cleared (only happens for the first window) or when screenclear()
1530 	 * was called directly above, "must_redraw" will have been set to
1531 	 * NOT_VALID, need to reset it here to avoid redrawing twice. */
1532 	if (screen_cleared == TRUE)
1533 	    must_redraw = 0;
1534     }
1535     else
1536     {
1537 	/* Not VALID or INVERTED: redraw all lines. */
1538 	mid_start = 0;
1539 	mid_end = wp->w_height;
1540     }
1541 
1542     if (type == SOME_VALID)
1543     {
1544 	/* SOME_VALID: redraw all lines. */
1545 	mid_start = 0;
1546 	mid_end = wp->w_height;
1547 	type = NOT_VALID;
1548     }
1549 
1550     /* check if we are updating or removing the inverted part */
1551     if ((VIsual_active && buf == curwin->w_buffer)
1552 	    || (wp->w_old_cursor_lnum != 0 && type != NOT_VALID))
1553     {
1554 	linenr_T    from, to;
1555 
1556 	if (VIsual_active)
1557 	{
1558 	    if (VIsual_active
1559 		    && (VIsual_mode != wp->w_old_visual_mode
1560 			|| type == INVERTED_ALL))
1561 	    {
1562 		/*
1563 		 * If the type of Visual selection changed, redraw the whole
1564 		 * selection.  Also when the ownership of the X selection is
1565 		 * gained or lost.
1566 		 */
1567 		if (curwin->w_cursor.lnum < VIsual.lnum)
1568 		{
1569 		    from = curwin->w_cursor.lnum;
1570 		    to = VIsual.lnum;
1571 		}
1572 		else
1573 		{
1574 		    from = VIsual.lnum;
1575 		    to = curwin->w_cursor.lnum;
1576 		}
1577 		/* redraw more when the cursor moved as well */
1578 		if (wp->w_old_cursor_lnum < from)
1579 		    from = wp->w_old_cursor_lnum;
1580 		if (wp->w_old_cursor_lnum > to)
1581 		    to = wp->w_old_cursor_lnum;
1582 		if (wp->w_old_visual_lnum < from)
1583 		    from = wp->w_old_visual_lnum;
1584 		if (wp->w_old_visual_lnum > to)
1585 		    to = wp->w_old_visual_lnum;
1586 	    }
1587 	    else
1588 	    {
1589 		/*
1590 		 * Find the line numbers that need to be updated: The lines
1591 		 * between the old cursor position and the current cursor
1592 		 * position.  Also check if the Visual position changed.
1593 		 */
1594 		if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
1595 		{
1596 		    from = curwin->w_cursor.lnum;
1597 		    to = wp->w_old_cursor_lnum;
1598 		}
1599 		else
1600 		{
1601 		    from = wp->w_old_cursor_lnum;
1602 		    to = curwin->w_cursor.lnum;
1603 		    if (from == 0)	/* Visual mode just started */
1604 			from = to;
1605 		}
1606 
1607 		if (VIsual.lnum != wp->w_old_visual_lnum
1608 					|| VIsual.col != wp->w_old_visual_col)
1609 		{
1610 		    if (wp->w_old_visual_lnum < from
1611 						&& wp->w_old_visual_lnum != 0)
1612 			from = wp->w_old_visual_lnum;
1613 		    if (wp->w_old_visual_lnum > to)
1614 			to = wp->w_old_visual_lnum;
1615 		    if (VIsual.lnum < from)
1616 			from = VIsual.lnum;
1617 		    if (VIsual.lnum > to)
1618 			to = VIsual.lnum;
1619 		}
1620 	    }
1621 
1622 	    /*
1623 	     * If in block mode and changed column or curwin->w_curswant:
1624 	     * update all lines.
1625 	     * First compute the actual start and end column.
1626 	     */
1627 	    if (VIsual_mode == Ctrl_V)
1628 	    {
1629 		colnr_T	    fromc, toc;
1630 #if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1631 		int	    save_ve_flags = ve_flags;
1632 
1633 		if (curwin->w_p_lbr)
1634 		    ve_flags = VE_ALL;
1635 #endif
1636 		getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
1637 #if defined(FEAT_VIRTUALEDIT) && defined(FEAT_LINEBREAK)
1638 		ve_flags = save_ve_flags;
1639 #endif
1640 		++toc;
1641 		if (curwin->w_curswant == MAXCOL)
1642 		    toc = MAXCOL;
1643 
1644 		if (fromc != wp->w_old_cursor_fcol
1645 			|| toc != wp->w_old_cursor_lcol)
1646 		{
1647 		    if (from > VIsual.lnum)
1648 			from = VIsual.lnum;
1649 		    if (to < VIsual.lnum)
1650 			to = VIsual.lnum;
1651 		}
1652 		wp->w_old_cursor_fcol = fromc;
1653 		wp->w_old_cursor_lcol = toc;
1654 	    }
1655 	}
1656 	else
1657 	{
1658 	    /* Use the line numbers of the old Visual area. */
1659 	    if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum)
1660 	    {
1661 		from = wp->w_old_cursor_lnum;
1662 		to = wp->w_old_visual_lnum;
1663 	    }
1664 	    else
1665 	    {
1666 		from = wp->w_old_visual_lnum;
1667 		to = wp->w_old_cursor_lnum;
1668 	    }
1669 	}
1670 
1671 	/*
1672 	 * There is no need to update lines above the top of the window.
1673 	 */
1674 	if (from < wp->w_topline)
1675 	    from = wp->w_topline;
1676 
1677 	/*
1678 	 * If we know the value of w_botline, use it to restrict the update to
1679 	 * the lines that are visible in the window.
1680 	 */
1681 	if (wp->w_valid & VALID_BOTLINE)
1682 	{
1683 	    if (from >= wp->w_botline)
1684 		from = wp->w_botline - 1;
1685 	    if (to >= wp->w_botline)
1686 		to = wp->w_botline - 1;
1687 	}
1688 
1689 	/*
1690 	 * Find the minimal part to be updated.
1691 	 * Watch out for scrolling that made entries in w_lines[] invalid.
1692 	 * E.g., CTRL-U makes the first half of w_lines[] invalid and sets
1693 	 * top_end; need to redraw from top_end to the "to" line.
1694 	 * A middle mouse click with a Visual selection may change the text
1695 	 * above the Visual area and reset wl_valid, do count these for
1696 	 * mid_end (in srow).
1697 	 */
1698 	if (mid_start > 0)
1699 	{
1700 	    lnum = wp->w_topline;
1701 	    idx = 0;
1702 	    srow = 0;
1703 	    if (scrolled_down)
1704 		mid_start = top_end;
1705 	    else
1706 		mid_start = 0;
1707 	    while (lnum < from && idx < wp->w_lines_valid)	/* find start */
1708 	    {
1709 		if (wp->w_lines[idx].wl_valid)
1710 		    mid_start += wp->w_lines[idx].wl_size;
1711 		else if (!scrolled_down)
1712 		    srow += wp->w_lines[idx].wl_size;
1713 		++idx;
1714 # ifdef FEAT_FOLDING
1715 		if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
1716 		    lnum = wp->w_lines[idx].wl_lnum;
1717 		else
1718 # endif
1719 		    ++lnum;
1720 	    }
1721 	    srow += mid_start;
1722 	    mid_end = wp->w_height;
1723 	    for ( ; idx < wp->w_lines_valid; ++idx)		/* find end */
1724 	    {
1725 		if (wp->w_lines[idx].wl_valid
1726 			&& wp->w_lines[idx].wl_lnum >= to + 1)
1727 		{
1728 		    /* Only update until first row of this line */
1729 		    mid_end = srow;
1730 		    break;
1731 		}
1732 		srow += wp->w_lines[idx].wl_size;
1733 	    }
1734 	}
1735     }
1736 
1737     if (VIsual_active && buf == curwin->w_buffer)
1738     {
1739 	wp->w_old_visual_mode = VIsual_mode;
1740 	wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
1741 	wp->w_old_visual_lnum = VIsual.lnum;
1742 	wp->w_old_visual_col = VIsual.col;
1743 	wp->w_old_curswant = curwin->w_curswant;
1744     }
1745     else
1746     {
1747 	wp->w_old_visual_mode = 0;
1748 	wp->w_old_cursor_lnum = 0;
1749 	wp->w_old_visual_lnum = 0;
1750 	wp->w_old_visual_col = 0;
1751     }
1752 
1753 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
1754     /* reset got_int, otherwise regexp won't work */
1755     save_got_int = got_int;
1756     got_int = 0;
1757 #endif
1758 #ifdef FEAT_FOLDING
1759     win_foldinfo.fi_level = 0;
1760 #endif
1761 
1762     /*
1763      * Update all the window rows.
1764      */
1765     idx = 0;		/* first entry in w_lines[].wl_size */
1766     row = 0;
1767     srow = 0;
1768     lnum = wp->w_topline;	/* first line shown in window */
1769     for (;;)
1770     {
1771 	/* stop updating when reached the end of the window (check for _past_
1772 	 * the end of the window is at the end of the loop) */
1773 	if (row == wp->w_height)
1774 	{
1775 	    didline = TRUE;
1776 	    break;
1777 	}
1778 
1779 	/* stop updating when hit the end of the file */
1780 	if (lnum > buf->b_ml.ml_line_count)
1781 	{
1782 	    eof = TRUE;
1783 	    break;
1784 	}
1785 
1786 	/* Remember the starting row of the line that is going to be dealt
1787 	 * with.  It is used further down when the line doesn't fit. */
1788 	srow = row;
1789 
1790 	/*
1791 	 * Update a line when it is in an area that needs updating, when it
1792 	 * has changes or w_lines[idx] is invalid.
1793 	 * bot_start may be halfway a wrapped line after using
1794 	 * win_del_lines(), check if the current line includes it.
1795 	 * When syntax folding is being used, the saved syntax states will
1796 	 * already have been updated, we can't see where the syntax state is
1797 	 * the same again, just update until the end of the window.
1798 	 */
1799 	if (row < top_end
1800 		|| (row >= mid_start && row < mid_end)
1801 #ifdef FEAT_SEARCH_EXTRA
1802 		|| top_to_mod
1803 #endif
1804 		|| idx >= wp->w_lines_valid
1805 		|| (row + wp->w_lines[idx].wl_size > bot_start)
1806 		|| (mod_top != 0
1807 		    && (lnum == mod_top
1808 			|| (lnum >= mod_top
1809 			    && (lnum < mod_bot
1810 #ifdef FEAT_SYN_HL
1811 				|| did_update == DID_FOLD
1812 				|| (did_update == DID_LINE
1813 				    && syntax_present(wp)
1814 				    && (
1815 # ifdef FEAT_FOLDING
1816 					(foldmethodIsSyntax(wp)
1817 						      && hasAnyFolding(wp)) ||
1818 # endif
1819 					syntax_check_changed(lnum)))
1820 #endif
1821 #ifdef FEAT_SEARCH_EXTRA
1822 				/* match in fixed position might need redraw
1823 				 * if lines were inserted or deleted */
1824 				|| (wp->w_match_head != NULL
1825 						    && buf->b_mod_xlines != 0)
1826 #endif
1827 				)))))
1828 	{
1829 #ifdef FEAT_SEARCH_EXTRA
1830 	    if (lnum == mod_top)
1831 		top_to_mod = FALSE;
1832 #endif
1833 
1834 	    /*
1835 	     * When at start of changed lines: May scroll following lines
1836 	     * up or down to minimize redrawing.
1837 	     * Don't do this when the change continues until the end.
1838 	     * Don't scroll when dollar_vcol >= 0, keep the "$".
1839 	     */
1840 	    if (lnum == mod_top
1841 		    && mod_bot != MAXLNUM
1842 		    && !(dollar_vcol >= 0 && mod_bot == mod_top + 1))
1843 	    {
1844 		int		old_rows = 0;
1845 		int		new_rows = 0;
1846 		int		xtra_rows;
1847 		linenr_T	l;
1848 
1849 		/* Count the old number of window rows, using w_lines[], which
1850 		 * should still contain the sizes for the lines as they are
1851 		 * currently displayed. */
1852 		for (i = idx; i < wp->w_lines_valid; ++i)
1853 		{
1854 		    /* Only valid lines have a meaningful wl_lnum.  Invalid
1855 		     * lines are part of the changed area. */
1856 		    if (wp->w_lines[i].wl_valid
1857 			    && wp->w_lines[i].wl_lnum == mod_bot)
1858 			break;
1859 		    old_rows += wp->w_lines[i].wl_size;
1860 #ifdef FEAT_FOLDING
1861 		    if (wp->w_lines[i].wl_valid
1862 			    && wp->w_lines[i].wl_lastlnum + 1 == mod_bot)
1863 		    {
1864 			/* Must have found the last valid entry above mod_bot.
1865 			 * Add following invalid entries. */
1866 			++i;
1867 			while (i < wp->w_lines_valid
1868 						  && !wp->w_lines[i].wl_valid)
1869 			    old_rows += wp->w_lines[i++].wl_size;
1870 			break;
1871 		    }
1872 #endif
1873 		}
1874 
1875 		if (i >= wp->w_lines_valid)
1876 		{
1877 		    /* We can't find a valid line below the changed lines,
1878 		     * need to redraw until the end of the window.
1879 		     * Inserting/deleting lines has no use. */
1880 		    bot_start = 0;
1881 		}
1882 		else
1883 		{
1884 		    /* Able to count old number of rows: Count new window
1885 		     * rows, and may insert/delete lines */
1886 		    j = idx;
1887 		    for (l = lnum; l < mod_bot; ++l)
1888 		    {
1889 #ifdef FEAT_FOLDING
1890 			if (hasFoldingWin(wp, l, NULL, &l, TRUE, NULL))
1891 			    ++new_rows;
1892 			else
1893 #endif
1894 #ifdef FEAT_DIFF
1895 			    if (l == wp->w_topline)
1896 			    new_rows += plines_win_nofill(wp, l, TRUE)
1897 							      + wp->w_topfill;
1898 			else
1899 #endif
1900 			    new_rows += plines_win(wp, l, TRUE);
1901 			++j;
1902 			if (new_rows > wp->w_height - row - 2)
1903 			{
1904 			    /* it's getting too much, must redraw the rest */
1905 			    new_rows = 9999;
1906 			    break;
1907 			}
1908 		    }
1909 		    xtra_rows = new_rows - old_rows;
1910 		    if (xtra_rows < 0)
1911 		    {
1912 			/* May scroll text up.  If there is not enough
1913 			 * remaining text or scrolling fails, must redraw the
1914 			 * rest.  If scrolling works, must redraw the text
1915 			 * below the scrolled text. */
1916 			if (row - xtra_rows >= wp->w_height - 2)
1917 			    mod_bot = MAXLNUM;
1918 			else
1919 			{
1920 			    check_for_delay(FALSE);
1921 			    if (win_del_lines(wp, row,
1922 					    -xtra_rows, FALSE, FALSE) == FAIL)
1923 				mod_bot = MAXLNUM;
1924 			    else
1925 				bot_start = wp->w_height + xtra_rows;
1926 			}
1927 		    }
1928 		    else if (xtra_rows > 0)
1929 		    {
1930 			/* May scroll text down.  If there is not enough
1931 			 * remaining text of scrolling fails, must redraw the
1932 			 * rest. */
1933 			if (row + xtra_rows >= wp->w_height - 2)
1934 			    mod_bot = MAXLNUM;
1935 			else
1936 			{
1937 			    check_for_delay(FALSE);
1938 			    if (win_ins_lines(wp, row + old_rows,
1939 					     xtra_rows, FALSE, FALSE) == FAIL)
1940 				mod_bot = MAXLNUM;
1941 			    else if (top_end > row + old_rows)
1942 				/* Scrolled the part at the top that requires
1943 				 * updating down. */
1944 				top_end += xtra_rows;
1945 			}
1946 		    }
1947 
1948 		    /* When not updating the rest, may need to move w_lines[]
1949 		     * entries. */
1950 		    if (mod_bot != MAXLNUM && i != j)
1951 		    {
1952 			if (j < i)
1953 			{
1954 			    int x = row + new_rows;
1955 
1956 			    /* move entries in w_lines[] upwards */
1957 			    for (;;)
1958 			    {
1959 				/* stop at last valid entry in w_lines[] */
1960 				if (i >= wp->w_lines_valid)
1961 				{
1962 				    wp->w_lines_valid = j;
1963 				    break;
1964 				}
1965 				wp->w_lines[j] = wp->w_lines[i];
1966 				/* stop at a line that won't fit */
1967 				if (x + (int)wp->w_lines[j].wl_size
1968 							   > wp->w_height)
1969 				{
1970 				    wp->w_lines_valid = j + 1;
1971 				    break;
1972 				}
1973 				x += wp->w_lines[j++].wl_size;
1974 				++i;
1975 			    }
1976 			    if (bot_start > x)
1977 				bot_start = x;
1978 			}
1979 			else /* j > i */
1980 			{
1981 			    /* move entries in w_lines[] downwards */
1982 			    j -= i;
1983 			    wp->w_lines_valid += j;
1984 			    if (wp->w_lines_valid > wp->w_height)
1985 				wp->w_lines_valid = wp->w_height;
1986 			    for (i = wp->w_lines_valid; i - j >= idx; --i)
1987 				wp->w_lines[i] = wp->w_lines[i - j];
1988 
1989 			    /* The w_lines[] entries for inserted lines are
1990 			     * now invalid, but wl_size may be used above.
1991 			     * Reset to zero. */
1992 			    while (i >= idx)
1993 			    {
1994 				wp->w_lines[i].wl_size = 0;
1995 				wp->w_lines[i--].wl_valid = FALSE;
1996 			    }
1997 			}
1998 		    }
1999 		}
2000 	    }
2001 
2002 #ifdef FEAT_FOLDING
2003 	    /*
2004 	     * When lines are folded, display one line for all of them.
2005 	     * Otherwise, display normally (can be several display lines when
2006 	     * 'wrap' is on).
2007 	     */
2008 	    fold_count = foldedCount(wp, lnum, &win_foldinfo);
2009 	    if (fold_count != 0)
2010 	    {
2011 		fold_line(wp, fold_count, &win_foldinfo, lnum, row);
2012 		++row;
2013 		--fold_count;
2014 		wp->w_lines[idx].wl_folded = TRUE;
2015 		wp->w_lines[idx].wl_lastlnum = lnum + fold_count;
2016 # ifdef FEAT_SYN_HL
2017 		did_update = DID_FOLD;
2018 # endif
2019 	    }
2020 	    else
2021 #endif
2022 	    if (idx < wp->w_lines_valid
2023 		    && wp->w_lines[idx].wl_valid
2024 		    && wp->w_lines[idx].wl_lnum == lnum
2025 		    && lnum > wp->w_topline
2026 		    && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
2027 		    && srow + wp->w_lines[idx].wl_size > wp->w_height
2028 #ifdef FEAT_DIFF
2029 		    && diff_check_fill(wp, lnum) == 0
2030 #endif
2031 		    )
2032 	    {
2033 		/* This line is not going to fit.  Don't draw anything here,
2034 		 * will draw "@  " lines below. */
2035 		row = wp->w_height + 1;
2036 	    }
2037 	    else
2038 	    {
2039 #ifdef FEAT_SEARCH_EXTRA
2040 		prepare_search_hl(wp, lnum);
2041 #endif
2042 #ifdef FEAT_SYN_HL
2043 		/* Let the syntax stuff know we skipped a few lines. */
2044 		if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
2045 						       && syntax_present(wp))
2046 		    syntax_end_parsing(syntax_last_parsed + 1);
2047 #endif
2048 
2049 		/*
2050 		 * Display one line.
2051 		 */
2052 		row = win_line(wp, lnum, srow, wp->w_height, mod_top == 0);
2053 
2054 #ifdef FEAT_FOLDING
2055 		wp->w_lines[idx].wl_folded = FALSE;
2056 		wp->w_lines[idx].wl_lastlnum = lnum;
2057 #endif
2058 #ifdef FEAT_SYN_HL
2059 		did_update = DID_LINE;
2060 		syntax_last_parsed = lnum;
2061 #endif
2062 	    }
2063 
2064 	    wp->w_lines[idx].wl_lnum = lnum;
2065 	    wp->w_lines[idx].wl_valid = TRUE;
2066 	    if (row > wp->w_height)	/* past end of screen */
2067 	    {
2068 		/* we may need the size of that too long line later on */
2069 		if (dollar_vcol == -1)
2070 		    wp->w_lines[idx].wl_size = plines_win(wp, lnum, TRUE);
2071 		++idx;
2072 		break;
2073 	    }
2074 	    if (dollar_vcol == -1)
2075 		wp->w_lines[idx].wl_size = row - srow;
2076 	    ++idx;
2077 #ifdef FEAT_FOLDING
2078 	    lnum += fold_count + 1;
2079 #else
2080 	    ++lnum;
2081 #endif
2082 	}
2083 	else
2084 	{
2085 	    /* This line does not need updating, advance to the next one */
2086 	    row += wp->w_lines[idx++].wl_size;
2087 	    if (row > wp->w_height)	/* past end of screen */
2088 		break;
2089 #ifdef FEAT_FOLDING
2090 	    lnum = wp->w_lines[idx - 1].wl_lastlnum + 1;
2091 #else
2092 	    ++lnum;
2093 #endif
2094 #ifdef FEAT_SYN_HL
2095 	    did_update = DID_NONE;
2096 #endif
2097 	}
2098 
2099 	if (lnum > buf->b_ml.ml_line_count)
2100 	{
2101 	    eof = TRUE;
2102 	    break;
2103 	}
2104     }
2105     /*
2106      * End of loop over all window lines.
2107      */
2108 
2109 
2110     if (idx > wp->w_lines_valid)
2111 	wp->w_lines_valid = idx;
2112 
2113 #ifdef FEAT_SYN_HL
2114     /*
2115      * Let the syntax stuff know we stop parsing here.
2116      */
2117     if (syntax_last_parsed != 0 && syntax_present(wp))
2118 	syntax_end_parsing(syntax_last_parsed + 1);
2119 #endif
2120 
2121     /*
2122      * If we didn't hit the end of the file, and we didn't finish the last
2123      * line we were working on, then the line didn't fit.
2124      */
2125     wp->w_empty_rows = 0;
2126 #ifdef FEAT_DIFF
2127     wp->w_filler_rows = 0;
2128 #endif
2129     if (!eof && !didline)
2130     {
2131 	if (lnum == wp->w_topline)
2132 	{
2133 	    /*
2134 	     * Single line that does not fit!
2135 	     * Don't overwrite it, it can be edited.
2136 	     */
2137 	    wp->w_botline = lnum + 1;
2138 	}
2139 #ifdef FEAT_DIFF
2140 	else if (diff_check_fill(wp, lnum) >= wp->w_height - srow)
2141 	{
2142 	    /* Window ends in filler lines. */
2143 	    wp->w_botline = lnum;
2144 	    wp->w_filler_rows = wp->w_height - srow;
2145 	}
2146 #endif
2147 	else if (dy_flags & DY_TRUNCATE)	/* 'display' has "truncate" */
2148 	{
2149 	    int scr_row = W_WINROW(wp) + wp->w_height - 1;
2150 
2151 	    /*
2152 	     * Last line isn't finished: Display "@@@" in the last screen line.
2153 	     */
2154 	    screen_puts_len((char_u *)"@@", 2, scr_row, W_WINCOL(wp),
2155 							      hl_attr(HLF_AT));
2156 	    screen_fill(scr_row, scr_row + 1,
2157 		    (int)W_WINCOL(wp) + 2, (int)W_ENDCOL(wp),
2158 		    '@', ' ', hl_attr(HLF_AT));
2159 	    set_empty_rows(wp, srow);
2160 	    wp->w_botline = lnum;
2161 	}
2162 	else if (dy_flags & DY_LASTLINE)	/* 'display' has "lastline" */
2163 	{
2164 	    /*
2165 	     * Last line isn't finished: Display "@@@" at the end.
2166 	     */
2167 	    screen_fill(W_WINROW(wp) + wp->w_height - 1,
2168 		    W_WINROW(wp) + wp->w_height,
2169 		    (int)W_ENDCOL(wp) - 3, (int)W_ENDCOL(wp),
2170 		    '@', '@', hl_attr(HLF_AT));
2171 	    set_empty_rows(wp, srow);
2172 	    wp->w_botline = lnum;
2173 	}
2174 	else
2175 	{
2176 	    win_draw_end(wp, '@', ' ', srow, wp->w_height, HLF_AT);
2177 	    wp->w_botline = lnum;
2178 	}
2179     }
2180     else
2181     {
2182 #ifdef FEAT_WINDOWS
2183 	draw_vsep_win(wp, row);
2184 #endif
2185 	if (eof)		/* we hit the end of the file */
2186 	{
2187 	    wp->w_botline = buf->b_ml.ml_line_count + 1;
2188 #ifdef FEAT_DIFF
2189 	    j = diff_check_fill(wp, wp->w_botline);
2190 	    if (j > 0 && !wp->w_botfill)
2191 	    {
2192 		/*
2193 		 * Display filler lines at the end of the file
2194 		 */
2195 		if (char2cells(fill_diff) > 1)
2196 		    i = '-';
2197 		else
2198 		    i = fill_diff;
2199 		if (row + j > wp->w_height)
2200 		    j = wp->w_height - row;
2201 		win_draw_end(wp, i, i, row, row + (int)j, HLF_DED);
2202 		row += j;
2203 	    }
2204 #endif
2205 	}
2206 	else if (dollar_vcol == -1)
2207 	    wp->w_botline = lnum;
2208 
2209 	/* make sure the rest of the screen is blank */
2210 	/* put '~'s on rows that aren't part of the file. */
2211 	win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_EOB);
2212     }
2213 
2214     /* Reset the type of redrawing required, the window has been updated. */
2215     wp->w_redr_type = 0;
2216 #ifdef FEAT_DIFF
2217     wp->w_old_topfill = wp->w_topfill;
2218     wp->w_old_botfill = wp->w_botfill;
2219 #endif
2220 
2221     if (dollar_vcol == -1)
2222     {
2223 	/*
2224 	 * There is a trick with w_botline.  If we invalidate it on each
2225 	 * change that might modify it, this will cause a lot of expensive
2226 	 * calls to plines() in update_topline() each time.  Therefore the
2227 	 * value of w_botline is often approximated, and this value is used to
2228 	 * compute the value of w_topline.  If the value of w_botline was
2229 	 * wrong, check that the value of w_topline is correct (cursor is on
2230 	 * the visible part of the text).  If it's not, we need to redraw
2231 	 * again.  Mostly this just means scrolling up a few lines, so it
2232 	 * doesn't look too bad.  Only do this for the current window (where
2233 	 * changes are relevant).
2234 	 */
2235 	wp->w_valid |= VALID_BOTLINE;
2236 	if (wp == curwin && wp->w_botline != old_botline && !recursive)
2237 	{
2238 	    recursive = TRUE;
2239 	    curwin->w_valid &= ~VALID_TOPLINE;
2240 	    update_topline();	/* may invalidate w_botline again */
2241 	    if (must_redraw != 0)
2242 	    {
2243 		/* Don't update for changes in buffer again. */
2244 		i = curbuf->b_mod_set;
2245 		curbuf->b_mod_set = FALSE;
2246 		win_update(curwin);
2247 		must_redraw = 0;
2248 		curbuf->b_mod_set = i;
2249 	    }
2250 	    recursive = FALSE;
2251 	}
2252     }
2253 
2254 #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
2255     /* restore got_int, unless CTRL-C was hit while redrawing */
2256     if (!got_int)
2257 	got_int = save_got_int;
2258 #endif
2259 }
2260 
2261 /*
2262  * Clear the rest of the window and mark the unused lines with "c1".  use "c2"
2263  * as the filler character.
2264  */
2265     static void
2266 win_draw_end(
2267     win_T	*wp,
2268     int		c1,
2269     int		c2,
2270     int		row,
2271     int		endrow,
2272     hlf_T	hl)
2273 {
2274 #if defined(FEAT_FOLDING) || defined(FEAT_SIGNS) || defined(FEAT_CMDWIN)
2275     int		n = 0;
2276 # define FDC_OFF n
2277 #else
2278 # define FDC_OFF 0
2279 #endif
2280 #ifdef FEAT_FOLDING
2281     int		fdc = compute_foldcolumn(wp, 0);
2282 #endif
2283 
2284 #ifdef FEAT_RIGHTLEFT
2285     if (wp->w_p_rl)
2286     {
2287 	/* No check for cmdline window: should never be right-left. */
2288 # ifdef FEAT_FOLDING
2289 	n = fdc;
2290 
2291 	if (n > 0)
2292 	{
2293 	    /* draw the fold column at the right */
2294 	    if (n > W_WIDTH(wp))
2295 		n = W_WIDTH(wp);
2296 	    screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2297 		    W_ENDCOL(wp) - n, (int)W_ENDCOL(wp),
2298 		    ' ', ' ', hl_attr(HLF_FC));
2299 	}
2300 # endif
2301 # ifdef FEAT_SIGNS
2302 	if (signcolumn_on(wp))
2303 	{
2304 	    int nn = n + 2;
2305 
2306 	    /* draw the sign column left of the fold column */
2307 	    if (nn > W_WIDTH(wp))
2308 		nn = W_WIDTH(wp);
2309 	    screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2310 		    W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
2311 		    ' ', ' ', hl_attr(HLF_SC));
2312 	    n = nn;
2313 	}
2314 # endif
2315 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2316 		W_WINCOL(wp), W_ENDCOL(wp) - 1 - FDC_OFF,
2317 		c2, c2, hl_attr(hl));
2318 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2319 		W_ENDCOL(wp) - 1 - FDC_OFF, W_ENDCOL(wp) - FDC_OFF,
2320 		c1, c2, hl_attr(hl));
2321     }
2322     else
2323 #endif
2324     {
2325 #ifdef FEAT_CMDWIN
2326 	if (cmdwin_type != 0 && wp == curwin)
2327 	{
2328 	    /* draw the cmdline character in the leftmost column */
2329 	    n = 1;
2330 	    if (n > wp->w_width)
2331 		n = wp->w_width;
2332 	    screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2333 		    W_WINCOL(wp), (int)W_WINCOL(wp) + n,
2334 		    cmdwin_type, ' ', hl_attr(HLF_AT));
2335 	}
2336 #endif
2337 #ifdef FEAT_FOLDING
2338 	if (fdc > 0)
2339 	{
2340 	    int	    nn = n + fdc;
2341 
2342 	    /* draw the fold column at the left */
2343 	    if (nn > W_WIDTH(wp))
2344 		nn = W_WIDTH(wp);
2345 	    screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2346 		    W_WINCOL(wp) + n, (int)W_WINCOL(wp) + nn,
2347 		    ' ', ' ', hl_attr(HLF_FC));
2348 	    n = nn;
2349 	}
2350 #endif
2351 #ifdef FEAT_SIGNS
2352 	if (signcolumn_on(wp))
2353 	{
2354 	    int	    nn = n + 2;
2355 
2356 	    /* draw the sign column after the fold column */
2357 	    if (nn > W_WIDTH(wp))
2358 		nn = W_WIDTH(wp);
2359 	    screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2360 		    W_WINCOL(wp) + n, (int)W_WINCOL(wp) + nn,
2361 		    ' ', ' ', hl_attr(HLF_SC));
2362 	    n = nn;
2363 	}
2364 #endif
2365 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
2366 		W_WINCOL(wp) + FDC_OFF, (int)W_ENDCOL(wp),
2367 		c1, c2, hl_attr(hl));
2368     }
2369     set_empty_rows(wp, row);
2370 }
2371 
2372 #ifdef FEAT_SYN_HL
2373 static int advance_color_col(int vcol, int **color_cols);
2374 
2375 /*
2376  * Advance **color_cols and return TRUE when there are columns to draw.
2377  */
2378     static int
2379 advance_color_col(int vcol, int **color_cols)
2380 {
2381     while (**color_cols >= 0 && vcol > **color_cols)
2382 	++*color_cols;
2383     return (**color_cols >= 0);
2384 }
2385 #endif
2386 
2387 #ifdef FEAT_FOLDING
2388 /*
2389  * Compute the width of the foldcolumn.  Based on 'foldcolumn' and how much
2390  * space is available for window "wp", minus "col".
2391  */
2392     static int
2393 compute_foldcolumn(win_T *wp, int col)
2394 {
2395     int fdc = wp->w_p_fdc;
2396     int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
2397     int wwidth = W_WIDTH(wp);
2398 
2399     if (fdc > wwidth - (col + wmw))
2400 	fdc = wwidth - (col + wmw);
2401     return fdc;
2402 }
2403 
2404 /*
2405  * Display one folded line.
2406  */
2407     static void
2408 fold_line(
2409     win_T	*wp,
2410     long	fold_count,
2411     foldinfo_T	*foldinfo,
2412     linenr_T	lnum,
2413     int		row)
2414 {
2415     char_u	buf[FOLD_TEXT_LEN];
2416     pos_T	*top, *bot;
2417     linenr_T	lnume = lnum + fold_count - 1;
2418     int		len;
2419     char_u	*text;
2420     int		fdc;
2421     int		col;
2422     int		txtcol;
2423     int		off = (int)(current_ScreenLine - ScreenLines);
2424     int		ri;
2425 
2426     /* Build the fold line:
2427      * 1. Add the cmdwin_type for the command-line window
2428      * 2. Add the 'foldcolumn'
2429      * 3. Add the 'number' or 'relativenumber' column
2430      * 4. Compose the text
2431      * 5. Add the text
2432      * 6. set highlighting for the Visual area an other text
2433      */
2434     col = 0;
2435 
2436     /*
2437      * 1. Add the cmdwin_type for the command-line window
2438      * Ignores 'rightleft', this window is never right-left.
2439      */
2440 #ifdef FEAT_CMDWIN
2441     if (cmdwin_type != 0 && wp == curwin)
2442     {
2443 	ScreenLines[off] = cmdwin_type;
2444 	ScreenAttrs[off] = hl_attr(HLF_AT);
2445 #ifdef FEAT_MBYTE
2446 	if (enc_utf8)
2447 	    ScreenLinesUC[off] = 0;
2448 #endif
2449 	++col;
2450     }
2451 #endif
2452 
2453     /*
2454      * 2. Add the 'foldcolumn'
2455      *    Reduce the width when there is not enough space.
2456      */
2457     fdc = compute_foldcolumn(wp, col);
2458     if (fdc > 0)
2459     {
2460 	fill_foldcolumn(buf, wp, TRUE, lnum);
2461 #ifdef FEAT_RIGHTLEFT
2462 	if (wp->w_p_rl)
2463 	{
2464 	    int		i;
2465 
2466 	    copy_text_attr(off + W_WIDTH(wp) - fdc - col, buf, fdc,
2467 							     hl_attr(HLF_FC));
2468 	    /* reverse the fold column */
2469 	    for (i = 0; i < fdc; ++i)
2470 		ScreenLines[off + W_WIDTH(wp) - i - 1 - col] = buf[i];
2471 	}
2472 	else
2473 #endif
2474 	    copy_text_attr(off + col, buf, fdc, hl_attr(HLF_FC));
2475 	col += fdc;
2476     }
2477 
2478 #ifdef FEAT_RIGHTLEFT
2479 # define RL_MEMSET(p, v, l)  if (wp->w_p_rl) \
2480 				for (ri = 0; ri < l; ++ri) \
2481 				   ScreenAttrs[off + (W_WIDTH(wp) - (p) - (l)) + ri] = v; \
2482 			     else \
2483 				for (ri = 0; ri < l; ++ri) \
2484 				   ScreenAttrs[off + (p) + ri] = v
2485 #else
2486 # define RL_MEMSET(p, v, l)   for (ri = 0; ri < l; ++ri) \
2487 				 ScreenAttrs[off + (p) + ri] = v
2488 #endif
2489 
2490     /* Set all attributes of the 'number' or 'relativenumber' column and the
2491      * text */
2492     RL_MEMSET(col, hl_attr(HLF_FL), W_WIDTH(wp) - col);
2493 
2494 #ifdef FEAT_SIGNS
2495     /* If signs are being displayed, add two spaces. */
2496     if (signcolumn_on(wp))
2497     {
2498 	len = W_WIDTH(wp) - col;
2499 	if (len > 0)
2500 	{
2501 	    if (len > 2)
2502 		len = 2;
2503 # ifdef FEAT_RIGHTLEFT
2504 	    if (wp->w_p_rl)
2505 		/* the line number isn't reversed */
2506 		copy_text_attr(off + W_WIDTH(wp) - len - col,
2507 					(char_u *)"  ", len, hl_attr(HLF_FL));
2508 	    else
2509 # endif
2510 		copy_text_attr(off + col, (char_u *)"  ", len, hl_attr(HLF_FL));
2511 	    col += len;
2512 	}
2513     }
2514 #endif
2515 
2516     /*
2517      * 3. Add the 'number' or 'relativenumber' column
2518      */
2519     if (wp->w_p_nu || wp->w_p_rnu)
2520     {
2521 	len = W_WIDTH(wp) - col;
2522 	if (len > 0)
2523 	{
2524 	    int	    w = number_width(wp);
2525 	    long    num;
2526 	    char    *fmt = "%*ld ";
2527 
2528 	    if (len > w + 1)
2529 		len = w + 1;
2530 
2531 	    if (wp->w_p_nu && !wp->w_p_rnu)
2532 		/* 'number' + 'norelativenumber' */
2533 		num = (long)lnum;
2534 	    else
2535 	    {
2536 		/* 'relativenumber', don't use negative numbers */
2537 		num = labs((long)get_cursor_rel_lnum(wp, lnum));
2538 		if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
2539 		{
2540 		    /* 'number' + 'relativenumber': cursor line shows absolute
2541 		     * line number */
2542 		    num = lnum;
2543 		    fmt = "%-*ld ";
2544 		}
2545 	    }
2546 
2547 	    sprintf((char *)buf, fmt, w, num);
2548 #ifdef FEAT_RIGHTLEFT
2549 	    if (wp->w_p_rl)
2550 		/* the line number isn't reversed */
2551 		copy_text_attr(off + W_WIDTH(wp) - len - col, buf, len,
2552 							     hl_attr(HLF_FL));
2553 	    else
2554 #endif
2555 		copy_text_attr(off + col, buf, len, hl_attr(HLF_FL));
2556 	    col += len;
2557 	}
2558     }
2559 
2560     /*
2561      * 4. Compose the folded-line string with 'foldtext', if set.
2562      */
2563     text = get_foldtext(wp, lnum, lnume, foldinfo, buf);
2564 
2565     txtcol = col;	/* remember where text starts */
2566 
2567     /*
2568      * 5. move the text to current_ScreenLine.  Fill up with "fill_fold".
2569      *    Right-left text is put in columns 0 - number-col, normal text is put
2570      *    in columns number-col - window-width.
2571      */
2572 #ifdef FEAT_MBYTE
2573     if (has_mbyte)
2574     {
2575 	int	cells;
2576 	int	u8c, u8cc[MAX_MCO];
2577 	int	i;
2578 	int	idx;
2579 	int	c_len;
2580 	char_u	*p;
2581 # ifdef FEAT_ARABIC
2582 	int	prev_c = 0;		/* previous Arabic character */
2583 	int	prev_c1 = 0;		/* first composing char for prev_c */
2584 # endif
2585 
2586 # ifdef FEAT_RIGHTLEFT
2587 	if (wp->w_p_rl)
2588 	    idx = off;
2589 	else
2590 # endif
2591 	    idx = off + col;
2592 
2593 	/* Store multibyte characters in ScreenLines[] et al. correctly. */
2594 	for (p = text; *p != NUL; )
2595 	{
2596 	    cells = (*mb_ptr2cells)(p);
2597 	    c_len = (*mb_ptr2len)(p);
2598 	    if (col + cells > W_WIDTH(wp)
2599 # ifdef FEAT_RIGHTLEFT
2600 		    - (wp->w_p_rl ? col : 0)
2601 # endif
2602 		    )
2603 		break;
2604 	    ScreenLines[idx] = *p;
2605 	    if (enc_utf8)
2606 	    {
2607 		u8c = utfc_ptr2char(p, u8cc);
2608 		if (*p < 0x80 && u8cc[0] == 0)
2609 		{
2610 		    ScreenLinesUC[idx] = 0;
2611 #ifdef FEAT_ARABIC
2612 		    prev_c = u8c;
2613 #endif
2614 		}
2615 		else
2616 		{
2617 #ifdef FEAT_ARABIC
2618 		    if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
2619 		    {
2620 			/* Do Arabic shaping. */
2621 			int	pc, pc1, nc;
2622 			int	pcc[MAX_MCO];
2623 			int	firstbyte = *p;
2624 
2625 			/* The idea of what is the previous and next
2626 			 * character depends on 'rightleft'. */
2627 			if (wp->w_p_rl)
2628 			{
2629 			    pc = prev_c;
2630 			    pc1 = prev_c1;
2631 			    nc = utf_ptr2char(p + c_len);
2632 			    prev_c1 = u8cc[0];
2633 			}
2634 			else
2635 			{
2636 			    pc = utfc_ptr2char(p + c_len, pcc);
2637 			    nc = prev_c;
2638 			    pc1 = pcc[0];
2639 			}
2640 			prev_c = u8c;
2641 
2642 			u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
2643 								 pc, pc1, nc);
2644 			ScreenLines[idx] = firstbyte;
2645 		    }
2646 		    else
2647 			prev_c = u8c;
2648 #endif
2649 		    /* Non-BMP character: display as ? or fullwidth ?. */
2650 #ifdef UNICODE16
2651 		    if (u8c >= 0x10000)
2652 			ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?';
2653 		    else
2654 #endif
2655 			ScreenLinesUC[idx] = u8c;
2656 		    for (i = 0; i < Screen_mco; ++i)
2657 		    {
2658 			ScreenLinesC[i][idx] = u8cc[i];
2659 			if (u8cc[i] == 0)
2660 			    break;
2661 		    }
2662 		}
2663 		if (cells > 1)
2664 		    ScreenLines[idx + 1] = 0;
2665 	    }
2666 	    else if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
2667 		/* double-byte single width character */
2668 		ScreenLines2[idx] = p[1];
2669 	    else if (cells > 1)
2670 		/* double-width character */
2671 		ScreenLines[idx + 1] = p[1];
2672 	    col += cells;
2673 	    idx += cells;
2674 	    p += c_len;
2675 	}
2676     }
2677     else
2678 #endif
2679     {
2680 	len = (int)STRLEN(text);
2681 	if (len > W_WIDTH(wp) - col)
2682 	    len = W_WIDTH(wp) - col;
2683 	if (len > 0)
2684 	{
2685 #ifdef FEAT_RIGHTLEFT
2686 	    if (wp->w_p_rl)
2687 		STRNCPY(current_ScreenLine, text, len);
2688 	    else
2689 #endif
2690 		STRNCPY(current_ScreenLine + col, text, len);
2691 	    col += len;
2692 	}
2693     }
2694 
2695     /* Fill the rest of the line with the fold filler */
2696 #ifdef FEAT_RIGHTLEFT
2697     if (wp->w_p_rl)
2698 	col -= txtcol;
2699 #endif
2700     while (col < W_WIDTH(wp)
2701 #ifdef FEAT_RIGHTLEFT
2702 		    - (wp->w_p_rl ? txtcol : 0)
2703 #endif
2704 	    )
2705     {
2706 #ifdef FEAT_MBYTE
2707 	if (enc_utf8)
2708 	{
2709 	    if (fill_fold >= 0x80)
2710 	    {
2711 		ScreenLinesUC[off + col] = fill_fold;
2712 		ScreenLinesC[0][off + col] = 0;
2713 	    }
2714 	    else
2715 		ScreenLinesUC[off + col] = 0;
2716 	}
2717 #endif
2718 	ScreenLines[off + col++] = fill_fold;
2719     }
2720 
2721     if (text != buf)
2722 	vim_free(text);
2723 
2724     /*
2725      * 6. set highlighting for the Visual area an other text.
2726      * If all folded lines are in the Visual area, highlight the line.
2727      */
2728     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
2729     {
2730 	if (ltoreq(curwin->w_cursor, VIsual))
2731 	{
2732 	    /* Visual is after curwin->w_cursor */
2733 	    top = &curwin->w_cursor;
2734 	    bot = &VIsual;
2735 	}
2736 	else
2737 	{
2738 	    /* Visual is before curwin->w_cursor */
2739 	    top = &VIsual;
2740 	    bot = &curwin->w_cursor;
2741 	}
2742 	if (lnum >= top->lnum
2743 		&& lnume <= bot->lnum
2744 		&& (VIsual_mode != 'v'
2745 		    || ((lnum > top->lnum
2746 			    || (lnum == top->lnum
2747 				&& top->col == 0))
2748 			&& (lnume < bot->lnum
2749 			    || (lnume == bot->lnum
2750 				&& (bot->col - (*p_sel == 'e'))
2751 		>= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
2752 	{
2753 	    if (VIsual_mode == Ctrl_V)
2754 	    {
2755 		/* Visual block mode: highlight the chars part of the block */
2756 		if (wp->w_old_cursor_fcol + txtcol < (colnr_T)W_WIDTH(wp))
2757 		{
2758 		    if (wp->w_old_cursor_lcol != MAXCOL
2759 			     && wp->w_old_cursor_lcol + txtcol
2760 						       < (colnr_T)W_WIDTH(wp))
2761 			len = wp->w_old_cursor_lcol;
2762 		    else
2763 			len = W_WIDTH(wp) - txtcol;
2764 		    RL_MEMSET(wp->w_old_cursor_fcol + txtcol, hl_attr(HLF_V),
2765 					    len - (int)wp->w_old_cursor_fcol);
2766 		}
2767 	    }
2768 	    else
2769 	    {
2770 		/* Set all attributes of the text */
2771 		RL_MEMSET(txtcol, hl_attr(HLF_V), W_WIDTH(wp) - txtcol);
2772 	    }
2773 	}
2774     }
2775 
2776 #ifdef FEAT_SYN_HL
2777     /* Show colorcolumn in the fold line, but let cursorcolumn override it. */
2778     if (wp->w_p_cc_cols)
2779     {
2780 	int i = 0;
2781 	int j = wp->w_p_cc_cols[i];
2782 	int old_txtcol = txtcol;
2783 
2784 	while (j > -1)
2785 	{
2786 	    txtcol += j;
2787 	    if (wp->w_p_wrap)
2788 		txtcol -= wp->w_skipcol;
2789 	    else
2790 		txtcol -= wp->w_leftcol;
2791 	    if (txtcol >= 0 && txtcol < W_WIDTH(wp))
2792 		ScreenAttrs[off + txtcol] = hl_combine_attr(
2793 				    ScreenAttrs[off + txtcol], hl_attr(HLF_MC));
2794 	    txtcol = old_txtcol;
2795 	    j = wp->w_p_cc_cols[++i];
2796 	}
2797     }
2798 
2799     /* Show 'cursorcolumn' in the fold line. */
2800     if (wp->w_p_cuc)
2801     {
2802 	txtcol += wp->w_virtcol;
2803 	if (wp->w_p_wrap)
2804 	    txtcol -= wp->w_skipcol;
2805 	else
2806 	    txtcol -= wp->w_leftcol;
2807 	if (txtcol >= 0 && txtcol < W_WIDTH(wp))
2808 	    ScreenAttrs[off + txtcol] = hl_combine_attr(
2809 				 ScreenAttrs[off + txtcol], hl_attr(HLF_CUC));
2810     }
2811 #endif
2812 
2813     SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
2814 						     (int)W_WIDTH(wp), FALSE);
2815 
2816     /*
2817      * Update w_cline_height and w_cline_folded if the cursor line was
2818      * updated (saves a call to plines() later).
2819      */
2820     if (wp == curwin
2821 	    && lnum <= curwin->w_cursor.lnum
2822 	    && lnume >= curwin->w_cursor.lnum)
2823     {
2824 	curwin->w_cline_row = row;
2825 	curwin->w_cline_height = 1;
2826 	curwin->w_cline_folded = TRUE;
2827 	curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
2828     }
2829 }
2830 
2831 /*
2832  * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
2833  */
2834     static void
2835 copy_text_attr(
2836     int		off,
2837     char_u	*buf,
2838     int		len,
2839     int		attr)
2840 {
2841     int		i;
2842 
2843     mch_memmove(ScreenLines + off, buf, (size_t)len);
2844 # ifdef FEAT_MBYTE
2845     if (enc_utf8)
2846 	vim_memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
2847 # endif
2848     for (i = 0; i < len; ++i)
2849 	ScreenAttrs[off + i] = attr;
2850 }
2851 
2852 /*
2853  * Fill the foldcolumn at "p" for window "wp".
2854  * Only to be called when 'foldcolumn' > 0.
2855  */
2856     static void
2857 fill_foldcolumn(
2858     char_u	*p,
2859     win_T	*wp,
2860     int		closed,		/* TRUE of FALSE */
2861     linenr_T	lnum)		/* current line number */
2862 {
2863     int		i = 0;
2864     int		level;
2865     int		first_level;
2866     int		empty;
2867     int		fdc = compute_foldcolumn(wp, 0);
2868 
2869     /* Init to all spaces. */
2870     vim_memset(p, ' ', (size_t)fdc);
2871 
2872     level = win_foldinfo.fi_level;
2873     if (level > 0)
2874     {
2875 	/* If there is only one column put more info in it. */
2876 	empty = (fdc == 1) ? 0 : 1;
2877 
2878 	/* If the column is too narrow, we start at the lowest level that
2879 	 * fits and use numbers to indicated the depth. */
2880 	first_level = level - fdc - closed + 1 + empty;
2881 	if (first_level < 1)
2882 	    first_level = 1;
2883 
2884 	for (i = 0; i + empty < fdc; ++i)
2885 	{
2886 	    if (win_foldinfo.fi_lnum == lnum
2887 			      && first_level + i >= win_foldinfo.fi_low_level)
2888 		p[i] = '-';
2889 	    else if (first_level == 1)
2890 		p[i] = '|';
2891 	    else if (first_level + i <= 9)
2892 		p[i] = '0' + first_level + i;
2893 	    else
2894 		p[i] = '>';
2895 	    if (first_level + i == level)
2896 		break;
2897 	}
2898     }
2899     if (closed)
2900 	p[i >= fdc ? i - 1 : i] = '+';
2901 }
2902 #endif /* FEAT_FOLDING */
2903 
2904 /*
2905  * Display line "lnum" of window 'wp' on the screen.
2906  * Start at row "startrow", stop when "endrow" is reached.
2907  * wp->w_virtcol needs to be valid.
2908  *
2909  * Return the number of last row the line occupies.
2910  */
2911     static int
2912 win_line(
2913     win_T	*wp,
2914     linenr_T	lnum,
2915     int		startrow,
2916     int		endrow,
2917     int		nochange UNUSED)	/* not updating for changed text */
2918 {
2919     int		col;			/* visual column on screen */
2920     unsigned	off;			/* offset in ScreenLines/ScreenAttrs */
2921     int		c = 0;			/* init for GCC */
2922     long	vcol = 0;		/* virtual column (for tabs) */
2923 #ifdef FEAT_LINEBREAK
2924     long	vcol_sbr = -1;		/* virtual column after showbreak */
2925 #endif
2926     long	vcol_prev = -1;		/* "vcol" of previous character */
2927     char_u	*line;			/* current line */
2928     char_u	*ptr;			/* current position in "line" */
2929     int		row;			/* row in the window, excl w_winrow */
2930     int		screen_row;		/* row on the screen, incl w_winrow */
2931 
2932     char_u	extra[18];		/* "%ld" and 'fdc' must fit in here */
2933     int		n_extra = 0;		/* number of extra chars */
2934     char_u	*p_extra = NULL;	/* string of extra chars, plus NUL */
2935     char_u	*p_extra_free = NULL;   /* p_extra needs to be freed */
2936     int		c_extra = NUL;		/* extra chars, all the same */
2937     int		extra_attr = 0;		/* attributes when n_extra != 0 */
2938     static char_u *at_end_str = (char_u *)""; /* used for p_extra when
2939 					   displaying lcs_eol at end-of-line */
2940     int		lcs_eol_one = lcs_eol;	/* lcs_eol until it's been used */
2941     int		lcs_prec_todo = lcs_prec;   /* lcs_prec until it's been used */
2942 
2943     /* saved "extra" items for when draw_state becomes WL_LINE (again) */
2944     int		saved_n_extra = 0;
2945     char_u	*saved_p_extra = NULL;
2946     int		saved_c_extra = 0;
2947     int		saved_char_attr = 0;
2948 
2949     int		n_attr = 0;		/* chars with special attr */
2950     int		saved_attr2 = 0;	/* char_attr saved for n_attr */
2951     int		n_attr3 = 0;		/* chars with overruling special attr */
2952     int		saved_attr3 = 0;	/* char_attr saved for n_attr3 */
2953 
2954     int		n_skip = 0;		/* nr of chars to skip for 'nowrap' */
2955 
2956     int		fromcol, tocol;		/* start/end of inverting */
2957     int		fromcol_prev = -2;	/* start of inverting after cursor */
2958     int		noinvcur = FALSE;	/* don't invert the cursor */
2959     pos_T	*top, *bot;
2960     int		lnum_in_visual_area = FALSE;
2961     pos_T	pos;
2962     long	v;
2963 
2964     int		char_attr = 0;		/* attributes for next character */
2965     int		attr_pri = FALSE;	/* char_attr has priority */
2966     int		area_highlighting = FALSE; /* Visual or incsearch highlighting
2967 					      in this line */
2968     int		attr = 0;		/* attributes for area highlighting */
2969     int		area_attr = 0;		/* attributes desired by highlighting */
2970     int		search_attr = 0;	/* attributes desired by 'hlsearch' */
2971 #ifdef FEAT_SYN_HL
2972     int		vcol_save_attr = 0;	/* saved attr for 'cursorcolumn' */
2973     int		syntax_attr = 0;	/* attributes desired by syntax */
2974     int		has_syntax = FALSE;	/* this buffer has syntax highl. */
2975     int		save_did_emsg;
2976     int		eol_hl_off = 0;		/* 1 if highlighted char after EOL */
2977     int		draw_color_col = FALSE;	/* highlight colorcolumn */
2978     int		*color_cols = NULL;	/* pointer to according columns array */
2979 #endif
2980 #ifdef FEAT_SPELL
2981     int		has_spell = FALSE;	/* this buffer has spell checking */
2982 # define SPWORDLEN 150
2983     char_u	nextline[SPWORDLEN * 2];/* text with start of the next line */
2984     int		nextlinecol = 0;	/* column where nextline[] starts */
2985     int		nextline_idx = 0;	/* index in nextline[] where next line
2986 					   starts */
2987     int		spell_attr = 0;		/* attributes desired by spelling */
2988     int		word_end = 0;		/* last byte with same spell_attr */
2989     static linenr_T  checked_lnum = 0;	/* line number for "checked_col" */
2990     static int	checked_col = 0;	/* column in "checked_lnum" up to which
2991 					 * there are no spell errors */
2992     static int	cap_col = -1;		/* column to check for Cap word */
2993     static linenr_T capcol_lnum = 0;	/* line number where "cap_col" used */
2994     int		cur_checked_col = 0;	/* checked column for current line */
2995 #endif
2996     int		extra_check;		/* has syntax or linebreak */
2997 #ifdef FEAT_MBYTE
2998     int		multi_attr = 0;		/* attributes desired by multibyte */
2999     int		mb_l = 1;		/* multi-byte byte length */
3000     int		mb_c = 0;		/* decoded multi-byte character */
3001     int		mb_utf8 = FALSE;	/* screen char is UTF-8 char */
3002     int		u8cc[MAX_MCO];		/* composing UTF-8 chars */
3003 #endif
3004 #ifdef FEAT_DIFF
3005     int		filler_lines;		/* nr of filler lines to be drawn */
3006     int		filler_todo;		/* nr of filler lines still to do + 1 */
3007     hlf_T	diff_hlf = (hlf_T)0;	/* type of diff highlighting */
3008     int		change_start = MAXCOL;	/* first col of changed area */
3009     int		change_end = -1;	/* last col of changed area */
3010 #endif
3011     colnr_T	trailcol = MAXCOL;	/* start of trailing spaces */
3012 #ifdef FEAT_LINEBREAK
3013     int		need_showbreak = FALSE; /* overlong line, skipping first x
3014 					   chars */
3015 #endif
3016 #if defined(FEAT_SIGNS) || (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
3017 	|| defined(FEAT_SYN_HL) || defined(FEAT_DIFF)
3018 # define LINE_ATTR
3019     int		line_attr = 0;		/* attribute for the whole line */
3020 #endif
3021 #ifdef FEAT_SEARCH_EXTRA
3022     matchitem_T *cur;			/* points to the match list */
3023     match_T	*shl;			/* points to search_hl or a match */
3024     int		shl_flag;		/* flag to indicate whether search_hl
3025 					   has been processed or not */
3026     int		pos_inprogress;		/* marks that position match search is
3027 					   in progress */
3028     int		prevcol_hl_flag;	/* flag to indicate whether prevcol
3029 					   equals startcol of search_hl or one
3030 					   of the matches */
3031 #endif
3032 #ifdef FEAT_ARABIC
3033     int		prev_c = 0;		/* previous Arabic character */
3034     int		prev_c1 = 0;		/* first composing char for prev_c */
3035 #endif
3036 #if defined(LINE_ATTR)
3037     int		did_line_attr = 0;
3038 #endif
3039 
3040     /* draw_state: items that are drawn in sequence: */
3041 #define WL_START	0		/* nothing done yet */
3042 #ifdef FEAT_CMDWIN
3043 # define WL_CMDLINE	WL_START + 1	/* cmdline window column */
3044 #else
3045 # define WL_CMDLINE	WL_START
3046 #endif
3047 #ifdef FEAT_FOLDING
3048 # define WL_FOLD	WL_CMDLINE + 1	/* 'foldcolumn' */
3049 #else
3050 # define WL_FOLD	WL_CMDLINE
3051 #endif
3052 #ifdef FEAT_SIGNS
3053 # define WL_SIGN	WL_FOLD + 1	/* column for signs */
3054 #else
3055 # define WL_SIGN	WL_FOLD		/* column for signs */
3056 #endif
3057 #define WL_NR		WL_SIGN + 1	/* line number */
3058 #ifdef FEAT_LINEBREAK
3059 # define WL_BRI		WL_NR + 1	/* 'breakindent' */
3060 #else
3061 # define WL_BRI		WL_NR
3062 #endif
3063 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3064 # define WL_SBR		WL_BRI + 1	/* 'showbreak' or 'diff' */
3065 #else
3066 # define WL_SBR		WL_BRI
3067 #endif
3068 #define WL_LINE		WL_SBR + 1	/* text in the line */
3069     int		draw_state = WL_START;	/* what to draw next */
3070 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
3071     int		feedback_col = 0;
3072     int		feedback_old_attr = -1;
3073 #endif
3074 
3075 #ifdef FEAT_CONCEAL
3076     int		syntax_flags	= 0;
3077     int		syntax_seqnr	= 0;
3078     int		prev_syntax_id	= 0;
3079     int		conceal_attr	= hl_attr(HLF_CONCEAL);
3080     int		is_concealing	= FALSE;
3081     int		boguscols	= 0;	/* nonexistent columns added to force
3082 					   wrapping */
3083     int		vcol_off	= 0;	/* offset for concealed characters */
3084     int		did_wcol	= FALSE;
3085     int		match_conc	= 0;	/* cchar for match functions */
3086     int		has_match_conc  = 0;	/* match wants to conceal */
3087     int		old_boguscols   = 0;
3088 # define VCOL_HLC (vcol - vcol_off)
3089 # define FIX_FOR_BOGUSCOLS \
3090     { \
3091 	n_extra += vcol_off; \
3092 	vcol -= vcol_off; \
3093 	vcol_off = 0; \
3094 	col -= boguscols; \
3095 	old_boguscols = boguscols; \
3096 	boguscols = 0; \
3097     }
3098 #else
3099 # define VCOL_HLC (vcol)
3100 #endif
3101 
3102     if (startrow > endrow)		/* past the end already! */
3103 	return startrow;
3104 
3105     row = startrow;
3106     screen_row = row + W_WINROW(wp);
3107 
3108     /*
3109      * To speed up the loop below, set extra_check when there is linebreak,
3110      * trailing white space and/or syntax processing to be done.
3111      */
3112 #ifdef FEAT_LINEBREAK
3113     extra_check = wp->w_p_lbr;
3114 #else
3115     extra_check = 0;
3116 #endif
3117 #ifdef FEAT_SYN_HL
3118     if (syntax_present(wp) && !wp->w_s->b_syn_error)
3119     {
3120 	/* Prepare for syntax highlighting in this line.  When there is an
3121 	 * error, stop syntax highlighting. */
3122 	save_did_emsg = did_emsg;
3123 	did_emsg = FALSE;
3124 	syntax_start(wp, lnum);
3125 	if (did_emsg)
3126 	    wp->w_s->b_syn_error = TRUE;
3127 	else
3128 	{
3129 	    did_emsg = save_did_emsg;
3130 	    has_syntax = TRUE;
3131 	    extra_check = TRUE;
3132 	}
3133     }
3134 
3135     /* Check for columns to display for 'colorcolumn'. */
3136     color_cols = wp->w_p_cc_cols;
3137     if (color_cols != NULL)
3138 	draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
3139 #endif
3140 
3141 #ifdef FEAT_SPELL
3142     if (wp->w_p_spell
3143 	    && *wp->w_s->b_p_spl != NUL
3144 	    && wp->w_s->b_langp.ga_len > 0
3145 	    && *(char **)(wp->w_s->b_langp.ga_data) != NULL)
3146     {
3147 	/* Prepare for spell checking. */
3148 	has_spell = TRUE;
3149 	extra_check = TRUE;
3150 
3151 	/* Get the start of the next line, so that words that wrap to the next
3152 	 * line are found too: "et<line-break>al.".
3153 	 * Trick: skip a few chars for C/shell/Vim comments */
3154 	nextline[SPWORDLEN] = NUL;
3155 	if (lnum < wp->w_buffer->b_ml.ml_line_count)
3156 	{
3157 	    line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE);
3158 	    spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN);
3159 	}
3160 
3161 	/* When a word wrapped from the previous line the start of the current
3162 	 * line is valid. */
3163 	if (lnum == checked_lnum)
3164 	    cur_checked_col = checked_col;
3165 	checked_lnum = 0;
3166 
3167 	/* When there was a sentence end in the previous line may require a
3168 	 * word starting with capital in this line.  In line 1 always check
3169 	 * the first word. */
3170 	if (lnum != capcol_lnum)
3171 	    cap_col = -1;
3172 	if (lnum == 1)
3173 	    cap_col = 0;
3174 	capcol_lnum = 0;
3175     }
3176 #endif
3177 
3178     /*
3179      * handle visual active in this window
3180      */
3181     fromcol = -10;
3182     tocol = MAXCOL;
3183     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
3184     {
3185 					/* Visual is after curwin->w_cursor */
3186 	if (ltoreq(curwin->w_cursor, VIsual))
3187 	{
3188 	    top = &curwin->w_cursor;
3189 	    bot = &VIsual;
3190 	}
3191 	else				/* Visual is before curwin->w_cursor */
3192 	{
3193 	    top = &VIsual;
3194 	    bot = &curwin->w_cursor;
3195 	}
3196 	lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
3197 	if (VIsual_mode == Ctrl_V)	/* block mode */
3198 	{
3199 	    if (lnum_in_visual_area)
3200 	    {
3201 		fromcol = wp->w_old_cursor_fcol;
3202 		tocol = wp->w_old_cursor_lcol;
3203 	    }
3204 	}
3205 	else				/* non-block mode */
3206 	{
3207 	    if (lnum > top->lnum && lnum <= bot->lnum)
3208 		fromcol = 0;
3209 	    else if (lnum == top->lnum)
3210 	    {
3211 		if (VIsual_mode == 'V')	/* linewise */
3212 		    fromcol = 0;
3213 		else
3214 		{
3215 		    getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL);
3216 		    if (gchar_pos(top) == NUL)
3217 			tocol = fromcol + 1;
3218 		}
3219 	    }
3220 	    if (VIsual_mode != 'V' && lnum == bot->lnum)
3221 	    {
3222 		if (*p_sel == 'e' && bot->col == 0
3223 #ifdef FEAT_VIRTUALEDIT
3224 			&& bot->coladd == 0
3225 #endif
3226 		   )
3227 		{
3228 		    fromcol = -10;
3229 		    tocol = MAXCOL;
3230 		}
3231 		else if (bot->col == MAXCOL)
3232 		    tocol = MAXCOL;
3233 		else
3234 		{
3235 		    pos = *bot;
3236 		    if (*p_sel == 'e')
3237 			getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL);
3238 		    else
3239 		    {
3240 			getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol);
3241 			++tocol;
3242 		    }
3243 		}
3244 	    }
3245 	}
3246 
3247 	/* Check if the character under the cursor should not be inverted */
3248 	if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
3249 #ifdef FEAT_GUI
3250 		&& !gui.in_use
3251 #endif
3252 		)
3253 	    noinvcur = TRUE;
3254 
3255 	/* if inverting in this line set area_highlighting */
3256 	if (fromcol >= 0)
3257 	{
3258 	    area_highlighting = TRUE;
3259 	    attr = hl_attr(HLF_V);
3260 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3261 	    if ((clip_star.available && !clip_star.owned
3262 						     && clip_isautosel_star())
3263 		    || (clip_plus.available && !clip_plus.owned
3264 						    && clip_isautosel_plus()))
3265 		attr = hl_attr(HLF_VNC);
3266 #endif
3267 	}
3268     }
3269 
3270     /*
3271      * handle 'incsearch' and ":s///c" highlighting
3272      */
3273     else if (highlight_match
3274 	    && wp == curwin
3275 	    && lnum >= curwin->w_cursor.lnum
3276 	    && lnum <= curwin->w_cursor.lnum + search_match_lines)
3277     {
3278 	if (lnum == curwin->w_cursor.lnum)
3279 	    getvcol(curwin, &(curwin->w_cursor),
3280 					     (colnr_T *)&fromcol, NULL, NULL);
3281 	else
3282 	    fromcol = 0;
3283 	if (lnum == curwin->w_cursor.lnum + search_match_lines)
3284 	{
3285 	    pos.lnum = lnum;
3286 	    pos.col = search_match_endcol;
3287 	    getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
3288 	}
3289 	else
3290 	    tocol = MAXCOL;
3291 	/* do at least one character; happens when past end of line */
3292 	if (fromcol == tocol)
3293 	    tocol = fromcol + 1;
3294 	area_highlighting = TRUE;
3295 	attr = hl_attr(HLF_I);
3296     }
3297 
3298 #ifdef FEAT_DIFF
3299     filler_lines = diff_check(wp, lnum);
3300     if (filler_lines < 0)
3301     {
3302 	if (filler_lines == -1)
3303 	{
3304 	    if (diff_find_change(wp, lnum, &change_start, &change_end))
3305 		diff_hlf = HLF_ADD;	/* added line */
3306 	    else if (change_start == 0)
3307 		diff_hlf = HLF_TXD;	/* changed text */
3308 	    else
3309 		diff_hlf = HLF_CHD;	/* changed line */
3310 	}
3311 	else
3312 	    diff_hlf = HLF_ADD;		/* added line */
3313 	filler_lines = 0;
3314 	area_highlighting = TRUE;
3315     }
3316     if (lnum == wp->w_topline)
3317 	filler_lines = wp->w_topfill;
3318     filler_todo = filler_lines;
3319 #endif
3320 
3321 #ifdef LINE_ATTR
3322 # ifdef FEAT_SIGNS
3323     /* If this line has a sign with line highlighting set line_attr. */
3324     v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
3325     if (v != 0)
3326 	line_attr = sign_get_attr((int)v, TRUE);
3327 # endif
3328 # if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
3329     /* Highlight the current line in the quickfix window. */
3330     if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
3331 	line_attr = hl_attr(HLF_L);
3332 # endif
3333     if (line_attr != 0)
3334 	area_highlighting = TRUE;
3335 #endif
3336 
3337     line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3338     ptr = line;
3339 
3340 #ifdef FEAT_SPELL
3341     if (has_spell)
3342     {
3343 	/* For checking first word with a capital skip white space. */
3344 	if (cap_col == 0)
3345 	    cap_col = (int)(skipwhite(line) - line);
3346 
3347 	/* To be able to spell-check over line boundaries copy the end of the
3348 	 * current line into nextline[].  Above the start of the next line was
3349 	 * copied to nextline[SPWORDLEN]. */
3350 	if (nextline[SPWORDLEN] == NUL)
3351 	{
3352 	    /* No next line or it is empty. */
3353 	    nextlinecol = MAXCOL;
3354 	    nextline_idx = 0;
3355 	}
3356 	else
3357 	{
3358 	    v = (long)STRLEN(line);
3359 	    if (v < SPWORDLEN)
3360 	    {
3361 		/* Short line, use it completely and append the start of the
3362 		 * next line. */
3363 		nextlinecol = 0;
3364 		mch_memmove(nextline, line, (size_t)v);
3365 		STRMOVE(nextline + v, nextline + SPWORDLEN);
3366 		nextline_idx = v + 1;
3367 	    }
3368 	    else
3369 	    {
3370 		/* Long line, use only the last SPWORDLEN bytes. */
3371 		nextlinecol = v - SPWORDLEN;
3372 		mch_memmove(nextline, line + nextlinecol, SPWORDLEN);
3373 		nextline_idx = SPWORDLEN + 1;
3374 	    }
3375 	}
3376     }
3377 #endif
3378 
3379     if (wp->w_p_list)
3380     {
3381 	if (lcs_space || lcs_trail)
3382 	    extra_check = TRUE;
3383 	/* find start of trailing whitespace */
3384 	if (lcs_trail)
3385 	{
3386 	    trailcol = (colnr_T)STRLEN(ptr);
3387 	    while (trailcol > (colnr_T)0 && vim_iswhite(ptr[trailcol - 1]))
3388 		--trailcol;
3389 	    trailcol += (colnr_T) (ptr - line);
3390 	}
3391     }
3392 
3393     /*
3394      * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
3395      * first character to be displayed.
3396      */
3397     if (wp->w_p_wrap)
3398 	v = wp->w_skipcol;
3399     else
3400 	v = wp->w_leftcol;
3401     if (v > 0)
3402     {
3403 #ifdef FEAT_MBYTE
3404 	char_u	*prev_ptr = ptr;
3405 #endif
3406 	while (vcol < v && *ptr != NUL)
3407 	{
3408 	    c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
3409 	    vcol += c;
3410 #ifdef FEAT_MBYTE
3411 	    prev_ptr = ptr;
3412 #endif
3413 	    mb_ptr_adv(ptr);
3414 	}
3415 
3416 	/* When:
3417 	 * - 'cuc' is set, or
3418 	 * - 'colorcolumn' is set, or
3419 	 * - 'virtualedit' is set, or
3420 	 * - the visual mode is active,
3421 	 * the end of the line may be before the start of the displayed part.
3422 	 */
3423 	if (vcol < v && (
3424 #ifdef FEAT_SYN_HL
3425 	     wp->w_p_cuc || draw_color_col ||
3426 #endif
3427 #ifdef FEAT_VIRTUALEDIT
3428 	     virtual_active() ||
3429 #endif
3430 	     (VIsual_active && wp->w_buffer == curwin->w_buffer)))
3431 	{
3432 	    vcol = v;
3433 	}
3434 
3435 	/* Handle a character that's not completely on the screen: Put ptr at
3436 	 * that character but skip the first few screen characters. */
3437 	if (vcol > v)
3438 	{
3439 	    vcol -= c;
3440 #ifdef FEAT_MBYTE
3441 	    ptr = prev_ptr;
3442 #else
3443 	    --ptr;
3444 #endif
3445 	    n_skip = v - vcol;
3446 	}
3447 
3448 	/*
3449 	 * Adjust for when the inverted text is before the screen,
3450 	 * and when the start of the inverted text is before the screen.
3451 	 */
3452 	if (tocol <= vcol)
3453 	    fromcol = 0;
3454 	else if (fromcol >= 0 && fromcol < vcol)
3455 	    fromcol = vcol;
3456 
3457 #ifdef FEAT_LINEBREAK
3458 	/* When w_skipcol is non-zero, first line needs 'showbreak' */
3459 	if (wp->w_p_wrap)
3460 	    need_showbreak = TRUE;
3461 #endif
3462 #ifdef FEAT_SPELL
3463 	/* When spell checking a word we need to figure out the start of the
3464 	 * word and if it's badly spelled or not. */
3465 	if (has_spell)
3466 	{
3467 	    int		len;
3468 	    colnr_T	linecol = (colnr_T)(ptr - line);
3469 	    hlf_T	spell_hlf = HLF_COUNT;
3470 
3471 	    pos = wp->w_cursor;
3472 	    wp->w_cursor.lnum = lnum;
3473 	    wp->w_cursor.col = linecol;
3474 	    len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
3475 
3476 	    /* spell_move_to() may call ml_get() and make "line" invalid */
3477 	    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3478 	    ptr = line + linecol;
3479 
3480 	    if (len == 0 || (int)wp->w_cursor.col > ptr - line)
3481 	    {
3482 		/* no bad word found at line start, don't check until end of a
3483 		 * word */
3484 		spell_hlf = HLF_COUNT;
3485 		word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
3486 	    }
3487 	    else
3488 	    {
3489 		/* bad word found, use attributes until end of word */
3490 		word_end = wp->w_cursor.col + len + 1;
3491 
3492 		/* Turn index into actual attributes. */
3493 		if (spell_hlf != HLF_COUNT)
3494 		    spell_attr = highlight_attr[spell_hlf];
3495 	    }
3496 	    wp->w_cursor = pos;
3497 
3498 # ifdef FEAT_SYN_HL
3499 	    /* Need to restart syntax highlighting for this line. */
3500 	    if (has_syntax)
3501 		syntax_start(wp, lnum);
3502 # endif
3503 	}
3504 #endif
3505     }
3506 
3507     /*
3508      * Correct highlighting for cursor that can't be disabled.
3509      * Avoids having to check this for each character.
3510      */
3511     if (fromcol >= 0)
3512     {
3513 	if (noinvcur)
3514 	{
3515 	    if ((colnr_T)fromcol == wp->w_virtcol)
3516 	    {
3517 		/* highlighting starts at cursor, let it start just after the
3518 		 * cursor */
3519 		fromcol_prev = fromcol;
3520 		fromcol = -1;
3521 	    }
3522 	    else if ((colnr_T)fromcol < wp->w_virtcol)
3523 		/* restart highlighting after the cursor */
3524 		fromcol_prev = wp->w_virtcol;
3525 	}
3526 	if (fromcol >= tocol)
3527 	    fromcol = -1;
3528     }
3529 
3530 #ifdef FEAT_SEARCH_EXTRA
3531     /*
3532      * Handle highlighting the last used search pattern and matches.
3533      * Do this for both search_hl and the match list.
3534      */
3535     cur = wp->w_match_head;
3536     shl_flag = FALSE;
3537     while (cur != NULL || shl_flag == FALSE)
3538     {
3539 	if (shl_flag == FALSE)
3540 	{
3541 	    shl = &search_hl;
3542 	    shl_flag = TRUE;
3543 	}
3544 	else
3545 	    shl = &cur->hl;
3546 	shl->startcol = MAXCOL;
3547 	shl->endcol = MAXCOL;
3548 	shl->attr_cur = 0;
3549 	shl->is_addpos = FALSE;
3550 	v = (long)(ptr - line);
3551 	if (cur != NULL)
3552 	    cur->pos.cur = 0;
3553 	next_search_hl(wp, shl, lnum, (colnr_T)v,
3554 					       shl == &search_hl ? NULL : cur);
3555 
3556 	/* Need to get the line again, a multi-line regexp may have made it
3557 	 * invalid. */
3558 	line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3559 	ptr = line + v;
3560 
3561 	if (shl->lnum != 0 && shl->lnum <= lnum)
3562 	{
3563 	    if (shl->lnum == lnum)
3564 		shl->startcol = shl->rm.startpos[0].col;
3565 	    else
3566 		shl->startcol = 0;
3567 	    if (lnum == shl->lnum + shl->rm.endpos[0].lnum
3568 						- shl->rm.startpos[0].lnum)
3569 		shl->endcol = shl->rm.endpos[0].col;
3570 	    else
3571 		shl->endcol = MAXCOL;
3572 	    /* Highlight one character for an empty match. */
3573 	    if (shl->startcol == shl->endcol)
3574 	    {
3575 #ifdef FEAT_MBYTE
3576 		if (has_mbyte && line[shl->endcol] != NUL)
3577 		    shl->endcol += (*mb_ptr2len)(line + shl->endcol);
3578 		else
3579 #endif
3580 		    ++shl->endcol;
3581 	    }
3582 	    if ((long)shl->startcol < v)  /* match at leftcol */
3583 	    {
3584 		shl->attr_cur = shl->attr;
3585 		search_attr = shl->attr;
3586 	    }
3587 	    area_highlighting = TRUE;
3588 	}
3589 	if (shl != &search_hl && cur != NULL)
3590 	    cur = cur->next;
3591     }
3592 #endif
3593 
3594 #ifdef FEAT_SYN_HL
3595     /* Cursor line highlighting for 'cursorline' in the current window.  Not
3596      * when Visual mode is active, because it's not clear what is selected
3597      * then. */
3598     if (wp->w_p_cul && lnum == wp->w_cursor.lnum
3599 					 && !(wp == curwin && VIsual_active))
3600     {
3601 	line_attr = hl_attr(HLF_CUL);
3602 	area_highlighting = TRUE;
3603     }
3604 #endif
3605 
3606     off = (unsigned)(current_ScreenLine - ScreenLines);
3607     col = 0;
3608 #ifdef FEAT_RIGHTLEFT
3609     if (wp->w_p_rl)
3610     {
3611 	/* Rightleft window: process the text in the normal direction, but put
3612 	 * it in current_ScreenLine[] from right to left.  Start at the
3613 	 * rightmost column of the window. */
3614 	col = W_WIDTH(wp) - 1;
3615 	off += col;
3616     }
3617 #endif
3618 
3619     /*
3620      * Repeat for the whole displayed line.
3621      */
3622     for (;;)
3623     {
3624 #ifdef FEAT_CONCEAL
3625 	has_match_conc = 0;
3626 #endif
3627 	/* Skip this quickly when working on the text. */
3628 	if (draw_state != WL_LINE)
3629 	{
3630 #ifdef FEAT_CMDWIN
3631 	    if (draw_state == WL_CMDLINE - 1 && n_extra == 0)
3632 	    {
3633 		draw_state = WL_CMDLINE;
3634 		if (cmdwin_type != 0 && wp == curwin)
3635 		{
3636 		    /* Draw the cmdline character. */
3637 		    n_extra = 1;
3638 		    c_extra = cmdwin_type;
3639 		    char_attr = hl_attr(HLF_AT);
3640 		}
3641 	    }
3642 #endif
3643 
3644 #ifdef FEAT_FOLDING
3645 	    if (draw_state == WL_FOLD - 1 && n_extra == 0)
3646 	    {
3647 		int fdc = compute_foldcolumn(wp, 0);
3648 
3649 		draw_state = WL_FOLD;
3650 		if (fdc > 0)
3651 		{
3652 		    /* Draw the 'foldcolumn'.  Allocate a buffer, "extra" may
3653 		     * already be in used. */
3654 		    p_extra_free = alloc(12 + 1);
3655 
3656 		    if (p_extra_free != NULL)
3657 		    {
3658 			fill_foldcolumn(p_extra_free, wp, FALSE, lnum);
3659 			n_extra = fdc;
3660 			p_extra_free[n_extra] = NUL;
3661 			p_extra = p_extra_free;
3662 			c_extra = NUL;
3663 			char_attr = hl_attr(HLF_FC);
3664 		    }
3665 		}
3666 	    }
3667 #endif
3668 
3669 #ifdef FEAT_SIGNS
3670 	    if (draw_state == WL_SIGN - 1 && n_extra == 0)
3671 	    {
3672 		draw_state = WL_SIGN;
3673 		/* Show the sign column when there are any signs in this
3674 		 * buffer or when using Netbeans. */
3675 		if (signcolumn_on(wp))
3676 		{
3677 		    int	text_sign;
3678 # ifdef FEAT_SIGN_ICONS
3679 		    int	icon_sign;
3680 # endif
3681 
3682 		    /* Draw two cells with the sign value or blank. */
3683 		    c_extra = ' ';
3684 		    char_attr = hl_attr(HLF_SC);
3685 		    n_extra = 2;
3686 
3687 		    if (row == startrow
3688 #ifdef FEAT_DIFF
3689 			    + filler_lines && filler_todo <= 0
3690 #endif
3691 			    )
3692 		    {
3693 			text_sign = buf_getsigntype(wp->w_buffer, lnum,
3694 								   SIGN_TEXT);
3695 # ifdef FEAT_SIGN_ICONS
3696 			icon_sign = buf_getsigntype(wp->w_buffer, lnum,
3697 								   SIGN_ICON);
3698 			if (gui.in_use && icon_sign != 0)
3699 			{
3700 			    /* Use the image in this position. */
3701 			    c_extra = SIGN_BYTE;
3702 #  ifdef FEAT_NETBEANS_INTG
3703 			    if (buf_signcount(wp->w_buffer, lnum) > 1)
3704 				c_extra = MULTISIGN_BYTE;
3705 #  endif
3706 			    char_attr = icon_sign;
3707 			}
3708 			else
3709 # endif
3710 			    if (text_sign != 0)
3711 			{
3712 			    p_extra = sign_get_text(text_sign);
3713 			    if (p_extra != NULL)
3714 			    {
3715 				c_extra = NUL;
3716 				n_extra = (int)STRLEN(p_extra);
3717 			    }
3718 			    char_attr = sign_get_attr(text_sign, FALSE);
3719 			}
3720 		    }
3721 		}
3722 	    }
3723 #endif
3724 
3725 	    if (draw_state == WL_NR - 1 && n_extra == 0)
3726 	    {
3727 		draw_state = WL_NR;
3728 		/* Display the absolute or relative line number. After the
3729 		 * first fill with blanks when the 'n' flag isn't in 'cpo' */
3730 		if ((wp->w_p_nu || wp->w_p_rnu)
3731 			&& (row == startrow
3732 #ifdef FEAT_DIFF
3733 			    + filler_lines
3734 #endif
3735 			    || vim_strchr(p_cpo, CPO_NUMCOL) == NULL))
3736 		{
3737 		    /* Draw the line number (empty space after wrapping). */
3738 		    if (row == startrow
3739 #ifdef FEAT_DIFF
3740 			    + filler_lines
3741 #endif
3742 			    )
3743 		    {
3744 			long num;
3745 			char *fmt = "%*ld ";
3746 
3747 			if (wp->w_p_nu && !wp->w_p_rnu)
3748 			    /* 'number' + 'norelativenumber' */
3749 			    num = (long)lnum;
3750 			else
3751 			{
3752 			    /* 'relativenumber', don't use negative numbers */
3753 			    num = labs((long)get_cursor_rel_lnum(wp, lnum));
3754 			    if (num == 0 && wp->w_p_nu && wp->w_p_rnu)
3755 			    {
3756 				/* 'number' + 'relativenumber' */
3757 				num = lnum;
3758 				fmt = "%-*ld ";
3759 			    }
3760 			}
3761 
3762 			sprintf((char *)extra, fmt,
3763 						number_width(wp), num);
3764 			if (wp->w_skipcol > 0)
3765 			    for (p_extra = extra; *p_extra == ' '; ++p_extra)
3766 				*p_extra = '-';
3767 #ifdef FEAT_RIGHTLEFT
3768 			if (wp->w_p_rl)		    /* reverse line numbers */
3769 			    rl_mirror(extra);
3770 #endif
3771 			p_extra = extra;
3772 			c_extra = NUL;
3773 		    }
3774 		    else
3775 			c_extra = ' ';
3776 		    n_extra = number_width(wp) + 1;
3777 		    char_attr = hl_attr(HLF_N);
3778 #ifdef FEAT_SYN_HL
3779 		    /* When 'cursorline' is set highlight the line number of
3780 		     * the current line differently.
3781 		     * TODO: Can we use CursorLine instead of CursorLineNr
3782 		     * when CursorLineNr isn't set? */
3783 		    if ((wp->w_p_cul || wp->w_p_rnu)
3784 						 && lnum == wp->w_cursor.lnum)
3785 			char_attr = hl_attr(HLF_CLN);
3786 #endif
3787 		}
3788 	    }
3789 
3790 #ifdef FEAT_LINEBREAK
3791 	    if (wp->w_p_brisbr && draw_state == WL_BRI - 1
3792 					     && n_extra == 0 && *p_sbr != NUL)
3793 		/* draw indent after showbreak value */
3794 		draw_state = WL_BRI;
3795 	    else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0)
3796 		/* After the showbreak, draw the breakindent */
3797 		draw_state = WL_BRI - 1;
3798 
3799 	    /* draw 'breakindent': indent wrapped text accordingly */
3800 	    if (draw_state == WL_BRI - 1 && n_extra == 0)
3801 	    {
3802 		draw_state = WL_BRI;
3803 		/* if need_showbreak is set, breakindent also applies */
3804 		if (wp->w_p_bri && n_extra == 0
3805 					 && (row != startrow || need_showbreak)
3806 # ifdef FEAT_DIFF
3807 			&& filler_lines == 0
3808 # endif
3809 		   )
3810 		{
3811 		    char_attr = 0;
3812 # ifdef FEAT_DIFF
3813 		    if (diff_hlf != (hlf_T)0)
3814 		    {
3815 			char_attr = hl_attr(diff_hlf);
3816 #  ifdef FEAT_SYN_HL
3817 			if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
3818 			    char_attr = hl_combine_attr(char_attr,
3819 							    hl_attr(HLF_CUL));
3820 #  endif
3821 		    }
3822 # endif
3823 		    p_extra = NULL;
3824 		    c_extra = ' ';
3825 		    n_extra = get_breakindent_win(wp,
3826 				       ml_get_buf(wp->w_buffer, lnum, FALSE));
3827 		    /* Correct end of highlighted area for 'breakindent',
3828 		     * required when 'linebreak' is also set. */
3829 		    if (tocol == vcol)
3830 			tocol += n_extra;
3831 		}
3832 	    }
3833 #endif
3834 
3835 #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF)
3836 	    if (draw_state == WL_SBR - 1 && n_extra == 0)
3837 	    {
3838 		draw_state = WL_SBR;
3839 # ifdef FEAT_DIFF
3840 		if (filler_todo > 0)
3841 		{
3842 		    /* Draw "deleted" diff line(s). */
3843 		    if (char2cells(fill_diff) > 1)
3844 			c_extra = '-';
3845 		    else
3846 			c_extra = fill_diff;
3847 #  ifdef FEAT_RIGHTLEFT
3848 		    if (wp->w_p_rl)
3849 			n_extra = col + 1;
3850 		    else
3851 #  endif
3852 			n_extra = W_WIDTH(wp) - col;
3853 		    char_attr = hl_attr(HLF_DED);
3854 		}
3855 # endif
3856 # ifdef FEAT_LINEBREAK
3857 		if (*p_sbr != NUL && need_showbreak)
3858 		{
3859 		    /* Draw 'showbreak' at the start of each broken line. */
3860 		    p_extra = p_sbr;
3861 		    c_extra = NUL;
3862 		    n_extra = (int)STRLEN(p_sbr);
3863 		    char_attr = hl_attr(HLF_AT);
3864 		    need_showbreak = FALSE;
3865 		    vcol_sbr = vcol + MB_CHARLEN(p_sbr);
3866 		    /* Correct end of highlighted area for 'showbreak',
3867 		     * required when 'linebreak' is also set. */
3868 		    if (tocol == vcol)
3869 			tocol += n_extra;
3870 #ifdef FEAT_SYN_HL
3871 		    /* combine 'showbreak' with 'cursorline' */
3872 		    if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
3873 			char_attr = hl_combine_attr(char_attr,
3874 							    hl_attr(HLF_CUL));
3875 #endif
3876 		}
3877 # endif
3878 	    }
3879 #endif
3880 
3881 	    if (draw_state == WL_LINE - 1 && n_extra == 0)
3882 	    {
3883 		draw_state = WL_LINE;
3884 		if (saved_n_extra)
3885 		{
3886 		    /* Continue item from end of wrapped line. */
3887 		    n_extra = saved_n_extra;
3888 		    c_extra = saved_c_extra;
3889 		    p_extra = saved_p_extra;
3890 		    char_attr = saved_char_attr;
3891 		}
3892 		else
3893 		    char_attr = 0;
3894 	    }
3895 	}
3896 
3897 	/* When still displaying '$' of change command, stop at cursor */
3898 	if (dollar_vcol >= 0 && wp == curwin
3899 		   && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
3900 #ifdef FEAT_DIFF
3901 				   && filler_todo <= 0
3902 #endif
3903 		)
3904 	{
3905 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
3906 								  wp->w_p_rl);
3907 	    /* Pretend we have finished updating the window.  Except when
3908 	     * 'cursorcolumn' is set. */
3909 #ifdef FEAT_SYN_HL
3910 	    if (wp->w_p_cuc)
3911 		row = wp->w_cline_row + wp->w_cline_height;
3912 	    else
3913 #endif
3914 		row = wp->w_height;
3915 	    break;
3916 	}
3917 
3918 	if (draw_state == WL_LINE && area_highlighting)
3919 	{
3920 	    /* handle Visual or match highlighting in this line */
3921 	    if (vcol == fromcol
3922 #ifdef FEAT_MBYTE
3923 		    || (has_mbyte && vcol + 1 == fromcol && n_extra == 0
3924 			&& (*mb_ptr2cells)(ptr) > 1)
3925 #endif
3926 		    || ((int)vcol_prev == fromcol_prev
3927 			&& vcol_prev < vcol	/* not at margin */
3928 			&& vcol < tocol))
3929 		area_attr = attr;		/* start highlighting */
3930 	    else if (area_attr != 0
3931 		    && (vcol == tocol
3932 			|| (noinvcur && (colnr_T)vcol == wp->w_virtcol)))
3933 		area_attr = 0;			/* stop highlighting */
3934 
3935 #ifdef FEAT_SEARCH_EXTRA
3936 	    if (!n_extra)
3937 	    {
3938 		/*
3939 		 * Check for start/end of search pattern match.
3940 		 * After end, check for start/end of next match.
3941 		 * When another match, have to check for start again.
3942 		 * Watch out for matching an empty string!
3943 		 * Do this for 'search_hl' and the match list (ordered by
3944 		 * priority).
3945 		 */
3946 		v = (long)(ptr - line);
3947 		cur = wp->w_match_head;
3948 		shl_flag = FALSE;
3949 		while (cur != NULL || shl_flag == FALSE)
3950 		{
3951 		    if (shl_flag == FALSE
3952 			    && ((cur != NULL
3953 				    && cur->priority > SEARCH_HL_PRIORITY)
3954 				|| cur == NULL))
3955 		    {
3956 			shl = &search_hl;
3957 			shl_flag = TRUE;
3958 		    }
3959 		    else
3960 			shl = &cur->hl;
3961 		    if (cur != NULL)
3962 			cur->pos.cur = 0;
3963 		    pos_inprogress = TRUE;
3964 		    while (shl->rm.regprog != NULL
3965 					   || (cur != NULL && pos_inprogress))
3966 		    {
3967 			if (shl->startcol != MAXCOL
3968 				&& v >= (long)shl->startcol
3969 				&& v < (long)shl->endcol)
3970 			{
3971 #ifdef FEAT_MBYTE
3972 			    int tmp_col = v + MB_PTR2LEN(ptr);
3973 
3974 			    if (shl->endcol < tmp_col)
3975 				shl->endcol = tmp_col;
3976 #endif
3977 			    shl->attr_cur = shl->attr;
3978 #ifdef FEAT_CONCEAL
3979 			    if (cur != NULL && syn_name2id((char_u *)"Conceal")
3980 							       == cur->hlg_id)
3981 			    {
3982 				has_match_conc =
3983 					     v == (long)shl->startcol ? 2 : 1;
3984 				match_conc = cur->conceal_char;
3985 			    }
3986 			    else
3987 				has_match_conc = match_conc = 0;
3988 #endif
3989 			}
3990 			else if (v == (long)shl->endcol)
3991 			{
3992 			    shl->attr_cur = 0;
3993 			    next_search_hl(wp, shl, lnum, (colnr_T)v,
3994 					       shl == &search_hl ? NULL : cur);
3995 			    pos_inprogress = cur == NULL || cur->pos.cur == 0
3996 							       ? FALSE : TRUE;
3997 
3998 			    /* Need to get the line again, a multi-line regexp
3999 			     * may have made it invalid. */
4000 			    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4001 			    ptr = line + v;
4002 
4003 			    if (shl->lnum == lnum)
4004 			    {
4005 				shl->startcol = shl->rm.startpos[0].col;
4006 				if (shl->rm.endpos[0].lnum == 0)
4007 				    shl->endcol = shl->rm.endpos[0].col;
4008 				else
4009 				    shl->endcol = MAXCOL;
4010 
4011 				if (shl->startcol == shl->endcol)
4012 				{
4013 				    /* highlight empty match, try again after
4014 				     * it */
4015 #ifdef FEAT_MBYTE
4016 				    if (has_mbyte)
4017 					shl->endcol += (*mb_ptr2len)(line
4018 							       + shl->endcol);
4019 				    else
4020 #endif
4021 					++shl->endcol;
4022 				}
4023 
4024 				/* Loop to check if the match starts at the
4025 				 * current position */
4026 				continue;
4027 			    }
4028 			}
4029 			break;
4030 		    }
4031 		    if (shl != &search_hl && cur != NULL)
4032 			cur = cur->next;
4033 		}
4034 
4035 		/* Use attributes from match with highest priority among
4036 		 * 'search_hl' and the match list. */
4037 		search_attr = search_hl.attr_cur;
4038 		cur = wp->w_match_head;
4039 		shl_flag = FALSE;
4040 		while (cur != NULL || shl_flag == FALSE)
4041 		{
4042 		    if (shl_flag == FALSE
4043 			    && ((cur != NULL
4044 				    && cur->priority > SEARCH_HL_PRIORITY)
4045 				|| cur == NULL))
4046 		    {
4047 			shl = &search_hl;
4048 			shl_flag = TRUE;
4049 		    }
4050 		    else
4051 			shl = &cur->hl;
4052 		    if (shl->attr_cur != 0)
4053 			search_attr = shl->attr_cur;
4054 		    if (shl != &search_hl && cur != NULL)
4055 			cur = cur->next;
4056 		}
4057 	    }
4058 #endif
4059 
4060 #ifdef FEAT_DIFF
4061 	    if (diff_hlf != (hlf_T)0)
4062 	    {
4063 		if (diff_hlf == HLF_CHD && ptr - line >= change_start
4064 							      && n_extra == 0)
4065 		    diff_hlf = HLF_TXD;		/* changed text */
4066 		if (diff_hlf == HLF_TXD && ptr - line > change_end
4067 							      && n_extra == 0)
4068 		    diff_hlf = HLF_CHD;		/* changed line */
4069 		line_attr = hl_attr(diff_hlf);
4070 		if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
4071 		    line_attr = hl_combine_attr(line_attr, hl_attr(HLF_CUL));
4072 	    }
4073 #endif
4074 
4075 	    /* Decide which of the highlight attributes to use. */
4076 	    attr_pri = TRUE;
4077 #ifdef LINE_ATTR
4078 	    if (area_attr != 0)
4079 		char_attr = hl_combine_attr(line_attr, area_attr);
4080 	    else if (search_attr != 0)
4081 		char_attr = hl_combine_attr(line_attr, search_attr);
4082 		/* Use line_attr when not in the Visual or 'incsearch' area
4083 		 * (area_attr may be 0 when "noinvcur" is set). */
4084 	    else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL)
4085 				|| vcol < fromcol || vcol_prev < fromcol_prev
4086 				|| vcol >= tocol))
4087 		char_attr = line_attr;
4088 #else
4089 	    if (area_attr != 0)
4090 		char_attr = area_attr;
4091 	    else if (search_attr != 0)
4092 		char_attr = search_attr;
4093 #endif
4094 	    else
4095 	    {
4096 		attr_pri = FALSE;
4097 #ifdef FEAT_SYN_HL
4098 		if (has_syntax)
4099 		    char_attr = syntax_attr;
4100 		else
4101 #endif
4102 		    char_attr = 0;
4103 	    }
4104 	}
4105 
4106 	/*
4107 	 * Get the next character to put on the screen.
4108 	 */
4109 	/*
4110 	 * The "p_extra" points to the extra stuff that is inserted to
4111 	 * represent special characters (non-printable stuff) and other
4112 	 * things.  When all characters are the same, c_extra is used.
4113 	 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
4114 	 * "p_extra[n_extra]".
4115 	 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
4116 	 */
4117 	if (n_extra > 0)
4118 	{
4119 	    if (c_extra != NUL)
4120 	    {
4121 		c = c_extra;
4122 #ifdef FEAT_MBYTE
4123 		mb_c = c;	/* doesn't handle non-utf-8 multi-byte! */
4124 		if (enc_utf8 && (*mb_char2len)(c) > 1)
4125 		{
4126 		    mb_utf8 = TRUE;
4127 		    u8cc[0] = 0;
4128 		    c = 0xc0;
4129 		}
4130 		else
4131 		    mb_utf8 = FALSE;
4132 #endif
4133 	    }
4134 	    else
4135 	    {
4136 		c = *p_extra;
4137 #ifdef FEAT_MBYTE
4138 		if (has_mbyte)
4139 		{
4140 		    mb_c = c;
4141 		    if (enc_utf8)
4142 		    {
4143 			/* If the UTF-8 character is more than one byte:
4144 			 * Decode it into "mb_c". */
4145 			mb_l = (*mb_ptr2len)(p_extra);
4146 			mb_utf8 = FALSE;
4147 			if (mb_l > n_extra)
4148 			    mb_l = 1;
4149 			else if (mb_l > 1)
4150 			{
4151 			    mb_c = utfc_ptr2char(p_extra, u8cc);
4152 			    mb_utf8 = TRUE;
4153 			    c = 0xc0;
4154 			}
4155 		    }
4156 		    else
4157 		    {
4158 			/* if this is a DBCS character, put it in "mb_c" */
4159 			mb_l = MB_BYTE2LEN(c);
4160 			if (mb_l >= n_extra)
4161 			    mb_l = 1;
4162 			else if (mb_l > 1)
4163 			    mb_c = (c << 8) + p_extra[1];
4164 		    }
4165 		    if (mb_l == 0)  /* at the NUL at end-of-line */
4166 			mb_l = 1;
4167 
4168 		    /* If a double-width char doesn't fit display a '>' in the
4169 		     * last column. */
4170 		    if ((
4171 # ifdef FEAT_RIGHTLEFT
4172 			    wp->w_p_rl ? (col <= 0) :
4173 # endif
4174 				    (col >= W_WIDTH(wp) - 1))
4175 			    && (*mb_char2cells)(mb_c) == 2)
4176 		    {
4177 			c = '>';
4178 			mb_c = c;
4179 			mb_l = 1;
4180 			mb_utf8 = FALSE;
4181 			multi_attr = hl_attr(HLF_AT);
4182 			/* put the pointer back to output the double-width
4183 			 * character at the start of the next line. */
4184 			++n_extra;
4185 			--p_extra;
4186 		    }
4187 		    else
4188 		    {
4189 			n_extra -= mb_l - 1;
4190 			p_extra += mb_l - 1;
4191 		    }
4192 		}
4193 #endif
4194 		++p_extra;
4195 	    }
4196 	    --n_extra;
4197 	}
4198 	else
4199 	{
4200 	    if (p_extra_free != NULL)
4201 	    {
4202 		vim_free(p_extra_free);
4203 		p_extra_free = NULL;
4204 	    }
4205 	    /*
4206 	     * Get a character from the line itself.
4207 	     */
4208 	    c = *ptr;
4209 #ifdef FEAT_MBYTE
4210 	    if (has_mbyte)
4211 	    {
4212 		mb_c = c;
4213 		if (enc_utf8)
4214 		{
4215 		    /* If the UTF-8 character is more than one byte: Decode it
4216 		     * into "mb_c". */
4217 		    mb_l = (*mb_ptr2len)(ptr);
4218 		    mb_utf8 = FALSE;
4219 		    if (mb_l > 1)
4220 		    {
4221 			mb_c = utfc_ptr2char(ptr, u8cc);
4222 			/* Overlong encoded ASCII or ASCII with composing char
4223 			 * is displayed normally, except a NUL. */
4224 			if (mb_c < 0x80)
4225 			    c = mb_c;
4226 			mb_utf8 = TRUE;
4227 
4228 			/* At start of the line we can have a composing char.
4229 			 * Draw it as a space with a composing char. */
4230 			if (utf_iscomposing(mb_c))
4231 			{
4232 			    int i;
4233 
4234 			    for (i = Screen_mco - 1; i > 0; --i)
4235 				u8cc[i] = u8cc[i - 1];
4236 			    u8cc[0] = mb_c;
4237 			    mb_c = ' ';
4238 			}
4239 		    }
4240 
4241 		    if ((mb_l == 1 && c >= 0x80)
4242 			    || (mb_l >= 1 && mb_c == 0)
4243 			    || (mb_l > 1 && (!vim_isprintc(mb_c)
4244 # ifdef UNICODE16
4245 							 || mb_c >= 0x10000
4246 # endif
4247 							 )))
4248 		    {
4249 			/*
4250 			 * Illegal UTF-8 byte: display as <xx>.
4251 			 * Non-BMP character : display as ? or fullwidth ?.
4252 			 */
4253 # ifdef UNICODE16
4254 			if (mb_c < 0x10000)
4255 # endif
4256 			{
4257 			    transchar_hex(extra, mb_c);
4258 # ifdef FEAT_RIGHTLEFT
4259 			    if (wp->w_p_rl)		/* reverse */
4260 				rl_mirror(extra);
4261 # endif
4262 			}
4263 # ifdef UNICODE16
4264 			else if (utf_char2cells(mb_c) != 2)
4265 			    STRCPY(extra, "?");
4266 			else
4267 			    /* 0xff1f in UTF-8: full-width '?' */
4268 			    STRCPY(extra, "\357\274\237");
4269 # endif
4270 
4271 			p_extra = extra;
4272 			c = *p_extra;
4273 			mb_c = mb_ptr2char_adv(&p_extra);
4274 			mb_utf8 = (c >= 0x80);
4275 			n_extra = (int)STRLEN(p_extra);
4276 			c_extra = NUL;
4277 			if (area_attr == 0 && search_attr == 0)
4278 			{
4279 			    n_attr = n_extra + 1;
4280 			    extra_attr = hl_attr(HLF_8);
4281 			    saved_attr2 = char_attr; /* save current attr */
4282 			}
4283 		    }
4284 		    else if (mb_l == 0)  /* at the NUL at end-of-line */
4285 			mb_l = 1;
4286 #ifdef FEAT_ARABIC
4287 		    else if (p_arshape && !p_tbidi && ARABIC_CHAR(mb_c))
4288 		    {
4289 			/* Do Arabic shaping. */
4290 			int	pc, pc1, nc;
4291 			int	pcc[MAX_MCO];
4292 
4293 			/* The idea of what is the previous and next
4294 			 * character depends on 'rightleft'. */
4295 			if (wp->w_p_rl)
4296 			{
4297 			    pc = prev_c;
4298 			    pc1 = prev_c1;
4299 			    nc = utf_ptr2char(ptr + mb_l);
4300 			    prev_c1 = u8cc[0];
4301 			}
4302 			else
4303 			{
4304 			    pc = utfc_ptr2char(ptr + mb_l, pcc);
4305 			    nc = prev_c;
4306 			    pc1 = pcc[0];
4307 			}
4308 			prev_c = mb_c;
4309 
4310 			mb_c = arabic_shape(mb_c, &c, &u8cc[0], pc, pc1, nc);
4311 		    }
4312 		    else
4313 			prev_c = mb_c;
4314 #endif
4315 		}
4316 		else	/* enc_dbcs */
4317 		{
4318 		    mb_l = MB_BYTE2LEN(c);
4319 		    if (mb_l == 0)  /* at the NUL at end-of-line */
4320 			mb_l = 1;
4321 		    else if (mb_l > 1)
4322 		    {
4323 			/* We assume a second byte below 32 is illegal.
4324 			 * Hopefully this is OK for all double-byte encodings!
4325 			 */
4326 			if (ptr[1] >= 32)
4327 			    mb_c = (c << 8) + ptr[1];
4328 			else
4329 			{
4330 			    if (ptr[1] == NUL)
4331 			    {
4332 				/* head byte at end of line */
4333 				mb_l = 1;
4334 				transchar_nonprint(extra, c);
4335 			    }
4336 			    else
4337 			    {
4338 				/* illegal tail byte */
4339 				mb_l = 2;
4340 				STRCPY(extra, "XX");
4341 			    }
4342 			    p_extra = extra;
4343 			    n_extra = (int)STRLEN(extra) - 1;
4344 			    c_extra = NUL;
4345 			    c = *p_extra++;
4346 			    if (area_attr == 0 && search_attr == 0)
4347 			    {
4348 				n_attr = n_extra + 1;
4349 				extra_attr = hl_attr(HLF_8);
4350 				saved_attr2 = char_attr; /* save current attr */
4351 			    }
4352 			    mb_c = c;
4353 			}
4354 		    }
4355 		}
4356 		/* If a double-width char doesn't fit display a '>' in the
4357 		 * last column; the character is displayed at the start of the
4358 		 * next line. */
4359 		if ((
4360 # ifdef FEAT_RIGHTLEFT
4361 			    wp->w_p_rl ? (col <= 0) :
4362 # endif
4363 				(col >= W_WIDTH(wp) - 1))
4364 			&& (*mb_char2cells)(mb_c) == 2)
4365 		{
4366 		    c = '>';
4367 		    mb_c = c;
4368 		    mb_utf8 = FALSE;
4369 		    mb_l = 1;
4370 		    multi_attr = hl_attr(HLF_AT);
4371 		    /* Put pointer back so that the character will be
4372 		     * displayed at the start of the next line. */
4373 		    --ptr;
4374 		}
4375 		else if (*ptr != NUL)
4376 		    ptr += mb_l - 1;
4377 
4378 		/* If a double-width char doesn't fit at the left side display
4379 		 * a '<' in the first column.  Don't do this for unprintable
4380 		 * characters. */
4381 		if (n_skip > 0 && mb_l > 1 && n_extra == 0)
4382 		{
4383 		    n_extra = 1;
4384 		    c_extra = MB_FILLER_CHAR;
4385 		    c = ' ';
4386 		    if (area_attr == 0 && search_attr == 0)
4387 		    {
4388 			n_attr = n_extra + 1;
4389 			extra_attr = hl_attr(HLF_AT);
4390 			saved_attr2 = char_attr; /* save current attr */
4391 		    }
4392 		    mb_c = c;
4393 		    mb_utf8 = FALSE;
4394 		    mb_l = 1;
4395 		}
4396 
4397 	    }
4398 #endif
4399 	    ++ptr;
4400 
4401 	    if (extra_check)
4402 	    {
4403 #ifdef FEAT_SPELL
4404 		int	can_spell = TRUE;
4405 #endif
4406 
4407 #ifdef FEAT_SYN_HL
4408 		/* Get syntax attribute, unless still at the start of the line
4409 		 * (double-wide char that doesn't fit). */
4410 		v = (long)(ptr - line);
4411 		if (has_syntax && v > 0)
4412 		{
4413 		    /* Get the syntax attribute for the character.  If there
4414 		     * is an error, disable syntax highlighting. */
4415 		    save_did_emsg = did_emsg;
4416 		    did_emsg = FALSE;
4417 
4418 		    syntax_attr = get_syntax_attr((colnr_T)v - 1,
4419 # ifdef FEAT_SPELL
4420 						has_spell ? &can_spell :
4421 # endif
4422 						NULL, FALSE);
4423 
4424 		    if (did_emsg)
4425 		    {
4426 			wp->w_s->b_syn_error = TRUE;
4427 			has_syntax = FALSE;
4428 		    }
4429 		    else
4430 			did_emsg = save_did_emsg;
4431 
4432 		    /* Need to get the line again, a multi-line regexp may
4433 		     * have made it invalid. */
4434 		    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
4435 		    ptr = line + v;
4436 
4437 		    if (!attr_pri)
4438 			char_attr = syntax_attr;
4439 		    else
4440 			char_attr = hl_combine_attr(syntax_attr, char_attr);
4441 # ifdef FEAT_CONCEAL
4442 		    /* no concealing past the end of the line, it interferes
4443 		     * with line highlighting */
4444 		    if (c == NUL)
4445 			syntax_flags = 0;
4446 		    else
4447 			syntax_flags = get_syntax_info(&syntax_seqnr);
4448 # endif
4449 		}
4450 #endif
4451 
4452 #ifdef FEAT_SPELL
4453 		/* Check spelling (unless at the end of the line).
4454 		 * Only do this when there is no syntax highlighting, the
4455 		 * @Spell cluster is not used or the current syntax item
4456 		 * contains the @Spell cluster. */
4457 		if (has_spell && v >= word_end && v > cur_checked_col)
4458 		{
4459 		    spell_attr = 0;
4460 # ifdef FEAT_SYN_HL
4461 		    if (!attr_pri)
4462 			char_attr = syntax_attr;
4463 # endif
4464 		    if (c != 0 && (
4465 # ifdef FEAT_SYN_HL
4466 				!has_syntax ||
4467 # endif
4468 				can_spell))
4469 		    {
4470 			char_u	*prev_ptr, *p;
4471 			int	len;
4472 			hlf_T	spell_hlf = HLF_COUNT;
4473 # ifdef FEAT_MBYTE
4474 			if (has_mbyte)
4475 			{
4476 			    prev_ptr = ptr - mb_l;
4477 			    v -= mb_l - 1;
4478 			}
4479 			else
4480 # endif
4481 			    prev_ptr = ptr - 1;
4482 
4483 			/* Use nextline[] if possible, it has the start of the
4484 			 * next line concatenated. */
4485 			if ((prev_ptr - line) - nextlinecol >= 0)
4486 			    p = nextline + (prev_ptr - line) - nextlinecol;
4487 			else
4488 			    p = prev_ptr;
4489 			cap_col -= (int)(prev_ptr - line);
4490 			len = spell_check(wp, p, &spell_hlf, &cap_col,
4491 								    nochange);
4492 			word_end = v + len;
4493 
4494 			/* In Insert mode only highlight a word that
4495 			 * doesn't touch the cursor. */
4496 			if (spell_hlf != HLF_COUNT
4497 				&& (State & INSERT) != 0
4498 				&& wp->w_cursor.lnum == lnum
4499 				&& wp->w_cursor.col >=
4500 						    (colnr_T)(prev_ptr - line)
4501 				&& wp->w_cursor.col < (colnr_T)word_end)
4502 			{
4503 			    spell_hlf = HLF_COUNT;
4504 			    spell_redraw_lnum = lnum;
4505 			}
4506 
4507 			if (spell_hlf == HLF_COUNT && p != prev_ptr
4508 				       && (p - nextline) + len > nextline_idx)
4509 			{
4510 			    /* Remember that the good word continues at the
4511 			     * start of the next line. */
4512 			    checked_lnum = lnum + 1;
4513 			    checked_col = (int)((p - nextline) + len - nextline_idx);
4514 			}
4515 
4516 			/* Turn index into actual attributes. */
4517 			if (spell_hlf != HLF_COUNT)
4518 			    spell_attr = highlight_attr[spell_hlf];
4519 
4520 			if (cap_col > 0)
4521 			{
4522 			    if (p != prev_ptr
4523 				   && (p - nextline) + cap_col >= nextline_idx)
4524 			    {
4525 				/* Remember that the word in the next line
4526 				 * must start with a capital. */
4527 				capcol_lnum = lnum + 1;
4528 				cap_col = (int)((p - nextline) + cap_col
4529 							       - nextline_idx);
4530 			    }
4531 			    else
4532 				/* Compute the actual column. */
4533 				cap_col += (int)(prev_ptr - line);
4534 			}
4535 		    }
4536 		}
4537 		if (spell_attr != 0)
4538 		{
4539 		    if (!attr_pri)
4540 			char_attr = hl_combine_attr(char_attr, spell_attr);
4541 		    else
4542 			char_attr = hl_combine_attr(spell_attr, char_attr);
4543 		}
4544 #endif
4545 #ifdef FEAT_LINEBREAK
4546 		/*
4547 		 * Found last space before word: check for line break.
4548 		 */
4549 		if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr))
4550 		{
4551 # ifdef FEAT_MBYTE
4552 		    int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0;
4553 # endif
4554 		    char_u *p = ptr - (
4555 # ifdef FEAT_MBYTE
4556 				mb_off +
4557 # endif
4558 				1);
4559 
4560 		    /* TODO: is passing p for start of the line OK? */
4561 		    n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
4562 								    NULL) - 1;
4563 		    if (c == TAB && n_extra + col > W_WIDTH(wp))
4564 			n_extra = (int)wp->w_buffer->b_p_ts
4565 				       - vcol % (int)wp->w_buffer->b_p_ts - 1;
4566 
4567 # ifdef FEAT_MBYTE
4568 		    c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
4569 # else
4570 		    c_extra = ' ';
4571 # endif
4572 		    if (vim_iswhite(c))
4573 		    {
4574 #ifdef FEAT_CONCEAL
4575 			if (c == TAB)
4576 			    /* See "Tab alignment" below. */
4577 			    FIX_FOR_BOGUSCOLS;
4578 #endif
4579 			if (!wp->w_p_list)
4580 			    c = ' ';
4581 		    }
4582 		}
4583 #endif
4584 
4585 		/* 'list': change char 160 to lcs_nbsp and space to lcs_space.
4586 		 */
4587 		if (wp->w_p_list
4588 			&& (((c == 160
4589 #ifdef FEAT_MBYTE
4590 			      || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f))
4591 #endif
4592 			     ) && lcs_nbsp)
4593 			|| (c == ' ' && lcs_space && ptr - line <= trailcol)))
4594 		{
4595 		    c = (c == ' ') ? lcs_space : lcs_nbsp;
4596 		    if (area_attr == 0 && search_attr == 0)
4597 		    {
4598 			n_attr = 1;
4599 			extra_attr = hl_attr(HLF_8);
4600 			saved_attr2 = char_attr; /* save current attr */
4601 		    }
4602 #ifdef FEAT_MBYTE
4603 		    mb_c = c;
4604 		    if (enc_utf8 && (*mb_char2len)(c) > 1)
4605 		    {
4606 			mb_utf8 = TRUE;
4607 			u8cc[0] = 0;
4608 			c = 0xc0;
4609 		    }
4610 		    else
4611 			mb_utf8 = FALSE;
4612 #endif
4613 		}
4614 
4615 		if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
4616 		{
4617 		    c = lcs_trail;
4618 		    if (!attr_pri)
4619 		    {
4620 			n_attr = 1;
4621 			extra_attr = hl_attr(HLF_8);
4622 			saved_attr2 = char_attr; /* save current attr */
4623 		    }
4624 #ifdef FEAT_MBYTE
4625 		    mb_c = c;
4626 		    if (enc_utf8 && (*mb_char2len)(c) > 1)
4627 		    {
4628 			mb_utf8 = TRUE;
4629 			u8cc[0] = 0;
4630 			c = 0xc0;
4631 		    }
4632 		    else
4633 			mb_utf8 = FALSE;
4634 #endif
4635 		}
4636 	    }
4637 
4638 	    /*
4639 	     * Handling of non-printable characters.
4640 	     */
4641 	    if (!vim_isprintc(c))
4642 	    {
4643 		/*
4644 		 * when getting a character from the file, we may have to
4645 		 * turn it into something else on the way to putting it
4646 		 * into "ScreenLines".
4647 		 */
4648 		if (c == TAB && (!wp->w_p_list || lcs_tab1))
4649 		{
4650 		    int tab_len = 0;
4651 		    long vcol_adjusted = vcol; /* removed showbreak length */
4652 #ifdef FEAT_LINEBREAK
4653 		    /* only adjust the tab_len, when at the first column
4654 		     * after the showbreak value was drawn */
4655 		    if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap)
4656 			vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
4657 #endif
4658 		    /* tab amount depends on current column */
4659 		    tab_len = (int)wp->w_buffer->b_p_ts
4660 					- vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
4661 
4662 #ifdef FEAT_LINEBREAK
4663 		    if (!wp->w_p_lbr || !wp->w_p_list)
4664 #endif
4665 		    /* tab amount depends on current column */
4666 			n_extra = tab_len;
4667 #ifdef FEAT_LINEBREAK
4668 		    else
4669 		    {
4670 			char_u *p;
4671 			int	len = n_extra;
4672 			int	i;
4673 			int	saved_nextra = n_extra;
4674 
4675 #ifdef FEAT_CONCEAL
4676 			if (vcol_off > 0)
4677 			    /* there are characters to conceal */
4678 			    tab_len += vcol_off;
4679 			/* boguscols before FIX_FOR_BOGUSCOLS macro from above
4680 			 */
4681 			if (wp->w_p_list && lcs_tab1 && old_boguscols > 0
4682 							 && n_extra > tab_len)
4683 			    tab_len += n_extra - tab_len;
4684 #endif
4685 
4686 			/* if n_extra > 0, it gives the number of chars, to
4687 			 * use for a tab, else we need to calculate the width
4688 			 * for a tab */
4689 #ifdef FEAT_MBYTE
4690 			len = (tab_len * mb_char2len(lcs_tab2));
4691 			if (n_extra > 0)
4692 			    len += n_extra - tab_len;
4693 #endif
4694 			c = lcs_tab1;
4695 			p = alloc((unsigned)(len + 1));
4696 			vim_memset(p, ' ', len);
4697 			p[len] = NUL;
4698 			p_extra_free = p;
4699 			for (i = 0; i < tab_len; i++)
4700 			{
4701 #ifdef FEAT_MBYTE
4702 			    mb_char2bytes(lcs_tab2, p);
4703 			    p += mb_char2len(lcs_tab2);
4704 			    n_extra += mb_char2len(lcs_tab2)
4705 						 - (saved_nextra > 0 ? 1 : 0);
4706 #else
4707 			    p[i] = lcs_tab2;
4708 #endif
4709 			}
4710 			p_extra = p_extra_free;
4711 #ifdef FEAT_CONCEAL
4712 			/* n_extra will be increased by FIX_FOX_BOGUSCOLS
4713 			 * macro below, so need to adjust for that here */
4714 			if (vcol_off > 0)
4715 			    n_extra -= vcol_off;
4716 #endif
4717 		    }
4718 #endif
4719 #ifdef FEAT_CONCEAL
4720 		    {
4721 			int vc_saved = vcol_off;
4722 
4723 			/* Tab alignment should be identical regardless of
4724 			 * 'conceallevel' value. So tab compensates of all
4725 			 * previous concealed characters, and thus resets
4726 			 * vcol_off and boguscols accumulated so far in the
4727 			 * line. Note that the tab can be longer than
4728 			 * 'tabstop' when there are concealed characters. */
4729 			FIX_FOR_BOGUSCOLS;
4730 
4731 			/* Make sure, the highlighting for the tab char will be
4732 			 * correctly set further below (effectively reverts the
4733 			 * FIX_FOR_BOGSUCOLS macro */
4734 			if (n_extra == tab_len + vc_saved && wp->w_p_list
4735 								  && lcs_tab1)
4736 			    tab_len += vc_saved;
4737 		    }
4738 #endif
4739 #ifdef FEAT_MBYTE
4740 		    mb_utf8 = FALSE;	/* don't draw as UTF-8 */
4741 #endif
4742 		    if (wp->w_p_list)
4743 		    {
4744 			c = lcs_tab1;
4745 #ifdef FEAT_LINEBREAK
4746 			if (wp->w_p_lbr)
4747 			    c_extra = NUL; /* using p_extra from above */
4748 			else
4749 #endif
4750 			    c_extra = lcs_tab2;
4751 			n_attr = tab_len + 1;
4752 			extra_attr = hl_attr(HLF_8);
4753 			saved_attr2 = char_attr; /* save current attr */
4754 #ifdef FEAT_MBYTE
4755 			mb_c = c;
4756 			if (enc_utf8 && (*mb_char2len)(c) > 1)
4757 			{
4758 			    mb_utf8 = TRUE;
4759 			    u8cc[0] = 0;
4760 			    c = 0xc0;
4761 			}
4762 #endif
4763 		    }
4764 		    else
4765 		    {
4766 			c_extra = ' ';
4767 			c = ' ';
4768 		    }
4769 		}
4770 		else if (c == NUL
4771 			&& (wp->w_p_list
4772 			    || ((fromcol >= 0 || fromcol_prev >= 0)
4773 				&& tocol > vcol
4774 				&& VIsual_mode != Ctrl_V
4775 				&& (
4776 # ifdef FEAT_RIGHTLEFT
4777 				    wp->w_p_rl ? (col >= 0) :
4778 # endif
4779 				    (col < W_WIDTH(wp)))
4780 				&& !(noinvcur
4781 				    && lnum == wp->w_cursor.lnum
4782 				    && (colnr_T)vcol == wp->w_virtcol)))
4783 			&& lcs_eol_one > 0)
4784 		{
4785 		    /* Display a '$' after the line or highlight an extra
4786 		     * character if the line break is included. */
4787 #if defined(FEAT_DIFF) || defined(LINE_ATTR)
4788 		    /* For a diff line the highlighting continues after the
4789 		     * "$". */
4790 		    if (
4791 # ifdef FEAT_DIFF
4792 			    diff_hlf == (hlf_T)0
4793 #  ifdef LINE_ATTR
4794 			    &&
4795 #  endif
4796 # endif
4797 # ifdef LINE_ATTR
4798 			    line_attr == 0
4799 # endif
4800 		       )
4801 #endif
4802 		    {
4803 #ifdef FEAT_VIRTUALEDIT
4804 			/* In virtualedit, visual selections may extend
4805 			 * beyond end of line. */
4806 			if (area_highlighting && virtual_active()
4807 				&& tocol != MAXCOL && vcol < tocol)
4808 			    n_extra = 0;
4809 			else
4810 #endif
4811 			{
4812 			    p_extra = at_end_str;
4813 			    n_extra = 1;
4814 			    c_extra = NUL;
4815 			}
4816 		    }
4817 		    if (wp->w_p_list && lcs_eol > 0)
4818 			c = lcs_eol;
4819 		    else
4820 			c = ' ';
4821 		    lcs_eol_one = -1;
4822 		    --ptr;	    /* put it back at the NUL */
4823 		    if (!attr_pri)
4824 		    {
4825 			extra_attr = hl_attr(HLF_AT);
4826 			n_attr = 1;
4827 		    }
4828 #ifdef FEAT_MBYTE
4829 		    mb_c = c;
4830 		    if (enc_utf8 && (*mb_char2len)(c) > 1)
4831 		    {
4832 			mb_utf8 = TRUE;
4833 			u8cc[0] = 0;
4834 			c = 0xc0;
4835 		    }
4836 		    else
4837 			mb_utf8 = FALSE;	/* don't draw as UTF-8 */
4838 #endif
4839 		}
4840 		else if (c != NUL)
4841 		{
4842 		    p_extra = transchar(c);
4843 		    if (n_extra == 0)
4844 			n_extra = byte2cells(c) - 1;
4845 #ifdef FEAT_RIGHTLEFT
4846 		    if ((dy_flags & DY_UHEX) && wp->w_p_rl)
4847 			rl_mirror(p_extra);	/* reverse "<12>" */
4848 #endif
4849 		    c_extra = NUL;
4850 #ifdef FEAT_LINEBREAK
4851 		    if (wp->w_p_lbr)
4852 		    {
4853 			char_u *p;
4854 
4855 			c = *p_extra;
4856 			p = alloc((unsigned)n_extra + 1);
4857 			vim_memset(p, ' ', n_extra);
4858 			STRNCPY(p, p_extra + 1, STRLEN(p_extra) - 1);
4859 			p[n_extra] = NUL;
4860 			p_extra_free = p_extra = p;
4861 		    }
4862 		    else
4863 #endif
4864 		    {
4865 			n_extra = byte2cells(c) - 1;
4866 			c = *p_extra++;
4867 		    }
4868 		    if (!attr_pri)
4869 		    {
4870 			n_attr = n_extra + 1;
4871 			extra_attr = hl_attr(HLF_8);
4872 			saved_attr2 = char_attr; /* save current attr */
4873 		    }
4874 #ifdef FEAT_MBYTE
4875 		    mb_utf8 = FALSE;	/* don't draw as UTF-8 */
4876 #endif
4877 		}
4878 #ifdef FEAT_VIRTUALEDIT
4879 		else if (VIsual_active
4880 			 && (VIsual_mode == Ctrl_V
4881 			     || VIsual_mode == 'v')
4882 			 && virtual_active()
4883 			 && tocol != MAXCOL
4884 			 && vcol < tocol
4885 			 && (
4886 # ifdef FEAT_RIGHTLEFT
4887 			    wp->w_p_rl ? (col >= 0) :
4888 # endif
4889 			    (col < W_WIDTH(wp))))
4890 		{
4891 		    c = ' ';
4892 		    --ptr;	    /* put it back at the NUL */
4893 		}
4894 #endif
4895 #if defined(LINE_ATTR)
4896 		else if ((
4897 # ifdef FEAT_DIFF
4898 			    diff_hlf != (hlf_T)0 ||
4899 # endif
4900 			    line_attr != 0
4901 			) && (
4902 # ifdef FEAT_RIGHTLEFT
4903 			    wp->w_p_rl ? (col >= 0) :
4904 # endif
4905 			    (col
4906 # ifdef FEAT_CONCEAL
4907 				- boguscols
4908 # endif
4909 					    < W_WIDTH(wp))))
4910 		{
4911 		    /* Highlight until the right side of the window */
4912 		    c = ' ';
4913 		    --ptr;	    /* put it back at the NUL */
4914 
4915 		    /* Remember we do the char for line highlighting. */
4916 		    ++did_line_attr;
4917 
4918 		    /* don't do search HL for the rest of the line */
4919 		    if (line_attr != 0 && char_attr == search_attr && col > 0)
4920 			char_attr = line_attr;
4921 # ifdef FEAT_DIFF
4922 		    if (diff_hlf == HLF_TXD)
4923 		    {
4924 			diff_hlf = HLF_CHD;
4925 			if (attr == 0 || char_attr != attr)
4926 			{
4927 			    char_attr = hl_attr(diff_hlf);
4928 			    if (wp->w_p_cul && lnum == wp->w_cursor.lnum)
4929 				char_attr = hl_combine_attr(char_attr,
4930 							    hl_attr(HLF_CUL));
4931 			}
4932 		    }
4933 # endif
4934 		}
4935 #endif
4936 	    }
4937 
4938 #ifdef FEAT_CONCEAL
4939 	    if (   wp->w_p_cole > 0
4940 		&& (wp != curwin || lnum != wp->w_cursor.lnum ||
4941 							conceal_cursor_line(wp) )
4942 		&& ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0)
4943 		&& !(lnum_in_visual_area
4944 				    && vim_strchr(wp->w_p_cocu, 'v') == NULL))
4945 	    {
4946 		char_attr = conceal_attr;
4947 		if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1)
4948 			&& (syn_get_sub_char() != NUL || match_conc
4949 							 || wp->w_p_cole == 1)
4950 			&& wp->w_p_cole != 3)
4951 		{
4952 		    /* First time at this concealed item: display one
4953 		     * character. */
4954 		    if (match_conc)
4955 			c = match_conc;
4956 		    else if (syn_get_sub_char() != NUL)
4957 			c = syn_get_sub_char();
4958 		    else if (lcs_conceal != NUL)
4959 			c = lcs_conceal;
4960 		    else
4961 			c = ' ';
4962 
4963 		    prev_syntax_id = syntax_seqnr;
4964 
4965 		    if (n_extra > 0)
4966 			vcol_off += n_extra;
4967 		    vcol += n_extra;
4968 		    if (wp->w_p_wrap && n_extra > 0)
4969 		    {
4970 # ifdef FEAT_RIGHTLEFT
4971 			if (wp->w_p_rl)
4972 			{
4973 			    col -= n_extra;
4974 			    boguscols -= n_extra;
4975 			}
4976 			else
4977 # endif
4978 			{
4979 			    boguscols += n_extra;
4980 			    col += n_extra;
4981 			}
4982 		    }
4983 		    n_extra = 0;
4984 		    n_attr = 0;
4985 		}
4986 		else if (n_skip == 0)
4987 		{
4988 		    is_concealing = TRUE;
4989 		    n_skip = 1;
4990 		}
4991 # ifdef FEAT_MBYTE
4992 		mb_c = c;
4993 		if (enc_utf8 && (*mb_char2len)(c) > 1)
4994 		{
4995 		    mb_utf8 = TRUE;
4996 		    u8cc[0] = 0;
4997 		    c = 0xc0;
4998 		}
4999 		else
5000 		    mb_utf8 = FALSE;	/* don't draw as UTF-8 */
5001 # endif
5002 	    }
5003 	    else
5004 	    {
5005 		prev_syntax_id = 0;
5006 		is_concealing = FALSE;
5007 	    }
5008 #endif /* FEAT_CONCEAL */
5009 	}
5010 
5011 #ifdef FEAT_CONCEAL
5012 	/* In the cursor line and we may be concealing characters: correct
5013 	 * the cursor column when we reach its position. */
5014 	if (!did_wcol && draw_state == WL_LINE
5015 		&& wp == curwin && lnum == wp->w_cursor.lnum
5016 		&& conceal_cursor_line(wp)
5017 		&& (int)wp->w_virtcol <= vcol + n_skip)
5018 	{
5019 #  ifdef FEAT_RIGHTLEFT
5020 	    if (wp->w_p_rl)
5021 		wp->w_wcol = W_WIDTH(wp) - col + boguscols - 1;
5022 	    else
5023 #  endif
5024 		wp->w_wcol = col - boguscols;
5025 	    wp->w_wrow = row;
5026 	    did_wcol = TRUE;
5027 	}
5028 #endif
5029 
5030 	/* Don't override visual selection highlighting. */
5031 	if (n_attr > 0
5032 		&& draw_state == WL_LINE
5033 		&& !attr_pri)
5034 	    char_attr = extra_attr;
5035 
5036 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
5037 	/* XIM don't send preedit_start and preedit_end, but they send
5038 	 * preedit_changed and commit.  Thus Vim can't set "im_is_active", use
5039 	 * im_is_preediting() here. */
5040 	if (xic != NULL
5041 		&& lnum == wp->w_cursor.lnum
5042 		&& (State & INSERT)
5043 		&& !p_imdisable
5044 		&& im_is_preediting()
5045 		&& draw_state == WL_LINE)
5046 	{
5047 	    colnr_T tcol;
5048 
5049 	    if (preedit_end_col == MAXCOL)
5050 		getvcol(curwin, &(wp->w_cursor), &tcol, NULL, NULL);
5051 	    else
5052 		tcol = preedit_end_col;
5053 	    if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
5054 	    {
5055 		if (feedback_old_attr < 0)
5056 		{
5057 		    feedback_col = 0;
5058 		    feedback_old_attr = char_attr;
5059 		}
5060 		char_attr = im_get_feedback_attr(feedback_col);
5061 		if (char_attr < 0)
5062 		    char_attr = feedback_old_attr;
5063 		feedback_col++;
5064 	    }
5065 	    else if (feedback_old_attr >= 0)
5066 	    {
5067 		char_attr = feedback_old_attr;
5068 		feedback_old_attr = -1;
5069 		feedback_col = 0;
5070 	    }
5071 	}
5072 #endif
5073 	/*
5074 	 * Handle the case where we are in column 0 but not on the first
5075 	 * character of the line and the user wants us to show us a
5076 	 * special character (via 'listchars' option "precedes:<char>".
5077 	 */
5078 	if (lcs_prec_todo != NUL
5079 		&& wp->w_p_list
5080 		&& (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
5081 #ifdef FEAT_DIFF
5082 		&& filler_todo <= 0
5083 #endif
5084 		&& draw_state > WL_NR
5085 		&& c != NUL)
5086 	{
5087 	    c = lcs_prec;
5088 	    lcs_prec_todo = NUL;
5089 #ifdef FEAT_MBYTE
5090 	    if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5091 	    {
5092 		/* Double-width character being overwritten by the "precedes"
5093 		 * character, need to fill up half the character. */
5094 		c_extra = MB_FILLER_CHAR;
5095 		n_extra = 1;
5096 		n_attr = 2;
5097 		extra_attr = hl_attr(HLF_AT);
5098 	    }
5099 	    mb_c = c;
5100 	    if (enc_utf8 && (*mb_char2len)(c) > 1)
5101 	    {
5102 		mb_utf8 = TRUE;
5103 		u8cc[0] = 0;
5104 		c = 0xc0;
5105 	    }
5106 	    else
5107 		mb_utf8 = FALSE;	/* don't draw as UTF-8 */
5108 #endif
5109 	    if (!attr_pri)
5110 	    {
5111 		saved_attr3 = char_attr; /* save current attr */
5112 		char_attr = hl_attr(HLF_AT); /* later copied to char_attr */
5113 		n_attr3 = 1;
5114 	    }
5115 	}
5116 
5117 	/*
5118 	 * At end of the text line or just after the last character.
5119 	 */
5120 	if (c == NUL
5121 #if defined(LINE_ATTR)
5122 		|| did_line_attr == 1
5123 #endif
5124 		)
5125 	{
5126 #ifdef FEAT_SEARCH_EXTRA
5127 	    long prevcol = (long)(ptr - line) - (c == NUL);
5128 
5129 	    /* we're not really at that column when skipping some text */
5130 	    if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
5131 		++prevcol;
5132 #endif
5133 
5134 	    /* Invert at least one char, used for Visual and empty line or
5135 	     * highlight match at end of line. If it's beyond the last
5136 	     * char on the screen, just overwrite that one (tricky!)  Not
5137 	     * needed when a '$' was displayed for 'list'. */
5138 #ifdef FEAT_SEARCH_EXTRA
5139 	    prevcol_hl_flag = FALSE;
5140 	    if (!search_hl.is_addpos && prevcol == (long)search_hl.startcol)
5141 		prevcol_hl_flag = TRUE;
5142 	    else
5143 	    {
5144 		cur = wp->w_match_head;
5145 		while (cur != NULL)
5146 		{
5147 		    if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol)
5148 		    {
5149 			prevcol_hl_flag = TRUE;
5150 			break;
5151 		    }
5152 		    cur = cur->next;
5153 		}
5154 	    }
5155 #endif
5156 	    if (lcs_eol == lcs_eol_one
5157 		    && ((area_attr != 0 && vcol == fromcol
5158 			    && (VIsual_mode != Ctrl_V
5159 				|| lnum == VIsual.lnum
5160 				|| lnum == curwin->w_cursor.lnum)
5161 			    && c == NUL)
5162 #ifdef FEAT_SEARCH_EXTRA
5163 			/* highlight 'hlsearch' match at end of line */
5164 			|| (prevcol_hl_flag == TRUE
5165 # if defined(LINE_ATTR)
5166 			    && did_line_attr <= 1
5167 # endif
5168 			   )
5169 #endif
5170 		       ))
5171 	    {
5172 		int n = 0;
5173 
5174 #ifdef FEAT_RIGHTLEFT
5175 		if (wp->w_p_rl)
5176 		{
5177 		    if (col < 0)
5178 			n = 1;
5179 		}
5180 		else
5181 #endif
5182 		{
5183 		    if (col >= W_WIDTH(wp))
5184 			n = -1;
5185 		}
5186 		if (n != 0)
5187 		{
5188 		    /* At the window boundary, highlight the last character
5189 		     * instead (better than nothing). */
5190 		    off += n;
5191 		    col += n;
5192 		}
5193 		else
5194 		{
5195 		    /* Add a blank character to highlight. */
5196 		    ScreenLines[off] = ' ';
5197 #ifdef FEAT_MBYTE
5198 		    if (enc_utf8)
5199 			ScreenLinesUC[off] = 0;
5200 #endif
5201 		}
5202 #ifdef FEAT_SEARCH_EXTRA
5203 		if (area_attr == 0)
5204 		{
5205 		    /* Use attributes from match with highest priority among
5206 		     * 'search_hl' and the match list. */
5207 		    char_attr = search_hl.attr;
5208 		    cur = wp->w_match_head;
5209 		    shl_flag = FALSE;
5210 		    while (cur != NULL || shl_flag == FALSE)
5211 		    {
5212 			if (shl_flag == FALSE
5213 				&& ((cur != NULL
5214 					&& cur->priority > SEARCH_HL_PRIORITY)
5215 				    || cur == NULL))
5216 			{
5217 			    shl = &search_hl;
5218 			    shl_flag = TRUE;
5219 			}
5220 			else
5221 			    shl = &cur->hl;
5222 			if ((ptr - line) - 1 == (long)shl->startcol
5223 				&& (shl == &search_hl || !shl->is_addpos))
5224 			    char_attr = shl->attr;
5225 			if (shl != &search_hl && cur != NULL)
5226 			    cur = cur->next;
5227 		    }
5228 		}
5229 #endif
5230 		ScreenAttrs[off] = char_attr;
5231 #ifdef FEAT_RIGHTLEFT
5232 		if (wp->w_p_rl)
5233 		{
5234 		    --col;
5235 		    --off;
5236 		}
5237 		else
5238 #endif
5239 		{
5240 		    ++col;
5241 		    ++off;
5242 		}
5243 		++vcol;
5244 #ifdef FEAT_SYN_HL
5245 		eol_hl_off = 1;
5246 #endif
5247 	    }
5248 	}
5249 
5250 	/*
5251 	 * At end of the text line.
5252 	 */
5253 	if (c == NUL)
5254 	{
5255 #ifdef FEAT_SYN_HL
5256 	    if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol
5257 		    && lnum == wp->w_cursor.lnum)
5258 	    {
5259 		/* highlight last char after line */
5260 		--col;
5261 		--off;
5262 		--vcol;
5263 	    }
5264 
5265 	    /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */
5266 	    if (wp->w_p_wrap)
5267 		v = wp->w_skipcol;
5268 	    else
5269 		v = wp->w_leftcol;
5270 
5271 	    /* check if line ends before left margin */
5272 	    if (vcol < v + col - win_col_off(wp))
5273 		vcol = v + col - win_col_off(wp);
5274 #ifdef FEAT_CONCEAL
5275 	    /* Get rid of the boguscols now, we want to draw until the right
5276 	     * edge for 'cursorcolumn'. */
5277 	    col -= boguscols;
5278 	    boguscols = 0;
5279 #endif
5280 
5281 	    if (draw_color_col)
5282 		draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
5283 
5284 	    if (((wp->w_p_cuc
5285 		      && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off
5286 		      && (int)wp->w_virtcol <
5287 					W_WIDTH(wp) * (row - startrow + 1) + v
5288 		      && lnum != wp->w_cursor.lnum)
5289 		    || draw_color_col)
5290 # ifdef FEAT_RIGHTLEFT
5291 		    && !wp->w_p_rl
5292 # endif
5293 		    )
5294 	    {
5295 		int	rightmost_vcol = 0;
5296 		int	i;
5297 
5298 		if (wp->w_p_cuc)
5299 		    rightmost_vcol = wp->w_virtcol;
5300 		if (draw_color_col)
5301 		    /* determine rightmost colorcolumn to possibly draw */
5302 		    for (i = 0; color_cols[i] >= 0; ++i)
5303 			if (rightmost_vcol < color_cols[i])
5304 			    rightmost_vcol = color_cols[i];
5305 
5306 		while (col < W_WIDTH(wp))
5307 		{
5308 		    ScreenLines[off] = ' ';
5309 #ifdef FEAT_MBYTE
5310 		    if (enc_utf8)
5311 			ScreenLinesUC[off] = 0;
5312 #endif
5313 		    ++col;
5314 		    if (draw_color_col)
5315 			draw_color_col = advance_color_col(VCOL_HLC,
5316 								 &color_cols);
5317 
5318 		    if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol)
5319 			ScreenAttrs[off++] = hl_attr(HLF_CUC);
5320 		    else if (draw_color_col && VCOL_HLC == *color_cols)
5321 			ScreenAttrs[off++] = hl_attr(HLF_MC);
5322 		    else
5323 			ScreenAttrs[off++] = 0;
5324 
5325 		    if (VCOL_HLC >= rightmost_vcol)
5326 			break;
5327 
5328 		    ++vcol;
5329 		}
5330 	    }
5331 #endif
5332 
5333 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col,
5334 						(int)W_WIDTH(wp), wp->w_p_rl);
5335 	    row++;
5336 
5337 	    /*
5338 	     * Update w_cline_height and w_cline_folded if the cursor line was
5339 	     * updated (saves a call to plines() later).
5340 	     */
5341 	    if (wp == curwin && lnum == curwin->w_cursor.lnum)
5342 	    {
5343 		curwin->w_cline_row = startrow;
5344 		curwin->w_cline_height = row - startrow;
5345 #ifdef FEAT_FOLDING
5346 		curwin->w_cline_folded = FALSE;
5347 #endif
5348 		curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
5349 	    }
5350 
5351 	    break;
5352 	}
5353 
5354 	/* line continues beyond line end */
5355 	if (lcs_ext
5356 		&& !wp->w_p_wrap
5357 #ifdef FEAT_DIFF
5358 		&& filler_todo <= 0
5359 #endif
5360 		&& (
5361 #ifdef FEAT_RIGHTLEFT
5362 		    wp->w_p_rl ? col == 0 :
5363 #endif
5364 		    col == W_WIDTH(wp) - 1)
5365 		&& (*ptr != NUL
5366 		    || (wp->w_p_list && lcs_eol_one > 0)
5367 		    || (n_extra && (c_extra != NUL || *p_extra != NUL))))
5368 	{
5369 	    c = lcs_ext;
5370 	    char_attr = hl_attr(HLF_AT);
5371 #ifdef FEAT_MBYTE
5372 	    mb_c = c;
5373 	    if (enc_utf8 && (*mb_char2len)(c) > 1)
5374 	    {
5375 		mb_utf8 = TRUE;
5376 		u8cc[0] = 0;
5377 		c = 0xc0;
5378 	    }
5379 	    else
5380 		mb_utf8 = FALSE;
5381 #endif
5382 	}
5383 
5384 #ifdef FEAT_SYN_HL
5385 	/* advance to the next 'colorcolumn' */
5386 	if (draw_color_col)
5387 	    draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
5388 
5389 	/* Highlight the cursor column if 'cursorcolumn' is set.  But don't
5390 	 * highlight the cursor position itself.
5391 	 * Also highlight the 'colorcolumn' if it is different than
5392 	 * 'cursorcolumn' */
5393 	vcol_save_attr = -1;
5394 	if (draw_state == WL_LINE && !lnum_in_visual_area)
5395 	{
5396 	    if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
5397 						 && lnum != wp->w_cursor.lnum)
5398 	    {
5399 		vcol_save_attr = char_attr;
5400 		char_attr = hl_combine_attr(char_attr, hl_attr(HLF_CUC));
5401 	    }
5402 	    else if (draw_color_col && VCOL_HLC == *color_cols)
5403 	    {
5404 		vcol_save_attr = char_attr;
5405 		char_attr = hl_combine_attr(char_attr, hl_attr(HLF_MC));
5406 	    }
5407 	}
5408 #endif
5409 
5410 	/*
5411 	 * Store character to be displayed.
5412 	 * Skip characters that are left of the screen for 'nowrap'.
5413 	 */
5414 	vcol_prev = vcol;
5415 	if (draw_state < WL_LINE || n_skip <= 0)
5416 	{
5417 	    /*
5418 	     * Store the character.
5419 	     */
5420 #if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
5421 	    if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
5422 	    {
5423 		/* A double-wide character is: put first halve in left cell. */
5424 		--off;
5425 		--col;
5426 	    }
5427 #endif
5428 	    ScreenLines[off] = c;
5429 #ifdef FEAT_MBYTE
5430 	    if (enc_dbcs == DBCS_JPNU)
5431 	    {
5432 		if ((mb_c & 0xff00) == 0x8e00)
5433 		    ScreenLines[off] = 0x8e;
5434 		ScreenLines2[off] = mb_c & 0xff;
5435 	    }
5436 	    else if (enc_utf8)
5437 	    {
5438 		if (mb_utf8)
5439 		{
5440 		    int i;
5441 
5442 		    ScreenLinesUC[off] = mb_c;
5443 		    if ((c & 0xff) == 0)
5444 			ScreenLines[off] = 0x80;   /* avoid storing zero */
5445 		    for (i = 0; i < Screen_mco; ++i)
5446 		    {
5447 			ScreenLinesC[i][off] = u8cc[i];
5448 			if (u8cc[i] == 0)
5449 			    break;
5450 		    }
5451 		}
5452 		else
5453 		    ScreenLinesUC[off] = 0;
5454 	    }
5455 	    if (multi_attr)
5456 	    {
5457 		ScreenAttrs[off] = multi_attr;
5458 		multi_attr = 0;
5459 	    }
5460 	    else
5461 #endif
5462 		ScreenAttrs[off] = char_attr;
5463 
5464 #ifdef FEAT_MBYTE
5465 	    if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5466 	    {
5467 		/* Need to fill two screen columns. */
5468 		++off;
5469 		++col;
5470 		if (enc_utf8)
5471 		    /* UTF-8: Put a 0 in the second screen char. */
5472 		    ScreenLines[off] = 0;
5473 		else
5474 		    /* DBCS: Put second byte in the second screen char. */
5475 		    ScreenLines[off] = mb_c & 0xff;
5476 		if (draw_state > WL_NR
5477 #ifdef FEAT_DIFF
5478 			&& filler_todo <= 0
5479 #endif
5480 			)
5481 		    ++vcol;
5482 		/* When "tocol" is halfway a character, set it to the end of
5483 		 * the character, otherwise highlighting won't stop. */
5484 		if (tocol == vcol)
5485 		    ++tocol;
5486 #ifdef FEAT_RIGHTLEFT
5487 		if (wp->w_p_rl)
5488 		{
5489 		    /* now it's time to backup one cell */
5490 		    --off;
5491 		    --col;
5492 		}
5493 #endif
5494 	    }
5495 #endif
5496 #ifdef FEAT_RIGHTLEFT
5497 	    if (wp->w_p_rl)
5498 	    {
5499 		--off;
5500 		--col;
5501 	    }
5502 	    else
5503 #endif
5504 	    {
5505 		++off;
5506 		++col;
5507 	    }
5508 	}
5509 #ifdef FEAT_CONCEAL
5510 	else if (wp->w_p_cole > 0 && is_concealing)
5511 	{
5512 	    --n_skip;
5513 	    ++vcol_off;
5514 	    if (n_extra > 0)
5515 		vcol_off += n_extra;
5516 	    if (wp->w_p_wrap)
5517 	    {
5518 		/*
5519 		 * Special voodoo required if 'wrap' is on.
5520 		 *
5521 		 * Advance the column indicator to force the line
5522 		 * drawing to wrap early. This will make the line
5523 		 * take up the same screen space when parts are concealed,
5524 		 * so that cursor line computations aren't messed up.
5525 		 *
5526 		 * To avoid the fictitious advance of 'col' causing
5527 		 * trailing junk to be written out of the screen line
5528 		 * we are building, 'boguscols' keeps track of the number
5529 		 * of bad columns we have advanced.
5530 		 */
5531 		if (n_extra > 0)
5532 		{
5533 		    vcol += n_extra;
5534 # ifdef FEAT_RIGHTLEFT
5535 		    if (wp->w_p_rl)
5536 		    {
5537 			col -= n_extra;
5538 			boguscols -= n_extra;
5539 		    }
5540 		    else
5541 # endif
5542 		    {
5543 			col += n_extra;
5544 			boguscols += n_extra;
5545 		    }
5546 		    n_extra = 0;
5547 		    n_attr = 0;
5548 		}
5549 
5550 
5551 # ifdef FEAT_MBYTE
5552 		if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
5553 		{
5554 		    /* Need to fill two screen columns. */
5555 #  ifdef FEAT_RIGHTLEFT
5556 		    if (wp->w_p_rl)
5557 		    {
5558 			--boguscols;
5559 			--col;
5560 		    }
5561 		    else
5562 #  endif
5563 		    {
5564 			++boguscols;
5565 			++col;
5566 		    }
5567 		}
5568 # endif
5569 
5570 # ifdef FEAT_RIGHTLEFT
5571 		if (wp->w_p_rl)
5572 		{
5573 		    --boguscols;
5574 		    --col;
5575 		}
5576 		else
5577 # endif
5578 		{
5579 		    ++boguscols;
5580 		    ++col;
5581 		}
5582 	    }
5583 	    else
5584 	    {
5585 		if (n_extra > 0)
5586 		{
5587 		    vcol += n_extra;
5588 		    n_extra = 0;
5589 		    n_attr = 0;
5590 		}
5591 	    }
5592 
5593 	}
5594 #endif /* FEAT_CONCEAL */
5595 	else
5596 	    --n_skip;
5597 
5598 	/* Only advance the "vcol" when after the 'number' or 'relativenumber'
5599 	 * column. */
5600 	if (draw_state > WL_NR
5601 #ifdef FEAT_DIFF
5602 		&& filler_todo <= 0
5603 #endif
5604 		)
5605 	    ++vcol;
5606 
5607 #ifdef FEAT_SYN_HL
5608 	if (vcol_save_attr >= 0)
5609 	    char_attr = vcol_save_attr;
5610 #endif
5611 
5612 	/* restore attributes after "predeces" in 'listchars' */
5613 	if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
5614 	    char_attr = saved_attr3;
5615 
5616 	/* restore attributes after last 'listchars' or 'number' char */
5617 	if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
5618 	    char_attr = saved_attr2;
5619 
5620 	/*
5621 	 * At end of screen line and there is more to come: Display the line
5622 	 * so far.  If there is no more to display it is caught above.
5623 	 */
5624 	if ((
5625 #ifdef FEAT_RIGHTLEFT
5626 	    wp->w_p_rl ? (col < 0) :
5627 #endif
5628 				    (col >= W_WIDTH(wp)))
5629 		&& (*ptr != NUL
5630 #ifdef FEAT_DIFF
5631 		    || filler_todo > 0
5632 #endif
5633 		    || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
5634 		    || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
5635 		)
5636 	{
5637 #ifdef FEAT_CONCEAL
5638 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols,
5639 						(int)W_WIDTH(wp), wp->w_p_rl);
5640 	    boguscols = 0;
5641 #else
5642 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col,
5643 						(int)W_WIDTH(wp), wp->w_p_rl);
5644 #endif
5645 	    ++row;
5646 	    ++screen_row;
5647 
5648 	    /* When not wrapping and finished diff lines, or when displayed
5649 	     * '$' and highlighting until last column, break here. */
5650 	    if ((!wp->w_p_wrap
5651 #ifdef FEAT_DIFF
5652 		    && filler_todo <= 0
5653 #endif
5654 		    ) || lcs_eol_one == -1)
5655 		break;
5656 
5657 	    /* When the window is too narrow draw all "@" lines. */
5658 	    if (draw_state != WL_LINE
5659 #ifdef FEAT_DIFF
5660 		    && filler_todo <= 0
5661 #endif
5662 		    )
5663 	    {
5664 		win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
5665 #ifdef FEAT_WINDOWS
5666 		draw_vsep_win(wp, row);
5667 #endif
5668 		row = endrow;
5669 	    }
5670 
5671 	    /* When line got too long for screen break here. */
5672 	    if (row == endrow)
5673 	    {
5674 		++row;
5675 		break;
5676 	    }
5677 
5678 	    if (screen_cur_row == screen_row - 1
5679 #ifdef FEAT_DIFF
5680 		     && filler_todo <= 0
5681 #endif
5682 #ifdef FEAT_WINDOWS
5683 		     && W_WIDTH(wp) == Columns
5684 #endif
5685 		     )
5686 	    {
5687 		/* Remember that the line wraps, used for modeless copy. */
5688 		LineWraps[screen_row - 1] = TRUE;
5689 
5690 		/*
5691 		 * Special trick to make copy/paste of wrapped lines work with
5692 		 * xterm/screen: write an extra character beyond the end of
5693 		 * the line. This will work with all terminal types
5694 		 * (regardless of the xn,am settings).
5695 		 * Only do this on a fast tty.
5696 		 * Only do this if the cursor is on the current line
5697 		 * (something has been written in it).
5698 		 * Don't do this for the GUI.
5699 		 * Don't do this for double-width characters.
5700 		 * Don't do this for a window not at the right screen border.
5701 		 */
5702 		if (p_tf
5703 #ifdef FEAT_GUI
5704 			 && !gui.in_use
5705 #endif
5706 #ifdef FEAT_MBYTE
5707 			 && !(has_mbyte
5708 			     && ((*mb_off2cells)(LineOffset[screen_row],
5709 				     LineOffset[screen_row] + screen_Columns)
5710 									  == 2
5711 				 || (*mb_off2cells)(LineOffset[screen_row - 1]
5712 							+ (int)Columns - 2,
5713 				     LineOffset[screen_row] + screen_Columns)
5714 									== 2))
5715 #endif
5716 		   )
5717 		{
5718 		    /* First make sure we are at the end of the screen line,
5719 		     * then output the same character again to let the
5720 		     * terminal know about the wrap.  If the terminal doesn't
5721 		     * auto-wrap, we overwrite the character. */
5722 		    if (screen_cur_col != W_WIDTH(wp))
5723 			screen_char(LineOffset[screen_row - 1]
5724 						      + (unsigned)Columns - 1,
5725 					  screen_row - 1, (int)(Columns - 1));
5726 
5727 #ifdef FEAT_MBYTE
5728 		    /* When there is a multi-byte character, just output a
5729 		     * space to keep it simple. */
5730 		    if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
5731 					screen_row - 1] + (Columns - 1)]) > 1)
5732 			out_char(' ');
5733 		    else
5734 #endif
5735 			out_char(ScreenLines[LineOffset[screen_row - 1]
5736 							    + (Columns - 1)]);
5737 		    /* force a redraw of the first char on the next line */
5738 		    ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
5739 		    screen_start();	/* don't know where cursor is now */
5740 		}
5741 	    }
5742 
5743 	    col = 0;
5744 	    off = (unsigned)(current_ScreenLine - ScreenLines);
5745 #ifdef FEAT_RIGHTLEFT
5746 	    if (wp->w_p_rl)
5747 	    {
5748 		col = W_WIDTH(wp) - 1;	/* col is not used if breaking! */
5749 		off += col;
5750 	    }
5751 #endif
5752 
5753 	    /* reset the drawing state for the start of a wrapped line */
5754 	    draw_state = WL_START;
5755 	    saved_n_extra = n_extra;
5756 	    saved_p_extra = p_extra;
5757 	    saved_c_extra = c_extra;
5758 	    saved_char_attr = char_attr;
5759 	    n_extra = 0;
5760 	    lcs_prec_todo = lcs_prec;
5761 #ifdef FEAT_LINEBREAK
5762 # ifdef FEAT_DIFF
5763 	    if (filler_todo <= 0)
5764 # endif
5765 		need_showbreak = TRUE;
5766 #endif
5767 #ifdef FEAT_DIFF
5768 	    --filler_todo;
5769 	    /* When the filler lines are actually below the last line of the
5770 	     * file, don't draw the line itself, break here. */
5771 	    if (filler_todo == 0 && wp->w_botfill)
5772 		break;
5773 #endif
5774 	}
5775 
5776     }	/* for every character in the line */
5777 
5778 #ifdef FEAT_SPELL
5779     /* After an empty line check first word for capital. */
5780     if (*skipwhite(line) == NUL)
5781     {
5782 	capcol_lnum = lnum + 1;
5783 	cap_col = 0;
5784     }
5785 #endif
5786 
5787     return row;
5788 }
5789 
5790 #ifdef FEAT_MBYTE
5791 static int comp_char_differs(int, int);
5792 
5793 /*
5794  * Return if the composing characters at "off_from" and "off_to" differ.
5795  * Only to be used when ScreenLinesUC[off_from] != 0.
5796  */
5797     static int
5798 comp_char_differs(int off_from, int off_to)
5799 {
5800     int	    i;
5801 
5802     for (i = 0; i < Screen_mco; ++i)
5803     {
5804 	if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
5805 	    return TRUE;
5806 	if (ScreenLinesC[i][off_from] == 0)
5807 	    break;
5808     }
5809     return FALSE;
5810 }
5811 #endif
5812 
5813 /*
5814  * Check whether the given character needs redrawing:
5815  * - the (first byte of the) character is different
5816  * - the attributes are different
5817  * - the character is multi-byte and the next byte is different
5818  * - the character is two cells wide and the second cell differs.
5819  */
5820     static int
5821 char_needs_redraw(int off_from, int off_to, int cols)
5822 {
5823     if (cols > 0
5824 	    && ((ScreenLines[off_from] != ScreenLines[off_to]
5825 		    || ScreenAttrs[off_from] != ScreenAttrs[off_to])
5826 
5827 #ifdef FEAT_MBYTE
5828 		|| (enc_dbcs != 0
5829 		    && MB_BYTE2LEN(ScreenLines[off_from]) > 1
5830 		    && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
5831 			? ScreenLines2[off_from] != ScreenLines2[off_to]
5832 			: (cols > 1 && ScreenLines[off_from + 1]
5833 						 != ScreenLines[off_to + 1])))
5834 		|| (enc_utf8
5835 		    && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
5836 			|| (ScreenLinesUC[off_from] != 0
5837 			    && comp_char_differs(off_from, off_to))
5838 			|| ((*mb_off2cells)(off_from, off_from + cols) > 1
5839 			    && ScreenLines[off_from + 1]
5840 						  != ScreenLines[off_to + 1])))
5841 #endif
5842 	       ))
5843 	return TRUE;
5844     return FALSE;
5845 }
5846 
5847 /*
5848  * Move one "cooked" screen line to the screen, but only the characters that
5849  * have actually changed.  Handle insert/delete character.
5850  * "coloff" gives the first column on the screen for this line.
5851  * "endcol" gives the columns where valid characters are.
5852  * "clear_width" is the width of the window.  It's > 0 if the rest of the line
5853  * needs to be cleared, negative otherwise.
5854  * "rlflag" is TRUE in a rightleft window:
5855  *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
5856  *    When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
5857  */
5858     static void
5859 screen_line(
5860     int	    row,
5861     int	    coloff,
5862     int	    endcol,
5863     int	    clear_width
5864 #ifdef FEAT_RIGHTLEFT
5865     , int   rlflag
5866 #endif
5867     )
5868 {
5869     unsigned	    off_from;
5870     unsigned	    off_to;
5871 #ifdef FEAT_MBYTE
5872     unsigned	    max_off_from;
5873     unsigned	    max_off_to;
5874 #endif
5875     int		    col = 0;
5876 #if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_WINDOWS)
5877     int		    hl;
5878 #endif
5879     int		    force = FALSE;	/* force update rest of the line */
5880     int		    redraw_this		/* bool: does character need redraw? */
5881 #ifdef FEAT_GUI
5882 				= TRUE	/* For GUI when while-loop empty */
5883 #endif
5884 				;
5885     int		    redraw_next;	/* redraw_this for next character */
5886 #ifdef FEAT_MBYTE
5887     int		    clear_next = FALSE;
5888     int		    char_cells;		/* 1: normal char */
5889 					/* 2: occupies two display cells */
5890 # define CHAR_CELLS char_cells
5891 #else
5892 # define CHAR_CELLS 1
5893 #endif
5894 
5895     /* Check for illegal row and col, just in case. */
5896     if (row >= Rows)
5897 	row = Rows - 1;
5898     if (endcol > Columns)
5899 	endcol = Columns;
5900 
5901 # ifdef FEAT_CLIPBOARD
5902     clip_may_clear_selection(row, row);
5903 # endif
5904 
5905     off_from = (unsigned)(current_ScreenLine - ScreenLines);
5906     off_to = LineOffset[row] + coloff;
5907 #ifdef FEAT_MBYTE
5908     max_off_from = off_from + screen_Columns;
5909     max_off_to = LineOffset[row] + screen_Columns;
5910 #endif
5911 
5912 #ifdef FEAT_RIGHTLEFT
5913     if (rlflag)
5914     {
5915 	/* Clear rest first, because it's left of the text. */
5916 	if (clear_width > 0)
5917 	{
5918 	    while (col <= endcol && ScreenLines[off_to] == ' '
5919 		    && ScreenAttrs[off_to] == 0
5920 # ifdef FEAT_MBYTE
5921 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
5922 # endif
5923 						  )
5924 	    {
5925 		++off_to;
5926 		++col;
5927 	    }
5928 	    if (col <= endcol)
5929 		screen_fill(row, row + 1, col + coloff,
5930 					    endcol + coloff + 1, ' ', ' ', 0);
5931 	}
5932 	col = endcol + 1;
5933 	off_to = LineOffset[row] + col + coloff;
5934 	off_from += col;
5935 	endcol = (clear_width > 0 ? clear_width : -clear_width);
5936     }
5937 #endif /* FEAT_RIGHTLEFT */
5938 
5939     redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
5940 
5941     while (col < endcol)
5942     {
5943 #ifdef FEAT_MBYTE
5944 	if (has_mbyte && (col + 1 < endcol))
5945 	    char_cells = (*mb_off2cells)(off_from, max_off_from);
5946 	else
5947 	    char_cells = 1;
5948 #endif
5949 
5950 	redraw_this = redraw_next;
5951 	redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
5952 			      off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
5953 
5954 #ifdef FEAT_GUI
5955 	/* If the next character was bold, then redraw the current character to
5956 	 * remove any pixels that might have spilt over into us.  This only
5957 	 * happens in the GUI.
5958 	 */
5959 	if (redraw_next && gui.in_use)
5960 	{
5961 	    hl = ScreenAttrs[off_to + CHAR_CELLS];
5962 	    if (hl > HL_ALL)
5963 		hl = syn_attr2attr(hl);
5964 	    if (hl & HL_BOLD)
5965 		redraw_this = TRUE;
5966 	}
5967 #endif
5968 
5969 	if (redraw_this)
5970 	{
5971 	    /*
5972 	     * Special handling when 'xs' termcap flag set (hpterm):
5973 	     * Attributes for characters are stored at the position where the
5974 	     * cursor is when writing the highlighting code.  The
5975 	     * start-highlighting code must be written with the cursor on the
5976 	     * first highlighted character.  The stop-highlighting code must
5977 	     * be written with the cursor just after the last highlighted
5978 	     * character.
5979 	     * Overwriting a character doesn't remove it's highlighting.  Need
5980 	     * to clear the rest of the line, and force redrawing it
5981 	     * completely.
5982 	     */
5983 	    if (       p_wiv
5984 		    && !force
5985 #ifdef FEAT_GUI
5986 		    && !gui.in_use
5987 #endif
5988 		    && ScreenAttrs[off_to] != 0
5989 		    && ScreenAttrs[off_from] != ScreenAttrs[off_to])
5990 	    {
5991 		/*
5992 		 * Need to remove highlighting attributes here.
5993 		 */
5994 		windgoto(row, col + coloff);
5995 		out_str(T_CE);		/* clear rest of this screen line */
5996 		screen_start();		/* don't know where cursor is now */
5997 		force = TRUE;		/* force redraw of rest of the line */
5998 		redraw_next = TRUE;	/* or else next char would miss out */
5999 
6000 		/*
6001 		 * If the previous character was highlighted, need to stop
6002 		 * highlighting at this character.
6003 		 */
6004 		if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
6005 		{
6006 		    screen_attr = ScreenAttrs[off_to - 1];
6007 		    term_windgoto(row, col + coloff);
6008 		    screen_stop_highlight();
6009 		}
6010 		else
6011 		    screen_attr = 0;	    /* highlighting has stopped */
6012 	    }
6013 #ifdef FEAT_MBYTE
6014 	    if (enc_dbcs != 0)
6015 	    {
6016 		/* Check if overwriting a double-byte with a single-byte or
6017 		 * the other way around requires another character to be
6018 		 * redrawn.  For UTF-8 this isn't needed, because comparing
6019 		 * ScreenLinesUC[] is sufficient. */
6020 		if (char_cells == 1
6021 			&& col + 1 < endcol
6022 			&& (*mb_off2cells)(off_to, max_off_to) > 1)
6023 		{
6024 		    /* Writing a single-cell character over a double-cell
6025 		     * character: need to redraw the next cell. */
6026 		    ScreenLines[off_to + 1] = 0;
6027 		    redraw_next = TRUE;
6028 		}
6029 		else if (char_cells == 2
6030 			&& col + 2 < endcol
6031 			&& (*mb_off2cells)(off_to, max_off_to) == 1
6032 			&& (*mb_off2cells)(off_to + 1, max_off_to) > 1)
6033 		{
6034 		    /* Writing the second half of a double-cell character over
6035 		     * a double-cell character: need to redraw the second
6036 		     * cell. */
6037 		    ScreenLines[off_to + 2] = 0;
6038 		    redraw_next = TRUE;
6039 		}
6040 
6041 		if (enc_dbcs == DBCS_JPNU)
6042 		    ScreenLines2[off_to] = ScreenLines2[off_from];
6043 	    }
6044 	    /* When writing a single-width character over a double-width
6045 	     * character and at the end of the redrawn text, need to clear out
6046 	     * the right halve of the old character.
6047 	     * Also required when writing the right halve of a double-width
6048 	     * char over the left halve of an existing one. */
6049 	    if (has_mbyte && col + char_cells == endcol
6050 		    && ((char_cells == 1
6051 			    && (*mb_off2cells)(off_to, max_off_to) > 1)
6052 			|| (char_cells == 2
6053 			    && (*mb_off2cells)(off_to, max_off_to) == 1
6054 			    && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
6055 		clear_next = TRUE;
6056 #endif
6057 
6058 	    ScreenLines[off_to] = ScreenLines[off_from];
6059 #ifdef FEAT_MBYTE
6060 	    if (enc_utf8)
6061 	    {
6062 		ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
6063 		if (ScreenLinesUC[off_from] != 0)
6064 		{
6065 		    int	    i;
6066 
6067 		    for (i = 0; i < Screen_mco; ++i)
6068 			ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
6069 		}
6070 	    }
6071 	    if (char_cells == 2)
6072 		ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
6073 #endif
6074 
6075 #if defined(FEAT_GUI) || defined(UNIX)
6076 	    /* The bold trick makes a single column of pixels appear in the
6077 	     * next character.  When a bold character is removed, the next
6078 	     * character should be redrawn too.  This happens for our own GUI
6079 	     * and for some xterms. */
6080 	    if (
6081 # ifdef FEAT_GUI
6082 		    gui.in_use
6083 # endif
6084 # if defined(FEAT_GUI) && defined(UNIX)
6085 		    ||
6086 # endif
6087 # ifdef UNIX
6088 		    term_is_xterm
6089 # endif
6090 		    )
6091 	    {
6092 		hl = ScreenAttrs[off_to];
6093 		if (hl > HL_ALL)
6094 		    hl = syn_attr2attr(hl);
6095 		if (hl & HL_BOLD)
6096 		    redraw_next = TRUE;
6097 	    }
6098 #endif
6099 	    ScreenAttrs[off_to] = ScreenAttrs[off_from];
6100 #ifdef FEAT_MBYTE
6101 	    /* For simplicity set the attributes of second half of a
6102 	     * double-wide character equal to the first half. */
6103 	    if (char_cells == 2)
6104 		ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
6105 
6106 	    if (enc_dbcs != 0 && char_cells == 2)
6107 		screen_char_2(off_to, row, col + coloff);
6108 	    else
6109 #endif
6110 		screen_char(off_to, row, col + coloff);
6111 	}
6112 	else if (  p_wiv
6113 #ifdef FEAT_GUI
6114 		&& !gui.in_use
6115 #endif
6116 		&& col + coloff > 0)
6117 	{
6118 	    if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
6119 	    {
6120 		/*
6121 		 * Don't output stop-highlight when moving the cursor, it will
6122 		 * stop the highlighting when it should continue.
6123 		 */
6124 		screen_attr = 0;
6125 	    }
6126 	    else if (screen_attr != 0)
6127 		screen_stop_highlight();
6128 	}
6129 
6130 	off_to += CHAR_CELLS;
6131 	off_from += CHAR_CELLS;
6132 	col += CHAR_CELLS;
6133     }
6134 
6135 #ifdef FEAT_MBYTE
6136     if (clear_next)
6137     {
6138 	/* Clear the second half of a double-wide character of which the left
6139 	 * half was overwritten with a single-wide character. */
6140 	ScreenLines[off_to] = ' ';
6141 	if (enc_utf8)
6142 	    ScreenLinesUC[off_to] = 0;
6143 	screen_char(off_to, row, col + coloff);
6144     }
6145 #endif
6146 
6147     if (clear_width > 0
6148 #ifdef FEAT_RIGHTLEFT
6149 		    && !rlflag
6150 #endif
6151 				   )
6152     {
6153 #ifdef FEAT_GUI
6154 	int startCol = col;
6155 #endif
6156 
6157 	/* blank out the rest of the line */
6158 	while (col < clear_width && ScreenLines[off_to] == ' '
6159 						  && ScreenAttrs[off_to] == 0
6160 #ifdef FEAT_MBYTE
6161 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
6162 #endif
6163 						  )
6164 	{
6165 	    ++off_to;
6166 	    ++col;
6167 	}
6168 	if (col < clear_width)
6169 	{
6170 #ifdef FEAT_GUI
6171 	    /*
6172 	     * In the GUI, clearing the rest of the line may leave pixels
6173 	     * behind if the first character cleared was bold.  Some bold
6174 	     * fonts spill over the left.  In this case we redraw the previous
6175 	     * character too.  If we didn't skip any blanks above, then we
6176 	     * only redraw if the character wasn't already redrawn anyway.
6177 	     */
6178 	    if (gui.in_use && (col > startCol || !redraw_this))
6179 	    {
6180 		hl = ScreenAttrs[off_to];
6181 		if (hl > HL_ALL || (hl & HL_BOLD))
6182 		{
6183 		    int prev_cells = 1;
6184 # ifdef FEAT_MBYTE
6185 		    if (enc_utf8)
6186 			/* for utf-8, ScreenLines[char_offset + 1] == 0 means
6187 			 * that its width is 2. */
6188 			prev_cells = ScreenLines[off_to - 1] == 0 ? 2 : 1;
6189 		    else if (enc_dbcs != 0)
6190 		    {
6191 			/* find previous character by counting from first
6192 			 * column and get its width. */
6193 			unsigned off = LineOffset[row];
6194 			unsigned max_off = LineOffset[row] + screen_Columns;
6195 
6196 			while (off < off_to)
6197 			{
6198 			    prev_cells = (*mb_off2cells)(off, max_off);
6199 			    off += prev_cells;
6200 			}
6201 		    }
6202 
6203 		    if (enc_dbcs != 0 && prev_cells > 1)
6204 			screen_char_2(off_to - prev_cells, row,
6205 						   col + coloff - prev_cells);
6206 		    else
6207 # endif
6208 			screen_char(off_to - prev_cells, row,
6209 						   col + coloff - prev_cells);
6210 		}
6211 	    }
6212 #endif
6213 	    screen_fill(row, row + 1, col + coloff, clear_width + coloff,
6214 								 ' ', ' ', 0);
6215 #ifdef FEAT_WINDOWS
6216 	    off_to += clear_width - col;
6217 	    col = clear_width;
6218 #endif
6219 	}
6220     }
6221 
6222     if (clear_width > 0)
6223     {
6224 #ifdef FEAT_WINDOWS
6225 	/* For a window that's left of another, draw the separator char. */
6226 	if (col + coloff < Columns)
6227 	{
6228 	    int c;
6229 
6230 	    c = fillchar_vsep(&hl);
6231 	    if (ScreenLines[off_to] != (schar_T)c
6232 # ifdef FEAT_MBYTE
6233 		    || (enc_utf8 && (int)ScreenLinesUC[off_to]
6234 						       != (c >= 0x80 ? c : 0))
6235 # endif
6236 		    || ScreenAttrs[off_to] != hl)
6237 	    {
6238 		ScreenLines[off_to] = c;
6239 		ScreenAttrs[off_to] = hl;
6240 # ifdef FEAT_MBYTE
6241 		if (enc_utf8)
6242 		{
6243 		    if (c >= 0x80)
6244 		    {
6245 			ScreenLinesUC[off_to] = c;
6246 			ScreenLinesC[0][off_to] = 0;
6247 		    }
6248 		    else
6249 			ScreenLinesUC[off_to] = 0;
6250 		}
6251 # endif
6252 		screen_char(off_to, row, col + coloff);
6253 	    }
6254 	}
6255 	else
6256 #endif
6257 	    LineWraps[row] = FALSE;
6258     }
6259 }
6260 
6261 #if defined(FEAT_RIGHTLEFT) || defined(PROTO)
6262 /*
6263  * Mirror text "str" for right-left displaying.
6264  * Only works for single-byte characters (e.g., numbers).
6265  */
6266     void
6267 rl_mirror(char_u *str)
6268 {
6269     char_u	*p1, *p2;
6270     int		t;
6271 
6272     for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
6273     {
6274 	t = *p1;
6275 	*p1 = *p2;
6276 	*p2 = t;
6277     }
6278 }
6279 #endif
6280 
6281 #if defined(FEAT_WINDOWS) || defined(PROTO)
6282 /*
6283  * mark all status lines for redraw; used after first :cd
6284  */
6285     void
6286 status_redraw_all(void)
6287 {
6288     win_T	*wp;
6289 
6290     FOR_ALL_WINDOWS(wp)
6291 	if (wp->w_status_height)
6292 	{
6293 	    wp->w_redr_status = TRUE;
6294 	    redraw_later(VALID);
6295 	}
6296 }
6297 
6298 /*
6299  * mark all status lines of the current buffer for redraw
6300  */
6301     void
6302 status_redraw_curbuf(void)
6303 {
6304     win_T	*wp;
6305 
6306     FOR_ALL_WINDOWS(wp)
6307 	if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
6308 	{
6309 	    wp->w_redr_status = TRUE;
6310 	    redraw_later(VALID);
6311 	}
6312 }
6313 
6314 /*
6315  * Redraw all status lines that need to be redrawn.
6316  */
6317     void
6318 redraw_statuslines(void)
6319 {
6320     win_T	*wp;
6321 
6322     FOR_ALL_WINDOWS(wp)
6323 	if (wp->w_redr_status)
6324 	    win_redr_status(wp);
6325     if (redraw_tabline)
6326 	draw_tabline();
6327 }
6328 #endif
6329 
6330 #if (defined(FEAT_WILDMENU) && defined(FEAT_WINDOWS)) || defined(PROTO)
6331 /*
6332  * Redraw all status lines at the bottom of frame "frp".
6333  */
6334     void
6335 win_redraw_last_status(frame_T *frp)
6336 {
6337     if (frp->fr_layout == FR_LEAF)
6338 	frp->fr_win->w_redr_status = TRUE;
6339     else if (frp->fr_layout == FR_ROW)
6340     {
6341 	for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
6342 	    win_redraw_last_status(frp);
6343     }
6344     else /* frp->fr_layout == FR_COL */
6345     {
6346 	frp = frp->fr_child;
6347 	while (frp->fr_next != NULL)
6348 	    frp = frp->fr_next;
6349 	win_redraw_last_status(frp);
6350     }
6351 }
6352 #endif
6353 
6354 #ifdef FEAT_WINDOWS
6355 /*
6356  * Draw the verticap separator right of window "wp" starting with line "row".
6357  */
6358     static void
6359 draw_vsep_win(win_T *wp, int row)
6360 {
6361     int		hl;
6362     int		c;
6363 
6364     if (wp->w_vsep_width)
6365     {
6366 	/* draw the vertical separator right of this window */
6367 	c = fillchar_vsep(&hl);
6368 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
6369 		W_ENDCOL(wp), W_ENDCOL(wp) + 1,
6370 		c, ' ', hl);
6371     }
6372 }
6373 #endif
6374 
6375 #ifdef FEAT_WILDMENU
6376 static int status_match_len(expand_T *xp, char_u *s);
6377 static int skip_status_match_char(expand_T *xp, char_u *s);
6378 
6379 /*
6380  * Get the length of an item as it will be shown in the status line.
6381  */
6382     static int
6383 status_match_len(expand_T *xp, char_u *s)
6384 {
6385     int	len = 0;
6386 
6387 #ifdef FEAT_MENU
6388     int emenu = (xp->xp_context == EXPAND_MENUS
6389 	    || xp->xp_context == EXPAND_MENUNAMES);
6390 
6391     /* Check for menu separators - replace with '|'. */
6392     if (emenu && menu_is_separator(s))
6393 	return 1;
6394 #endif
6395 
6396     while (*s != NUL)
6397     {
6398 	s += skip_status_match_char(xp, s);
6399 	len += ptr2cells(s);
6400 	mb_ptr_adv(s);
6401     }
6402 
6403     return len;
6404 }
6405 
6406 /*
6407  * Return the number of characters that should be skipped in a status match.
6408  * These are backslashes used for escaping.  Do show backslashes in help tags.
6409  */
6410     static int
6411 skip_status_match_char(expand_T *xp, char_u *s)
6412 {
6413     if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
6414 #ifdef FEAT_MENU
6415 	    || ((xp->xp_context == EXPAND_MENUS
6416 		    || xp->xp_context == EXPAND_MENUNAMES)
6417 			  && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
6418 #endif
6419 	   )
6420     {
6421 #ifndef BACKSLASH_IN_FILENAME
6422 	if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
6423 	    return 2;
6424 #endif
6425 	return 1;
6426     }
6427     return 0;
6428 }
6429 
6430 /*
6431  * Show wildchar matches in the status line.
6432  * Show at least the "match" item.
6433  * We start at item 'first_match' in the list and show all matches that fit.
6434  *
6435  * If inversion is possible we use it. Else '=' characters are used.
6436  */
6437     void
6438 win_redr_status_matches(
6439     expand_T	*xp,
6440     int		num_matches,
6441     char_u	**matches,	/* list of matches */
6442     int		match,
6443     int		showtail)
6444 {
6445 #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
6446     int		row;
6447     char_u	*buf;
6448     int		len;
6449     int		clen;		/* length in screen cells */
6450     int		fillchar;
6451     int		attr;
6452     int		i;
6453     int		highlight = TRUE;
6454     char_u	*selstart = NULL;
6455     int		selstart_col = 0;
6456     char_u	*selend = NULL;
6457     static int	first_match = 0;
6458     int		add_left = FALSE;
6459     char_u	*s;
6460 #ifdef FEAT_MENU
6461     int		emenu;
6462 #endif
6463 #if defined(FEAT_MBYTE) || defined(FEAT_MENU)
6464     int		l;
6465 #endif
6466 
6467     if (matches == NULL)	/* interrupted completion? */
6468 	return;
6469 
6470 #ifdef FEAT_MBYTE
6471     if (has_mbyte)
6472 	buf = alloc((unsigned)Columns * MB_MAXBYTES + 1);
6473     else
6474 #endif
6475 	buf = alloc((unsigned)Columns + 1);
6476     if (buf == NULL)
6477 	return;
6478 
6479     if (match == -1)	/* don't show match but original text */
6480     {
6481 	match = 0;
6482 	highlight = FALSE;
6483     }
6484     /* count 1 for the ending ">" */
6485     clen = status_match_len(xp, L_MATCH(match)) + 3;
6486     if (match == 0)
6487 	first_match = 0;
6488     else if (match < first_match)
6489     {
6490 	/* jumping left, as far as we can go */
6491 	first_match = match;
6492 	add_left = TRUE;
6493     }
6494     else
6495     {
6496 	/* check if match fits on the screen */
6497 	for (i = first_match; i < match; ++i)
6498 	    clen += status_match_len(xp, L_MATCH(i)) + 2;
6499 	if (first_match > 0)
6500 	    clen += 2;
6501 	/* jumping right, put match at the left */
6502 	if ((long)clen > Columns)
6503 	{
6504 	    first_match = match;
6505 	    /* if showing the last match, we can add some on the left */
6506 	    clen = 2;
6507 	    for (i = match; i < num_matches; ++i)
6508 	    {
6509 		clen += status_match_len(xp, L_MATCH(i)) + 2;
6510 		if ((long)clen >= Columns)
6511 		    break;
6512 	    }
6513 	    if (i == num_matches)
6514 		add_left = TRUE;
6515 	}
6516     }
6517     if (add_left)
6518 	while (first_match > 0)
6519 	{
6520 	    clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
6521 	    if ((long)clen >= Columns)
6522 		break;
6523 	    --first_match;
6524 	}
6525 
6526     fillchar = fillchar_status(&attr, TRUE);
6527 
6528     if (first_match == 0)
6529     {
6530 	*buf = NUL;
6531 	len = 0;
6532     }
6533     else
6534     {
6535 	STRCPY(buf, "< ");
6536 	len = 2;
6537     }
6538     clen = len;
6539 
6540     i = first_match;
6541     while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
6542     {
6543 	if (i == match)
6544 	{
6545 	    selstart = buf + len;
6546 	    selstart_col = clen;
6547 	}
6548 
6549 	s = L_MATCH(i);
6550 	/* Check for menu separators - replace with '|' */
6551 #ifdef FEAT_MENU
6552 	emenu = (xp->xp_context == EXPAND_MENUS
6553 		|| xp->xp_context == EXPAND_MENUNAMES);
6554 	if (emenu && menu_is_separator(s))
6555 	{
6556 	    STRCPY(buf + len, transchar('|'));
6557 	    l = (int)STRLEN(buf + len);
6558 	    len += l;
6559 	    clen += l;
6560 	}
6561 	else
6562 #endif
6563 	    for ( ; *s != NUL; ++s)
6564 	{
6565 	    s += skip_status_match_char(xp, s);
6566 	    clen += ptr2cells(s);
6567 #ifdef FEAT_MBYTE
6568 	    if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1)
6569 	    {
6570 		STRNCPY(buf + len, s, l);
6571 		s += l - 1;
6572 		len += l;
6573 	    }
6574 	    else
6575 #endif
6576 	    {
6577 		STRCPY(buf + len, transchar_byte(*s));
6578 		len += (int)STRLEN(buf + len);
6579 	    }
6580 	}
6581 	if (i == match)
6582 	    selend = buf + len;
6583 
6584 	*(buf + len++) = ' ';
6585 	*(buf + len++) = ' ';
6586 	clen += 2;
6587 	if (++i == num_matches)
6588 		break;
6589     }
6590 
6591     if (i != num_matches)
6592     {
6593 	*(buf + len++) = '>';
6594 	++clen;
6595     }
6596 
6597     buf[len] = NUL;
6598 
6599     row = cmdline_row - 1;
6600     if (row >= 0)
6601     {
6602 	if (wild_menu_showing == 0)
6603 	{
6604 	    if (msg_scrolled > 0)
6605 	    {
6606 		/* Put the wildmenu just above the command line.  If there is
6607 		 * no room, scroll the screen one line up. */
6608 		if (cmdline_row == Rows - 1)
6609 		{
6610 		    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
6611 		    ++msg_scrolled;
6612 		}
6613 		else
6614 		{
6615 		    ++cmdline_row;
6616 		    ++row;
6617 		}
6618 		wild_menu_showing = WM_SCROLLED;
6619 	    }
6620 	    else
6621 	    {
6622 		/* Create status line if needed by setting 'laststatus' to 2.
6623 		 * Set 'winminheight' to zero to avoid that the window is
6624 		 * resized. */
6625 		if (lastwin->w_status_height == 0)
6626 		{
6627 		    save_p_ls = p_ls;
6628 		    save_p_wmh = p_wmh;
6629 		    p_ls = 2;
6630 		    p_wmh = 0;
6631 		    last_status(FALSE);
6632 		}
6633 		wild_menu_showing = WM_SHOWN;
6634 	    }
6635 	}
6636 
6637 	screen_puts(buf, row, 0, attr);
6638 	if (selstart != NULL && highlight)
6639 	{
6640 	    *selend = NUL;
6641 	    screen_puts(selstart, row, selstart_col, hl_attr(HLF_WM));
6642 	}
6643 
6644 	screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
6645     }
6646 
6647 #ifdef FEAT_WINDOWS
6648     win_redraw_last_status(topframe);
6649 #else
6650     lastwin->w_redr_status = TRUE;
6651 #endif
6652     vim_free(buf);
6653 }
6654 #endif
6655 
6656 #if defined(FEAT_WINDOWS) || defined(PROTO)
6657 /*
6658  * Redraw the status line of window wp.
6659  *
6660  * If inversion is possible we use it. Else '=' characters are used.
6661  */
6662     void
6663 win_redr_status(win_T *wp)
6664 {
6665     int		row;
6666     char_u	*p;
6667     int		len;
6668     int		fillchar;
6669     int		attr;
6670     int		this_ru_col;
6671     static int  busy = FALSE;
6672 
6673     /* It's possible to get here recursively when 'statusline' (indirectly)
6674      * invokes ":redrawstatus".  Simply ignore the call then. */
6675     if (busy)
6676 	return;
6677     busy = TRUE;
6678 
6679     wp->w_redr_status = FALSE;
6680     if (wp->w_status_height == 0)
6681     {
6682 	/* no status line, can only be last window */
6683 	redraw_cmdline = TRUE;
6684     }
6685     else if (!redrawing()
6686 #ifdef FEAT_INS_EXPAND
6687 	    /* don't update status line when popup menu is visible and may be
6688 	     * drawn over it */
6689 	    || pum_visible()
6690 #endif
6691 	    )
6692     {
6693 	/* Don't redraw right now, do it later. */
6694 	wp->w_redr_status = TRUE;
6695     }
6696 #ifdef FEAT_STL_OPT
6697     else if (*p_stl != NUL || *wp->w_p_stl != NUL)
6698     {
6699 	/* redraw custom status line */
6700 	redraw_custom_statusline(wp);
6701     }
6702 #endif
6703     else
6704     {
6705 	fillchar = fillchar_status(&attr, wp == curwin);
6706 
6707 	get_trans_bufname(wp->w_buffer);
6708 	p = NameBuff;
6709 	len = (int)STRLEN(p);
6710 
6711 	if (wp->w_buffer->b_help
6712 #ifdef FEAT_QUICKFIX
6713 		|| wp->w_p_pvw
6714 #endif
6715 		|| bufIsChanged(wp->w_buffer)
6716 		|| wp->w_buffer->b_p_ro)
6717 	    *(p + len++) = ' ';
6718 	if (wp->w_buffer->b_help)
6719 	{
6720 	    STRCPY(p + len, _("[Help]"));
6721 	    len += (int)STRLEN(p + len);
6722 	}
6723 #ifdef FEAT_QUICKFIX
6724 	if (wp->w_p_pvw)
6725 	{
6726 	    STRCPY(p + len, _("[Preview]"));
6727 	    len += (int)STRLEN(p + len);
6728 	}
6729 #endif
6730 	if (bufIsChanged(wp->w_buffer))
6731 	{
6732 	    STRCPY(p + len, "[+]");
6733 	    len += 3;
6734 	}
6735 	if (wp->w_buffer->b_p_ro)
6736 	{
6737 	    STRCPY(p + len, _("[RO]"));
6738 	    len += 4;
6739 	}
6740 
6741 	this_ru_col = ru_col - (Columns - W_WIDTH(wp));
6742 	if (this_ru_col < (W_WIDTH(wp) + 1) / 2)
6743 	    this_ru_col = (W_WIDTH(wp) + 1) / 2;
6744 	if (this_ru_col <= 1)
6745 	{
6746 	    p = (char_u *)"<";		/* No room for file name! */
6747 	    len = 1;
6748 	}
6749 	else
6750 #ifdef FEAT_MBYTE
6751 	    if (has_mbyte)
6752 	    {
6753 		int	clen = 0, i;
6754 
6755 		/* Count total number of display cells. */
6756 		clen = mb_string2cells(p, -1);
6757 
6758 		/* Find first character that will fit.
6759 		 * Going from start to end is much faster for DBCS. */
6760 		for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
6761 					      i += (*mb_ptr2len)(p + i))
6762 		    clen -= (*mb_ptr2cells)(p + i);
6763 		len = clen;
6764 		if (i > 0)
6765 		{
6766 		    p = p + i - 1;
6767 		    *p = '<';
6768 		    ++len;
6769 		}
6770 
6771 	    }
6772 	    else
6773 #endif
6774 	    if (len > this_ru_col - 1)
6775 	    {
6776 		p += len - (this_ru_col - 1);
6777 		*p = '<';
6778 		len = this_ru_col - 1;
6779 	    }
6780 
6781 	row = W_WINROW(wp) + wp->w_height;
6782 	screen_puts(p, row, W_WINCOL(wp), attr);
6783 	screen_fill(row, row + 1, len + W_WINCOL(wp),
6784 			this_ru_col + W_WINCOL(wp), fillchar, fillchar, attr);
6785 
6786 	if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
6787 		&& (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
6788 	    screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
6789 						   - 1 + W_WINCOL(wp)), attr);
6790 
6791 #ifdef FEAT_CMDL_INFO
6792 	win_redr_ruler(wp, TRUE);
6793 #endif
6794     }
6795 
6796     /*
6797      * May need to draw the character below the vertical separator.
6798      */
6799     if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
6800     {
6801 	if (stl_connected(wp))
6802 	    fillchar = fillchar_status(&attr, wp == curwin);
6803 	else
6804 	    fillchar = fillchar_vsep(&attr);
6805 	screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
6806 									attr);
6807     }
6808     busy = FALSE;
6809 }
6810 
6811 #ifdef FEAT_STL_OPT
6812 /*
6813  * Redraw the status line according to 'statusline' and take care of any
6814  * errors encountered.
6815  */
6816     static void
6817 redraw_custom_statusline(win_T *wp)
6818 {
6819     static int	    entered = FALSE;
6820     int		    saved_did_emsg = did_emsg;
6821 
6822     /* When called recursively return.  This can happen when the statusline
6823      * contains an expression that triggers a redraw. */
6824     if (entered)
6825 	return;
6826     entered = TRUE;
6827 
6828     did_emsg = FALSE;
6829     win_redr_custom(wp, FALSE);
6830     if (did_emsg)
6831     {
6832 	/* When there is an error disable the statusline, otherwise the
6833 	 * display is messed up with errors and a redraw triggers the problem
6834 	 * again and again. */
6835 	set_string_option_direct((char_u *)"statusline", -1,
6836 		(char_u *)"", OPT_FREE | (*wp->w_p_stl != NUL
6837 					? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
6838     }
6839     did_emsg |= saved_did_emsg;
6840     entered = FALSE;
6841 }
6842 #endif
6843 
6844 /*
6845  * Return TRUE if the status line of window "wp" is connected to the status
6846  * line of the window right of it.  If not, then it's a vertical separator.
6847  * Only call if (wp->w_vsep_width != 0).
6848  */
6849     int
6850 stl_connected(win_T *wp)
6851 {
6852     frame_T	*fr;
6853 
6854     fr = wp->w_frame;
6855     while (fr->fr_parent != NULL)
6856     {
6857 	if (fr->fr_parent->fr_layout == FR_COL)
6858 	{
6859 	    if (fr->fr_next != NULL)
6860 		break;
6861 	}
6862 	else
6863 	{
6864 	    if (fr->fr_next != NULL)
6865 		return TRUE;
6866 	}
6867 	fr = fr->fr_parent;
6868     }
6869     return FALSE;
6870 }
6871 
6872 #endif /* FEAT_WINDOWS */
6873 
6874 #if defined(FEAT_WINDOWS) || defined(FEAT_STL_OPT) || defined(PROTO)
6875 /*
6876  * Get the value to show for the language mappings, active 'keymap'.
6877  */
6878     int
6879 get_keymap_str(
6880     win_T	*wp,
6881     char_u	*fmt,	    /* format string containing one %s item */
6882     char_u	*buf,	    /* buffer for the result */
6883     int		len)	    /* length of buffer */
6884 {
6885     char_u	*p;
6886 
6887     if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
6888 	return FALSE;
6889 
6890     {
6891 #ifdef FEAT_EVAL
6892 	buf_T	*old_curbuf = curbuf;
6893 	win_T	*old_curwin = curwin;
6894 	char_u	*s;
6895 
6896 	curbuf = wp->w_buffer;
6897 	curwin = wp;
6898 	STRCPY(buf, "b:keymap_name");	/* must be writable */
6899 	++emsg_skip;
6900 	s = p = eval_to_string(buf, NULL, FALSE);
6901 	--emsg_skip;
6902 	curbuf = old_curbuf;
6903 	curwin = old_curwin;
6904 	if (p == NULL || *p == NUL)
6905 #endif
6906 	{
6907 #ifdef FEAT_KEYMAP
6908 	    if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
6909 		p = wp->w_buffer->b_p_keymap;
6910 	    else
6911 #endif
6912 		p = (char_u *)"lang";
6913 	}
6914 	if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1)
6915 	    buf[0] = NUL;
6916 #ifdef FEAT_EVAL
6917 	vim_free(s);
6918 #endif
6919     }
6920     return buf[0] != NUL;
6921 }
6922 #endif
6923 
6924 #if defined(FEAT_STL_OPT) || defined(PROTO)
6925 /*
6926  * Redraw the status line or ruler of window "wp".
6927  * When "wp" is NULL redraw the tab pages line from 'tabline'.
6928  */
6929     static void
6930 win_redr_custom(
6931     win_T	*wp,
6932     int		draw_ruler)	/* TRUE or FALSE */
6933 {
6934     static int	entered = FALSE;
6935     int		attr;
6936     int		curattr;
6937     int		row;
6938     int		col = 0;
6939     int		maxwidth;
6940     int		width;
6941     int		n;
6942     int		len;
6943     int		fillchar;
6944     char_u	buf[MAXPATHL];
6945     char_u	*stl;
6946     char_u	*p;
6947     struct	stl_hlrec hltab[STL_MAX_ITEM];
6948     struct	stl_hlrec tabtab[STL_MAX_ITEM];
6949     int		use_sandbox = FALSE;
6950     win_T	*ewp;
6951     int		p_crb_save;
6952 
6953     /* There is a tiny chance that this gets called recursively: When
6954      * redrawing a status line triggers redrawing the ruler or tabline.
6955      * Avoid trouble by not allowing recursion. */
6956     if (entered)
6957 	return;
6958     entered = TRUE;
6959 
6960     /* setup environment for the task at hand */
6961     if (wp == NULL)
6962     {
6963 	/* Use 'tabline'.  Always at the first line of the screen. */
6964 	stl = p_tal;
6965 	row = 0;
6966 	fillchar = ' ';
6967 	attr = hl_attr(HLF_TPF);
6968 	maxwidth = Columns;
6969 # ifdef FEAT_EVAL
6970 	use_sandbox = was_set_insecurely((char_u *)"tabline", 0);
6971 # endif
6972     }
6973     else
6974     {
6975 	row = W_WINROW(wp) + wp->w_height;
6976 	fillchar = fillchar_status(&attr, wp == curwin);
6977 	maxwidth = W_WIDTH(wp);
6978 
6979 	if (draw_ruler)
6980 	{
6981 	    stl = p_ruf;
6982 	    /* advance past any leading group spec - implicit in ru_col */
6983 	    if (*stl == '%')
6984 	    {
6985 		if (*++stl == '-')
6986 		    stl++;
6987 		if (atoi((char *)stl))
6988 		    while (VIM_ISDIGIT(*stl))
6989 			stl++;
6990 		if (*stl++ != '(')
6991 		    stl = p_ruf;
6992 	    }
6993 #ifdef FEAT_WINDOWS
6994 	    col = ru_col - (Columns - W_WIDTH(wp));
6995 	    if (col < (W_WIDTH(wp) + 1) / 2)
6996 		col = (W_WIDTH(wp) + 1) / 2;
6997 #else
6998 	    col = ru_col;
6999 	    if (col > (Columns + 1) / 2)
7000 		col = (Columns + 1) / 2;
7001 #endif
7002 	    maxwidth = W_WIDTH(wp) - col;
7003 #ifdef FEAT_WINDOWS
7004 	    if (!wp->w_status_height)
7005 #endif
7006 	    {
7007 		row = Rows - 1;
7008 		--maxwidth;	/* writing in last column may cause scrolling */
7009 		fillchar = ' ';
7010 		attr = 0;
7011 	    }
7012 
7013 # ifdef FEAT_EVAL
7014 	    use_sandbox = was_set_insecurely((char_u *)"rulerformat", 0);
7015 # endif
7016 	}
7017 	else
7018 	{
7019 	    if (*wp->w_p_stl != NUL)
7020 		stl = wp->w_p_stl;
7021 	    else
7022 		stl = p_stl;
7023 # ifdef FEAT_EVAL
7024 	    use_sandbox = was_set_insecurely((char_u *)"statusline",
7025 					 *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
7026 # endif
7027 	}
7028 
7029 #ifdef FEAT_WINDOWS
7030 	col += W_WINCOL(wp);
7031 #endif
7032     }
7033 
7034     if (maxwidth <= 0)
7035 	goto theend;
7036 
7037     /* Temporarily reset 'cursorbind', we don't want a side effect from moving
7038      * the cursor away and back. */
7039     ewp = wp == NULL ? curwin : wp;
7040     p_crb_save = ewp->w_p_crb;
7041     ewp->w_p_crb = FALSE;
7042 
7043     /* Make a copy, because the statusline may include a function call that
7044      * might change the option value and free the memory. */
7045     stl = vim_strsave(stl);
7046     width = build_stl_str_hl(ewp, buf, sizeof(buf),
7047 				stl, use_sandbox,
7048 				fillchar, maxwidth, hltab, tabtab);
7049     vim_free(stl);
7050     ewp->w_p_crb = p_crb_save;
7051 
7052     /* Make all characters printable. */
7053     p = transstr(buf);
7054     if (p != NULL)
7055     {
7056 	vim_strncpy(buf, p, sizeof(buf) - 1);
7057 	vim_free(p);
7058     }
7059 
7060     /* fill up with "fillchar" */
7061     len = (int)STRLEN(buf);
7062     while (width < maxwidth && len < (int)sizeof(buf) - 1)
7063     {
7064 #ifdef FEAT_MBYTE
7065 	len += (*mb_char2bytes)(fillchar, buf + len);
7066 #else
7067 	buf[len++] = fillchar;
7068 #endif
7069 	++width;
7070     }
7071     buf[len] = NUL;
7072 
7073     /*
7074      * Draw each snippet with the specified highlighting.
7075      */
7076     curattr = attr;
7077     p = buf;
7078     for (n = 0; hltab[n].start != NULL; n++)
7079     {
7080 	len = (int)(hltab[n].start - p);
7081 	screen_puts_len(p, len, row, col, curattr);
7082 	col += vim_strnsize(p, len);
7083 	p = hltab[n].start;
7084 
7085 	if (hltab[n].userhl == 0)
7086 	    curattr = attr;
7087 	else if (hltab[n].userhl < 0)
7088 	    curattr = syn_id2attr(-hltab[n].userhl);
7089 #ifdef FEAT_WINDOWS
7090 	else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
7091 	    curattr = highlight_stlnc[hltab[n].userhl - 1];
7092 #endif
7093 	else
7094 	    curattr = highlight_user[hltab[n].userhl - 1];
7095     }
7096     screen_puts(p, row, col, curattr);
7097 
7098     if (wp == NULL)
7099     {
7100 	/* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
7101 	col = 0;
7102 	len = 0;
7103 	p = buf;
7104 	fillchar = 0;
7105 	for (n = 0; tabtab[n].start != NULL; n++)
7106 	{
7107 	    len += vim_strnsize(p, (int)(tabtab[n].start - p));
7108 	    while (col < len)
7109 		TabPageIdxs[col++] = fillchar;
7110 	    p = tabtab[n].start;
7111 	    fillchar = tabtab[n].userhl;
7112 	}
7113 	while (col < Columns)
7114 	    TabPageIdxs[col++] = fillchar;
7115     }
7116 
7117 theend:
7118     entered = FALSE;
7119 }
7120 
7121 #endif /* FEAT_STL_OPT */
7122 
7123 /*
7124  * Output a single character directly to the screen and update ScreenLines.
7125  */
7126     void
7127 screen_putchar(int c, int row, int col, int attr)
7128 {
7129     char_u	buf[MB_MAXBYTES + 1];
7130 
7131 #ifdef FEAT_MBYTE
7132     if (has_mbyte)
7133 	buf[(*mb_char2bytes)(c, buf)] = NUL;
7134     else
7135 #endif
7136     {
7137 	buf[0] = c;
7138 	buf[1] = NUL;
7139     }
7140     screen_puts(buf, row, col, attr);
7141 }
7142 
7143 /*
7144  * Get a single character directly from ScreenLines into "bytes[]".
7145  * Also return its attribute in *attrp;
7146  */
7147     void
7148 screen_getbytes(int row, int col, char_u *bytes, int *attrp)
7149 {
7150     unsigned off;
7151 
7152     /* safety check */
7153     if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
7154     {
7155 	off = LineOffset[row] + col;
7156 	*attrp = ScreenAttrs[off];
7157 	bytes[0] = ScreenLines[off];
7158 	bytes[1] = NUL;
7159 
7160 #ifdef FEAT_MBYTE
7161 	if (enc_utf8 && ScreenLinesUC[off] != 0)
7162 	    bytes[utfc_char2bytes(off, bytes)] = NUL;
7163 	else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
7164 	{
7165 	    bytes[0] = ScreenLines[off];
7166 	    bytes[1] = ScreenLines2[off];
7167 	    bytes[2] = NUL;
7168 	}
7169 	else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
7170 	{
7171 	    bytes[1] = ScreenLines[off + 1];
7172 	    bytes[2] = NUL;
7173 	}
7174 #endif
7175     }
7176 }
7177 
7178 #ifdef FEAT_MBYTE
7179 static int screen_comp_differs(int, int*);
7180 
7181 /*
7182  * Return TRUE if composing characters for screen posn "off" differs from
7183  * composing characters in "u8cc".
7184  * Only to be used when ScreenLinesUC[off] != 0.
7185  */
7186     static int
7187 screen_comp_differs(int off, int *u8cc)
7188 {
7189     int	    i;
7190 
7191     for (i = 0; i < Screen_mco; ++i)
7192     {
7193 	if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
7194 	    return TRUE;
7195 	if (u8cc[i] == 0)
7196 	    break;
7197     }
7198     return FALSE;
7199 }
7200 #endif
7201 
7202 /*
7203  * Put string '*text' on the screen at position 'row' and 'col', with
7204  * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
7205  * Note: only outputs within one row, message is truncated at screen boundary!
7206  * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
7207  */
7208     void
7209 screen_puts(
7210     char_u	*text,
7211     int		row,
7212     int		col,
7213     int		attr)
7214 {
7215     screen_puts_len(text, -1, row, col, attr);
7216 }
7217 
7218 /*
7219  * Like screen_puts(), but output "text[len]".  When "len" is -1 output up to
7220  * a NUL.
7221  */
7222     void
7223 screen_puts_len(
7224     char_u	*text,
7225     int		textlen,
7226     int		row,
7227     int		col,
7228     int		attr)
7229 {
7230     unsigned	off;
7231     char_u	*ptr = text;
7232     int		len = textlen;
7233     int		c;
7234 #ifdef FEAT_MBYTE
7235     unsigned	max_off;
7236     int		mbyte_blen = 1;
7237     int		mbyte_cells = 1;
7238     int		u8c = 0;
7239     int		u8cc[MAX_MCO];
7240     int		clear_next_cell = FALSE;
7241 # ifdef FEAT_ARABIC
7242     int		prev_c = 0;		/* previous Arabic character */
7243     int		pc, nc, nc1;
7244     int		pcc[MAX_MCO];
7245 # endif
7246 #endif
7247 #if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7248     int		force_redraw_this;
7249     int		force_redraw_next = FALSE;
7250 #endif
7251     int		need_redraw;
7252 
7253     if (ScreenLines == NULL || row >= screen_Rows)	/* safety check */
7254 	return;
7255     off = LineOffset[row] + col;
7256 
7257 #ifdef FEAT_MBYTE
7258     /* When drawing over the right halve of a double-wide char clear out the
7259      * left halve.  Only needed in a terminal. */
7260     if (has_mbyte && col > 0 && col < screen_Columns
7261 # ifdef FEAT_GUI
7262 	    && !gui.in_use
7263 # endif
7264 	    && mb_fix_col(col, row) != col)
7265     {
7266 	ScreenLines[off - 1] = ' ';
7267 	ScreenAttrs[off - 1] = 0;
7268 	if (enc_utf8)
7269 	{
7270 	    ScreenLinesUC[off - 1] = 0;
7271 	    ScreenLinesC[0][off - 1] = 0;
7272 	}
7273 	/* redraw the previous cell, make it empty */
7274 	screen_char(off - 1, row, col - 1);
7275 	/* force the cell at "col" to be redrawn */
7276 	force_redraw_next = TRUE;
7277     }
7278 #endif
7279 
7280 #ifdef FEAT_MBYTE
7281     max_off = LineOffset[row] + screen_Columns;
7282 #endif
7283     while (col < screen_Columns
7284 	    && (len < 0 || (int)(ptr - text) < len)
7285 	    && *ptr != NUL)
7286     {
7287 	c = *ptr;
7288 #ifdef FEAT_MBYTE
7289 	/* check if this is the first byte of a multibyte */
7290 	if (has_mbyte)
7291 	{
7292 	    if (enc_utf8 && len > 0)
7293 		mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
7294 	    else
7295 		mbyte_blen = (*mb_ptr2len)(ptr);
7296 	    if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7297 		mbyte_cells = 1;
7298 	    else if (enc_dbcs != 0)
7299 		mbyte_cells = mbyte_blen;
7300 	    else	/* enc_utf8 */
7301 	    {
7302 		if (len >= 0)
7303 		    u8c = utfc_ptr2char_len(ptr, u8cc,
7304 						   (int)((text + len) - ptr));
7305 		else
7306 		    u8c = utfc_ptr2char(ptr, u8cc);
7307 		mbyte_cells = utf_char2cells(u8c);
7308 # ifdef UNICODE16
7309 		/* Non-BMP character: display as ? or fullwidth ?. */
7310 		if (u8c >= 0x10000)
7311 		{
7312 		    u8c = (mbyte_cells == 2) ? 0xff1f : (int)'?';
7313 		    if (attr == 0)
7314 			attr = hl_attr(HLF_8);
7315 		}
7316 # endif
7317 # ifdef FEAT_ARABIC
7318 		if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
7319 		{
7320 		    /* Do Arabic shaping. */
7321 		    if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
7322 		    {
7323 			/* Past end of string to be displayed. */
7324 			nc = NUL;
7325 			nc1 = NUL;
7326 		    }
7327 		    else
7328 		    {
7329 			nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
7330 				      (int)((text + len) - ptr - mbyte_blen));
7331 			nc1 = pcc[0];
7332 		    }
7333 		    pc = prev_c;
7334 		    prev_c = u8c;
7335 		    u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
7336 		}
7337 		else
7338 		    prev_c = u8c;
7339 # endif
7340 		if (col + mbyte_cells > screen_Columns)
7341 		{
7342 		    /* Only 1 cell left, but character requires 2 cells:
7343 		     * display a '>' in the last column to avoid wrapping. */
7344 		    c = '>';
7345 		    mbyte_cells = 1;
7346 		}
7347 	    }
7348 	}
7349 #endif
7350 
7351 #if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7352 	force_redraw_this = force_redraw_next;
7353 	force_redraw_next = FALSE;
7354 #endif
7355 
7356 	need_redraw = ScreenLines[off] != c
7357 #ifdef FEAT_MBYTE
7358 		|| (mbyte_cells == 2
7359 		    && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
7360 		|| (enc_dbcs == DBCS_JPNU
7361 		    && c == 0x8e
7362 		    && ScreenLines2[off] != ptr[1])
7363 		|| (enc_utf8
7364 		    && (ScreenLinesUC[off] !=
7365 				(u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
7366 			|| (ScreenLinesUC[off] != 0
7367 					  && screen_comp_differs(off, u8cc))))
7368 #endif
7369 		|| ScreenAttrs[off] != attr
7370 		|| exmode_active;
7371 
7372 	if (need_redraw
7373 #if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7374 		|| force_redraw_this
7375 #endif
7376 		)
7377 	{
7378 #if defined(FEAT_GUI) || defined(UNIX)
7379 	    /* The bold trick makes a single row of pixels appear in the next
7380 	     * character.  When a bold character is removed, the next
7381 	     * character should be redrawn too.  This happens for our own GUI
7382 	     * and for some xterms. */
7383 	    if (need_redraw && ScreenLines[off] != ' ' && (
7384 # ifdef FEAT_GUI
7385 		    gui.in_use
7386 # endif
7387 # if defined(FEAT_GUI) && defined(UNIX)
7388 		    ||
7389 # endif
7390 # ifdef UNIX
7391 		    term_is_xterm
7392 # endif
7393 		    ))
7394 	    {
7395 		int	n = ScreenAttrs[off];
7396 
7397 		if (n > HL_ALL)
7398 		    n = syn_attr2attr(n);
7399 		if (n & HL_BOLD)
7400 		    force_redraw_next = TRUE;
7401 	    }
7402 #endif
7403 #ifdef FEAT_MBYTE
7404 	    /* When at the end of the text and overwriting a two-cell
7405 	     * character with a one-cell character, need to clear the next
7406 	     * cell.  Also when overwriting the left halve of a two-cell char
7407 	     * with the right halve of a two-cell char.  Do this only once
7408 	     * (mb_off2cells() may return 2 on the right halve). */
7409 	    if (clear_next_cell)
7410 		clear_next_cell = FALSE;
7411 	    else if (has_mbyte
7412 		    && (len < 0 ? ptr[mbyte_blen] == NUL
7413 					     : ptr + mbyte_blen >= text + len)
7414 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
7415 			|| (mbyte_cells == 2
7416 			    && (*mb_off2cells)(off, max_off) == 1
7417 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
7418 		clear_next_cell = TRUE;
7419 
7420 	    /* Make sure we never leave a second byte of a double-byte behind,
7421 	     * it confuses mb_off2cells(). */
7422 	    if (enc_dbcs
7423 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
7424 			|| (mbyte_cells == 2
7425 			    && (*mb_off2cells)(off, max_off) == 1
7426 			    && (*mb_off2cells)(off + 1, max_off) > 1)))
7427 		ScreenLines[off + mbyte_blen] = 0;
7428 #endif
7429 	    ScreenLines[off] = c;
7430 	    ScreenAttrs[off] = attr;
7431 #ifdef FEAT_MBYTE
7432 	    if (enc_utf8)
7433 	    {
7434 		if (c < 0x80 && u8cc[0] == 0)
7435 		    ScreenLinesUC[off] = 0;
7436 		else
7437 		{
7438 		    int	    i;
7439 
7440 		    ScreenLinesUC[off] = u8c;
7441 		    for (i = 0; i < Screen_mco; ++i)
7442 		    {
7443 			ScreenLinesC[i][off] = u8cc[i];
7444 			if (u8cc[i] == 0)
7445 			    break;
7446 		    }
7447 		}
7448 		if (mbyte_cells == 2)
7449 		{
7450 		    ScreenLines[off + 1] = 0;
7451 		    ScreenAttrs[off + 1] = attr;
7452 		}
7453 		screen_char(off, row, col);
7454 	    }
7455 	    else if (mbyte_cells == 2)
7456 	    {
7457 		ScreenLines[off + 1] = ptr[1];
7458 		ScreenAttrs[off + 1] = attr;
7459 		screen_char_2(off, row, col);
7460 	    }
7461 	    else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
7462 	    {
7463 		ScreenLines2[off] = ptr[1];
7464 		screen_char(off, row, col);
7465 	    }
7466 	    else
7467 #endif
7468 		screen_char(off, row, col);
7469 	}
7470 #ifdef FEAT_MBYTE
7471 	if (has_mbyte)
7472 	{
7473 	    off += mbyte_cells;
7474 	    col += mbyte_cells;
7475 	    ptr += mbyte_blen;
7476 	    if (clear_next_cell)
7477 	    {
7478 		/* This only happens at the end, display one space next. */
7479 		ptr = (char_u *)" ";
7480 		len = -1;
7481 	    }
7482 	}
7483 	else
7484 #endif
7485 	{
7486 	    ++off;
7487 	    ++col;
7488 	    ++ptr;
7489 	}
7490     }
7491 
7492 #if defined(FEAT_MBYTE) || defined(FEAT_GUI) || defined(UNIX)
7493     /* If we detected the next character needs to be redrawn, but the text
7494      * doesn't extend up to there, update the character here. */
7495     if (force_redraw_next && col < screen_Columns)
7496     {
7497 # ifdef FEAT_MBYTE
7498 	if (enc_dbcs != 0 && dbcs_off2cells(off, max_off) > 1)
7499 	    screen_char_2(off, row, col);
7500 	else
7501 # endif
7502 	    screen_char(off, row, col);
7503     }
7504 #endif
7505 }
7506 
7507 #ifdef FEAT_SEARCH_EXTRA
7508 /*
7509  * Prepare for 'hlsearch' highlighting.
7510  */
7511     static void
7512 start_search_hl(void)
7513 {
7514     if (p_hls && !no_hlsearch)
7515     {
7516 	last_pat_prog(&search_hl.rm);
7517 	search_hl.attr = hl_attr(HLF_L);
7518 # ifdef FEAT_RELTIME
7519 	/* Set the time limit to 'redrawtime'. */
7520 	profile_setlimit(p_rdt, &search_hl.tm);
7521 # endif
7522     }
7523 }
7524 
7525 /*
7526  * Clean up for 'hlsearch' highlighting.
7527  */
7528     static void
7529 end_search_hl(void)
7530 {
7531     if (search_hl.rm.regprog != NULL)
7532     {
7533 	vim_regfree(search_hl.rm.regprog);
7534 	search_hl.rm.regprog = NULL;
7535     }
7536 }
7537 
7538 /*
7539  * Init for calling prepare_search_hl().
7540  */
7541     static void
7542 init_search_hl(win_T *wp)
7543 {
7544     matchitem_T *cur;
7545 
7546     /* Setup for match and 'hlsearch' highlighting.  Disable any previous
7547      * match */
7548     cur = wp->w_match_head;
7549     while (cur != NULL)
7550     {
7551 	cur->hl.rm = cur->match;
7552 	if (cur->hlg_id == 0)
7553 	    cur->hl.attr = 0;
7554 	else
7555 	    cur->hl.attr = syn_id2attr(cur->hlg_id);
7556 	cur->hl.buf = wp->w_buffer;
7557 	cur->hl.lnum = 0;
7558 	cur->hl.first_lnum = 0;
7559 # ifdef FEAT_RELTIME
7560 	/* Set the time limit to 'redrawtime'. */
7561 	profile_setlimit(p_rdt, &(cur->hl.tm));
7562 # endif
7563 	cur = cur->next;
7564     }
7565     search_hl.buf = wp->w_buffer;
7566     search_hl.lnum = 0;
7567     search_hl.first_lnum = 0;
7568     /* time limit is set at the toplevel, for all windows */
7569 }
7570 
7571 /*
7572  * Advance to the match in window "wp" line "lnum" or past it.
7573  */
7574     static void
7575 prepare_search_hl(win_T *wp, linenr_T lnum)
7576 {
7577     matchitem_T *cur;		/* points to the match list */
7578     match_T	*shl;		/* points to search_hl or a match */
7579     int		shl_flag;	/* flag to indicate whether search_hl
7580 				   has been processed or not */
7581     int		pos_inprogress;	/* marks that position match search is
7582 				   in progress */
7583     int		n;
7584 
7585     /*
7586      * When using a multi-line pattern, start searching at the top
7587      * of the window or just after a closed fold.
7588      * Do this both for search_hl and the match list.
7589      */
7590     cur = wp->w_match_head;
7591     shl_flag = FALSE;
7592     while (cur != NULL || shl_flag == FALSE)
7593     {
7594 	if (shl_flag == FALSE)
7595 	{
7596 	    shl = &search_hl;
7597 	    shl_flag = TRUE;
7598 	}
7599 	else
7600 	    shl = &cur->hl;
7601 	if (shl->rm.regprog != NULL
7602 		&& shl->lnum == 0
7603 		&& re_multiline(shl->rm.regprog))
7604 	{
7605 	    if (shl->first_lnum == 0)
7606 	    {
7607 # ifdef FEAT_FOLDING
7608 		for (shl->first_lnum = lnum;
7609 			   shl->first_lnum > wp->w_topline; --shl->first_lnum)
7610 		    if (hasFoldingWin(wp, shl->first_lnum - 1,
7611 						      NULL, NULL, TRUE, NULL))
7612 			break;
7613 # else
7614 		shl->first_lnum = wp->w_topline;
7615 # endif
7616 	    }
7617 	    if (cur != NULL)
7618 		cur->pos.cur = 0;
7619 	    pos_inprogress = TRUE;
7620 	    n = 0;
7621 	    while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
7622 					  || (cur != NULL && pos_inprogress)))
7623 	    {
7624 		next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n,
7625 					       shl == &search_hl ? NULL : cur);
7626 		pos_inprogress = cur == NULL || cur->pos.cur == 0
7627 							      ? FALSE : TRUE;
7628 		if (shl->lnum != 0)
7629 		{
7630 		    shl->first_lnum = shl->lnum
7631 				    + shl->rm.endpos[0].lnum
7632 				    - shl->rm.startpos[0].lnum;
7633 		    n = shl->rm.endpos[0].col;
7634 		}
7635 		else
7636 		{
7637 		    ++shl->first_lnum;
7638 		    n = 0;
7639 		}
7640 	    }
7641 	}
7642 	if (shl != &search_hl && cur != NULL)
7643 	    cur = cur->next;
7644     }
7645 }
7646 
7647 /*
7648  * Search for a next 'hlsearch' or match.
7649  * Uses shl->buf.
7650  * Sets shl->lnum and shl->rm contents.
7651  * Note: Assumes a previous match is always before "lnum", unless
7652  * shl->lnum is zero.
7653  * Careful: Any pointers for buffer lines will become invalid.
7654  */
7655     static void
7656 next_search_hl(
7657     win_T	    *win,
7658     match_T	    *shl,	/* points to search_hl or a match */
7659     linenr_T	    lnum,
7660     colnr_T	    mincol,	/* minimal column for a match */
7661     matchitem_T	    *cur)	/* to retrieve match positions if any */
7662 {
7663     linenr_T	l;
7664     colnr_T	matchcol;
7665     long	nmatched;
7666 
7667     if (shl->lnum != 0)
7668     {
7669 	/* Check for three situations:
7670 	 * 1. If the "lnum" is below a previous match, start a new search.
7671 	 * 2. If the previous match includes "mincol", use it.
7672 	 * 3. Continue after the previous match.
7673 	 */
7674 	l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
7675 	if (lnum > l)
7676 	    shl->lnum = 0;
7677 	else if (lnum < l || shl->rm.endpos[0].col > mincol)
7678 	    return;
7679     }
7680 
7681     /*
7682      * Repeat searching for a match until one is found that includes "mincol"
7683      * or none is found in this line.
7684      */
7685     called_emsg = FALSE;
7686     for (;;)
7687     {
7688 #ifdef FEAT_RELTIME
7689 	/* Stop searching after passing the time limit. */
7690 	if (profile_passed_limit(&(shl->tm)))
7691 	{
7692 	    shl->lnum = 0;		/* no match found in time */
7693 	    break;
7694 	}
7695 #endif
7696 	/* Three situations:
7697 	 * 1. No useful previous match: search from start of line.
7698 	 * 2. Not Vi compatible or empty match: continue at next character.
7699 	 *    Break the loop if this is beyond the end of the line.
7700 	 * 3. Vi compatible searching: continue at end of previous match.
7701 	 */
7702 	if (shl->lnum == 0)
7703 	    matchcol = 0;
7704 	else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
7705 		|| (shl->rm.endpos[0].lnum == 0
7706 		    && shl->rm.endpos[0].col <= shl->rm.startpos[0].col))
7707 	{
7708 	    char_u	*ml;
7709 
7710 	    matchcol = shl->rm.startpos[0].col;
7711 	    ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
7712 	    if (*ml == NUL)
7713 	    {
7714 		++matchcol;
7715 		shl->lnum = 0;
7716 		break;
7717 	    }
7718 #ifdef FEAT_MBYTE
7719 	    if (has_mbyte)
7720 		matchcol += mb_ptr2len(ml);
7721 	    else
7722 #endif
7723 		++matchcol;
7724 	}
7725 	else
7726 	    matchcol = shl->rm.endpos[0].col;
7727 
7728 	shl->lnum = lnum;
7729 	if (shl->rm.regprog != NULL)
7730 	{
7731 	    /* Remember whether shl->rm is using a copy of the regprog in
7732 	     * cur->match. */
7733 	    int regprog_is_copy = (shl != &search_hl && cur != NULL
7734 				&& shl == &cur->hl
7735 				&& cur->match.regprog == cur->hl.rm.regprog);
7736 
7737 	    nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
7738 		    matchcol,
7739 #ifdef FEAT_RELTIME
7740 		    &(shl->tm)
7741 #else
7742 		    NULL
7743 #endif
7744 		    );
7745 	    /* Copy the regprog, in case it got freed and recompiled. */
7746 	    if (regprog_is_copy)
7747 		cur->match.regprog = cur->hl.rm.regprog;
7748 
7749 	    if (called_emsg || got_int)
7750 	    {
7751 		/* Error while handling regexp: stop using this regexp. */
7752 		if (shl == &search_hl)
7753 		{
7754 		    /* don't free regprog in the match list, it's a copy */
7755 		    vim_regfree(shl->rm.regprog);
7756 		    SET_NO_HLSEARCH(TRUE);
7757 		}
7758 		shl->rm.regprog = NULL;
7759 		shl->lnum = 0;
7760 		got_int = FALSE;  /* avoid the "Type :quit to exit Vim"
7761 				     message */
7762 		break;
7763 	    }
7764 	}
7765 	else if (cur != NULL)
7766 	    nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol);
7767 	else
7768 	    nmatched = 0;
7769 	if (nmatched == 0)
7770 	{
7771 	    shl->lnum = 0;		/* no match found */
7772 	    break;
7773 	}
7774 	if (shl->rm.startpos[0].lnum > 0
7775 		|| shl->rm.startpos[0].col >= mincol
7776 		|| nmatched > 1
7777 		|| shl->rm.endpos[0].col > mincol)
7778 	{
7779 	    shl->lnum += shl->rm.startpos[0].lnum;
7780 	    break;			/* useful match found */
7781 	}
7782     }
7783 }
7784 
7785 /*
7786  * If there is a match fill "shl" and return one.
7787  * Return zero otherwise.
7788  */
7789     static int
7790 next_search_hl_pos(
7791     match_T	    *shl,	/* points to a match */
7792     linenr_T	    lnum,
7793     posmatch_T	    *posmatch,	/* match positions */
7794     colnr_T	    mincol)	/* minimal column for a match */
7795 {
7796     int	    i;
7797     int	    found = -1;
7798 
7799     for (i = posmatch->cur; i < MAXPOSMATCH; i++)
7800     {
7801 	llpos_T	*pos = &posmatch->pos[i];
7802 
7803 	if (pos->lnum == 0)
7804 	    break;
7805 	if (pos->len == 0 && pos->col < mincol)
7806 	    continue;
7807 	if (pos->lnum == lnum)
7808 	{
7809 	    if (found >= 0)
7810 	    {
7811 		/* if this match comes before the one at "found" then swap
7812 		 * them */
7813 		if (pos->col < posmatch->pos[found].col)
7814 		{
7815 		    llpos_T	tmp = *pos;
7816 
7817 		    *pos = posmatch->pos[found];
7818 		    posmatch->pos[found] = tmp;
7819 		}
7820 	    }
7821 	    else
7822 		found = i;
7823 	}
7824     }
7825     posmatch->cur = 0;
7826     if (found >= 0)
7827     {
7828 	colnr_T	start = posmatch->pos[found].col == 0
7829 					    ? 0 : posmatch->pos[found].col - 1;
7830 	colnr_T	end = posmatch->pos[found].col == 0
7831 				   ? MAXCOL : start + posmatch->pos[found].len;
7832 
7833 	shl->lnum = lnum;
7834 	shl->rm.startpos[0].lnum = 0;
7835 	shl->rm.startpos[0].col = start;
7836 	shl->rm.endpos[0].lnum = 0;
7837 	shl->rm.endpos[0].col = end;
7838 	shl->is_addpos = TRUE;
7839 	posmatch->cur = found + 1;
7840 	return 1;
7841     }
7842     return 0;
7843 }
7844 #endif
7845 
7846       static void
7847 screen_start_highlight(int attr)
7848 {
7849     attrentry_T *aep = NULL;
7850 
7851     screen_attr = attr;
7852     if (full_screen
7853 #ifdef WIN3264
7854 		    && termcap_active
7855 #endif
7856 				       )
7857     {
7858 #ifdef FEAT_GUI
7859 	if (gui.in_use)
7860 	{
7861 	    char	buf[20];
7862 
7863 	    /* The GUI handles this internally. */
7864 	    sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);
7865 	    OUT_STR(buf);
7866 	}
7867 	else
7868 #endif
7869 	{
7870 	    if (attr > HL_ALL)				/* special HL attr. */
7871 	    {
7872 		if (IS_CTERM)
7873 		    aep = syn_cterm_attr2entry(attr);
7874 		else
7875 		    aep = syn_term_attr2entry(attr);
7876 		if (aep == NULL)	    /* did ":syntax clear" */
7877 		    attr = 0;
7878 		else
7879 		    attr = aep->ae_attr;
7880 	    }
7881 	    if ((attr & HL_BOLD) && T_MD != NULL)	/* bold */
7882 		out_str(T_MD);
7883 	    else if (aep != NULL && cterm_normal_fg_bold &&
7884 #ifdef FEAT_TERMGUICOLORS
7885 			(p_tgc ?
7886 			    (aep->ae_u.cterm.fg_rgb != INVALCOLOR):
7887 #endif
7888 			    (t_colors > 1 && aep->ae_u.cterm.fg_color)
7889 #ifdef FEAT_TERMGUICOLORS
7890 			)
7891 #endif
7892 		    )
7893 		/* If the Normal FG color has BOLD attribute and the new HL
7894 		 * has a FG color defined, clear BOLD. */
7895 		out_str(T_ME);
7896 	    if ((attr & HL_STANDOUT) && T_SO != NULL)	/* standout */
7897 		out_str(T_SO);
7898 	    if ((attr & (HL_UNDERLINE | HL_UNDERCURL)) && T_US != NULL)
7899 						   /* underline or undercurl */
7900 		out_str(T_US);
7901 	    if ((attr & HL_ITALIC) && T_CZH != NULL)	/* italic */
7902 		out_str(T_CZH);
7903 	    if ((attr & HL_INVERSE) && T_MR != NULL)	/* inverse (reverse) */
7904 		out_str(T_MR);
7905 
7906 	    /*
7907 	     * Output the color or start string after bold etc., in case the
7908 	     * bold etc. override the color setting.
7909 	     */
7910 	    if (aep != NULL)
7911 	    {
7912 #ifdef FEAT_TERMGUICOLORS
7913 		if (p_tgc)
7914 		{
7915 		    if (aep->ae_u.cterm.fg_rgb != INVALCOLOR)
7916 			term_fg_rgb_color(aep->ae_u.cterm.fg_rgb);
7917 		    if (aep->ae_u.cterm.bg_rgb != INVALCOLOR)
7918 			term_bg_rgb_color(aep->ae_u.cterm.bg_rgb);
7919 		}
7920 		else
7921 #endif
7922 		{
7923 		    if (t_colors > 1)
7924 		    {
7925 			if (aep->ae_u.cterm.fg_color)
7926 			    term_fg_color(aep->ae_u.cterm.fg_color - 1);
7927 			if (aep->ae_u.cterm.bg_color)
7928 			    term_bg_color(aep->ae_u.cterm.bg_color - 1);
7929 		    }
7930 		    else
7931 		    {
7932 			if (aep->ae_u.term.start != NULL)
7933 			    out_str(aep->ae_u.term.start);
7934 		    }
7935 		}
7936 	    }
7937 	}
7938     }
7939 }
7940 
7941       void
7942 screen_stop_highlight(void)
7943 {
7944     int	    do_ME = FALSE;	    /* output T_ME code */
7945 
7946     if (screen_attr != 0
7947 #ifdef WIN3264
7948 			&& termcap_active
7949 #endif
7950 					   )
7951     {
7952 #ifdef FEAT_GUI
7953 	if (gui.in_use)
7954 	{
7955 	    char	buf[20];
7956 
7957 	    /* use internal GUI code */
7958 	    sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
7959 	    OUT_STR(buf);
7960 	}
7961 	else
7962 #endif
7963 	{
7964 	    if (screen_attr > HL_ALL)			/* special HL attr. */
7965 	    {
7966 		attrentry_T *aep;
7967 
7968 		if (IS_CTERM)
7969 		{
7970 		    /*
7971 		     * Assume that t_me restores the original colors!
7972 		     */
7973 		    aep = syn_cterm_attr2entry(screen_attr);
7974 		    if (aep != NULL &&
7975 #ifdef FEAT_TERMGUICOLORS
7976 			    (p_tgc ?
7977 				(aep->ae_u.cterm.fg_rgb != INVALCOLOR
7978 				 || aep->ae_u.cterm.bg_rgb != INVALCOLOR):
7979 #endif
7980 				(aep->ae_u.cterm.fg_color || aep->ae_u.cterm.bg_color)
7981 #ifdef FEAT_TERMGUICOLORS
7982 			    )
7983 #endif
7984 			)
7985 			do_ME = TRUE;
7986 		}
7987 		else
7988 		{
7989 		    aep = syn_term_attr2entry(screen_attr);
7990 		    if (aep != NULL && aep->ae_u.term.stop != NULL)
7991 		    {
7992 			if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
7993 			    do_ME = TRUE;
7994 			else
7995 			    out_str(aep->ae_u.term.stop);
7996 		    }
7997 		}
7998 		if (aep == NULL)	    /* did ":syntax clear" */
7999 		    screen_attr = 0;
8000 		else
8001 		    screen_attr = aep->ae_attr;
8002 	    }
8003 
8004 	    /*
8005 	     * Often all ending-codes are equal to T_ME.  Avoid outputting the
8006 	     * same sequence several times.
8007 	     */
8008 	    if (screen_attr & HL_STANDOUT)
8009 	    {
8010 		if (STRCMP(T_SE, T_ME) == 0)
8011 		    do_ME = TRUE;
8012 		else
8013 		    out_str(T_SE);
8014 	    }
8015 	    if (screen_attr & (HL_UNDERLINE | HL_UNDERCURL))
8016 	    {
8017 		if (STRCMP(T_UE, T_ME) == 0)
8018 		    do_ME = TRUE;
8019 		else
8020 		    out_str(T_UE);
8021 	    }
8022 	    if (screen_attr & HL_ITALIC)
8023 	    {
8024 		if (STRCMP(T_CZR, T_ME) == 0)
8025 		    do_ME = TRUE;
8026 		else
8027 		    out_str(T_CZR);
8028 	    }
8029 	    if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
8030 		out_str(T_ME);
8031 
8032 #ifdef FEAT_TERMGUICOLORS
8033 	    if (p_tgc)
8034 	    {
8035 		if (cterm_normal_fg_gui_color != INVALCOLOR)
8036 		    term_fg_rgb_color(cterm_normal_fg_gui_color);
8037 		if (cterm_normal_bg_gui_color != INVALCOLOR)
8038 		    term_bg_rgb_color(cterm_normal_bg_gui_color);
8039 	    }
8040 	    else
8041 #endif
8042 	    {
8043 		if (t_colors > 1)
8044 		{
8045 		    /* set Normal cterm colors */
8046 		    if (cterm_normal_fg_color != 0)
8047 			term_fg_color(cterm_normal_fg_color - 1);
8048 		    if (cterm_normal_bg_color != 0)
8049 			term_bg_color(cterm_normal_bg_color - 1);
8050 		    if (cterm_normal_fg_bold)
8051 			out_str(T_MD);
8052 		}
8053 	    }
8054 	}
8055     }
8056     screen_attr = 0;
8057 }
8058 
8059 /*
8060  * Reset the colors for a cterm.  Used when leaving Vim.
8061  * The machine specific code may override this again.
8062  */
8063     void
8064 reset_cterm_colors(void)
8065 {
8066     if (IS_CTERM)
8067     {
8068 	/* set Normal cterm colors */
8069 #ifdef FEAT_TERMGUICOLORS
8070 	if (p_tgc ? (cterm_normal_fg_gui_color != INVALCOLOR
8071 		 || cterm_normal_bg_gui_color != INVALCOLOR)
8072 		: (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0))
8073 #else
8074 	if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
8075 #endif
8076 	{
8077 	    out_str(T_OP);
8078 	    screen_attr = -1;
8079 	}
8080 	if (cterm_normal_fg_bold)
8081 	{
8082 	    out_str(T_ME);
8083 	    screen_attr = -1;
8084 	}
8085     }
8086 }
8087 
8088 /*
8089  * Put character ScreenLines["off"] on the screen at position "row" and "col",
8090  * using the attributes from ScreenAttrs["off"].
8091  */
8092     static void
8093 screen_char(unsigned off, int row, int col)
8094 {
8095     int		attr;
8096 
8097     /* Check for illegal values, just in case (could happen just after
8098      * resizing). */
8099     if (row >= screen_Rows || col >= screen_Columns)
8100 	return;
8101 
8102     /* Outputting a character in the last cell on the screen may scroll the
8103      * screen up.  Only do it when the "xn" termcap property is set, otherwise
8104      * mark the character invalid (update it when scrolled up). */
8105     if (*T_XN == NUL
8106 	    && row == screen_Rows - 1 && col == screen_Columns - 1
8107 #ifdef FEAT_RIGHTLEFT
8108 	    /* account for first command-line character in rightleft mode */
8109 	    && !cmdmsg_rl
8110 #endif
8111        )
8112     {
8113 	ScreenAttrs[off] = (sattr_T)-1;
8114 	return;
8115     }
8116 
8117     /*
8118      * Stop highlighting first, so it's easier to move the cursor.
8119      */
8120 #if defined(FEAT_CLIPBOARD) || defined(FEAT_WINDOWS)
8121     if (screen_char_attr != 0)
8122 	attr = screen_char_attr;
8123     else
8124 #endif
8125 	attr = ScreenAttrs[off];
8126     if (screen_attr != attr)
8127 	screen_stop_highlight();
8128 
8129     windgoto(row, col);
8130 
8131     if (screen_attr != attr)
8132 	screen_start_highlight(attr);
8133 
8134 #ifdef FEAT_MBYTE
8135     if (enc_utf8 && ScreenLinesUC[off] != 0)
8136     {
8137 	char_u	    buf[MB_MAXBYTES + 1];
8138 
8139 	/* Convert UTF-8 character to bytes and write it. */
8140 
8141 	buf[utfc_char2bytes(off, buf)] = NUL;
8142 
8143 	out_str(buf);
8144 	if (utf_ambiguous_width(ScreenLinesUC[off]))
8145 	    screen_cur_col = 9999;
8146 	else if (utf_char2cells(ScreenLinesUC[off]) > 1)
8147 	    ++screen_cur_col;
8148     }
8149     else
8150 #endif
8151     {
8152 #ifdef FEAT_MBYTE
8153 	out_flush_check();
8154 #endif
8155 	out_char(ScreenLines[off]);
8156 #ifdef FEAT_MBYTE
8157 	/* double-byte character in single-width cell */
8158 	if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
8159 	    out_char(ScreenLines2[off]);
8160 #endif
8161     }
8162 
8163     screen_cur_col++;
8164 }
8165 
8166 #ifdef FEAT_MBYTE
8167 
8168 /*
8169  * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
8170  * on the screen at position 'row' and 'col'.
8171  * The attributes of the first byte is used for all.  This is required to
8172  * output the two bytes of a double-byte character with nothing in between.
8173  */
8174     static void
8175 screen_char_2(unsigned off, int row, int col)
8176 {
8177     /* Check for illegal values (could be wrong when screen was resized). */
8178     if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
8179 	return;
8180 
8181     /* Outputting the last character on the screen may scrollup the screen.
8182      * Don't to it!  Mark the character invalid (update it when scrolled up) */
8183     if (row == screen_Rows - 1 && col >= screen_Columns - 2)
8184     {
8185 	ScreenAttrs[off] = (sattr_T)-1;
8186 	return;
8187     }
8188 
8189     /* Output the first byte normally (positions the cursor), then write the
8190      * second byte directly. */
8191     screen_char(off, row, col);
8192     out_char(ScreenLines[off + 1]);
8193     ++screen_cur_col;
8194 }
8195 #endif
8196 
8197 #if defined(FEAT_CLIPBOARD) || defined(FEAT_WINDOWS) || defined(PROTO)
8198 /*
8199  * Draw a rectangle of the screen, inverted when "invert" is TRUE.
8200  * This uses the contents of ScreenLines[] and doesn't change it.
8201  */
8202     void
8203 screen_draw_rectangle(
8204     int		row,
8205     int		col,
8206     int		height,
8207     int		width,
8208     int		invert)
8209 {
8210     int		r, c;
8211     int		off;
8212 #ifdef FEAT_MBYTE
8213     int		max_off;
8214 #endif
8215 
8216     /* Can't use ScreenLines unless initialized */
8217     if (ScreenLines == NULL)
8218 	return;
8219 
8220     if (invert)
8221 	screen_char_attr = HL_INVERSE;
8222     for (r = row; r < row + height; ++r)
8223     {
8224 	off = LineOffset[r];
8225 #ifdef FEAT_MBYTE
8226 	max_off = off + screen_Columns;
8227 #endif
8228 	for (c = col; c < col + width; ++c)
8229 	{
8230 #ifdef FEAT_MBYTE
8231 	    if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1)
8232 	    {
8233 		screen_char_2(off + c, r, c);
8234 		++c;
8235 	    }
8236 	    else
8237 #endif
8238 	    {
8239 		screen_char(off + c, r, c);
8240 #ifdef FEAT_MBYTE
8241 		if (utf_off2cells(off + c, max_off) > 1)
8242 		    ++c;
8243 #endif
8244 	    }
8245 	}
8246     }
8247     screen_char_attr = 0;
8248 }
8249 #endif
8250 
8251 #ifdef FEAT_WINDOWS
8252 /*
8253  * Redraw the characters for a vertically split window.
8254  */
8255     static void
8256 redraw_block(int row, int end, win_T *wp)
8257 {
8258     int		col;
8259     int		width;
8260 
8261 # ifdef FEAT_CLIPBOARD
8262     clip_may_clear_selection(row, end - 1);
8263 # endif
8264 
8265     if (wp == NULL)
8266     {
8267 	col = 0;
8268 	width = Columns;
8269     }
8270     else
8271     {
8272 	col = wp->w_wincol;
8273 	width = wp->w_width;
8274     }
8275     screen_draw_rectangle(row, col, end - row, width, FALSE);
8276 }
8277 #endif
8278 
8279 /*
8280  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
8281  * with character 'c1' in first column followed by 'c2' in the other columns.
8282  * Use attributes 'attr'.
8283  */
8284     void
8285 screen_fill(
8286     int	    start_row,
8287     int	    end_row,
8288     int	    start_col,
8289     int	    end_col,
8290     int	    c1,
8291     int	    c2,
8292     int	    attr)
8293 {
8294     int		    row;
8295     int		    col;
8296     int		    off;
8297     int		    end_off;
8298     int		    did_delete;
8299     int		    c;
8300     int		    norm_term;
8301 #if defined(FEAT_GUI) || defined(UNIX)
8302     int		    force_next = FALSE;
8303 #endif
8304 
8305     if (end_row > screen_Rows)		/* safety check */
8306 	end_row = screen_Rows;
8307     if (end_col > screen_Columns)	/* safety check */
8308 	end_col = screen_Columns;
8309     if (ScreenLines == NULL
8310 	    || start_row >= end_row
8311 	    || start_col >= end_col)	/* nothing to do */
8312 	return;
8313 
8314     /* it's a "normal" terminal when not in a GUI or cterm */
8315     norm_term = (
8316 #ifdef FEAT_GUI
8317 	    !gui.in_use &&
8318 #endif
8319 	    !IS_CTERM);
8320     for (row = start_row; row < end_row; ++row)
8321     {
8322 #ifdef FEAT_MBYTE
8323 	if (has_mbyte
8324 # ifdef FEAT_GUI
8325 		&& !gui.in_use
8326 # endif
8327 	   )
8328 	{
8329 	    /* When drawing over the right halve of a double-wide char clear
8330 	     * out the left halve.  When drawing over the left halve of a
8331 	     * double wide-char clear out the right halve.  Only needed in a
8332 	     * terminal. */
8333 	    if (start_col > 0 && mb_fix_col(start_col, row) != start_col)
8334 		screen_puts_len((char_u *)" ", 1, row, start_col - 1, 0);
8335 	    if (end_col < screen_Columns && mb_fix_col(end_col, row) != end_col)
8336 		screen_puts_len((char_u *)" ", 1, row, end_col, 0);
8337 	}
8338 #endif
8339 	/*
8340 	 * Try to use delete-line termcap code, when no attributes or in a
8341 	 * "normal" terminal, where a bold/italic space is just a
8342 	 * space.
8343 	 */
8344 	did_delete = FALSE;
8345 	if (c2 == ' '
8346 		&& end_col == Columns
8347 		&& can_clear(T_CE)
8348 		&& (attr == 0
8349 		    || (norm_term
8350 			&& attr <= HL_ALL
8351 			&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
8352 	{
8353 	    /*
8354 	     * check if we really need to clear something
8355 	     */
8356 	    col = start_col;
8357 	    if (c1 != ' ')			/* don't clear first char */
8358 		++col;
8359 
8360 	    off = LineOffset[row] + col;
8361 	    end_off = LineOffset[row] + end_col;
8362 
8363 	    /* skip blanks (used often, keep it fast!) */
8364 #ifdef FEAT_MBYTE
8365 	    if (enc_utf8)
8366 		while (off < end_off && ScreenLines[off] == ' '
8367 			  && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
8368 		    ++off;
8369 	    else
8370 #endif
8371 		while (off < end_off && ScreenLines[off] == ' '
8372 						     && ScreenAttrs[off] == 0)
8373 		    ++off;
8374 	    if (off < end_off)		/* something to be cleared */
8375 	    {
8376 		col = off - LineOffset[row];
8377 		screen_stop_highlight();
8378 		term_windgoto(row, col);/* clear rest of this screen line */
8379 		out_str(T_CE);
8380 		screen_start();		/* don't know where cursor is now */
8381 		col = end_col - col;
8382 		while (col--)		/* clear chars in ScreenLines */
8383 		{
8384 		    ScreenLines[off] = ' ';
8385 #ifdef FEAT_MBYTE
8386 		    if (enc_utf8)
8387 			ScreenLinesUC[off] = 0;
8388 #endif
8389 		    ScreenAttrs[off] = 0;
8390 		    ++off;
8391 		}
8392 	    }
8393 	    did_delete = TRUE;		/* the chars are cleared now */
8394 	}
8395 
8396 	off = LineOffset[row] + start_col;
8397 	c = c1;
8398 	for (col = start_col; col < end_col; ++col)
8399 	{
8400 	    if (ScreenLines[off] != c
8401 #ifdef FEAT_MBYTE
8402 		    || (enc_utf8 && (int)ScreenLinesUC[off]
8403 						       != (c >= 0x80 ? c : 0))
8404 #endif
8405 		    || ScreenAttrs[off] != attr
8406 #if defined(FEAT_GUI) || defined(UNIX)
8407 		    || force_next
8408 #endif
8409 		    )
8410 	    {
8411 #if defined(FEAT_GUI) || defined(UNIX)
8412 		/* The bold trick may make a single row of pixels appear in
8413 		 * the next character.  When a bold character is removed, the
8414 		 * next character should be redrawn too.  This happens for our
8415 		 * own GUI and for some xterms.  */
8416 		if (
8417 # ifdef FEAT_GUI
8418 			gui.in_use
8419 # endif
8420 # if defined(FEAT_GUI) && defined(UNIX)
8421 			||
8422 # endif
8423 # ifdef UNIX
8424 			term_is_xterm
8425 # endif
8426 		   )
8427 		{
8428 		    if (ScreenLines[off] != ' '
8429 			    && (ScreenAttrs[off] > HL_ALL
8430 				|| ScreenAttrs[off] & HL_BOLD))
8431 			force_next = TRUE;
8432 		    else
8433 			force_next = FALSE;
8434 		}
8435 #endif
8436 		ScreenLines[off] = c;
8437 #ifdef FEAT_MBYTE
8438 		if (enc_utf8)
8439 		{
8440 		    if (c >= 0x80)
8441 		    {
8442 			ScreenLinesUC[off] = c;
8443 			ScreenLinesC[0][off] = 0;
8444 		    }
8445 		    else
8446 			ScreenLinesUC[off] = 0;
8447 		}
8448 #endif
8449 		ScreenAttrs[off] = attr;
8450 		if (!did_delete || c != ' ')
8451 		    screen_char(off, row, col);
8452 	    }
8453 	    ++off;
8454 	    if (col == start_col)
8455 	    {
8456 		if (did_delete)
8457 		    break;
8458 		c = c2;
8459 	    }
8460 	}
8461 	if (end_col == Columns)
8462 	    LineWraps[row] = FALSE;
8463 	if (row == Rows - 1)		/* overwritten the command line */
8464 	{
8465 	    redraw_cmdline = TRUE;
8466 	    if (c1 == ' ' && c2 == ' ')
8467 		clear_cmdline = FALSE;	/* command line has been cleared */
8468 	    if (start_col == 0)
8469 		mode_displayed = FALSE; /* mode cleared or overwritten */
8470 	}
8471     }
8472 }
8473 
8474 /*
8475  * Check if there should be a delay.  Used before clearing or redrawing the
8476  * screen or the command line.
8477  */
8478     void
8479 check_for_delay(int check_msg_scroll)
8480 {
8481     if ((emsg_on_display || (check_msg_scroll && msg_scroll))
8482 	    && !did_wait_return
8483 	    && emsg_silent == 0)
8484     {
8485 	out_flush();
8486 	ui_delay(1000L, TRUE);
8487 	emsg_on_display = FALSE;
8488 	if (check_msg_scroll)
8489 	    msg_scroll = FALSE;
8490     }
8491 }
8492 
8493 /*
8494  * screen_valid -  allocate screen buffers if size changed
8495  *   If "doclear" is TRUE: clear screen if it has been resized.
8496  *	Returns TRUE if there is a valid screen to write to.
8497  *	Returns FALSE when starting up and screen not initialized yet.
8498  */
8499     int
8500 screen_valid(int doclear)
8501 {
8502     screenalloc(doclear);	   /* allocate screen buffers if size changed */
8503     return (ScreenLines != NULL);
8504 }
8505 
8506 /*
8507  * Resize the shell to Rows and Columns.
8508  * Allocate ScreenLines[] and associated items.
8509  *
8510  * There may be some time between setting Rows and Columns and (re)allocating
8511  * ScreenLines[].  This happens when starting up and when (manually) changing
8512  * the shell size.  Always use screen_Rows and screen_Columns to access items
8513  * in ScreenLines[].  Use Rows and Columns for positioning text etc. where the
8514  * final size of the shell is needed.
8515  */
8516     void
8517 screenalloc(int doclear)
8518 {
8519     int		    new_row, old_row;
8520 #ifdef FEAT_GUI
8521     int		    old_Rows;
8522 #endif
8523     win_T	    *wp;
8524     int		    outofmem = FALSE;
8525     int		    len;
8526     schar_T	    *new_ScreenLines;
8527 #ifdef FEAT_MBYTE
8528     u8char_T	    *new_ScreenLinesUC = NULL;
8529     u8char_T	    *new_ScreenLinesC[MAX_MCO];
8530     schar_T	    *new_ScreenLines2 = NULL;
8531     int		    i;
8532 #endif
8533     sattr_T	    *new_ScreenAttrs;
8534     unsigned	    *new_LineOffset;
8535     char_u	    *new_LineWraps;
8536 #ifdef FEAT_WINDOWS
8537     short	    *new_TabPageIdxs;
8538     tabpage_T	    *tp;
8539 #endif
8540     static int	    entered = FALSE;		/* avoid recursiveness */
8541     static int	    done_outofmem_msg = FALSE;	/* did outofmem message */
8542 #ifdef FEAT_AUTOCMD
8543     int		    retry_count = 0;
8544 
8545 retry:
8546 #endif
8547     /*
8548      * Allocation of the screen buffers is done only when the size changes and
8549      * when Rows and Columns have been set and we have started doing full
8550      * screen stuff.
8551      */
8552     if ((ScreenLines != NULL
8553 		&& Rows == screen_Rows
8554 		&& Columns == screen_Columns
8555 #ifdef FEAT_MBYTE
8556 		&& enc_utf8 == (ScreenLinesUC != NULL)
8557 		&& (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
8558 		&& p_mco == Screen_mco
8559 #endif
8560 		)
8561 	    || Rows == 0
8562 	    || Columns == 0
8563 	    || (!full_screen && ScreenLines == NULL))
8564 	return;
8565 
8566     /*
8567      * It's possible that we produce an out-of-memory message below, which
8568      * will cause this function to be called again.  To break the loop, just
8569      * return here.
8570      */
8571     if (entered)
8572 	return;
8573     entered = TRUE;
8574 
8575     /*
8576      * Note that the window sizes are updated before reallocating the arrays,
8577      * thus we must not redraw here!
8578      */
8579     ++RedrawingDisabled;
8580 
8581     win_new_shellsize();    /* fit the windows in the new sized shell */
8582 
8583     comp_col();		/* recompute columns for shown command and ruler */
8584 
8585     /*
8586      * We're changing the size of the screen.
8587      * - Allocate new arrays for ScreenLines and ScreenAttrs.
8588      * - Move lines from the old arrays into the new arrays, clear extra
8589      *	 lines (unless the screen is going to be cleared).
8590      * - Free the old arrays.
8591      *
8592      * If anything fails, make ScreenLines NULL, so we don't do anything!
8593      * Continuing with the old ScreenLines may result in a crash, because the
8594      * size is wrong.
8595      */
8596     FOR_ALL_TAB_WINDOWS(tp, wp)
8597 	win_free_lsize(wp);
8598 #ifdef FEAT_AUTOCMD
8599     if (aucmd_win != NULL)
8600 	win_free_lsize(aucmd_win);
8601 #endif
8602 
8603     new_ScreenLines = (schar_T *)lalloc((long_u)(
8604 			      (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
8605 #ifdef FEAT_MBYTE
8606     vim_memset(new_ScreenLinesC, 0, sizeof(u8char_T *) * MAX_MCO);
8607     if (enc_utf8)
8608     {
8609 	new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
8610 			     (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
8611 	for (i = 0; i < p_mco; ++i)
8612 	    new_ScreenLinesC[i] = (u8char_T *)lalloc_clear((long_u)(
8613 			     (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
8614     }
8615     if (enc_dbcs == DBCS_JPNU)
8616 	new_ScreenLines2 = (schar_T *)lalloc((long_u)(
8617 			     (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
8618 #endif
8619     new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
8620 			      (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
8621     new_LineOffset = (unsigned *)lalloc((long_u)(
8622 					 Rows * sizeof(unsigned)), FALSE);
8623     new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
8624 #ifdef FEAT_WINDOWS
8625     new_TabPageIdxs = (short *)lalloc((long_u)(Columns * sizeof(short)), FALSE);
8626 #endif
8627 
8628     FOR_ALL_TAB_WINDOWS(tp, wp)
8629     {
8630 	if (win_alloc_lines(wp) == FAIL)
8631 	{
8632 	    outofmem = TRUE;
8633 #ifdef FEAT_WINDOWS
8634 	    goto give_up;
8635 #endif
8636 	}
8637     }
8638 #ifdef FEAT_AUTOCMD
8639     if (aucmd_win != NULL && aucmd_win->w_lines == NULL
8640 					&& win_alloc_lines(aucmd_win) == FAIL)
8641 	outofmem = TRUE;
8642 #endif
8643 #ifdef FEAT_WINDOWS
8644 give_up:
8645 #endif
8646 
8647 #ifdef FEAT_MBYTE
8648     for (i = 0; i < p_mco; ++i)
8649 	if (new_ScreenLinesC[i] == NULL)
8650 	    break;
8651 #endif
8652     if (new_ScreenLines == NULL
8653 #ifdef FEAT_MBYTE
8654 	    || (enc_utf8 && (new_ScreenLinesUC == NULL || i != p_mco))
8655 	    || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
8656 #endif
8657 	    || new_ScreenAttrs == NULL
8658 	    || new_LineOffset == NULL
8659 	    || new_LineWraps == NULL
8660 #ifdef FEAT_WINDOWS
8661 	    || new_TabPageIdxs == NULL
8662 #endif
8663 	    || outofmem)
8664     {
8665 	if (ScreenLines != NULL || !done_outofmem_msg)
8666 	{
8667 	    /* guess the size */
8668 	    do_outofmem_msg((long_u)((Rows + 1) * Columns));
8669 
8670 	    /* Remember we did this to avoid getting outofmem messages over
8671 	     * and over again. */
8672 	    done_outofmem_msg = TRUE;
8673 	}
8674 	vim_free(new_ScreenLines);
8675 	new_ScreenLines = NULL;
8676 #ifdef FEAT_MBYTE
8677 	vim_free(new_ScreenLinesUC);
8678 	new_ScreenLinesUC = NULL;
8679 	for (i = 0; i < p_mco; ++i)
8680 	{
8681 	    vim_free(new_ScreenLinesC[i]);
8682 	    new_ScreenLinesC[i] = NULL;
8683 	}
8684 	vim_free(new_ScreenLines2);
8685 	new_ScreenLines2 = NULL;
8686 #endif
8687 	vim_free(new_ScreenAttrs);
8688 	new_ScreenAttrs = NULL;
8689 	vim_free(new_LineOffset);
8690 	new_LineOffset = NULL;
8691 	vim_free(new_LineWraps);
8692 	new_LineWraps = NULL;
8693 #ifdef FEAT_WINDOWS
8694 	vim_free(new_TabPageIdxs);
8695 	new_TabPageIdxs = NULL;
8696 #endif
8697     }
8698     else
8699     {
8700 	done_outofmem_msg = FALSE;
8701 
8702 	for (new_row = 0; new_row < Rows; ++new_row)
8703 	{
8704 	    new_LineOffset[new_row] = new_row * Columns;
8705 	    new_LineWraps[new_row] = FALSE;
8706 
8707 	    /*
8708 	     * If the screen is not going to be cleared, copy as much as
8709 	     * possible from the old screen to the new one and clear the rest
8710 	     * (used when resizing the window at the "--more--" prompt or when
8711 	     * executing an external command, for the GUI).
8712 	     */
8713 	    if (!doclear)
8714 	    {
8715 		(void)vim_memset(new_ScreenLines + new_row * Columns,
8716 				      ' ', (size_t)Columns * sizeof(schar_T));
8717 #ifdef FEAT_MBYTE
8718 		if (enc_utf8)
8719 		{
8720 		    (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
8721 				       0, (size_t)Columns * sizeof(u8char_T));
8722 		    for (i = 0; i < p_mco; ++i)
8723 			(void)vim_memset(new_ScreenLinesC[i]
8724 							  + new_row * Columns,
8725 				       0, (size_t)Columns * sizeof(u8char_T));
8726 		}
8727 		if (enc_dbcs == DBCS_JPNU)
8728 		    (void)vim_memset(new_ScreenLines2 + new_row * Columns,
8729 				       0, (size_t)Columns * sizeof(schar_T));
8730 #endif
8731 		(void)vim_memset(new_ScreenAttrs + new_row * Columns,
8732 					0, (size_t)Columns * sizeof(sattr_T));
8733 		old_row = new_row + (screen_Rows - Rows);
8734 		if (old_row >= 0 && ScreenLines != NULL)
8735 		{
8736 		    if (screen_Columns < Columns)
8737 			len = screen_Columns;
8738 		    else
8739 			len = Columns;
8740 #ifdef FEAT_MBYTE
8741 		    /* When switching to utf-8 don't copy characters, they
8742 		     * may be invalid now.  Also when p_mco changes. */
8743 		    if (!(enc_utf8 && ScreenLinesUC == NULL)
8744 						       && p_mco == Screen_mco)
8745 #endif
8746 			mch_memmove(new_ScreenLines + new_LineOffset[new_row],
8747 				ScreenLines + LineOffset[old_row],
8748 				(size_t)len * sizeof(schar_T));
8749 #ifdef FEAT_MBYTE
8750 		    if (enc_utf8 && ScreenLinesUC != NULL
8751 						       && p_mco == Screen_mco)
8752 		    {
8753 			mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
8754 				ScreenLinesUC + LineOffset[old_row],
8755 				(size_t)len * sizeof(u8char_T));
8756 			for (i = 0; i < p_mco; ++i)
8757 			    mch_memmove(new_ScreenLinesC[i]
8758 						    + new_LineOffset[new_row],
8759 				ScreenLinesC[i] + LineOffset[old_row],
8760 				(size_t)len * sizeof(u8char_T));
8761 		    }
8762 		    if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
8763 			mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
8764 				ScreenLines2 + LineOffset[old_row],
8765 				(size_t)len * sizeof(schar_T));
8766 #endif
8767 		    mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
8768 			    ScreenAttrs + LineOffset[old_row],
8769 			    (size_t)len * sizeof(sattr_T));
8770 		}
8771 	    }
8772 	}
8773 	/* Use the last line of the screen for the current line. */
8774 	current_ScreenLine = new_ScreenLines + Rows * Columns;
8775     }
8776 
8777     free_screenlines();
8778 
8779     ScreenLines = new_ScreenLines;
8780 #ifdef FEAT_MBYTE
8781     ScreenLinesUC = new_ScreenLinesUC;
8782     for (i = 0; i < p_mco; ++i)
8783 	ScreenLinesC[i] = new_ScreenLinesC[i];
8784     Screen_mco = p_mco;
8785     ScreenLines2 = new_ScreenLines2;
8786 #endif
8787     ScreenAttrs = new_ScreenAttrs;
8788     LineOffset = new_LineOffset;
8789     LineWraps = new_LineWraps;
8790 #ifdef FEAT_WINDOWS
8791     TabPageIdxs = new_TabPageIdxs;
8792 #endif
8793 
8794     /* It's important that screen_Rows and screen_Columns reflect the actual
8795      * size of ScreenLines[].  Set them before calling anything. */
8796 #ifdef FEAT_GUI
8797     old_Rows = screen_Rows;
8798 #endif
8799     screen_Rows = Rows;
8800     screen_Columns = Columns;
8801 
8802     must_redraw = CLEAR;	/* need to clear the screen later */
8803     if (doclear)
8804 	screenclear2();
8805 
8806 #ifdef FEAT_GUI
8807     else if (gui.in_use
8808 	    && !gui.starting
8809 	    && ScreenLines != NULL
8810 	    && old_Rows != Rows)
8811     {
8812 	(void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
8813 	/*
8814 	 * Adjust the position of the cursor, for when executing an external
8815 	 * command.
8816 	 */
8817 	if (msg_row >= Rows)		/* Rows got smaller */
8818 	    msg_row = Rows - 1;		/* put cursor at last row */
8819 	else if (Rows > old_Rows)	/* Rows got bigger */
8820 	    msg_row += Rows - old_Rows; /* put cursor in same place */
8821 	if (msg_col >= Columns)		/* Columns got smaller */
8822 	    msg_col = Columns - 1;	/* put cursor at last column */
8823     }
8824 #endif
8825 
8826     entered = FALSE;
8827     --RedrawingDisabled;
8828 
8829 #ifdef FEAT_AUTOCMD
8830     /*
8831      * Do not apply autocommands more than 3 times to avoid an endless loop
8832      * in case applying autocommands always changes Rows or Columns.
8833      */
8834     if (starting == 0 && ++retry_count <= 3)
8835     {
8836 	apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
8837 	/* In rare cases, autocommands may have altered Rows or Columns,
8838 	 * jump back to check if we need to allocate the screen again. */
8839 	goto retry;
8840     }
8841 #endif
8842 }
8843 
8844     void
8845 free_screenlines(void)
8846 {
8847 #ifdef FEAT_MBYTE
8848     int		i;
8849 
8850     vim_free(ScreenLinesUC);
8851     for (i = 0; i < Screen_mco; ++i)
8852 	vim_free(ScreenLinesC[i]);
8853     vim_free(ScreenLines2);
8854 #endif
8855     vim_free(ScreenLines);
8856     vim_free(ScreenAttrs);
8857     vim_free(LineOffset);
8858     vim_free(LineWraps);
8859 #ifdef FEAT_WINDOWS
8860     vim_free(TabPageIdxs);
8861 #endif
8862 }
8863 
8864     void
8865 screenclear(void)
8866 {
8867     check_for_delay(FALSE);
8868     screenalloc(FALSE);	    /* allocate screen buffers if size changed */
8869     screenclear2();	    /* clear the screen */
8870 }
8871 
8872     static void
8873 screenclear2(void)
8874 {
8875     int	    i;
8876 
8877     if (starting == NO_SCREEN || ScreenLines == NULL
8878 #ifdef FEAT_GUI
8879 	    || (gui.in_use && gui.starting)
8880 #endif
8881 	    )
8882 	return;
8883 
8884 #ifdef FEAT_GUI
8885     if (!gui.in_use)
8886 #endif
8887 	screen_attr = -1;	/* force setting the Normal colors */
8888     screen_stop_highlight();	/* don't want highlighting here */
8889 
8890 #ifdef FEAT_CLIPBOARD
8891     /* disable selection without redrawing it */
8892     clip_scroll_selection(9999);
8893 #endif
8894 
8895     /* blank out ScreenLines */
8896     for (i = 0; i < Rows; ++i)
8897     {
8898 	lineclear(LineOffset[i], (int)Columns);
8899 	LineWraps[i] = FALSE;
8900     }
8901 
8902     if (can_clear(T_CL))
8903     {
8904 	out_str(T_CL);		/* clear the display */
8905 	clear_cmdline = FALSE;
8906 	mode_displayed = FALSE;
8907     }
8908     else
8909     {
8910 	/* can't clear the screen, mark all chars with invalid attributes */
8911 	for (i = 0; i < Rows; ++i)
8912 	    lineinvalid(LineOffset[i], (int)Columns);
8913 	clear_cmdline = TRUE;
8914     }
8915 
8916     screen_cleared = TRUE;	/* can use contents of ScreenLines now */
8917 
8918     win_rest_invalid(firstwin);
8919     redraw_cmdline = TRUE;
8920 #ifdef FEAT_WINDOWS
8921     redraw_tabline = TRUE;
8922 #endif
8923     if (must_redraw == CLEAR)	/* no need to clear again */
8924 	must_redraw = NOT_VALID;
8925     compute_cmdrow();
8926     msg_row = cmdline_row;	/* put cursor on last line for messages */
8927     msg_col = 0;
8928     screen_start();		/* don't know where cursor is now */
8929     msg_scrolled = 0;		/* can't scroll back */
8930     msg_didany = FALSE;
8931     msg_didout = FALSE;
8932 }
8933 
8934 /*
8935  * Clear one line in ScreenLines.
8936  */
8937     static void
8938 lineclear(unsigned off, int width)
8939 {
8940     (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
8941 #ifdef FEAT_MBYTE
8942     if (enc_utf8)
8943 	(void)vim_memset(ScreenLinesUC + off, 0,
8944 					  (size_t)width * sizeof(u8char_T));
8945 #endif
8946     (void)vim_memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
8947 }
8948 
8949 /*
8950  * Mark one line in ScreenLines invalid by setting the attributes to an
8951  * invalid value.
8952  */
8953     static void
8954 lineinvalid(unsigned off, int width)
8955 {
8956     (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
8957 }
8958 
8959 #ifdef FEAT_WINDOWS
8960 /*
8961  * Copy part of a Screenline for vertically split window "wp".
8962  */
8963     static void
8964 linecopy(int to, int from, win_T *wp)
8965 {
8966     unsigned	off_to = LineOffset[to] + wp->w_wincol;
8967     unsigned	off_from = LineOffset[from] + wp->w_wincol;
8968 
8969     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
8970 	    wp->w_width * sizeof(schar_T));
8971 # ifdef FEAT_MBYTE
8972     if (enc_utf8)
8973     {
8974 	int	i;
8975 
8976 	mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
8977 		wp->w_width * sizeof(u8char_T));
8978 	for (i = 0; i < p_mco; ++i)
8979 	    mch_memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
8980 		    wp->w_width * sizeof(u8char_T));
8981     }
8982     if (enc_dbcs == DBCS_JPNU)
8983 	mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
8984 		wp->w_width * sizeof(schar_T));
8985 # endif
8986     mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
8987 	    wp->w_width * sizeof(sattr_T));
8988 }
8989 #endif
8990 
8991 /*
8992  * Return TRUE if clearing with term string "p" would work.
8993  * It can't work when the string is empty or it won't set the right background.
8994  */
8995     int
8996 can_clear(char_u *p)
8997 {
8998     return (*p != NUL && (t_colors <= 1
8999 #ifdef FEAT_GUI
9000 		|| gui.in_use
9001 #endif
9002 #ifdef FEAT_TERMGUICOLORS
9003 		|| (p_tgc && cterm_normal_bg_gui_color == INVALCOLOR)
9004 		|| (!p_tgc && cterm_normal_bg_color == 0)
9005 #else
9006 		|| cterm_normal_bg_color == 0
9007 #endif
9008 		|| *T_UT != NUL));
9009 }
9010 
9011 /*
9012  * Reset cursor position. Use whenever cursor was moved because of outputting
9013  * something directly to the screen (shell commands) or a terminal control
9014  * code.
9015  */
9016     void
9017 screen_start(void)
9018 {
9019     screen_cur_row = screen_cur_col = 9999;
9020 }
9021 
9022 /*
9023  * Move the cursor to position "row","col" in the screen.
9024  * This tries to find the most efficient way to move, minimizing the number of
9025  * characters sent to the terminal.
9026  */
9027     void
9028 windgoto(int row, int col)
9029 {
9030     sattr_T	    *p;
9031     int		    i;
9032     int		    plan;
9033     int		    cost;
9034     int		    wouldbe_col;
9035     int		    noinvcurs;
9036     char_u	    *bs;
9037     int		    goto_cost;
9038     int		    attr;
9039 
9040 #define GOTO_COST   7	/* assume a term_windgoto() takes about 7 chars */
9041 #define HIGHL_COST  5	/* assume unhighlight takes 5 chars */
9042 
9043 #define PLAN_LE	    1
9044 #define PLAN_CR	    2
9045 #define PLAN_NL	    3
9046 #define PLAN_WRITE  4
9047     /* Can't use ScreenLines unless initialized */
9048     if (ScreenLines == NULL)
9049 	return;
9050 
9051     if (col != screen_cur_col || row != screen_cur_row)
9052     {
9053 	/* Check for valid position. */
9054 	if (row < 0)	/* window without text lines? */
9055 	    row = 0;
9056 	if (row >= screen_Rows)
9057 	    row = screen_Rows - 1;
9058 	if (col >= screen_Columns)
9059 	    col = screen_Columns - 1;
9060 
9061 	/* check if no cursor movement is allowed in highlight mode */
9062 	if (screen_attr && *T_MS == NUL)
9063 	    noinvcurs = HIGHL_COST;
9064 	else
9065 	    noinvcurs = 0;
9066 	goto_cost = GOTO_COST + noinvcurs;
9067 
9068 	/*
9069 	 * Plan how to do the positioning:
9070 	 * 1. Use CR to move it to column 0, same row.
9071 	 * 2. Use T_LE to move it a few columns to the left.
9072 	 * 3. Use NL to move a few lines down, column 0.
9073 	 * 4. Move a few columns to the right with T_ND or by writing chars.
9074 	 *
9075 	 * Don't do this if the cursor went beyond the last column, the cursor
9076 	 * position is unknown then (some terminals wrap, some don't )
9077 	 *
9078 	 * First check if the highlighting attributes allow us to write
9079 	 * characters to move the cursor to the right.
9080 	 */
9081 	if (row >= screen_cur_row && screen_cur_col < Columns)
9082 	{
9083 	    /*
9084 	     * If the cursor is in the same row, bigger col, we can use CR
9085 	     * or T_LE.
9086 	     */
9087 	    bs = NULL;			    /* init for GCC */
9088 	    attr = screen_attr;
9089 	    if (row == screen_cur_row && col < screen_cur_col)
9090 	    {
9091 		/* "le" is preferred over "bc", because "bc" is obsolete */
9092 		if (*T_LE)
9093 		    bs = T_LE;		    /* "cursor left" */
9094 		else
9095 		    bs = T_BC;		    /* "backspace character (old) */
9096 		if (*bs)
9097 		    cost = (screen_cur_col - col) * (int)STRLEN(bs);
9098 		else
9099 		    cost = 999;
9100 		if (col + 1 < cost)	    /* using CR is less characters */
9101 		{
9102 		    plan = PLAN_CR;
9103 		    wouldbe_col = 0;
9104 		    cost = 1;		    /* CR is just one character */
9105 		}
9106 		else
9107 		{
9108 		    plan = PLAN_LE;
9109 		    wouldbe_col = col;
9110 		}
9111 		if (noinvcurs)		    /* will stop highlighting */
9112 		{
9113 		    cost += noinvcurs;
9114 		    attr = 0;
9115 		}
9116 	    }
9117 
9118 	    /*
9119 	     * If the cursor is above where we want to be, we can use CR LF.
9120 	     */
9121 	    else if (row > screen_cur_row)
9122 	    {
9123 		plan = PLAN_NL;
9124 		wouldbe_col = 0;
9125 		cost = (row - screen_cur_row) * 2;  /* CR LF */
9126 		if (noinvcurs)		    /* will stop highlighting */
9127 		{
9128 		    cost += noinvcurs;
9129 		    attr = 0;
9130 		}
9131 	    }
9132 
9133 	    /*
9134 	     * If the cursor is in the same row, smaller col, just use write.
9135 	     */
9136 	    else
9137 	    {
9138 		plan = PLAN_WRITE;
9139 		wouldbe_col = screen_cur_col;
9140 		cost = 0;
9141 	    }
9142 
9143 	    /*
9144 	     * Check if any characters that need to be written have the
9145 	     * correct attributes.  Also avoid UTF-8 characters.
9146 	     */
9147 	    i = col - wouldbe_col;
9148 	    if (i > 0)
9149 		cost += i;
9150 	    if (cost < goto_cost && i > 0)
9151 	    {
9152 		/*
9153 		 * Check if the attributes are correct without additionally
9154 		 * stopping highlighting.
9155 		 */
9156 		p = ScreenAttrs + LineOffset[row] + wouldbe_col;
9157 		while (i && *p++ == attr)
9158 		    --i;
9159 		if (i != 0)
9160 		{
9161 		    /*
9162 		     * Try if it works when highlighting is stopped here.
9163 		     */
9164 		    if (*--p == 0)
9165 		    {
9166 			cost += noinvcurs;
9167 			while (i && *p++ == 0)
9168 			    --i;
9169 		    }
9170 		    if (i != 0)
9171 			cost = 999;	/* different attributes, don't do it */
9172 		}
9173 #ifdef FEAT_MBYTE
9174 		if (enc_utf8)
9175 		{
9176 		    /* Don't use an UTF-8 char for positioning, it's slow. */
9177 		    for (i = wouldbe_col; i < col; ++i)
9178 			if (ScreenLinesUC[LineOffset[row] + i] != 0)
9179 			{
9180 			    cost = 999;
9181 			    break;
9182 			}
9183 		}
9184 #endif
9185 	    }
9186 
9187 	    /*
9188 	     * We can do it without term_windgoto()!
9189 	     */
9190 	    if (cost < goto_cost)
9191 	    {
9192 		if (plan == PLAN_LE)
9193 		{
9194 		    if (noinvcurs)
9195 			screen_stop_highlight();
9196 		    while (screen_cur_col > col)
9197 		    {
9198 			out_str(bs);
9199 			--screen_cur_col;
9200 		    }
9201 		}
9202 		else if (plan == PLAN_CR)
9203 		{
9204 		    if (noinvcurs)
9205 			screen_stop_highlight();
9206 		    out_char('\r');
9207 		    screen_cur_col = 0;
9208 		}
9209 		else if (plan == PLAN_NL)
9210 		{
9211 		    if (noinvcurs)
9212 			screen_stop_highlight();
9213 		    while (screen_cur_row < row)
9214 		    {
9215 			out_char('\n');
9216 			++screen_cur_row;
9217 		    }
9218 		    screen_cur_col = 0;
9219 		}
9220 
9221 		i = col - screen_cur_col;
9222 		if (i > 0)
9223 		{
9224 		    /*
9225 		     * Use cursor-right if it's one character only.  Avoids
9226 		     * removing a line of pixels from the last bold char, when
9227 		     * using the bold trick in the GUI.
9228 		     */
9229 		    if (T_ND[0] != NUL && T_ND[1] == NUL)
9230 		    {
9231 			while (i-- > 0)
9232 			    out_char(*T_ND);
9233 		    }
9234 		    else
9235 		    {
9236 			int	off;
9237 
9238 			off = LineOffset[row] + screen_cur_col;
9239 			while (i-- > 0)
9240 			{
9241 			    if (ScreenAttrs[off] != screen_attr)
9242 				screen_stop_highlight();
9243 #ifdef FEAT_MBYTE
9244 			    out_flush_check();
9245 #endif
9246 			    out_char(ScreenLines[off]);
9247 #ifdef FEAT_MBYTE
9248 			    if (enc_dbcs == DBCS_JPNU
9249 						  && ScreenLines[off] == 0x8e)
9250 				out_char(ScreenLines2[off]);
9251 #endif
9252 			    ++off;
9253 			}
9254 		    }
9255 		}
9256 	    }
9257 	}
9258 	else
9259 	    cost = 999;
9260 
9261 	if (cost >= goto_cost)
9262 	{
9263 	    if (noinvcurs)
9264 		screen_stop_highlight();
9265 	    if (row == screen_cur_row && (col > screen_cur_col)
9266 							     && *T_CRI != NUL)
9267 		term_cursor_right(col - screen_cur_col);
9268 	    else
9269 		term_windgoto(row, col);
9270 	}
9271 	screen_cur_row = row;
9272 	screen_cur_col = col;
9273     }
9274 }
9275 
9276 /*
9277  * Set cursor to its position in the current window.
9278  */
9279     void
9280 setcursor(void)
9281 {
9282     if (redrawing())
9283     {
9284 	validate_cursor();
9285 	windgoto(W_WINROW(curwin) + curwin->w_wrow,
9286 		W_WINCOL(curwin) + (
9287 #ifdef FEAT_RIGHTLEFT
9288 		/* With 'rightleft' set and the cursor on a double-wide
9289 		 * character, position it on the leftmost column. */
9290 		curwin->w_p_rl ? ((int)W_WIDTH(curwin) - curwin->w_wcol - (
9291 # ifdef FEAT_MBYTE
9292 			(has_mbyte
9293 			   && (*mb_ptr2cells)(ml_get_cursor()) == 2
9294 			   && vim_isprintc(gchar_cursor())) ? 2 :
9295 # endif
9296 			1)) :
9297 #endif
9298 							    curwin->w_wcol));
9299     }
9300 }
9301 
9302 
9303 /*
9304  * insert 'line_count' lines at 'row' in window 'wp'
9305  * if 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
9306  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
9307  * scrolling.
9308  * Returns FAIL if the lines are not inserted, OK for success.
9309  */
9310     int
9311 win_ins_lines(
9312     win_T	*wp,
9313     int		row,
9314     int		line_count,
9315     int		invalid,
9316     int		mayclear)
9317 {
9318     int		did_delete;
9319     int		nextrow;
9320     int		lastrow;
9321     int		retval;
9322 
9323     if (invalid)
9324 	wp->w_lines_valid = 0;
9325 
9326     if (wp->w_height < 5)
9327 	return FAIL;
9328 
9329     if (line_count > wp->w_height - row)
9330 	line_count = wp->w_height - row;
9331 
9332     retval = win_do_lines(wp, row, line_count, mayclear, FALSE);
9333     if (retval != MAYBE)
9334 	return retval;
9335 
9336     /*
9337      * If there is a next window or a status line, we first try to delete the
9338      * lines at the bottom to avoid messing what is after the window.
9339      * If this fails and there are following windows, don't do anything to avoid
9340      * messing up those windows, better just redraw.
9341      */
9342     did_delete = FALSE;
9343 #ifdef FEAT_WINDOWS
9344     if (wp->w_next != NULL || wp->w_status_height)
9345     {
9346 	if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
9347 				    line_count, (int)Rows, FALSE, NULL) == OK)
9348 	    did_delete = TRUE;
9349 	else if (wp->w_next)
9350 	    return FAIL;
9351     }
9352 #endif
9353     /*
9354      * if no lines deleted, blank the lines that will end up below the window
9355      */
9356     if (!did_delete)
9357     {
9358 #ifdef FEAT_WINDOWS
9359 	wp->w_redr_status = TRUE;
9360 #endif
9361 	redraw_cmdline = TRUE;
9362 	nextrow = W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp);
9363 	lastrow = nextrow + line_count;
9364 	if (lastrow > Rows)
9365 	    lastrow = Rows;
9366 	screen_fill(nextrow - line_count, lastrow - line_count,
9367 		  W_WINCOL(wp), (int)W_ENDCOL(wp),
9368 		  ' ', ' ', 0);
9369     }
9370 
9371     if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, NULL)
9372 								      == FAIL)
9373     {
9374 	    /* deletion will have messed up other windows */
9375 	if (did_delete)
9376 	{
9377 #ifdef FEAT_WINDOWS
9378 	    wp->w_redr_status = TRUE;
9379 #endif
9380 	    win_rest_invalid(W_NEXT(wp));
9381 	}
9382 	return FAIL;
9383     }
9384 
9385     return OK;
9386 }
9387 
9388 /*
9389  * delete "line_count" window lines at "row" in window "wp"
9390  * If "invalid" is TRUE curwin->w_lines[] is invalidated.
9391  * If "mayclear" is TRUE the screen will be cleared if it is faster than
9392  * scrolling
9393  * Return OK for success, FAIL if the lines are not deleted.
9394  */
9395     int
9396 win_del_lines(
9397     win_T	*wp,
9398     int		row,
9399     int		line_count,
9400     int		invalid,
9401     int		mayclear)
9402 {
9403     int		retval;
9404 
9405     if (invalid)
9406 	wp->w_lines_valid = 0;
9407 
9408     if (line_count > wp->w_height - row)
9409 	line_count = wp->w_height - row;
9410 
9411     retval = win_do_lines(wp, row, line_count, mayclear, TRUE);
9412     if (retval != MAYBE)
9413 	return retval;
9414 
9415     if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
9416 					      (int)Rows, FALSE, NULL) == FAIL)
9417 	return FAIL;
9418 
9419 #ifdef FEAT_WINDOWS
9420     /*
9421      * If there are windows or status lines below, try to put them at the
9422      * correct place. If we can't do that, they have to be redrawn.
9423      */
9424     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
9425     {
9426 	if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
9427 					 line_count, (int)Rows, NULL) == FAIL)
9428 	{
9429 	    wp->w_redr_status = TRUE;
9430 	    win_rest_invalid(wp->w_next);
9431 	}
9432     }
9433     /*
9434      * If this is the last window and there is no status line, redraw the
9435      * command line later.
9436      */
9437     else
9438 #endif
9439 	redraw_cmdline = TRUE;
9440     return OK;
9441 }
9442 
9443 /*
9444  * Common code for win_ins_lines() and win_del_lines().
9445  * Returns OK or FAIL when the work has been done.
9446  * Returns MAYBE when not finished yet.
9447  */
9448     static int
9449 win_do_lines(
9450     win_T	*wp,
9451     int		row,
9452     int		line_count,
9453     int		mayclear,
9454     int		del)
9455 {
9456     int		retval;
9457 
9458     if (!redrawing() || line_count <= 0)
9459 	return FAIL;
9460 
9461     /* only a few lines left: redraw is faster */
9462     if (mayclear && Rows - line_count < 5
9463 #ifdef FEAT_WINDOWS
9464 	    && wp->w_width == Columns
9465 #endif
9466 	    )
9467     {
9468 	screenclear();	    /* will set wp->w_lines_valid to 0 */
9469 	return FAIL;
9470     }
9471 
9472     /*
9473      * Delete all remaining lines
9474      */
9475     if (row + line_count >= wp->w_height)
9476     {
9477 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
9478 		W_WINCOL(wp), (int)W_ENDCOL(wp),
9479 		' ', ' ', 0);
9480 	return OK;
9481     }
9482 
9483     /*
9484      * when scrolling, the message on the command line should be cleared,
9485      * otherwise it will stay there forever.
9486      */
9487     clear_cmdline = TRUE;
9488 
9489     /*
9490      * If the terminal can set a scroll region, use that.
9491      * Always do this in a vertically split window.  This will redraw from
9492      * ScreenLines[] when t_CV isn't defined.  That's faster than using
9493      * win_line().
9494      * Don't use a scroll region when we are going to redraw the text, writing
9495      * a character in the lower right corner of the scroll region may cause a
9496      * scroll-up .
9497      */
9498     if (scroll_region
9499 #ifdef FEAT_WINDOWS
9500 	    || W_WIDTH(wp) != Columns
9501 #endif
9502 	    )
9503     {
9504 #ifdef FEAT_WINDOWS
9505 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
9506 #endif
9507 	    scroll_region_set(wp, row);
9508 	if (del)
9509 	    retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
9510 					       wp->w_height - row, FALSE, wp);
9511 	else
9512 	    retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
9513 						      wp->w_height - row, wp);
9514 #ifdef FEAT_WINDOWS
9515 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
9516 #endif
9517 	    scroll_region_reset();
9518 	return retval;
9519     }
9520 
9521 #ifdef FEAT_WINDOWS
9522     if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
9523 	return FAIL;
9524 #endif
9525 
9526     return MAYBE;
9527 }
9528 
9529 /*
9530  * window 'wp' and everything after it is messed up, mark it for redraw
9531  */
9532     static void
9533 win_rest_invalid(win_T *wp)
9534 {
9535 #ifdef FEAT_WINDOWS
9536     while (wp != NULL)
9537 #else
9538     if (wp != NULL)
9539 #endif
9540     {
9541 	redraw_win_later(wp, NOT_VALID);
9542 #ifdef FEAT_WINDOWS
9543 	wp->w_redr_status = TRUE;
9544 	wp = wp->w_next;
9545 #endif
9546     }
9547     redraw_cmdline = TRUE;
9548 }
9549 
9550 /*
9551  * The rest of the routines in this file perform screen manipulations. The
9552  * given operation is performed physically on the screen. The corresponding
9553  * change is also made to the internal screen image. In this way, the editor
9554  * anticipates the effect of editing changes on the appearance of the screen.
9555  * That way, when we call screenupdate a complete redraw isn't usually
9556  * necessary. Another advantage is that we can keep adding code to anticipate
9557  * screen changes, and in the meantime, everything still works.
9558  */
9559 
9560 /*
9561  * types for inserting or deleting lines
9562  */
9563 #define USE_T_CAL   1
9564 #define USE_T_CDL   2
9565 #define USE_T_AL    3
9566 #define USE_T_CE    4
9567 #define USE_T_DL    5
9568 #define USE_T_SR    6
9569 #define USE_NL	    7
9570 #define USE_T_CD    8
9571 #define USE_REDRAW  9
9572 
9573 /*
9574  * insert lines on the screen and update ScreenLines[]
9575  * 'end' is the line after the scrolled part. Normally it is Rows.
9576  * When scrolling region used 'off' is the offset from the top for the region.
9577  * 'row' and 'end' are relative to the start of the region.
9578  *
9579  * return FAIL for failure, OK for success.
9580  */
9581     int
9582 screen_ins_lines(
9583     int		off,
9584     int		row,
9585     int		line_count,
9586     int		end,
9587     win_T	*wp)	    /* NULL or window to use width from */
9588 {
9589     int		i;
9590     int		j;
9591     unsigned	temp;
9592     int		cursor_row;
9593     int		type;
9594     int		result_empty;
9595     int		can_ce = can_clear(T_CE);
9596 
9597     /*
9598      * FAIL if
9599      * - there is no valid screen
9600      * - the screen has to be redrawn completely
9601      * - the line count is less than one
9602      * - the line count is more than 'ttyscroll'
9603      */
9604     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
9605 	return FAIL;
9606 
9607     /*
9608      * There are seven ways to insert lines:
9609      * 0. When in a vertically split window and t_CV isn't set, redraw the
9610      *    characters from ScreenLines[].
9611      * 1. Use T_CD (clear to end of display) if it exists and the result of
9612      *	  the insert is just empty lines
9613      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
9614      *	  present or line_count > 1. It looks better if we do all the inserts
9615      *	  at once.
9616      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
9617      *	  insert is just empty lines and T_CE is not present or line_count >
9618      *	  1.
9619      * 4. Use T_AL (insert line) if it exists.
9620      * 5. Use T_CE (erase line) if it exists and the result of the insert is
9621      *	  just empty lines.
9622      * 6. Use T_DL (delete line) if it exists and the result of the insert is
9623      *	  just empty lines.
9624      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
9625      *	  the 'da' flag is not set or we have clear line capability.
9626      * 8. redraw the characters from ScreenLines[].
9627      *
9628      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
9629      * the scrollbar for the window. It does have insert line, use that if it
9630      * exists.
9631      */
9632     result_empty = (row + line_count >= end);
9633 #ifdef FEAT_WINDOWS
9634     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9635 	type = USE_REDRAW;
9636     else
9637 #endif
9638     if (can_clear(T_CD) && result_empty)
9639 	type = USE_T_CD;
9640     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
9641 	type = USE_T_CAL;
9642     else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
9643 	type = USE_T_CDL;
9644     else if (*T_AL != NUL)
9645 	type = USE_T_AL;
9646     else if (can_ce && result_empty)
9647 	type = USE_T_CE;
9648     else if (*T_DL != NUL && result_empty)
9649 	type = USE_T_DL;
9650     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
9651 	type = USE_T_SR;
9652     else
9653 	return FAIL;
9654 
9655     /*
9656      * For clearing the lines screen_del_lines() is used. This will also take
9657      * care of t_db if necessary.
9658      */
9659     if (type == USE_T_CD || type == USE_T_CDL ||
9660 					 type == USE_T_CE || type == USE_T_DL)
9661 	return screen_del_lines(off, row, line_count, end, FALSE, wp);
9662 
9663     /*
9664      * If text is retained below the screen, first clear or delete as many
9665      * lines at the bottom of the window as are about to be inserted so that
9666      * the deleted lines won't later surface during a screen_del_lines.
9667      */
9668     if (*T_DB)
9669 	screen_del_lines(off, end - line_count, line_count, end, FALSE, wp);
9670 
9671 #ifdef FEAT_CLIPBOARD
9672     /* Remove a modeless selection when inserting lines halfway the screen
9673      * or not the full width of the screen. */
9674     if (off + row > 0
9675 # ifdef FEAT_WINDOWS
9676 	    || (wp != NULL && wp->w_width != Columns)
9677 # endif
9678        )
9679 	clip_clear_selection(&clip_star);
9680     else
9681 	clip_scroll_selection(-line_count);
9682 #endif
9683 
9684 #ifdef FEAT_GUI
9685     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9686      * scrolling is actually carried out. */
9687     gui_dont_update_cursor(row + off <= gui.cursor_row);
9688 #endif
9689 
9690     if (*T_CCS != NUL)	   /* cursor relative to region */
9691 	cursor_row = row;
9692     else
9693 	cursor_row = row + off;
9694 
9695     /*
9696      * Shift LineOffset[] line_count down to reflect the inserted lines.
9697      * Clear the inserted lines in ScreenLines[].
9698      */
9699     row += off;
9700     end += off;
9701     for (i = 0; i < line_count; ++i)
9702     {
9703 #ifdef FEAT_WINDOWS
9704 	if (wp != NULL && wp->w_width != Columns)
9705 	{
9706 	    /* need to copy part of a line */
9707 	    j = end - 1 - i;
9708 	    while ((j -= line_count) >= row)
9709 		linecopy(j + line_count, j, wp);
9710 	    j += line_count;
9711 	    if (can_clear((char_u *)" "))
9712 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
9713 	    else
9714 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9715 	    LineWraps[j] = FALSE;
9716 	}
9717 	else
9718 #endif
9719 	{
9720 	    j = end - 1 - i;
9721 	    temp = LineOffset[j];
9722 	    while ((j -= line_count) >= row)
9723 	    {
9724 		LineOffset[j + line_count] = LineOffset[j];
9725 		LineWraps[j + line_count] = LineWraps[j];
9726 	    }
9727 	    LineOffset[j + line_count] = temp;
9728 	    LineWraps[j + line_count] = FALSE;
9729 	    if (can_clear((char_u *)" "))
9730 		lineclear(temp, (int)Columns);
9731 	    else
9732 		lineinvalid(temp, (int)Columns);
9733 	}
9734     }
9735 
9736     screen_stop_highlight();
9737     windgoto(cursor_row, 0);
9738 
9739 #ifdef FEAT_WINDOWS
9740     /* redraw the characters */
9741     if (type == USE_REDRAW)
9742 	redraw_block(row, end, wp);
9743     else
9744 #endif
9745 	if (type == USE_T_CAL)
9746     {
9747 	term_append_lines(line_count);
9748 	screen_start();		/* don't know where cursor is now */
9749     }
9750     else
9751     {
9752 	for (i = 0; i < line_count; i++)
9753 	{
9754 	    if (type == USE_T_AL)
9755 	    {
9756 		if (i && cursor_row != 0)
9757 		    windgoto(cursor_row, 0);
9758 		out_str(T_AL);
9759 	    }
9760 	    else  /* type == USE_T_SR */
9761 		out_str(T_SR);
9762 	    screen_start();	    /* don't know where cursor is now */
9763 	}
9764     }
9765 
9766     /*
9767      * With scroll-reverse and 'da' flag set we need to clear the lines that
9768      * have been scrolled down into the region.
9769      */
9770     if (type == USE_T_SR && *T_DA)
9771     {
9772 	for (i = 0; i < line_count; ++i)
9773 	{
9774 	    windgoto(off + i, 0);
9775 	    out_str(T_CE);
9776 	    screen_start();	    /* don't know where cursor is now */
9777 	}
9778     }
9779 
9780 #ifdef FEAT_GUI
9781     gui_can_update_cursor();
9782     if (gui.in_use)
9783 	out_flush();	/* always flush after a scroll */
9784 #endif
9785     return OK;
9786 }
9787 
9788 /*
9789  * Delete lines on the screen and update ScreenLines[].
9790  * "end" is the line after the scrolled part. Normally it is Rows.
9791  * When scrolling region used "off" is the offset from the top for the region.
9792  * "row" and "end" are relative to the start of the region.
9793  *
9794  * Return OK for success, FAIL if the lines are not deleted.
9795  */
9796     int
9797 screen_del_lines(
9798     int		off,
9799     int		row,
9800     int		line_count,
9801     int		end,
9802     int		force,		/* even when line_count > p_ttyscroll */
9803     win_T	*wp UNUSED)	/* NULL or window to use width from */
9804 {
9805     int		j;
9806     int		i;
9807     unsigned	temp;
9808     int		cursor_row;
9809     int		cursor_end;
9810     int		result_empty;	/* result is empty until end of region */
9811     int		can_delete;	/* deleting line codes can be used */
9812     int		type;
9813 
9814     /*
9815      * FAIL if
9816      * - there is no valid screen
9817      * - the screen has to be redrawn completely
9818      * - the line count is less than one
9819      * - the line count is more than 'ttyscroll'
9820      */
9821     if (!screen_valid(TRUE) || line_count <= 0 ||
9822 					 (!force && line_count > p_ttyscroll))
9823 	return FAIL;
9824 
9825     /*
9826      * Check if the rest of the current region will become empty.
9827      */
9828     result_empty = row + line_count >= end;
9829 
9830     /*
9831      * We can delete lines only when 'db' flag not set or when 'ce' option
9832      * available.
9833      */
9834     can_delete = (*T_DB == NUL || can_clear(T_CE));
9835 
9836     /*
9837      * There are six ways to delete lines:
9838      * 0. When in a vertically split window and t_CV isn't set, redraw the
9839      *    characters from ScreenLines[].
9840      * 1. Use T_CD if it exists and the result is empty.
9841      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
9842      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
9843      *	  none of the other ways work.
9844      * 4. Use T_CE (erase line) if the result is empty.
9845      * 5. Use T_DL (delete line) if it exists.
9846      * 6. redraw the characters from ScreenLines[].
9847      */
9848 #ifdef FEAT_WINDOWS
9849     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
9850 	type = USE_REDRAW;
9851     else
9852 #endif
9853     if (can_clear(T_CD) && result_empty)
9854 	type = USE_T_CD;
9855 #if defined(__BEOS__) && defined(BEOS_DR8)
9856     /*
9857      * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
9858      * its internal termcap... this works okay for tests which test *T_DB !=
9859      * NUL.  It has the disadvantage that the user cannot use any :set t_*
9860      * command to get T_DB (back) to empty_option, only :set term=... will do
9861      * the trick...
9862      * Anyway, this hack will hopefully go away with the next OS release.
9863      * (Olaf Seibert)
9864      */
9865     else if (row == 0 && T_DB == empty_option
9866 					&& (line_count == 1 || *T_CDL == NUL))
9867 #else
9868     else if (row == 0 && (
9869 #ifndef AMIGA
9870 	/* On the Amiga, somehow '\n' on the last line doesn't always scroll
9871 	 * up, so use delete-line command */
9872 			    line_count == 1 ||
9873 #endif
9874 						*T_CDL == NUL))
9875 #endif
9876 	type = USE_NL;
9877     else if (*T_CDL != NUL && line_count > 1 && can_delete)
9878 	type = USE_T_CDL;
9879     else if (can_clear(T_CE) && result_empty
9880 #ifdef FEAT_WINDOWS
9881 	    && (wp == NULL || wp->w_width == Columns)
9882 #endif
9883 	    )
9884 	type = USE_T_CE;
9885     else if (*T_DL != NUL && can_delete)
9886 	type = USE_T_DL;
9887     else if (*T_CDL != NUL && can_delete)
9888 	type = USE_T_CDL;
9889     else
9890 	return FAIL;
9891 
9892 #ifdef FEAT_CLIPBOARD
9893     /* Remove a modeless selection when deleting lines halfway the screen or
9894      * not the full width of the screen. */
9895     if (off + row > 0
9896 # ifdef FEAT_WINDOWS
9897 	    || (wp != NULL && wp->w_width != Columns)
9898 # endif
9899        )
9900 	clip_clear_selection(&clip_star);
9901     else
9902 	clip_scroll_selection(line_count);
9903 #endif
9904 
9905 #ifdef FEAT_GUI
9906     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
9907      * scrolling is actually carried out. */
9908     gui_dont_update_cursor(gui.cursor_row >= row + off
9909 						&& gui.cursor_row < end + off);
9910 #endif
9911 
9912     if (*T_CCS != NUL)	    /* cursor relative to region */
9913     {
9914 	cursor_row = row;
9915 	cursor_end = end;
9916     }
9917     else
9918     {
9919 	cursor_row = row + off;
9920 	cursor_end = end + off;
9921     }
9922 
9923     /*
9924      * Now shift LineOffset[] line_count up to reflect the deleted lines.
9925      * Clear the inserted lines in ScreenLines[].
9926      */
9927     row += off;
9928     end += off;
9929     for (i = 0; i < line_count; ++i)
9930     {
9931 #ifdef FEAT_WINDOWS
9932 	if (wp != NULL && wp->w_width != Columns)
9933 	{
9934 	    /* need to copy part of a line */
9935 	    j = row + i;
9936 	    while ((j += line_count) <= end - 1)
9937 		linecopy(j - line_count, j, wp);
9938 	    j -= line_count;
9939 	    if (can_clear((char_u *)" "))
9940 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
9941 	    else
9942 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
9943 	    LineWraps[j] = FALSE;
9944 	}
9945 	else
9946 #endif
9947 	{
9948 	    /* whole width, moving the line pointers is faster */
9949 	    j = row + i;
9950 	    temp = LineOffset[j];
9951 	    while ((j += line_count) <= end - 1)
9952 	    {
9953 		LineOffset[j - line_count] = LineOffset[j];
9954 		LineWraps[j - line_count] = LineWraps[j];
9955 	    }
9956 	    LineOffset[j - line_count] = temp;
9957 	    LineWraps[j - line_count] = FALSE;
9958 	    if (can_clear((char_u *)" "))
9959 		lineclear(temp, (int)Columns);
9960 	    else
9961 		lineinvalid(temp, (int)Columns);
9962 	}
9963     }
9964 
9965     screen_stop_highlight();
9966 
9967 #ifdef FEAT_WINDOWS
9968     /* redraw the characters */
9969     if (type == USE_REDRAW)
9970 	redraw_block(row, end, wp);
9971     else
9972 #endif
9973 	if (type == USE_T_CD)	/* delete the lines */
9974     {
9975 	windgoto(cursor_row, 0);
9976 	out_str(T_CD);
9977 	screen_start();			/* don't know where cursor is now */
9978     }
9979     else if (type == USE_T_CDL)
9980     {
9981 	windgoto(cursor_row, 0);
9982 	term_delete_lines(line_count);
9983 	screen_start();			/* don't know where cursor is now */
9984     }
9985     /*
9986      * Deleting lines at top of the screen or scroll region: Just scroll
9987      * the whole screen (scroll region) up by outputting newlines on the
9988      * last line.
9989      */
9990     else if (type == USE_NL)
9991     {
9992 	windgoto(cursor_end - 1, 0);
9993 	for (i = line_count; --i >= 0; )
9994 	    out_char('\n');		/* cursor will remain on same line */
9995     }
9996     else
9997     {
9998 	for (i = line_count; --i >= 0; )
9999 	{
10000 	    if (type == USE_T_DL)
10001 	    {
10002 		windgoto(cursor_row, 0);
10003 		out_str(T_DL);		/* delete a line */
10004 	    }
10005 	    else /* type == USE_T_CE */
10006 	    {
10007 		windgoto(cursor_row + i, 0);
10008 		out_str(T_CE);		/* erase a line */
10009 	    }
10010 	    screen_start();		/* don't know where cursor is now */
10011 	}
10012     }
10013 
10014     /*
10015      * If the 'db' flag is set, we need to clear the lines that have been
10016      * scrolled up at the bottom of the region.
10017      */
10018     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
10019     {
10020 	for (i = line_count; i > 0; --i)
10021 	{
10022 	    windgoto(cursor_end - i, 0);
10023 	    out_str(T_CE);		/* erase a line */
10024 	    screen_start();		/* don't know where cursor is now */
10025 	}
10026     }
10027 
10028 #ifdef FEAT_GUI
10029     gui_can_update_cursor();
10030     if (gui.in_use)
10031 	out_flush();	/* always flush after a scroll */
10032 #endif
10033 
10034     return OK;
10035 }
10036 
10037 /*
10038  * show the current mode and ruler
10039  *
10040  * If clear_cmdline is TRUE, clear the rest of the cmdline.
10041  * If clear_cmdline is FALSE there may be a message there that needs to be
10042  * cleared only if a mode is shown.
10043  * Return the length of the message (0 if no message).
10044  */
10045     int
10046 showmode(void)
10047 {
10048     int		need_clear;
10049     int		length = 0;
10050     int		do_mode;
10051     int		attr;
10052     int		nwr_save;
10053 #ifdef FEAT_INS_EXPAND
10054     int		sub_attr;
10055 #endif
10056 
10057     do_mode = ((p_smd && msg_silent == 0)
10058 	    && ((State & INSERT)
10059 		|| restart_edit
10060 		|| VIsual_active));
10061     if (do_mode || Recording)
10062     {
10063 	/*
10064 	 * Don't show mode right now, when not redrawing or inside a mapping.
10065 	 * Call char_avail() only when we are going to show something, because
10066 	 * it takes a bit of time.
10067 	 */
10068 	if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0)
10069 	{
10070 	    redraw_cmdline = TRUE;		/* show mode later */
10071 	    return 0;
10072 	}
10073 
10074 	nwr_save = need_wait_return;
10075 
10076 	/* wait a bit before overwriting an important message */
10077 	check_for_delay(FALSE);
10078 
10079 	/* if the cmdline is more than one line high, erase top lines */
10080 	need_clear = clear_cmdline;
10081 	if (clear_cmdline && cmdline_row < Rows - 1)
10082 	    msg_clr_cmdline();			/* will reset clear_cmdline */
10083 
10084 	/* Position on the last line in the window, column 0 */
10085 	msg_pos_mode();
10086 	cursor_off();
10087 	attr = hl_attr(HLF_CM);			/* Highlight mode */
10088 	if (do_mode)
10089 	{
10090 	    MSG_PUTS_ATTR("--", attr);
10091 #if defined(FEAT_XIM)
10092 	    if (
10093 # ifdef FEAT_GUI_GTK
10094 		    preedit_get_status()
10095 # else
10096 		    im_get_status()
10097 # endif
10098 	       )
10099 # ifdef FEAT_GUI_GTK /* most of the time, it's not XIM being used */
10100 		MSG_PUTS_ATTR(" IM", attr);
10101 # else
10102 		MSG_PUTS_ATTR(" XIM", attr);
10103 # endif
10104 #endif
10105 #if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
10106 	    if (gui.in_use)
10107 	    {
10108 		if (hangul_input_state_get())
10109 		{
10110 		    /* HANGUL */
10111 		    if (enc_utf8)
10112 			MSG_PUTS_ATTR(" \355\225\234\352\270\200", attr);
10113 		    else
10114 			MSG_PUTS_ATTR(" \307\321\261\333", attr);
10115 		}
10116 	    }
10117 #endif
10118 #ifdef FEAT_INS_EXPAND
10119 	    /* CTRL-X in Insert mode */
10120 	    if (edit_submode != NULL && !shortmess(SHM_COMPLETIONMENU))
10121 	    {
10122 		/* These messages can get long, avoid a wrap in a narrow
10123 		 * window.  Prefer showing edit_submode_extra. */
10124 		length = (Rows - msg_row) * Columns - 3;
10125 		if (edit_submode_extra != NULL)
10126 		    length -= vim_strsize(edit_submode_extra);
10127 		if (length > 0)
10128 		{
10129 		    if (edit_submode_pre != NULL)
10130 			length -= vim_strsize(edit_submode_pre);
10131 		    if (length - vim_strsize(edit_submode) > 0)
10132 		    {
10133 			if (edit_submode_pre != NULL)
10134 			    msg_puts_attr(edit_submode_pre, attr);
10135 			msg_puts_attr(edit_submode, attr);
10136 		    }
10137 		    if (edit_submode_extra != NULL)
10138 		    {
10139 			MSG_PUTS_ATTR(" ", attr);  /* add a space in between */
10140 			if ((int)edit_submode_highl < (int)HLF_COUNT)
10141 			    sub_attr = hl_attr(edit_submode_highl);
10142 			else
10143 			    sub_attr = attr;
10144 			msg_puts_attr(edit_submode_extra, sub_attr);
10145 		    }
10146 		}
10147 		length = 0;
10148 	    }
10149 	    else
10150 #endif
10151 	    {
10152 #ifdef FEAT_VREPLACE
10153 		if (State & VREPLACE_FLAG)
10154 		    MSG_PUTS_ATTR(_(" VREPLACE"), attr);
10155 		else
10156 #endif
10157 		    if (State & REPLACE_FLAG)
10158 		    MSG_PUTS_ATTR(_(" REPLACE"), attr);
10159 		else if (State & INSERT)
10160 		{
10161 #ifdef FEAT_RIGHTLEFT
10162 		    if (p_ri)
10163 			MSG_PUTS_ATTR(_(" REVERSE"), attr);
10164 #endif
10165 		    MSG_PUTS_ATTR(_(" INSERT"), attr);
10166 		}
10167 		else if (restart_edit == 'I')
10168 		    MSG_PUTS_ATTR(_(" (insert)"), attr);
10169 		else if (restart_edit == 'R')
10170 		    MSG_PUTS_ATTR(_(" (replace)"), attr);
10171 		else if (restart_edit == 'V')
10172 		    MSG_PUTS_ATTR(_(" (vreplace)"), attr);
10173 #ifdef FEAT_RIGHTLEFT
10174 		if (p_hkmap)
10175 		    MSG_PUTS_ATTR(_(" Hebrew"), attr);
10176 # ifdef FEAT_FKMAP
10177 		if (p_fkmap)
10178 		    MSG_PUTS_ATTR(farsi_text_5, attr);
10179 # endif
10180 #endif
10181 #ifdef FEAT_KEYMAP
10182 		if (State & LANGMAP)
10183 		{
10184 # ifdef FEAT_ARABIC
10185 		    if (curwin->w_p_arab)
10186 			MSG_PUTS_ATTR(_(" Arabic"), attr);
10187 		    else
10188 # endif
10189 			if (get_keymap_str(curwin, (char_u *)" (%s)",
10190 							   NameBuff, MAXPATHL))
10191 			    MSG_PUTS_ATTR(NameBuff, attr);
10192 		}
10193 #endif
10194 		if ((State & INSERT) && p_paste)
10195 		    MSG_PUTS_ATTR(_(" (paste)"), attr);
10196 
10197 		if (VIsual_active)
10198 		{
10199 		    char *p;
10200 
10201 		    /* Don't concatenate separate words to avoid translation
10202 		     * problems. */
10203 		    switch ((VIsual_select ? 4 : 0)
10204 			    + (VIsual_mode == Ctrl_V) * 2
10205 			    + (VIsual_mode == 'V'))
10206 		    {
10207 			case 0:	p = N_(" VISUAL"); break;
10208 			case 1: p = N_(" VISUAL LINE"); break;
10209 			case 2: p = N_(" VISUAL BLOCK"); break;
10210 			case 4: p = N_(" SELECT"); break;
10211 			case 5: p = N_(" SELECT LINE"); break;
10212 			default: p = N_(" SELECT BLOCK"); break;
10213 		    }
10214 		    MSG_PUTS_ATTR(_(p), attr);
10215 		}
10216 		MSG_PUTS_ATTR(" --", attr);
10217 	    }
10218 
10219 	    need_clear = TRUE;
10220 	}
10221 	if (Recording
10222 #ifdef FEAT_INS_EXPAND
10223 		&& edit_submode == NULL	    /* otherwise it gets too long */
10224 #endif
10225 		)
10226 	{
10227 	    recording_mode(attr);
10228 	    need_clear = TRUE;
10229 	}
10230 
10231 	mode_displayed = TRUE;
10232 	if (need_clear || clear_cmdline)
10233 	    msg_clr_eos();
10234 	msg_didout = FALSE;		/* overwrite this message */
10235 	length = msg_col;
10236 	msg_col = 0;
10237 	need_wait_return = nwr_save;	/* never ask for hit-return for this */
10238     }
10239     else if (clear_cmdline && msg_silent == 0)
10240 	/* Clear the whole command line.  Will reset "clear_cmdline". */
10241 	msg_clr_cmdline();
10242 
10243 #ifdef FEAT_CMDL_INFO
10244     /* In Visual mode the size of the selected area must be redrawn. */
10245     if (VIsual_active)
10246 	clear_showcmd();
10247 
10248     /* If the last window has no status line, the ruler is after the mode
10249      * message and must be redrawn */
10250     if (redrawing()
10251 # ifdef FEAT_WINDOWS
10252 	    && lastwin->w_status_height == 0
10253 # endif
10254        )
10255 	win_redr_ruler(lastwin, TRUE);
10256 #endif
10257     redraw_cmdline = FALSE;
10258     clear_cmdline = FALSE;
10259 
10260     return length;
10261 }
10262 
10263 /*
10264  * Position for a mode message.
10265  */
10266     static void
10267 msg_pos_mode(void)
10268 {
10269     msg_col = 0;
10270     msg_row = Rows - 1;
10271 }
10272 
10273 /*
10274  * Delete mode message.  Used when ESC is typed which is expected to end
10275  * Insert mode (but Insert mode didn't end yet!).
10276  * Caller should check "mode_displayed".
10277  */
10278     void
10279 unshowmode(int force)
10280 {
10281     /*
10282      * Don't delete it right now, when not redrawing or inside a mapping.
10283      */
10284     if (!redrawing() || (!force && char_avail() && !KeyTyped))
10285 	redraw_cmdline = TRUE;		/* delete mode later */
10286     else
10287 	clearmode();
10288 }
10289 
10290 /*
10291  * Clear the mode message.
10292  */
10293     void
10294 clearmode(void)
10295 {
10296     msg_pos_mode();
10297     if (Recording)
10298 	recording_mode(hl_attr(HLF_CM));
10299     msg_clr_eos();
10300 }
10301 
10302     static void
10303 recording_mode(int attr)
10304 {
10305     MSG_PUTS_ATTR(_("recording"), attr);
10306     if (!shortmess(SHM_RECORDING))
10307     {
10308 	char_u s[4];
10309 	sprintf((char *)s, " @%c", Recording);
10310 	MSG_PUTS_ATTR(s, attr);
10311     }
10312 }
10313 
10314 #if defined(FEAT_WINDOWS)
10315 /*
10316  * Draw the tab pages line at the top of the Vim window.
10317  */
10318     static void
10319 draw_tabline(void)
10320 {
10321     int		tabcount = 0;
10322     tabpage_T	*tp;
10323     int		tabwidth;
10324     int		col = 0;
10325     int		scol = 0;
10326     int		attr;
10327     win_T	*wp;
10328     win_T	*cwp;
10329     int		wincount;
10330     int		modified;
10331     int		c;
10332     int		len;
10333     int		attr_sel = hl_attr(HLF_TPS);
10334     int		attr_nosel = hl_attr(HLF_TP);
10335     int		attr_fill = hl_attr(HLF_TPF);
10336     char_u	*p;
10337     int		room;
10338     int		use_sep_chars = (t_colors < 8
10339 #ifdef FEAT_GUI
10340 					    && !gui.in_use
10341 #endif
10342 #ifdef FEAT_TERMGUICOLORS
10343 					    && !p_tgc
10344 #endif
10345 					    );
10346 
10347     redraw_tabline = FALSE;
10348 
10349 #ifdef FEAT_GUI_TABLINE
10350     /* Take care of a GUI tabline. */
10351     if (gui_use_tabline())
10352     {
10353 	gui_update_tabline();
10354 	return;
10355     }
10356 #endif
10357 
10358     if (tabline_height() < 1)
10359 	return;
10360 
10361 #if defined(FEAT_STL_OPT)
10362 
10363     /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
10364     for (scol = 0; scol < Columns; ++scol)
10365 	TabPageIdxs[scol] = 0;
10366 
10367     /* Use the 'tabline' option if it's set. */
10368     if (*p_tal != NUL)
10369     {
10370 	int	saved_did_emsg = did_emsg;
10371 
10372 	/* Check for an error.  If there is one we would loop in redrawing the
10373 	 * screen.  Avoid that by making 'tabline' empty. */
10374 	did_emsg = FALSE;
10375 	win_redr_custom(NULL, FALSE);
10376 	if (did_emsg)
10377 	    set_string_option_direct((char_u *)"tabline", -1,
10378 					   (char_u *)"", OPT_FREE, SID_ERROR);
10379 	did_emsg |= saved_did_emsg;
10380     }
10381     else
10382 #endif
10383     {
10384 	FOR_ALL_TABPAGES(tp)
10385 	    ++tabcount;
10386 
10387 	tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
10388 	if (tabwidth < 6)
10389 	    tabwidth = 6;
10390 
10391 	attr = attr_nosel;
10392 	tabcount = 0;
10393 	scol = 0;
10394 	for (tp = first_tabpage; tp != NULL && col < Columns - 4;
10395 							     tp = tp->tp_next)
10396 	{
10397 	    scol = col;
10398 
10399 	    if (tp->tp_topframe == topframe)
10400 		attr = attr_sel;
10401 	    if (use_sep_chars && col > 0)
10402 		screen_putchar('|', 0, col++, attr);
10403 
10404 	    if (tp->tp_topframe != topframe)
10405 		attr = attr_nosel;
10406 
10407 	    screen_putchar(' ', 0, col++, attr);
10408 
10409 	    if (tp == curtab)
10410 	    {
10411 		cwp = curwin;
10412 		wp = firstwin;
10413 	    }
10414 	    else
10415 	    {
10416 		cwp = tp->tp_curwin;
10417 		wp = tp->tp_firstwin;
10418 	    }
10419 
10420 	    modified = FALSE;
10421 	    for (wincount = 0; wp != NULL; wp = wp->w_next, ++wincount)
10422 		if (bufIsChanged(wp->w_buffer))
10423 		    modified = TRUE;
10424 	    if (modified || wincount > 1)
10425 	    {
10426 		if (wincount > 1)
10427 		{
10428 		    vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
10429 		    len = (int)STRLEN(NameBuff);
10430 		    if (col + len >= Columns - 3)
10431 			break;
10432 		    screen_puts_len(NameBuff, len, 0, col,
10433 #if defined(FEAT_SYN_HL)
10434 					 hl_combine_attr(attr, hl_attr(HLF_T))
10435 #else
10436 					 attr
10437 #endif
10438 					       );
10439 		    col += len;
10440 		}
10441 		if (modified)
10442 		    screen_puts_len((char_u *)"+", 1, 0, col++, attr);
10443 		screen_putchar(' ', 0, col++, attr);
10444 	    }
10445 
10446 	    room = scol - col + tabwidth - 1;
10447 	    if (room > 0)
10448 	    {
10449 		/* Get buffer name in NameBuff[] */
10450 		get_trans_bufname(cwp->w_buffer);
10451 		shorten_dir(NameBuff);
10452 		len = vim_strsize(NameBuff);
10453 		p = NameBuff;
10454 #ifdef FEAT_MBYTE
10455 		if (has_mbyte)
10456 		    while (len > room)
10457 		    {
10458 			len -= ptr2cells(p);
10459 			mb_ptr_adv(p);
10460 		    }
10461 		else
10462 #endif
10463 		    if (len > room)
10464 		{
10465 		    p += len - room;
10466 		    len = room;
10467 		}
10468 		if (len > Columns - col - 1)
10469 		    len = Columns - col - 1;
10470 
10471 		screen_puts_len(p, (int)STRLEN(p), 0, col, attr);
10472 		col += len;
10473 	    }
10474 	    screen_putchar(' ', 0, col++, attr);
10475 
10476 	    /* Store the tab page number in TabPageIdxs[], so that
10477 	     * jump_to_mouse() knows where each one is. */
10478 	    ++tabcount;
10479 	    while (scol < col)
10480 		TabPageIdxs[scol++] = tabcount;
10481 	}
10482 
10483 	if (use_sep_chars)
10484 	    c = '_';
10485 	else
10486 	    c = ' ';
10487 	screen_fill(0, 1, col, (int)Columns, c, c, attr_fill);
10488 
10489 	/* Put an "X" for closing the current tab if there are several. */
10490 	if (first_tabpage->tp_next != NULL)
10491 	{
10492 	    screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
10493 	    TabPageIdxs[Columns - 1] = -999;
10494 	}
10495     }
10496 
10497     /* Reset the flag here again, in case evaluating 'tabline' causes it to be
10498      * set. */
10499     redraw_tabline = FALSE;
10500 }
10501 
10502 /*
10503  * Get buffer name for "buf" into NameBuff[].
10504  * Takes care of special buffer names and translates special characters.
10505  */
10506     void
10507 get_trans_bufname(buf_T *buf)
10508 {
10509     if (buf_spname(buf) != NULL)
10510 	vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
10511     else
10512 	home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
10513     trans_characters(NameBuff, MAXPATHL);
10514 }
10515 #endif
10516 
10517 #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
10518 /*
10519  * Get the character to use in a status line.  Get its attributes in "*attr".
10520  */
10521     static int
10522 fillchar_status(int *attr, int is_curwin)
10523 {
10524     int fill;
10525     if (is_curwin)
10526     {
10527 	*attr = hl_attr(HLF_S);
10528 	fill = fill_stl;
10529     }
10530     else
10531     {
10532 	*attr = hl_attr(HLF_SNC);
10533 	fill = fill_stlnc;
10534     }
10535     /* Use fill when there is highlighting, and highlighting of current
10536      * window differs, or the fillchars differ, or this is not the
10537      * current window */
10538     if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC)
10539 			|| !is_curwin || ONE_WINDOW)
10540 		    || (fill_stl != fill_stlnc)))
10541 	return fill;
10542     if (is_curwin)
10543 	return '^';
10544     return '=';
10545 }
10546 #endif
10547 
10548 #ifdef FEAT_WINDOWS
10549 /*
10550  * Get the character to use in a separator between vertically split windows.
10551  * Get its attributes in "*attr".
10552  */
10553     static int
10554 fillchar_vsep(int *attr)
10555 {
10556     *attr = hl_attr(HLF_C);
10557     if (*attr == 0 && fill_vert == ' ')
10558 	return '|';
10559     else
10560 	return fill_vert;
10561 }
10562 #endif
10563 
10564 /*
10565  * Return TRUE if redrawing should currently be done.
10566  */
10567     int
10568 redrawing(void)
10569 {
10570     return (!RedrawingDisabled
10571 		       && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
10572 }
10573 
10574 /*
10575  * Return TRUE if printing messages should currently be done.
10576  */
10577     int
10578 messaging(void)
10579 {
10580     return (!(p_lz && char_avail() && !KeyTyped));
10581 }
10582 
10583 /*
10584  * Show current status info in ruler and various other places
10585  * If always is FALSE, only show ruler if position has changed.
10586  */
10587     void
10588 showruler(int always)
10589 {
10590     if (!always && !redrawing())
10591 	return;
10592 #ifdef FEAT_INS_EXPAND
10593     if (pum_visible())
10594     {
10595 # ifdef FEAT_WINDOWS
10596 	/* Don't redraw right now, do it later. */
10597 	curwin->w_redr_status = TRUE;
10598 # endif
10599 	return;
10600     }
10601 #endif
10602 #if defined(FEAT_STL_OPT) && defined(FEAT_WINDOWS)
10603     if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height)
10604     {
10605 	redraw_custom_statusline(curwin);
10606     }
10607     else
10608 #endif
10609 #ifdef FEAT_CMDL_INFO
10610 	win_redr_ruler(curwin, always);
10611 #endif
10612 
10613 #ifdef FEAT_TITLE
10614     if (need_maketitle
10615 # ifdef FEAT_STL_OPT
10616 	    || (p_icon && (stl_syntax & STL_IN_ICON))
10617 	    || (p_title && (stl_syntax & STL_IN_TITLE))
10618 # endif
10619        )
10620 	maketitle();
10621 #endif
10622 #ifdef FEAT_WINDOWS
10623     /* Redraw the tab pages line if needed. */
10624     if (redraw_tabline)
10625 	draw_tabline();
10626 #endif
10627 }
10628 
10629 #ifdef FEAT_CMDL_INFO
10630     static void
10631 win_redr_ruler(win_T *wp, int always)
10632 {
10633 #define RULER_BUF_LEN 70
10634     char_u	buffer[RULER_BUF_LEN];
10635     int		row;
10636     int		fillchar;
10637     int		attr;
10638     int		empty_line = FALSE;
10639     colnr_T	virtcol;
10640     int		i;
10641     size_t	len;
10642     int		o;
10643 #ifdef FEAT_WINDOWS
10644     int		this_ru_col;
10645     int		off = 0;
10646     int		width = Columns;
10647 # define WITH_OFF(x) x
10648 # define WITH_WIDTH(x) x
10649 #else
10650 # define WITH_OFF(x) 0
10651 # define WITH_WIDTH(x) Columns
10652 # define this_ru_col ru_col
10653 #endif
10654 
10655     /* If 'ruler' off or redrawing disabled, don't do anything */
10656     if (!p_ru)
10657 	return;
10658 
10659     /*
10660      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
10661      * after deleting lines, before cursor.lnum is corrected.
10662      */
10663     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
10664 	return;
10665 
10666 #ifdef FEAT_INS_EXPAND
10667     /* Don't draw the ruler while doing insert-completion, it might overwrite
10668      * the (long) mode message. */
10669 # ifdef FEAT_WINDOWS
10670     if (wp == lastwin && lastwin->w_status_height == 0)
10671 # endif
10672 	if (edit_submode != NULL)
10673 	    return;
10674     /* Don't draw the ruler when the popup menu is visible, it may overlap. */
10675     if (pum_visible())
10676 	return;
10677 #endif
10678 
10679 #ifdef FEAT_STL_OPT
10680     if (*p_ruf)
10681     {
10682 	int	save_called_emsg = called_emsg;
10683 
10684 	called_emsg = FALSE;
10685 	win_redr_custom(wp, TRUE);
10686 	if (called_emsg)
10687 	    set_string_option_direct((char_u *)"rulerformat", -1,
10688 					   (char_u *)"", OPT_FREE, SID_ERROR);
10689 	called_emsg |= save_called_emsg;
10690 	return;
10691     }
10692 #endif
10693 
10694     /*
10695      * Check if not in Insert mode and the line is empty (will show "0-1").
10696      */
10697     if (!(State & INSERT)
10698 		&& *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
10699 	empty_line = TRUE;
10700 
10701     /*
10702      * Only draw the ruler when something changed.
10703      */
10704     validate_virtcol_win(wp);
10705     if (       redraw_cmdline
10706 	    || always
10707 	    || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
10708 	    || wp->w_cursor.col != wp->w_ru_cursor.col
10709 	    || wp->w_virtcol != wp->w_ru_virtcol
10710 #ifdef FEAT_VIRTUALEDIT
10711 	    || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
10712 #endif
10713 	    || wp->w_topline != wp->w_ru_topline
10714 	    || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
10715 #ifdef FEAT_DIFF
10716 	    || wp->w_topfill != wp->w_ru_topfill
10717 #endif
10718 	    || empty_line != wp->w_ru_empty)
10719     {
10720 	cursor_off();
10721 #ifdef FEAT_WINDOWS
10722 	if (wp->w_status_height)
10723 	{
10724 	    row = W_WINROW(wp) + wp->w_height;
10725 	    fillchar = fillchar_status(&attr, wp == curwin);
10726 	    off = W_WINCOL(wp);
10727 	    width = W_WIDTH(wp);
10728 	}
10729 	else
10730 #endif
10731 	{
10732 	    row = Rows - 1;
10733 	    fillchar = ' ';
10734 	    attr = 0;
10735 #ifdef FEAT_WINDOWS
10736 	    width = Columns;
10737 	    off = 0;
10738 #endif
10739 	}
10740 
10741 	/* In list mode virtcol needs to be recomputed */
10742 	virtcol = wp->w_virtcol;
10743 	if (wp->w_p_list && lcs_tab1 == NUL)
10744 	{
10745 	    wp->w_p_list = FALSE;
10746 	    getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
10747 	    wp->w_p_list = TRUE;
10748 	}
10749 
10750 	/*
10751 	 * Some sprintfs return the length, some return a pointer.
10752 	 * To avoid portability problems we use strlen() here.
10753 	 */
10754 	vim_snprintf((char *)buffer, RULER_BUF_LEN, "%ld,",
10755 		(wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
10756 		    ? 0L
10757 		    : (long)(wp->w_cursor.lnum));
10758 	len = STRLEN(buffer);
10759 	col_print(buffer + len, RULER_BUF_LEN - len,
10760 			empty_line ? 0 : (int)wp->w_cursor.col + 1,
10761 			(int)virtcol + 1);
10762 
10763 	/*
10764 	 * Add a "50%" if there is room for it.
10765 	 * On the last line, don't print in the last column (scrolls the
10766 	 * screen up on some terminals).
10767 	 */
10768 	i = (int)STRLEN(buffer);
10769 	get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
10770 	o = i + vim_strsize(buffer + i + 1);
10771 #ifdef FEAT_WINDOWS
10772 	if (wp->w_status_height == 0)	/* can't use last char of screen */
10773 #endif
10774 	    ++o;
10775 #ifdef FEAT_WINDOWS
10776 	this_ru_col = ru_col - (Columns - width);
10777 	if (this_ru_col < 0)
10778 	    this_ru_col = 0;
10779 #endif
10780 	/* Never use more than half the window/screen width, leave the other
10781 	 * half for the filename. */
10782 	if (this_ru_col < (WITH_WIDTH(width) + 1) / 2)
10783 	    this_ru_col = (WITH_WIDTH(width) + 1) / 2;
10784 	if (this_ru_col + o < WITH_WIDTH(width))
10785 	{
10786 	    /* need at least 3 chars left for get_rel_pos() + NUL */
10787 	    while (this_ru_col + o < WITH_WIDTH(width) && RULER_BUF_LEN > i + 4)
10788 	    {
10789 #ifdef FEAT_MBYTE
10790 		if (has_mbyte)
10791 		    i += (*mb_char2bytes)(fillchar, buffer + i);
10792 		else
10793 #endif
10794 		    buffer[i++] = fillchar;
10795 		++o;
10796 	    }
10797 	    get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
10798 	}
10799 	/* Truncate at window boundary. */
10800 #ifdef FEAT_MBYTE
10801 	if (has_mbyte)
10802 	{
10803 	    o = 0;
10804 	    for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len)(buffer + i))
10805 	    {
10806 		o += (*mb_ptr2cells)(buffer + i);
10807 		if (this_ru_col + o > WITH_WIDTH(width))
10808 		{
10809 		    buffer[i] = NUL;
10810 		    break;
10811 		}
10812 	    }
10813 	}
10814 	else
10815 #endif
10816 	if (this_ru_col + (int)STRLEN(buffer) > WITH_WIDTH(width))
10817 	    buffer[WITH_WIDTH(width) - this_ru_col] = NUL;
10818 
10819 	screen_puts(buffer, row, this_ru_col + WITH_OFF(off), attr);
10820 	i = redraw_cmdline;
10821 	screen_fill(row, row + 1,
10822 		this_ru_col + WITH_OFF(off) + (int)STRLEN(buffer),
10823 		(int)(WITH_OFF(off) + WITH_WIDTH(width)),
10824 		fillchar, fillchar, attr);
10825 	/* don't redraw the cmdline because of showing the ruler */
10826 	redraw_cmdline = i;
10827 	wp->w_ru_cursor = wp->w_cursor;
10828 	wp->w_ru_virtcol = wp->w_virtcol;
10829 	wp->w_ru_empty = empty_line;
10830 	wp->w_ru_topline = wp->w_topline;
10831 	wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
10832 #ifdef FEAT_DIFF
10833 	wp->w_ru_topfill = wp->w_topfill;
10834 #endif
10835     }
10836 }
10837 #endif
10838 
10839 #if defined(FEAT_LINEBREAK) || defined(PROTO)
10840 /*
10841  * Return the width of the 'number' and 'relativenumber' column.
10842  * Caller may need to check if 'number' or 'relativenumber' is set.
10843  * Otherwise it depends on 'numberwidth' and the line count.
10844  */
10845     int
10846 number_width(win_T *wp)
10847 {
10848     int		n;
10849     linenr_T	lnum;
10850 
10851     if (wp->w_p_rnu && !wp->w_p_nu)
10852 	/* cursor line shows "0" */
10853 	lnum = wp->w_height;
10854     else
10855 	/* cursor line shows absolute line number */
10856 	lnum = wp->w_buffer->b_ml.ml_line_count;
10857 
10858     if (lnum == wp->w_nrwidth_line_count && wp->w_nuw_cached == wp->w_p_nuw)
10859 	return wp->w_nrwidth_width;
10860     wp->w_nrwidth_line_count = lnum;
10861 
10862     n = 0;
10863     do
10864     {
10865 	lnum /= 10;
10866 	++n;
10867     } while (lnum > 0);
10868 
10869     /* 'numberwidth' gives the minimal width plus one */
10870     if (n < wp->w_p_nuw - 1)
10871 	n = wp->w_p_nuw - 1;
10872 
10873     wp->w_nrwidth_width = n;
10874     wp->w_nuw_cached = wp->w_p_nuw;
10875     return n;
10876 }
10877 #endif
10878 
10879 /*
10880  * Return the current cursor column. This is the actual position on the
10881  * screen. First column is 0.
10882  */
10883     int
10884 screen_screencol(void)
10885 {
10886     return screen_cur_col;
10887 }
10888 
10889 /*
10890  * Return the current cursor row. This is the actual position on the screen.
10891  * First row is 0.
10892  */
10893     int
10894 screen_screenrow(void)
10895 {
10896     return screen_cur_row;
10897 }
10898