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