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