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