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