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