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