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