xref: /vim-8.2.3635/src/screen.c (revision cfbc5ee4)
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 	    /* 'list' : change char 160 to lcs_nbsp. */
3553 	    if (wp->w_p_list && c == 160 && lcs_nbsp)
3554 	    {
3555 		c = lcs_nbsp;
3556 		if (area_attr == 0 && search_attr == 0)
3557 		{
3558 		    n_attr = 1;
3559 		    extra_attr = hl_attr(HLF_8);
3560 		    saved_attr2 = char_attr; /* save current attr */
3561 		}
3562 #ifdef FEAT_MBYTE
3563 		mb_c = c;
3564 		if (enc_utf8 && (*mb_char2len)(c) > 1)
3565 		{
3566 		    mb_utf8 = TRUE;
3567 		    u8c_c1 = u8c_c2 = 0;
3568 		}
3569 		else
3570 		    mb_utf8 = FALSE;
3571 #endif
3572 	    }
3573 
3574 	    if (extra_check)
3575 	    {
3576 #ifdef FEAT_SYN_HL
3577 		/* Get syntax attribute, unless still at the start of the line
3578 		 * (double-wide char that doesn't fit). */
3579 		if (has_syntax && (v = (long)(ptr - line)) > 0)
3580 		{
3581 		    /* Get the syntax attribute for the character.  If there
3582 		     * is an error, disable syntax highlighting. */
3583 		    save_did_emsg = did_emsg;
3584 		    did_emsg = FALSE;
3585 
3586 		    syntax_attr = get_syntax_attr((colnr_T)v - 1);
3587 
3588 		    if (did_emsg)
3589 			syntax_clear(wp->w_buffer);
3590 		    else
3591 			did_emsg = save_did_emsg;
3592 
3593 		    /* Need to get the line again, a multi-line regexp may
3594 		     * have made it invalid. */
3595 		    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
3596 		    ptr = line + v;
3597 
3598 		    if (area_attr == 0 && search_attr == 0)
3599 			char_attr = syntax_attr;
3600 		}
3601 #endif
3602 #ifdef FEAT_LINEBREAK
3603 		/*
3604 		 * Found last space before word: check for line break
3605 		 */
3606 		if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
3607 						      && !wp->w_p_list)
3608 		{
3609 		    n_extra = win_lbr_chartabsize(wp, ptr - (
3610 # ifdef FEAT_MBYTE
3611 				has_mbyte ? mb_l :
3612 # endif
3613 				1), (colnr_T)vcol, NULL) - 1;
3614 		    c_extra = ' ';
3615 		    if (vim_iswhite(c))
3616 			c = ' ';
3617 		}
3618 #endif
3619 
3620 		if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
3621 		{
3622 		    c = lcs_trail;
3623 		    if (area_attr == 0 && search_attr == 0)
3624 		    {
3625 			n_attr = 1;
3626 			extra_attr = hl_attr(HLF_8);
3627 			saved_attr2 = char_attr; /* save current attr */
3628 		    }
3629 #ifdef FEAT_MBYTE
3630 		    mb_c = c;
3631 		    if (enc_utf8 && (*mb_char2len)(c) > 1)
3632 		    {
3633 			mb_utf8 = TRUE;
3634 			u8c_c1 = u8c_c2 = 0;
3635 		    }
3636 		    else
3637 			mb_utf8 = FALSE;
3638 #endif
3639 		}
3640 	    }
3641 
3642 	    /*
3643 	     * Handling of non-printable characters.
3644 	     */
3645 	    if (!(chartab[c] & CT_PRINT_CHAR))
3646 	    {
3647 		/*
3648 		 * when getting a character from the file, we may have to
3649 		 * turn it into something else on the way to putting it
3650 		 * into "ScreenLines".
3651 		 */
3652 		if (c == TAB && (!wp->w_p_list || lcs_tab1))
3653 		{
3654 		    /* tab amount depends on current column */
3655 		    n_extra = (int)wp->w_buffer->b_p_ts
3656 				   - vcol % (int)wp->w_buffer->b_p_ts - 1;
3657 #ifdef FEAT_MBYTE
3658 		    mb_utf8 = FALSE;	/* don't draw as UTF-8 */
3659 #endif
3660 		    if (wp->w_p_list)
3661 		    {
3662 			c = lcs_tab1;
3663 			c_extra = lcs_tab2;
3664 			n_attr = n_extra + 1;
3665 			extra_attr = hl_attr(HLF_8);
3666 			saved_attr2 = char_attr; /* save current attr */
3667 #ifdef FEAT_MBYTE
3668 			mb_c = c;
3669 			if (enc_utf8 && (*mb_char2len)(c) > 1)
3670 			{
3671 			    mb_utf8 = TRUE;
3672 			    u8c_c1 = u8c_c2 = 0;
3673 			}
3674 #endif
3675 		    }
3676 		    else
3677 		    {
3678 			c_extra = ' ';
3679 			c = ' ';
3680 		    }
3681 		}
3682 		else if (c == NUL && wp->w_p_list && lcs_eol_one > 0)
3683 		{
3684 #if defined(FEAT_DIFF) || defined(LINE_ATTR)
3685 		    /* For a diff line the highlighting continues after the
3686 		     * "$". */
3687 		    if (
3688 # ifdef FEAT_DIFF
3689 			    diff_hlf == (enum hlf_value)0
3690 #  ifdef LINE_ATTR
3691 			    &&
3692 #  endif
3693 # endif
3694 # ifdef LINE_ATTR
3695 			    line_attr == 0
3696 # endif
3697 		       )
3698 #endif
3699 		    {
3700 #ifdef FEAT_VIRTUALEDIT
3701 			/* In virtualedit, visual selections may extend
3702 			 * beyond end of line. */
3703 			if (area_highlighting && virtual_active()
3704 				&& tocol != MAXCOL && vcol < tocol)
3705 			    n_extra = 0;
3706 			else
3707 #endif
3708 			{
3709 			    p_extra = at_end_str;
3710 			    n_extra = 1;
3711 			    c_extra = NUL;
3712 			}
3713 		    }
3714 		    c = lcs_eol;
3715 		    lcs_eol_one = -1;
3716 		    --ptr;	    /* put it back at the NUL */
3717 		    if (area_attr == 0 && search_attr == 0)
3718 		    {
3719 			extra_attr = hl_attr(HLF_AT);
3720 			n_attr = 1;
3721 		    }
3722 #ifdef FEAT_MBYTE
3723 		    mb_c = c;
3724 		    if (enc_utf8 && (*mb_char2len)(c) > 1)
3725 		    {
3726 			mb_utf8 = TRUE;
3727 			u8c_c1 = u8c_c2 = 0;
3728 		    }
3729 		    else
3730 			mb_utf8 = FALSE;	/* don't draw as UTF-8 */
3731 #endif
3732 		}
3733 		else if (c != NUL)
3734 		{
3735 		    p_extra = transchar(c);
3736 #ifdef FEAT_RIGHTLEFT
3737 		    if ((dy_flags & DY_UHEX) && wp->w_p_rl)
3738 			rl_mirror(p_extra);	/* reverse "<12>" */
3739 #endif
3740 		    n_extra = byte2cells(c) - 1;
3741 		    c_extra = NUL;
3742 		    c = *p_extra++;
3743 		    if (area_attr == 0 && search_attr == 0)
3744 		    {
3745 			n_attr = n_extra + 1;
3746 			extra_attr = hl_attr(HLF_8);
3747 			saved_attr2 = char_attr; /* save current attr */
3748 		    }
3749 #ifdef FEAT_MBYTE
3750 		    mb_utf8 = FALSE;	/* don't draw as UTF-8 */
3751 #endif
3752 		}
3753 #ifdef FEAT_VIRTUALEDIT
3754 		else if (VIsual_active
3755 			 && (VIsual_mode == Ctrl_V
3756 			     || VIsual_mode == 'v')
3757 			 && virtual_active()
3758 			 && tocol != MAXCOL
3759 			 && vcol < tocol
3760 			 && (
3761 # ifdef FEAT_RIGHTLEFT
3762 			    wp->w_p_rl ? (col >= 0) :
3763 # endif
3764 			    (col < W_WIDTH(wp))))
3765 		{
3766 		    c = ' ';
3767 		    --ptr;	    /* put it back at the NUL */
3768 		}
3769 #endif
3770 #if defined(FEAT_DIFF) || defined(LINE_ATTR)
3771 		else if ((
3772 # ifdef FEAT_DIFF
3773 			    diff_hlf != (enum hlf_value)0
3774 #  ifdef LINE_ATTR
3775 			    ||
3776 #  endif
3777 # endif
3778 # ifdef LINE_ATTR
3779 			    line_attr != 0
3780 # endif
3781 			) && (
3782 # ifdef FEAT_RIGHTLEFT
3783 			    wp->w_p_rl ? (col >= 0) :
3784 # endif
3785 			    (col < W_WIDTH(wp))))
3786 		{
3787 		    /* Highlight until the right side of the window */
3788 		    c = ' ';
3789 		    --ptr;	    /* put it back at the NUL */
3790 # ifdef FEAT_DIFF
3791 		    if (diff_hlf == HLF_TXD)
3792 		    {
3793 			diff_hlf = HLF_CHD;
3794 			if (attr == 0 || char_attr != attr)
3795 			    char_attr = hl_attr(diff_hlf);
3796 		    }
3797 # endif
3798 		}
3799 #endif
3800 	    }
3801 	}
3802 
3803 	/* Don't override visual selection highlighting. */
3804 	if (n_attr > 0
3805 		&& draw_state == WL_LINE
3806 		&& (area_attr == 0 || char_attr != area_attr)
3807 		&& (search_attr == 0 || char_attr != search_attr))
3808 	    char_attr = extra_attr;
3809 
3810 #if defined(FEAT_XIM) && (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE))
3811 	/* XIM don't send preedit_start and preedit_end, but they send
3812 	 * preedit_changed and commit.  Thus Vim can't set "im_is_active", use
3813 	 * im_is_preediting() here. */
3814 	if (xic != NULL
3815 		&& lnum == curwin->w_cursor.lnum
3816 		&& (State & INSERT)
3817 		&& !p_imdisable
3818 		&& im_is_preediting()
3819 		&& draw_state == WL_LINE)
3820 	{
3821 	    colnr_T tcol;
3822 
3823 	    if (preedit_end_col == MAXCOL)
3824 		getvcol(curwin, &(curwin->w_cursor), &tcol, NULL, NULL);
3825 	    else
3826 		tcol = preedit_end_col;
3827 	    if ((long)preedit_start_col <= vcol && vcol < (long)tcol)
3828 	    {
3829 		if (feedback_old_attr < 0)
3830 		{
3831 		    feedback_col = 0;
3832 		    feedback_old_attr = char_attr;
3833 		}
3834 		char_attr = im_get_feedback_attr(feedback_col);
3835 		if (char_attr < 0)
3836 		    char_attr = feedback_old_attr;
3837 		feedback_col++;
3838 	    }
3839 	    else if (feedback_old_attr >= 0)
3840 	    {
3841 		char_attr = feedback_old_attr;
3842 		feedback_old_attr = -1;
3843 		feedback_col = 0;
3844 	    }
3845 	}
3846 #endif
3847 	/*
3848 	 * Handle the case where we are in column 0 but not on the first
3849 	 * character of the line and the user wants us to show us a
3850 	 * special character (via 'listchars' option "precedes:<char>".
3851 	 */
3852 	if (lcs_prec_todo != NUL
3853 		&& (wp->w_p_wrap ? wp->w_skipcol > 0 : wp->w_leftcol > 0)
3854 #ifdef FEAT_DIFF
3855 		&& filler_todo <= 0
3856 #endif
3857 		&& draw_state > WL_NR
3858 		&& c != NUL)
3859 	{
3860 	    c = lcs_prec;
3861 	    lcs_prec_todo = NUL;
3862 #ifdef FEAT_MBYTE
3863 	    mb_c = c;
3864 	    if (enc_utf8 && (*mb_char2len)(c) > 1)
3865 	    {
3866 		mb_utf8 = TRUE;
3867 		u8c_c1 = u8c_c2 = 0;
3868 	    }
3869 	    else
3870 		mb_utf8 = FALSE;	/* don't draw as UTF-8 */
3871 #endif
3872 	    if ((area_attr == 0 || char_attr != area_attr)
3873 		    && (search_attr == 0 || char_attr != search_attr))
3874 	    {
3875 		saved_attr3 = char_attr; /* save current attr */
3876 		char_attr = hl_attr(HLF_AT); /* later copied to char_attr */
3877 		n_attr3 = 1;
3878 	    }
3879 	}
3880 
3881 	/*
3882 	 * At end of the text line.
3883 	 */
3884 	if (c == NUL)
3885 	{
3886 	    /* invert at least one char, used for Visual and empty line or
3887 	     * highlight match at end of line. If it's beyond the last
3888 	     * char on the screen, just overwrite that one (tricky!)  Not
3889 	     * needed when a '$' was displayed for 'list'. */
3890 	    if (lcs_eol == lcs_eol_one
3891 		    && ((area_attr != 0 && vcol == fromcol)
3892 #ifdef FEAT_SEARCH_EXTRA
3893 			/* highlight 'hlsearch' match at end of line */
3894 			|| ptr - 1 == search_hl.startp
3895 			|| ptr - 1 == match_hl.startp
3896 #endif
3897 		       ))
3898 	    {
3899 		int n = 0;
3900 
3901 #ifdef FEAT_RIGHTLEFT
3902 		if (wp->w_p_rl)
3903 		{
3904 		    if (col < 0)
3905 			n = 1;
3906 		}
3907 		else
3908 #endif
3909 		{
3910 		    if (col >= W_WIDTH(wp))
3911 			n = -1;
3912 		}
3913 		if (n != 0)
3914 		{
3915 		    /* At the window boundary, highlight the last character
3916 		     * instead (better than nothing). */
3917 		    off += n;
3918 		    col += n;
3919 		}
3920 		else
3921 		{
3922 		    /* Add a blank character to highlight. */
3923 		    ScreenLines[off] = ' ';
3924 #ifdef FEAT_MBYTE
3925 		    if (enc_utf8)
3926 			ScreenLinesUC[off] = 0;
3927 #endif
3928 		}
3929 #ifdef FEAT_SEARCH_EXTRA
3930 		if (area_attr == 0)
3931 		{
3932 		    if (ptr - 1 == match_hl.startp)
3933 			char_attr = match_hl.attr;
3934 		    else
3935 			char_attr = search_hl.attr;
3936 		}
3937 #endif
3938 		ScreenAttrs[off] = char_attr;
3939 #ifdef FEAT_RIGHTLEFT
3940 		if (wp->w_p_rl)
3941 		    --col;
3942 		else
3943 #endif
3944 		    ++col;
3945 	    }
3946 
3947 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp),
3948 								  wp->w_p_rl);
3949 	    row++;
3950 
3951 	    /*
3952 	     * Update w_cline_height and w_cline_folded if the cursor line was
3953 	     * updated (saves a call to plines() later).
3954 	     */
3955 	    if (wp == curwin && lnum == curwin->w_cursor.lnum)
3956 	    {
3957 		curwin->w_cline_row = startrow;
3958 		curwin->w_cline_height = row - startrow;
3959 #ifdef FEAT_FOLDING
3960 		curwin->w_cline_folded = FALSE;
3961 #endif
3962 		curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
3963 	    }
3964 
3965 	    break;
3966 	}
3967 
3968 	/* line continues beyond line end */
3969 	if (lcs_ext
3970 		&& !wp->w_p_wrap
3971 #ifdef FEAT_DIFF
3972 		&& filler_todo <= 0
3973 #endif
3974 		&& (
3975 #ifdef FEAT_RIGHTLEFT
3976 		    wp->w_p_rl ? col == 0 :
3977 #endif
3978 		    col == W_WIDTH(wp) - 1)
3979 		&& (*ptr != NUL
3980 		    || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
3981 		    || (n_extra && (c_extra != NUL || *p_extra != NUL))))
3982 	{
3983 	    c = lcs_ext;
3984 	    char_attr = hl_attr(HLF_AT);
3985 #ifdef FEAT_MBYTE
3986 	    mb_c = c;
3987 	    if (enc_utf8 && (*mb_char2len)(c) > 1)
3988 	    {
3989 		mb_utf8 = TRUE;
3990 		u8c_c1 = u8c_c2 = 0;
3991 	    }
3992 	    else
3993 		mb_utf8 = FALSE;
3994 #endif
3995 	}
3996 
3997 	/*
3998 	 * Store character to be displayed.
3999 	 * Skip characters that are left of the screen for 'nowrap'.
4000 	 */
4001 	vcol_prev = vcol;
4002 	if (draw_state < WL_LINE || n_skip <= 0)
4003 	{
4004 	    /*
4005 	     * Store the character.
4006 	     */
4007 #if defined(FEAT_RIGHTLEFT) && defined(FEAT_MBYTE)
4008 	    if (has_mbyte && wp->w_p_rl && (*mb_char2cells)(mb_c) > 1)
4009 	    {
4010 		/* A double-wide character is: put first halve in left cell. */
4011 		--off;
4012 		--col;
4013 	    }
4014 #endif
4015 	    ScreenLines[off] = c;
4016 #ifdef FEAT_MBYTE
4017 	    if (enc_dbcs == DBCS_JPNU)
4018 		ScreenLines2[off] = mb_c & 0xff;
4019 	    else if (enc_utf8)
4020 	    {
4021 		if (mb_utf8)
4022 		{
4023 		    ScreenLinesUC[off] = mb_c;
4024 		    ScreenLinesC1[off] = u8c_c1;
4025 		    ScreenLinesC2[off] = u8c_c2;
4026 		}
4027 		else
4028 		    ScreenLinesUC[off] = 0;
4029 	    }
4030 	    if (multi_attr)
4031 	    {
4032 		ScreenAttrs[off] = multi_attr;
4033 		multi_attr = 0;
4034 	    }
4035 	    else
4036 #endif
4037 		ScreenAttrs[off] = char_attr;
4038 
4039 #ifdef FEAT_MBYTE
4040 	    if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
4041 	    {
4042 		/* Need to fill two screen columns. */
4043 		++off;
4044 		++col;
4045 		if (enc_utf8)
4046 		    /* UTF-8: Put a 0 in the second screen char. */
4047 		    ScreenLines[off] = 0;
4048 		else
4049 		    /* DBCS: Put second byte in the second screen char. */
4050 		    ScreenLines[off] = mb_c & 0xff;
4051 		++vcol;
4052 		/* When "tocol" is halfway a character, set it to the end of
4053 		 * the character, otherwise highlighting won't stop. */
4054 		if (tocol == vcol)
4055 		    ++tocol;
4056 #ifdef FEAT_RIGHTLEFT
4057 		if (wp->w_p_rl)
4058 		{
4059 		    /* now it's time to backup one cell */
4060 		    --off;
4061 		    --col;
4062 		}
4063 #endif
4064 	    }
4065 #endif
4066 #ifdef FEAT_RIGHTLEFT
4067 	    if (wp->w_p_rl)
4068 	    {
4069 		--off;
4070 		--col;
4071 	    }
4072 	    else
4073 #endif
4074 	    {
4075 		++off;
4076 		++col;
4077 	    }
4078 	}
4079 	else
4080 	    --n_skip;
4081 
4082 	/* Only advance the "vcol" when after the 'number' column. */
4083 	if (draw_state >= WL_SBR
4084 #ifdef FEAT_DIFF
4085 		&& filler_todo <= 0
4086 #endif
4087 		)
4088 	    ++vcol;
4089 
4090 	/* restore attributes after "predeces" in 'listchars' */
4091 	if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
4092 	    char_attr = saved_attr3;
4093 
4094 	/* restore attributes after last 'listchars' or 'number' char */
4095 	if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
4096 	    char_attr = saved_attr2;
4097 
4098 	/*
4099 	 * At end of screen line and there is more to come: Display the line
4100 	 * so far.  If there is no more to display it is catched above.
4101 	 */
4102 	if ((
4103 #ifdef FEAT_RIGHTLEFT
4104 	    wp->w_p_rl ? (col < 0) :
4105 #endif
4106 				    (col >= W_WIDTH(wp)))
4107 		&& (*ptr != NUL
4108 #ifdef FEAT_DIFF
4109 		    || filler_todo > 0
4110 #endif
4111 		    || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
4112 		    || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
4113 		)
4114 	{
4115 	    SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp),
4116 								  wp->w_p_rl);
4117 	    ++row;
4118 	    ++screen_row;
4119 
4120 	    /* When not wrapping and finished diff lines, or when displayed
4121 	     * '$' and highlighting until last column, break here. */
4122 	    if ((!wp->w_p_wrap
4123 #ifdef FEAT_DIFF
4124 		    && filler_todo <= 0
4125 #endif
4126 		    ) || lcs_eol_one == -1)
4127 		break;
4128 
4129 	    /* When the window is too narrow draw all "@" lines. */
4130 	    if (draw_state != WL_LINE
4131 #ifdef FEAT_DIFF
4132 		    && filler_todo <= 0
4133 #endif
4134 		    )
4135 	    {
4136 		win_draw_end(wp, '@', ' ', row, wp->w_height, HLF_AT);
4137 #ifdef FEAT_VERTSPLIT
4138 		draw_vsep_win(wp, row);
4139 #endif
4140 		row = endrow;
4141 	    }
4142 
4143 	    /* When line got too long for screen break here. */
4144 	    if (row == endrow)
4145 	    {
4146 		++row;
4147 		break;
4148 	    }
4149 
4150 	    if (screen_cur_row == screen_row - 1
4151 #ifdef FEAT_DIFF
4152 		     && filler_todo <= 0
4153 #endif
4154 		     && W_WIDTH(wp) == Columns)
4155 	    {
4156 		/* Remember that the line wraps, used for modeless copy. */
4157 		LineWraps[screen_row - 1] = TRUE;
4158 
4159 		/*
4160 		 * Special trick to make copy/paste of wrapped lines work with
4161 		 * xterm/screen: write an extra character beyond the end of
4162 		 * the line. This will work with all terminal types
4163 		 * (regardless of the xn,am settings).
4164 		 * Only do this on a fast tty.
4165 		 * Only do this if the cursor is on the current line
4166 		 * (something has been written in it).
4167 		 * Don't do this for the GUI.
4168 		 * Don't do this for double-width characters.
4169 		 * Don't do this for a window not at the right screen border.
4170 		 */
4171 		if (p_tf
4172 #ifdef FEAT_GUI
4173 			 && !gui.in_use
4174 #endif
4175 #ifdef FEAT_MBYTE
4176 			 && !(has_mbyte
4177 			     && ((*mb_off2cells)(LineOffset[screen_row]) == 2
4178 				 || (*mb_off2cells)(LineOffset[screen_row - 1]
4179 							+ (int)Columns - 2) == 2))
4180 #endif
4181 		   )
4182 		{
4183 		    /* First make sure we are at the end of the screen line,
4184 		     * then output the same character again to let the
4185 		     * terminal know about the wrap.  If the terminal doesn't
4186 		     * auto-wrap, we overwrite the character. */
4187 		    if (screen_cur_col != W_WIDTH(wp))
4188 			screen_char(LineOffset[screen_row - 1]
4189 						      + (unsigned)Columns - 1,
4190 					  screen_row - 1, (int)(Columns - 1));
4191 
4192 #ifdef FEAT_MBYTE
4193 		    /* When there is a multi-byte character, just output a
4194 		     * space to keep it simple. */
4195 		    if (has_mbyte && mb_off2cells(LineOffset[screen_row - 1]
4196 						+ (unsigned)Columns - 1) != 1)
4197 			out_char(' ');
4198 		    else
4199 #endif
4200 			out_char(ScreenLines[LineOffset[screen_row - 1]
4201 							    + (Columns - 1)]);
4202 		    /* force a redraw of the first char on the next line */
4203 		    ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
4204 		    screen_start();	/* don't know where cursor is now */
4205 		}
4206 	    }
4207 
4208 	    col = 0;
4209 	    off = (unsigned)(current_ScreenLine - ScreenLines);
4210 #ifdef FEAT_RIGHTLEFT
4211 	    if (wp->w_p_rl)
4212 	    {
4213 		col = W_WIDTH(wp) - 1;	/* col is not used if breaking! */
4214 		off += col;
4215 	    }
4216 #endif
4217 
4218 	    /* reset the drawing state for the start of a wrapped line */
4219 	    draw_state = WL_START;
4220 	    saved_n_extra = n_extra;
4221 	    saved_p_extra = p_extra;
4222 	    saved_c_extra = c_extra;
4223 	    saved_char_attr = char_attr;
4224 	    n_extra = 0;
4225 	    lcs_prec_todo = lcs_prec;
4226 #ifdef FEAT_LINEBREAK
4227 # ifdef FEAT_DIFF
4228 	    if (filler_todo <= 0)
4229 # endif
4230 		need_showbreak = TRUE;
4231 #endif
4232 #ifdef FEAT_DIFF
4233 	    --filler_todo;
4234 	    /* When the filler lines are actually below the last line of the
4235 	     * file, don't draw the line itself, break here. */
4236 	    if (filler_todo == 0 && wp->w_botfill)
4237 		break;
4238 #endif
4239 	}
4240 
4241     }	/* for every character in the line */
4242 
4243     return row;
4244 }
4245 
4246 /*
4247  * Check whether the given character needs redrawing:
4248  * - the (first byte of the) character is different
4249  * - the attributes are different
4250  * - the character is multi-byte and the next byte is different
4251  */
4252     static int
4253 char_needs_redraw(off_from, off_to, cols)
4254     int		off_from;
4255     int		off_to;
4256     int		cols;
4257 {
4258     if (cols > 0
4259 	    && ((ScreenLines[off_from] != ScreenLines[off_to]
4260 		    || ScreenAttrs[off_from] != ScreenAttrs[off_to])
4261 
4262 #ifdef FEAT_MBYTE
4263 		|| (enc_dbcs != 0
4264 		    && MB_BYTE2LEN(ScreenLines[off_from]) > 1
4265 		    && (enc_dbcs == DBCS_JPNU && ScreenLines[off_from] == 0x8e
4266 			? ScreenLines2[off_from] != ScreenLines2[off_to]
4267 			: (cols > 1 && ScreenLines[off_from + 1]
4268 						 != ScreenLines[off_to + 1])))
4269 		|| (enc_utf8
4270 		    && (ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
4271 			|| (ScreenLinesUC[off_from] != 0
4272 			    && (ScreenLinesC1[off_from]
4273 						      != ScreenLinesC1[off_to]
4274 				|| ScreenLinesC2[off_from]
4275 						  != ScreenLinesC2[off_to]))))
4276 #endif
4277 	       ))
4278 	return TRUE;
4279     return FALSE;
4280 }
4281 
4282 /*
4283  * Move one "cooked" screen line to the screen, but only the characters that
4284  * have actually changed.  Handle insert/delete character.
4285  * "coloff" gives the first column on the screen for this line.
4286  * "endcol" gives the columns where valid characters are.
4287  * "clear_width" is the width of the window.  It's > 0 if the rest of the line
4288  * needs to be cleared, negative otherwise.
4289  * "rlflag" is TRUE in a rightleft window:
4290  *    When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
4291  *    When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
4292  */
4293     static void
4294 screen_line(row, coloff, endcol, clear_width
4295 #ifdef FEAT_RIGHTLEFT
4296 				    , rlflag
4297 #endif
4298 						)
4299     int	    row;
4300     int	    coloff;
4301     int	    endcol;
4302     int	    clear_width;
4303 #ifdef FEAT_RIGHTLEFT
4304     int	    rlflag;
4305 #endif
4306 {
4307     unsigned	    off_from;
4308     unsigned	    off_to;
4309     int		    col = 0;
4310 #if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_VERTSPLIT)
4311     int		    hl;
4312 #endif
4313     int		    force = FALSE;	/* force update rest of the line */
4314     int		    redraw_this		/* bool: does character need redraw? */
4315 #ifdef FEAT_GUI
4316 				= TRUE	/* For GUI when while-loop empty */
4317 #endif
4318 				;
4319     int		    redraw_next;	/* redraw_this for next character */
4320 #ifdef FEAT_MBYTE
4321     int		    clear_next = FALSE;
4322     int		    char_cells;		/* 1: normal char */
4323 					/* 2: occupies two display cells */
4324 # define CHAR_CELLS char_cells
4325 #else
4326 # define CHAR_CELLS 1
4327 #endif
4328 
4329 # ifdef FEAT_CLIPBOARD
4330     clip_may_clear_selection(row, row);
4331 # endif
4332 
4333     off_from = (unsigned)(current_ScreenLine - ScreenLines);
4334     off_to = LineOffset[row] + coloff;
4335 
4336 #ifdef FEAT_RIGHTLEFT
4337     if (rlflag)
4338     {
4339 	/* Clear rest first, because it's left of the text. */
4340 	if (clear_width > 0)
4341 	{
4342 	    while (col <= endcol && ScreenLines[off_to] == ' '
4343 		    && ScreenAttrs[off_to] == 0
4344 # ifdef FEAT_MBYTE
4345 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
4346 # endif
4347 						  )
4348 	    {
4349 		++off_to;
4350 		++col;
4351 	    }
4352 	    if (col <= endcol)
4353 		screen_fill(row, row + 1, col + coloff,
4354 					    endcol + coloff + 1, ' ', ' ', 0);
4355 	}
4356 	col = endcol + 1;
4357 	off_to = LineOffset[row] + col + coloff;
4358 	off_from += col;
4359 	endcol = (clear_width > 0 ? clear_width : -clear_width);
4360     }
4361 #endif /* FEAT_RIGHTLEFT */
4362 
4363     redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
4364 
4365     while (col < endcol)
4366     {
4367 #ifdef FEAT_MBYTE
4368 	if (has_mbyte && (col + 1 < endcol))
4369 	    char_cells = (*mb_off2cells)(off_from);
4370 	else
4371 	    char_cells = 1;
4372 #endif
4373 
4374 	redraw_this = redraw_next;
4375 	redraw_next = force || char_needs_redraw(off_from + CHAR_CELLS,
4376 			      off_to + CHAR_CELLS, endcol - col - CHAR_CELLS);
4377 
4378 #ifdef FEAT_GUI
4379 	/* If the next character was bold, then redraw the current character to
4380 	 * remove any pixels that might have spilt over into us.  This only
4381 	 * happens in the GUI.
4382 	 */
4383 	if (redraw_next && gui.in_use)
4384 	{
4385 	    hl = ScreenAttrs[off_to + CHAR_CELLS];
4386 	    if (hl > HL_ALL || (hl & HL_BOLD))
4387 		redraw_this = TRUE;
4388 	}
4389 #endif
4390 
4391 	if (redraw_this)
4392 	{
4393 	    /*
4394 	     * Special handling when 'xs' termcap flag set (hpterm):
4395 	     * Attributes for characters are stored at the position where the
4396 	     * cursor is when writing the highlighting code.  The
4397 	     * start-highlighting code must be written with the cursor on the
4398 	     * first highlighted character.  The stop-highlighting code must
4399 	     * be written with the cursor just after the last highlighted
4400 	     * character.
4401 	     * Overwriting a character doesn't remove it's highlighting.  Need
4402 	     * to clear the rest of the line, and force redrawing it
4403 	     * completely.
4404 	     */
4405 	    if (       p_wiv
4406 		    && !force
4407 #ifdef FEAT_GUI
4408 		    && !gui.in_use
4409 #endif
4410 		    && ScreenAttrs[off_to] != 0
4411 		    && ScreenAttrs[off_from] != ScreenAttrs[off_to])
4412 	    {
4413 		/*
4414 		 * Need to remove highlighting attributes here.
4415 		 */
4416 		windgoto(row, col + coloff);
4417 		out_str(T_CE);		/* clear rest of this screen line */
4418 		screen_start();		/* don't know where cursor is now */
4419 		force = TRUE;		/* force redraw of rest of the line */
4420 		redraw_next = TRUE;	/* or else next char would miss out */
4421 
4422 		/*
4423 		 * If the previous character was highlighted, need to stop
4424 		 * highlighting at this character.
4425 		 */
4426 		if (col + coloff > 0 && ScreenAttrs[off_to - 1] != 0)
4427 		{
4428 		    screen_attr = ScreenAttrs[off_to - 1];
4429 		    term_windgoto(row, col + coloff);
4430 		    screen_stop_highlight();
4431 		}
4432 		else
4433 		    screen_attr = 0;	    /* highlighting has stopped */
4434 	    }
4435 #ifdef FEAT_MBYTE
4436 	    if (enc_dbcs != 0)
4437 	    {
4438 		/* Check if overwriting a double-byte with a single-byte or
4439 		 * the other way around requires another character to be
4440 		 * redrawn.  For UTF-8 this isn't needed, because comparing
4441 		 * ScreenLinesUC[] is sufficient. */
4442 		if (char_cells == 1
4443 			&& col + 1 < endcol
4444 			&& (*mb_off2cells)(off_to) > 1)
4445 		{
4446 		    /* Writing a single-cell character over a double-cell
4447 		     * character: need to redraw the next cell. */
4448 		    ScreenLines[off_to + 1] = 0;
4449 		    redraw_next = TRUE;
4450 		}
4451 		else if (char_cells == 2
4452 			&& col + 2 < endcol
4453 			&& (*mb_off2cells)(off_to) == 1
4454 			&& (*mb_off2cells)(off_to + 1) > 1)
4455 		{
4456 		    /* Writing the second half of a double-cell character over
4457 		     * a double-cell character: need to redraw the second
4458 		     * cell. */
4459 		    ScreenLines[off_to + 2] = 0;
4460 		    redraw_next = TRUE;
4461 		}
4462 
4463 		if (enc_dbcs == DBCS_JPNU)
4464 		    ScreenLines2[off_to] = ScreenLines2[off_from];
4465 	    }
4466 	    /* When writing a single-width character over a double-width
4467 	     * character and at the end of the redrawn text, need to clear out
4468 	     * the right halve of the old character.
4469 	     * Also required when writing the right halve of a double-width
4470 	     * char over the left halve of an existing one. */
4471 	    if (has_mbyte && col + char_cells == endcol
4472 		    && ((char_cells == 1
4473 			    && (*mb_off2cells)(off_to) > 1)
4474 			|| (char_cells == 2
4475 			    && (*mb_off2cells)(off_to) == 1
4476 			    && (*mb_off2cells)(off_to + 1) > 1)))
4477 		clear_next = TRUE;
4478 #endif
4479 
4480 	    ScreenLines[off_to] = ScreenLines[off_from];
4481 #ifdef FEAT_MBYTE
4482 	    if (enc_utf8)
4483 	    {
4484 		ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
4485 		if (ScreenLinesUC[off_from] != 0)
4486 		{
4487 		    ScreenLinesC1[off_to] = ScreenLinesC1[off_from];
4488 		    ScreenLinesC2[off_to] = ScreenLinesC2[off_from];
4489 		}
4490 	    }
4491 	    if (char_cells == 2)
4492 		ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
4493 #endif
4494 
4495 #if defined(FEAT_GUI) || defined(UNIX)
4496 	    /* The bold trick makes a single row of pixels appear in the next
4497 	     * character.  When a bold character is removed, the next
4498 	     * character should be redrawn too.  This happens for our own GUI
4499 	     * and for some xterms. */
4500 	    if (
4501 # ifdef FEAT_GUI
4502 		    gui.in_use
4503 # endif
4504 # if defined(FEAT_GUI) && defined(UNIX)
4505 		    ||
4506 # endif
4507 # ifdef UNIX
4508 		    term_is_xterm
4509 # endif
4510 		    )
4511 	    {
4512 		hl = ScreenAttrs[off_to];
4513 		if (hl > HL_ALL || (hl & HL_BOLD))
4514 		    redraw_next = TRUE;
4515 	    }
4516 #endif
4517 	    ScreenAttrs[off_to] = ScreenAttrs[off_from];
4518 #ifdef FEAT_MBYTE
4519 	    if (enc_dbcs != 0 && char_cells == 2)
4520 	    {
4521 		/* just a hack: It makes two bytes of DBCS have same attr */
4522 		ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
4523 		screen_char_2(off_to, row, col + coloff);
4524 	    }
4525 	    else
4526 #endif
4527 		screen_char(off_to, row, col + coloff);
4528 	}
4529 	else if (  p_wiv
4530 #ifdef FEAT_GUI
4531 		&& !gui.in_use
4532 #endif
4533 		&& col + coloff > 0)
4534 	{
4535 	    if (ScreenAttrs[off_to] == ScreenAttrs[off_to - 1])
4536 	    {
4537 		/*
4538 		 * Don't output stop-highlight when moving the cursor, it will
4539 		 * stop the highlighting when it should continue.
4540 		 */
4541 		screen_attr = 0;
4542 	    }
4543 	    else if (screen_attr != 0)
4544 		screen_stop_highlight();
4545 	}
4546 
4547 	off_to += CHAR_CELLS;
4548 	off_from += CHAR_CELLS;
4549 	col += CHAR_CELLS;
4550     }
4551 
4552 #ifdef FEAT_MBYTE
4553     if (clear_next)
4554     {
4555 	/* Clear the second half of a double-wide character of which the left
4556 	 * half was overwritten with a single-wide character. */
4557 	ScreenLines[off_to] = ' ';
4558 	if (enc_utf8)
4559 	    ScreenLinesUC[off_to] = 0;
4560 	screen_char(off_to, row, col + coloff);
4561     }
4562 #endif
4563 
4564     if (clear_width > 0
4565 #ifdef FEAT_RIGHTLEFT
4566 		    && !rlflag
4567 #endif
4568 				   )
4569     {
4570 #ifdef FEAT_GUI
4571 	int startCol = col;
4572 #endif
4573 
4574 	/* blank out the rest of the line */
4575 	while (col < clear_width && ScreenLines[off_to] == ' '
4576 						  && ScreenAttrs[off_to] == 0
4577 #ifdef FEAT_MBYTE
4578 				  && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
4579 #endif
4580 						  )
4581 	{
4582 	    ++off_to;
4583 	    ++col;
4584 	}
4585 	if (col < clear_width)
4586 	{
4587 #ifdef FEAT_GUI
4588 	    /*
4589 	     * In the GUI, clearing the rest of the line may leave pixels
4590 	     * behind if the first character cleared was bold.  Some bold
4591 	     * fonts spill over the left.  In this case we redraw the previous
4592 	     * character too.  If we didn't skip any blanks above, then we
4593 	     * only redraw if the character wasn't already redrawn anyway.
4594 	     */
4595 	    if (gui.in_use && (col > startCol || !redraw_this)
4596 # ifdef FEAT_MBYTE
4597 		    && enc_dbcs == 0
4598 # endif
4599 	       )
4600 	    {
4601 		hl = ScreenAttrs[off_to];
4602 		if (hl > HL_ALL || (hl & HL_BOLD))
4603 		    screen_char(off_to - 1, row, col + coloff - 1);
4604 	    }
4605 #endif
4606 	    screen_fill(row, row + 1, col + coloff, clear_width + coloff,
4607 								 ' ', ' ', 0);
4608 #ifdef FEAT_VERTSPLIT
4609 	    off_to += clear_width - col;
4610 	    col = clear_width;
4611 #endif
4612 	}
4613     }
4614 
4615     if (clear_width > 0)
4616     {
4617 #ifdef FEAT_VERTSPLIT
4618 	/* For a window that's left of another, draw the separator char. */
4619 	if (col + coloff < Columns)
4620 	{
4621 	    int c;
4622 
4623 	    c = fillchar_vsep(&hl);
4624 	    if (ScreenLines[off_to] != c
4625 # ifdef FEAT_MBYTE
4626 		    || (enc_utf8
4627 			      && ScreenLinesUC[off_to] != (c >= 0x80 ? c : 0))
4628 # endif
4629 		    || ScreenAttrs[off_to] != hl)
4630 	    {
4631 		ScreenLines[off_to] = c;
4632 		ScreenAttrs[off_to] = hl;
4633 # ifdef FEAT_MBYTE
4634 		if (enc_utf8)
4635 		{
4636 		    if (c >= 0x80)
4637 		    {
4638 			ScreenLinesUC[off_to] = c;
4639 			ScreenLinesC1[off_to] = 0;
4640 			ScreenLinesC2[off_to] = 0;
4641 		    }
4642 		    else
4643 			ScreenLinesUC[off_to] = 0;
4644 		}
4645 # endif
4646 		screen_char(off_to, row, col + coloff);
4647 	    }
4648 	}
4649 	else
4650 #endif
4651 	    LineWraps[row] = FALSE;
4652     }
4653 }
4654 
4655 #ifdef FEAT_RIGHTLEFT
4656 /*
4657  * Mirror text "str" for right-lieft displaying.
4658  */
4659     static void
4660 rl_mirror(str)
4661     char_u	*str;
4662 {
4663     char_u	*p1, *p2;
4664     int		t;
4665 
4666     for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2)
4667     {
4668 	t = *p1;
4669 	*p1 = *p2;
4670 	*p2 = t;
4671     }
4672 }
4673 #endif
4674 
4675 #if defined(FEAT_WINDOWS) || defined(PROTO)
4676 /*
4677  * mark all status lines for redraw; used after first :cd
4678  */
4679     void
4680 status_redraw_all()
4681 {
4682     win_T	*wp;
4683 
4684     for (wp = firstwin; wp; wp = wp->w_next)
4685 	if (wp->w_status_height)
4686 	{
4687 	    wp->w_redr_status = TRUE;
4688 	    redraw_later(VALID);
4689 	}
4690 }
4691 
4692 /*
4693  * mark all status lines of the current buffer for redraw
4694  */
4695     void
4696 status_redraw_curbuf()
4697 {
4698     win_T	*wp;
4699 
4700     for (wp = firstwin; wp; wp = wp->w_next)
4701 	if (wp->w_status_height != 0 && wp->w_buffer == curbuf)
4702 	{
4703 	    wp->w_redr_status = TRUE;
4704 	    redraw_later(VALID);
4705 	}
4706 }
4707 
4708 /*
4709  * Redraw all status lines that need to be redrawn.
4710  */
4711     void
4712 redraw_statuslines()
4713 {
4714     win_T	*wp;
4715 
4716     for (wp = firstwin; wp; wp = wp->w_next)
4717 	if (wp->w_redr_status)
4718 	    win_redr_status(wp);
4719 }
4720 #endif
4721 
4722 #if (defined(FEAT_WILDMENU) && defined(FEAT_VERTSPLIT)) || defined(PROTO)
4723 /*
4724  * Redraw all status lines at the bottom of frame "frp".
4725  */
4726     void
4727 win_redraw_last_status(frp)
4728     frame_T	*frp;
4729 {
4730     if (frp->fr_layout == FR_LEAF)
4731 	frp->fr_win->w_redr_status = TRUE;
4732     else if (frp->fr_layout == FR_ROW)
4733     {
4734 	for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
4735 	    win_redraw_last_status(frp);
4736     }
4737     else /* frp->fr_layout == FR_COL */
4738     {
4739 	frp = frp->fr_child;
4740 	while (frp->fr_next != NULL)
4741 	    frp = frp->fr_next;
4742 	win_redraw_last_status(frp);
4743     }
4744 }
4745 #endif
4746 
4747 #ifdef FEAT_VERTSPLIT
4748 /*
4749  * Draw the verticap separator right of window "wp" starting with line "row".
4750  */
4751     static void
4752 draw_vsep_win(wp, row)
4753     win_T	*wp;
4754     int		row;
4755 {
4756     int		hl;
4757     int		c;
4758 
4759     if (wp->w_vsep_width)
4760     {
4761 	/* draw the vertical separator right of this window */
4762 	c = fillchar_vsep(&hl);
4763 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
4764 		W_ENDCOL(wp), W_ENDCOL(wp) + 1,
4765 		c, ' ', hl);
4766     }
4767 }
4768 #endif
4769 
4770 #ifdef FEAT_WILDMENU
4771 static int status_match_len __ARGS((expand_T *xp, char_u *s));
4772 
4773 /*
4774  * Get the lenght of an item as it will be shown in the status line.
4775  */
4776     static int
4777 status_match_len(xp, s)
4778     expand_T	*xp;
4779     char_u	*s;
4780 {
4781     int	len = 0;
4782 
4783 #ifdef FEAT_MENU
4784     int emenu = (xp->xp_context == EXPAND_MENUS
4785 	    || xp->xp_context == EXPAND_MENUNAMES);
4786 
4787     /* Check for menu separators - replace with '|'. */
4788     if (emenu && menu_is_separator(s))
4789 	return 1;
4790 #endif
4791 
4792     while (*s != NUL)
4793     {
4794 	/* Don't display backslashes used for escaping, they look ugly. */
4795 	if (rem_backslash(s)
4796 #ifdef FEAT_MENU
4797 		|| (emenu && (s[0] == '\\' && s[1] != NUL))
4798 #endif
4799 		)
4800 	    ++s;
4801 #ifdef FEAT_MBYTE
4802 	if (has_mbyte)
4803 	{
4804 	    len += ptr2cells(s);
4805 	    s += (*mb_ptr2len_check)(s);
4806 	}
4807 	else
4808 #endif
4809 	    len += ptr2cells(s++);
4810 
4811     }
4812 
4813     return len;
4814 }
4815 
4816 /*
4817  * Show wildchar matches in the status line.
4818  * Show at least the "match" item.
4819  * We start at item 'first_match' in the list and show all matches that fit.
4820  *
4821  * If inversion is possible we use it. Else '=' characters are used.
4822  */
4823     void
4824 win_redr_status_matches(xp, num_matches, matches, match, showtail)
4825     expand_T	*xp;
4826     int		num_matches;
4827     char_u	**matches;	/* list of matches */
4828     int		match;
4829     int		showtail;
4830 {
4831 #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
4832     int		row;
4833     char_u	*buf;
4834     int		len;
4835     int		clen;		/* lenght in screen cells */
4836     int		fillchar;
4837     int		attr;
4838     int		i;
4839     int		highlight = TRUE;
4840     char_u	*selstart = NULL;
4841     int		selstart_col = 0;
4842     char_u	*selend = NULL;
4843     static int	first_match = 0;
4844     int		add_left = FALSE;
4845     char_u	*s;
4846 #ifdef FEAT_MENU
4847     int		emenu;
4848 #endif
4849 #if defined(FEAT_MBYTE) || defined(FEAT_MENU)
4850     int		l;
4851 #endif
4852 
4853     if (matches == NULL)	/* interrupted completion? */
4854 	return;
4855 
4856     buf = alloc((unsigned)Columns + 1);
4857     if (buf == NULL)
4858 	return;
4859 
4860     if (match == -1)	/* don't show match but original text */
4861     {
4862 	match = 0;
4863 	highlight = FALSE;
4864     }
4865     /* count 1 for the ending ">" */
4866     clen = status_match_len(xp, L_MATCH(match)) + 3;
4867     if (match == 0)
4868 	first_match = 0;
4869     else if (match < first_match)
4870     {
4871 	/* jumping left, as far as we can go */
4872 	first_match = match;
4873 	add_left = TRUE;
4874     }
4875     else
4876     {
4877 	/* check if match fits on the screen */
4878 	for (i = first_match; i < match; ++i)
4879 	    clen += status_match_len(xp, L_MATCH(i)) + 2;
4880 	if (first_match > 0)
4881 	    clen += 2;
4882 	/* jumping right, put match at the left */
4883 	if ((long)clen > Columns)
4884 	{
4885 	    first_match = match;
4886 	    /* if showing the last match, we can add some on the left */
4887 	    clen = 2;
4888 	    for (i = match; i < num_matches; ++i)
4889 	    {
4890 		clen += status_match_len(xp, L_MATCH(i)) + 2;
4891 		if ((long)clen >= Columns)
4892 		    break;
4893 	    }
4894 	    if (i == num_matches)
4895 		add_left = TRUE;
4896 	}
4897     }
4898     if (add_left)
4899 	while (first_match > 0)
4900 	{
4901 	    clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
4902 	    if ((long)clen >= Columns)
4903 		break;
4904 	    --first_match;
4905 	}
4906 
4907     fillchar = fillchar_status(&attr, TRUE);
4908 
4909     if (first_match == 0)
4910     {
4911 	*buf = NUL;
4912 	len = 0;
4913     }
4914     else
4915     {
4916 	STRCPY(buf, "< ");
4917 	len = 2;
4918     }
4919     clen = len;
4920 
4921     i = first_match;
4922     while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns)
4923     {
4924 	if (i == match)
4925 	{
4926 	    selstart = buf + len;
4927 	    selstart_col = clen;
4928 	}
4929 
4930 	s = L_MATCH(i);
4931 	/* Check for menu separators - replace with '|' */
4932 #ifdef FEAT_MENU
4933 	emenu = (xp->xp_context == EXPAND_MENUS
4934 		|| xp->xp_context == EXPAND_MENUNAMES);
4935 	if (emenu && menu_is_separator(s))
4936 	{
4937 	    STRCPY(buf + len, transchar('|'));
4938 	    l = (int)STRLEN(buf + len);
4939 	    len += l;
4940 	    clen += l;
4941 	}
4942 	else
4943 #endif
4944 	    for ( ; *s != NUL; ++s)
4945 	{
4946 	    /* Don't display backslashes used for escaping, they look ugly. */
4947 	    if (rem_backslash(s)
4948 #ifdef FEAT_MENU
4949 		    || (emenu
4950 			  && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
4951 #endif
4952 		    )
4953 		++s;
4954 	    clen += ptr2cells(s);
4955 #ifdef FEAT_MBYTE
4956 	    if (has_mbyte && (l = (*mb_ptr2len_check)(s)) > 1)
4957 	    {
4958 		STRNCPY(buf + len, s, l);
4959 		s += l - 1;
4960 		len += l;
4961 	    }
4962 	    else
4963 #endif
4964 	    {
4965 		STRCPY(buf + len, transchar_byte(*s));
4966 		len += (int)STRLEN(buf + len);
4967 	    }
4968 	}
4969 	if (i == match)
4970 	    selend = buf + len;
4971 
4972 	*(buf + len++) = ' ';
4973 	*(buf + len++) = ' ';
4974 	clen += 2;
4975 	if (++i == num_matches)
4976 		break;
4977     }
4978 
4979     if (i != num_matches)
4980     {
4981 	*(buf + len++) = '>';
4982 	++clen;
4983     }
4984 
4985     buf[len] = NUL;
4986 
4987     row = cmdline_row - 1;
4988     if (row >= 0)
4989     {
4990 	if (wild_menu_showing == 0)
4991 	{
4992 	    if (msg_scrolled > 0)
4993 	    {
4994 		/* Put the wildmenu just above the command line.  If there is
4995 		 * no room, scroll the screen one line up. */
4996 		if (cmdline_row == Rows - 1)
4997 		{
4998 		    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
4999 		    ++msg_scrolled;
5000 		}
5001 		else
5002 		{
5003 		    ++cmdline_row;
5004 		    ++row;
5005 		}
5006 		wild_menu_showing = WM_SCROLLED;
5007 	    }
5008 	    else
5009 	    {
5010 		/* Create status line if needed by setting 'laststatus' to 2.
5011 		 * Set 'winminheight' to zero to avoid that the window is
5012 		 * resized. */
5013 		if (lastwin->w_status_height == 0)
5014 		{
5015 		    save_p_ls = p_ls;
5016 		    save_p_wmh = p_wmh;
5017 		    p_ls = 2;
5018 		    p_wmh = 0;
5019 		    last_status(FALSE);
5020 		}
5021 		wild_menu_showing = WM_SHOWN;
5022 	    }
5023 	}
5024 
5025 	screen_puts(buf, row, 0, attr);
5026 	if (selstart != NULL && highlight)
5027 	{
5028 	    *selend = NUL;
5029 	    screen_puts(selstart, row, selstart_col, hl_attr(HLF_WM));
5030 	}
5031 
5032 	screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr);
5033     }
5034 
5035 #ifdef FEAT_VERTSPLIT
5036     win_redraw_last_status(topframe);
5037 #else
5038     lastwin->w_redr_status = TRUE;
5039 #endif
5040     vim_free(buf);
5041 }
5042 #endif
5043 
5044 #if defined(FEAT_WINDOWS) || defined(PROTO)
5045 /*
5046  * Redraw the status line of window wp.
5047  *
5048  * If inversion is possible we use it. Else '=' characters are used.
5049  */
5050     void
5051 win_redr_status(wp)
5052     win_T	*wp;
5053 {
5054     int		row;
5055     char_u	*p;
5056     int		len;
5057     int		fillchar;
5058     int		attr;
5059     int		this_ru_col;
5060 
5061     wp->w_redr_status = FALSE;
5062     if (wp->w_status_height == 0)
5063     {
5064 	/* no status line, can only be last window */
5065 	redraw_cmdline = TRUE;
5066     }
5067     else if (!redrawing())
5068     {
5069 	/* Don't redraw right now, do it later. */
5070 	wp->w_redr_status = TRUE;
5071     }
5072 #ifdef FEAT_STL_OPT
5073     else if (*p_stl)
5074     {
5075 	/* redraw custom status line */
5076 	win_redr_custom(wp, FALSE);
5077     }
5078 #endif
5079     else
5080     {
5081 	fillchar = fillchar_status(&attr, wp == curwin);
5082 
5083 	if (buf_spname(wp->w_buffer) != NULL)
5084 	    STRCPY(NameBuff, buf_spname(wp->w_buffer));
5085 	else
5086 	    home_replace(wp->w_buffer, wp->w_buffer->b_fname, NameBuff,
5087 							      MAXPATHL, TRUE);
5088 	trans_characters(NameBuff, MAXPATHL);
5089 	p = NameBuff;
5090 	len = (int)STRLEN(p);
5091 
5092 	if (wp->w_buffer->b_help
5093 #ifdef FEAT_QUICKFIX
5094 		|| wp->w_p_pvw
5095 #endif
5096 		|| bufIsChanged(wp->w_buffer)
5097 		|| wp->w_buffer->b_p_ro)
5098 	    *(p + len++) = ' ';
5099 	if (wp->w_buffer->b_help)
5100 	{
5101 	    STRCPY(p + len, _("[help]"));
5102 	    len += (int)STRLEN(p + len);
5103 	}
5104 #ifdef FEAT_QUICKFIX
5105 	if (wp->w_p_pvw)
5106 	{
5107 	    STRCPY(p + len, _("[Preview]"));
5108 	    len += (int)STRLEN(p + len);
5109 	}
5110 #endif
5111 	if (bufIsChanged(wp->w_buffer))
5112 	{
5113 	    STRCPY(p + len, "[+]");
5114 	    len += 3;
5115 	}
5116 	if (wp->w_buffer->b_p_ro)
5117 	{
5118 	    STRCPY(p + len, "[RO]");
5119 	    len += 4;
5120 	}
5121 
5122 #ifndef FEAT_VERTSPLIT
5123 	this_ru_col = ru_col;
5124 	if (this_ru_col < (Columns + 1) / 2)
5125 	    this_ru_col = (Columns + 1) / 2;
5126 #else
5127 	this_ru_col = ru_col - (Columns - W_WIDTH(wp));
5128 	if (this_ru_col < (W_WIDTH(wp) + 1) / 2)
5129 	    this_ru_col = (W_WIDTH(wp) + 1) / 2;
5130 	if (this_ru_col <= 1)
5131 	{
5132 	    p = (char_u *)"<";		/* No room for file name! */
5133 	    len = 1;
5134 	}
5135 	else
5136 #endif
5137 #ifdef FEAT_MBYTE
5138 	    if (has_mbyte)
5139 	    {
5140 		int	clen = 0, i;
5141 
5142 		/* Count total number of display cells. */
5143 		for (i = 0; p[i] != NUL; i += (*mb_ptr2len_check)(p + i))
5144 		    clen += (*mb_ptr2cells)(p + i);
5145 		/* Find first character that will fit.
5146 		 * Going from start to end is much faster for DBCS. */
5147 		for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;
5148 					      i += (*mb_ptr2len_check)(p + i))
5149 		    clen -= (*mb_ptr2cells)(p + i);
5150 		len = clen;
5151 		if (i > 0)
5152 		{
5153 		    p = p + i - 1;
5154 		    *p = '<';
5155 		    ++len;
5156 		}
5157 
5158 	    }
5159 	    else
5160 #endif
5161 	    if (len > this_ru_col - 1)
5162 	    {
5163 		p += len - (this_ru_col - 1);
5164 		*p = '<';
5165 		len = this_ru_col - 1;
5166 	    }
5167 
5168 	row = W_WINROW(wp) + wp->w_height;
5169 	screen_puts(p, row, W_WINCOL(wp), attr);
5170 	screen_fill(row, row + 1, len + W_WINCOL(wp),
5171 			this_ru_col + W_WINCOL(wp), fillchar, fillchar, attr);
5172 
5173 	if (get_keymap_str(wp, NameBuff, MAXPATHL)
5174 		&& (int)(this_ru_col - len) > (int)(STRLEN(NameBuff) + 1))
5175 	    screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
5176 						   - 1 + W_WINCOL(wp)), attr);
5177 
5178 #ifdef FEAT_CMDL_INFO
5179 	win_redr_ruler(wp, TRUE);
5180 #endif
5181     }
5182 
5183 #ifdef FEAT_VERTSPLIT
5184     /*
5185      * May need to draw the character below the vertical separator.
5186      */
5187     if (wp->w_vsep_width != 0 && wp->w_status_height != 0 && redrawing())
5188     {
5189 	if (stl_connected(wp))
5190 	    fillchar = fillchar_status(&attr, wp == curwin);
5191 	else
5192 	    fillchar = fillchar_vsep(&attr);
5193 	screen_putchar(fillchar, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp),
5194 									attr);
5195     }
5196 #endif
5197 }
5198 
5199 # ifdef FEAT_VERTSPLIT
5200 /*
5201  * Return TRUE if the status line of window "wp" is connected to the status
5202  * line of the window right of it.  If not, then it's a vertical separator.
5203  * Only call if (wp->w_vsep_width != 0).
5204  */
5205     int
5206 stl_connected(wp)
5207     win_T	*wp;
5208 {
5209     frame_T	*fr;
5210 
5211     fr = wp->w_frame;
5212     while (fr->fr_parent != NULL)
5213     {
5214 	if (fr->fr_parent->fr_layout == FR_COL)
5215 	{
5216 	    if (fr->fr_next != NULL)
5217 		break;
5218 	}
5219 	else
5220 	{
5221 	    if (fr->fr_next != NULL)
5222 		return TRUE;
5223 	}
5224 	fr = fr->fr_parent;
5225     }
5226     return FALSE;
5227 }
5228 # endif
5229 
5230 #endif /* FEAT_WINDOWS */
5231 
5232 #if defined(FEAT_WINDOWS) || defined(FEAT_STL_OPT) || defined(PROTO)
5233 /*
5234  * Get the value to show for the language mappings, active 'keymap'.
5235  */
5236     int
5237 get_keymap_str(wp, buf, len)
5238     win_T	*wp;
5239     char_u	*buf;	    /* buffer for the result */
5240     int		len;	    /* length of buffer */
5241 {
5242     char_u	*p;
5243 
5244     if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
5245 	return FALSE;
5246 
5247     {
5248 #ifdef FEAT_EVAL
5249 	buf_T	*old_curbuf = curbuf;
5250 	win_T	*old_curwin = curwin;
5251 	char_u	*s;
5252 
5253 	curbuf = wp->w_buffer;
5254 	curwin = wp;
5255 	STRCPY(buf, "b:keymap_name");	/* must be writable */
5256 	++emsg_skip;
5257 	s = p = eval_to_string(buf, NULL);
5258 	--emsg_skip;
5259 	curbuf = old_curbuf;
5260 	curwin = old_curwin;
5261 	if (p == NULL || *p == NUL)
5262 #endif
5263 	{
5264 #ifdef FEAT_KEYMAP
5265 	    if (wp->w_buffer->b_kmap_state & KEYMAP_LOADED)
5266 		p = wp->w_buffer->b_p_keymap;
5267 	    else
5268 #endif
5269 		p = (char_u *)"lang";
5270 	}
5271 	if ((int)(STRLEN(p) + 3) < len)
5272 	    sprintf((char *)buf, "<%s>", p);
5273 	else
5274 	    buf[0] = NUL;
5275 #ifdef FEAT_EVAL
5276 	vim_free(s);
5277 #endif
5278     }
5279     return buf[0] != NUL;
5280 }
5281 #endif
5282 
5283 #if defined(FEAT_STL_OPT) || defined(PROTO)
5284 /*
5285  * Redraw the status line or ruler of window wp.
5286  */
5287     static void
5288 win_redr_custom(wp, Ruler)
5289     win_T	*wp;
5290     int		Ruler;
5291 {
5292     int		attr;
5293     int		curattr;
5294     int		row;
5295     int		col = 0;
5296     int		maxwidth;
5297     int		width;
5298     int		n;
5299     int		len;
5300     int		fillchar;
5301     char_u	buf[MAXPATHL];
5302     char_u	*p;
5303     struct	stl_hlrec hl[STL_MAX_ITEM];
5304 
5305     /* setup environment for the task at hand */
5306     row = W_WINROW(wp) + wp->w_height;
5307     fillchar = fillchar_status(&attr, wp == curwin);
5308     maxwidth = W_WIDTH(wp);
5309     p = p_stl;
5310     if (Ruler)
5311     {
5312 	p = p_ruf;
5313 	/* advance past any leading group spec - implicit in ru_col */
5314 	if (*p == '%')
5315 	{
5316 	    if (*++p == '-')
5317 		p++;
5318 	    if (atoi((char *) p))
5319 		while (VIM_ISDIGIT(*p))
5320 		    p++;
5321 	    if (*p++ != '(')
5322 		p = p_ruf;
5323 	}
5324 #ifdef FEAT_VERTSPLIT
5325 	col = ru_col - (Columns - W_WIDTH(wp));
5326 	if (col < (W_WIDTH(wp) + 1) / 2)
5327 	    col = (W_WIDTH(wp) + 1) / 2;
5328 #else
5329 	col = ru_col;
5330 	if (col > (Columns + 1) / 2)
5331 	    col = (Columns + 1) / 2;
5332 #endif
5333 	maxwidth = W_WIDTH(wp) - col;
5334 #ifdef FEAT_WINDOWS
5335 	if (!wp->w_status_height)
5336 #endif
5337 	{
5338 	    row = Rows - 1;
5339 	    --maxwidth;	/* writing in last column may cause scrolling */
5340 	    fillchar = ' ';
5341 	    attr = 0;
5342 	}
5343     }
5344     if (maxwidth <= 0)
5345 	return;
5346 #ifdef FEAT_VERTSPLIT
5347     col += W_WINCOL(wp);
5348 #endif
5349 
5350     width = build_stl_str_hl(wp, buf, sizeof(buf), p, fillchar, maxwidth, hl);
5351     len = STRLEN(buf);
5352 
5353     while (width < maxwidth && len < sizeof(buf) - 1)
5354     {
5355 #ifdef FEAT_MBYTE
5356 	len += (*mb_char2bytes)(fillchar, buf + len);
5357 #else
5358 	buf[len++] = fillchar;
5359 #endif
5360 	++width;
5361     }
5362     buf[len] = NUL;
5363 
5364     curattr = attr;
5365     p = buf;
5366     for (n = 0; hl[n].start != NULL; n++)
5367     {
5368 	len = (int)(hl[n].start - p);
5369 	screen_puts_len(p, len, row, col, curattr);
5370 	col += vim_strnsize(p, len);
5371 	p = hl[n].start;
5372 
5373 	if (hl[n].userhl == 0)
5374 	    curattr = attr;
5375 #ifdef FEAT_WINDOWS
5376 	else if (wp != curwin && wp->w_status_height != 0)
5377 	    curattr = highlight_stlnc[hl[n].userhl - 1];
5378 #endif
5379 	else
5380 	    curattr = highlight_user[hl[n].userhl - 1];
5381     }
5382     screen_puts(p, row, col, curattr);
5383 }
5384 
5385 #endif /* FEAT_STL_OPT */
5386 
5387 /*
5388  * Output a single character directly to the screen and update ScreenLines.
5389  */
5390     void
5391 screen_putchar(c, row, col, attr)
5392     int	    c;
5393     int	    row, col;
5394     int	    attr;
5395 {
5396 #ifdef FEAT_MBYTE
5397     char_u	buf[MB_MAXBYTES + 1];
5398 
5399     buf[(*mb_char2bytes)(c, buf)] = NUL;
5400 #else
5401     char_u	buf[2];
5402 
5403     buf[0] = c;
5404     buf[1] = NUL;
5405 #endif
5406     screen_puts(buf, row, col, attr);
5407 }
5408 
5409 /*
5410  * Get a single character directly from ScreenLines into "bytes[]".
5411  * Also return its attribute in *attrp;
5412  */
5413     void
5414 screen_getbytes(row, col, bytes, attrp)
5415     int	    row, col;
5416     char_u  *bytes;
5417     int	    *attrp;
5418 {
5419     unsigned off;
5420 
5421     /* safety check */
5422     if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns)
5423     {
5424 	off = LineOffset[row] + col;
5425 	*attrp = ScreenAttrs[off];
5426 	bytes[0] = ScreenLines[off];
5427 	bytes[1] = NUL;
5428 
5429 #ifdef FEAT_MBYTE
5430 	if (enc_utf8 && ScreenLinesUC[off] != 0)
5431 	    bytes[utfc_char2bytes(off, bytes)] = NUL;
5432 	else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
5433 	{
5434 	    bytes[0] = ScreenLines[off];
5435 	    bytes[1] = ScreenLines2[off];
5436 	    bytes[2] = NUL;
5437 	}
5438 	else if (enc_dbcs && MB_BYTE2LEN(bytes[0]) > 1)
5439 	{
5440 	    bytes[1] = ScreenLines[off + 1];
5441 	    bytes[2] = NUL;
5442 	}
5443 #endif
5444     }
5445 }
5446 
5447 /*
5448  * Put string '*text' on the screen at position 'row' and 'col', with
5449  * attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
5450  * Note: only outputs within one row, message is truncated at screen boundary!
5451  * Note: if ScreenLines[], row and/or col is invalid, nothing is done.
5452  */
5453     void
5454 screen_puts(text, row, col, attr)
5455     char_u	*text;
5456     int		row;
5457     int		col;
5458     int		attr;
5459 {
5460     screen_puts_len(text, -1, row, col, attr);
5461 }
5462 
5463 /*
5464  * Like screen_puts(), but output "text[len]".  When "len" is -1 output up to
5465  * a NUL.
5466  */
5467     void
5468 screen_puts_len(text, len, row, col, attr)
5469     char_u	*text;
5470     int		len;
5471     int		row;
5472     int		col;
5473     int		attr;
5474 {
5475     unsigned	off;
5476     char_u	*ptr = text;
5477     int		c;
5478 #ifdef FEAT_MBYTE
5479     int		mbyte_blen = 1;
5480     int		mbyte_cells = 1;
5481     int		u8c = 0;
5482     int		u8c_c1 = 0;
5483     int		u8c_c2 = 0;
5484     int		clear_next_cell = FALSE;
5485 # ifdef FEAT_ARABIC
5486     int		prev_c = 0;		/* previous Arabic character */
5487     int		pc, nc, nc1, dummy;
5488 # endif
5489 #endif
5490 
5491     if (ScreenLines == NULL || row >= screen_Rows)	/* safety check */
5492 	return;
5493 
5494     off = LineOffset[row] + col;
5495     while (*ptr != NUL && col < screen_Columns
5496 				      && (len < 0 || (int)(ptr - text) < len))
5497     {
5498 	c = *ptr;
5499 #ifdef FEAT_MBYTE
5500 	/* check if this is the first byte of a multibyte */
5501 	if (has_mbyte)
5502 	{
5503 	    if (enc_utf8 && len > 0)
5504 		mbyte_blen = utfc_ptr2len_check_len(ptr,
5505 						   (int)((text + len) - ptr));
5506 	    else
5507 		mbyte_blen = (*mb_ptr2len_check)(ptr);
5508 	    if (enc_dbcs == DBCS_JPNU && c == 0x8e)
5509 		mbyte_cells = 1;
5510 	    else if (enc_dbcs != 0)
5511 		mbyte_cells = mbyte_blen;
5512 	    else	/* enc_utf8 */
5513 	    {
5514 		if (len >= 0)
5515 		    u8c = utfc_ptr2char_len(ptr, &u8c_c1, &u8c_c2,
5516 						   (int)((text + len) - ptr));
5517 		else
5518 		    u8c = utfc_ptr2char(ptr, &u8c_c1, &u8c_c2);
5519 		mbyte_cells = utf_char2cells(u8c);
5520 		/* Non-BMP character: display as ? or fullwidth ?. */
5521 		if (u8c >= 0x10000)
5522 		{
5523 		    u8c = (mbyte_cells == 2) ? 0xff1f : (int)'?';
5524 		    if (attr == 0)
5525 			attr = hl_attr(HLF_8);
5526 		}
5527 # ifdef FEAT_ARABIC
5528 		if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c))
5529 		{
5530 		    /* Do Arabic shaping. */
5531 		    if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len)
5532 		    {
5533 			/* Past end of string to be displayed. */
5534 			nc = NUL;
5535 			nc1 = NUL;
5536 		    }
5537 		    else
5538 			nc = utfc_ptr2char(ptr + mbyte_blen, &nc1, &dummy);
5539 		    pc = prev_c;
5540 		    prev_c = u8c;
5541 		    u8c = arabic_shape(u8c, &c, &u8c_c1, nc, nc1, pc);
5542 		}
5543 		else
5544 		    prev_c = u8c;
5545 # endif
5546 	    }
5547 	}
5548 #endif
5549 
5550 	if (ScreenLines[off] != c
5551 #ifdef FEAT_MBYTE
5552 		|| (mbyte_cells == 2
5553 		    && ScreenLines[off + 1] != (enc_dbcs ? ptr[1] : 0))
5554 		|| (enc_dbcs == DBCS_JPNU
5555 		    && c == 0x8e
5556 		    && ScreenLines2[off] != ptr[1])
5557 		|| (enc_utf8
5558 		    && mbyte_blen > 1
5559 		    && (ScreenLinesUC[off] != u8c
5560 			|| ScreenLinesC1[off] != u8c_c1
5561 			|| ScreenLinesC2[off] != u8c_c2))
5562 #endif
5563 		|| ScreenAttrs[off] != attr
5564 		|| exmode_active
5565 		)
5566 	{
5567 #if defined(FEAT_GUI) || defined(UNIX)
5568 	    /* The bold trick makes a single row of pixels appear in the next
5569 	     * character.  When a bold character is removed, the next
5570 	     * character should be redrawn too.  This happens for our own GUI
5571 	     * and for some xterms.
5572 	     * Force the redraw by setting the attribute to a different value
5573 	     * than "attr", the contents of ScreenLines[] may be needed by
5574 	     * mb_off2cells() further on.
5575 	     * Don't do this for the last drawn character, because the next
5576 	     * character may not be redrawn. */
5577 	    if (
5578 # ifdef FEAT_GUI
5579 		    gui.in_use
5580 # endif
5581 # if defined(FEAT_GUI) && defined(UNIX)
5582 		    ||
5583 # endif
5584 # ifdef UNIX
5585 		    term_is_xterm
5586 # endif
5587 	       )
5588 	    {
5589 		int		n;
5590 
5591 		n = ScreenAttrs[off];
5592 # ifdef FEAT_MBYTE
5593 		if (col + mbyte_cells < screen_Columns
5594 			&& (n > HL_ALL || (n & HL_BOLD))
5595 			&& (len < 0 ? ptr[mbyte_blen] != NUL
5596 					     : ptr + mbyte_blen < text + len))
5597 		    ScreenAttrs[off + mbyte_cells] = attr + 1;
5598 # else
5599 		if (col + 1 < screen_Columns
5600 			&& (n > HL_ALL || (n & HL_BOLD))
5601 			&& (len < 0 ? ptr[1] != NUL : ptr + 1 < text + len))
5602 		    ScreenLines[off + 1] = 0;
5603 # endif
5604 	    }
5605 #endif
5606 #ifdef FEAT_MBYTE
5607 	    /* When at the end of the text and overwriting a two-cell
5608 	     * character with a one-cell character, need to clear the next
5609 	     * cell.  Also when overwriting the left halve of a two-cell char
5610 	     * with the right halve of a two-cell char.  Do this only once
5611 	     * (mb_off2cells() may return 2 on the right halve). */
5612 	    if (clear_next_cell)
5613 		clear_next_cell = FALSE;
5614 	    else if (has_mbyte
5615 		    && (len < 0 ? ptr[mbyte_blen] == NUL
5616 					     : ptr + mbyte_blen >= text + len)
5617 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1)
5618 			|| (mbyte_cells == 2
5619 			    && (*mb_off2cells)(off) == 1
5620 			    && (*mb_off2cells)(off + 1) > 1)))
5621 		clear_next_cell = TRUE;
5622 
5623 	    /* Make sure we never leave a second byte of a double-byte behind,
5624 	     * it confuses mb_off2cells(). */
5625 	    if (enc_dbcs
5626 		    && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1)
5627 			|| (mbyte_cells == 2
5628 			    && (*mb_off2cells)(off) == 1
5629 			    && (*mb_off2cells)(off + 1) > 1)))
5630 		ScreenLines[off + mbyte_blen] = 0;
5631 #endif
5632 	    ScreenLines[off] = c;
5633 	    ScreenAttrs[off] = attr;
5634 #ifdef FEAT_MBYTE
5635 	    if (enc_utf8)
5636 	    {
5637 		if (c < 0x80 && u8c_c1 == 0 && u8c_c2 == 0)
5638 		    ScreenLinesUC[off] = 0;
5639 		else
5640 		{
5641 		    ScreenLinesUC[off] = u8c;
5642 		    ScreenLinesC1[off] = u8c_c1;
5643 		    ScreenLinesC2[off] = u8c_c2;
5644 		}
5645 		if (mbyte_cells == 2)
5646 		{
5647 		    ScreenLines[off + 1] = 0;
5648 		    ScreenAttrs[off + 1] = attr;
5649 		}
5650 		screen_char(off, row, col);
5651 	    }
5652 	    else if (mbyte_cells == 2)
5653 	    {
5654 		ScreenLines[off + 1] = ptr[1];
5655 		ScreenAttrs[off + 1] = attr;
5656 		screen_char_2(off, row, col);
5657 	    }
5658 	    else if (enc_dbcs == DBCS_JPNU && c == 0x8e)
5659 	    {
5660 		ScreenLines2[off] = ptr[1];
5661 		screen_char(off, row, col);
5662 	    }
5663 	    else
5664 #endif
5665 		screen_char(off, row, col);
5666 	}
5667 #ifdef FEAT_MBYTE
5668 	if (has_mbyte)
5669 	{
5670 	    off += mbyte_cells;
5671 	    col += mbyte_cells;
5672 	    ptr += mbyte_blen;
5673 	    if (clear_next_cell)
5674 		ptr = (char_u *)" ";
5675 	}
5676 	else
5677 #endif
5678 	{
5679 	    ++off;
5680 	    ++col;
5681 	    ++ptr;
5682 	}
5683     }
5684 }
5685 
5686 #ifdef FEAT_SEARCH_EXTRA
5687 /*
5688  * Prepare for 'searchhl' highlighting.
5689  */
5690     static void
5691 start_search_hl()
5692 {
5693     if (p_hls && !no_hlsearch)
5694     {
5695 	last_pat_prog(&search_hl.rm);
5696 	search_hl.attr = hl_attr(HLF_L);
5697     }
5698 }
5699 
5700 /*
5701  * Clean up for 'searchhl' highlighting.
5702  */
5703     static void
5704 end_search_hl()
5705 {
5706     if (search_hl.rm.regprog != NULL)
5707     {
5708 	vim_free(search_hl.rm.regprog);
5709 	search_hl.rm.regprog = NULL;
5710     }
5711 }
5712 
5713 /*
5714  * Advance to the match in window "wp" line "lnum" or past it.
5715  */
5716     static void
5717 prepare_search_hl(wp, lnum)
5718     win_T	*wp;
5719     linenr_T	lnum;
5720 {
5721     match_T	*shl;		/* points to search_hl or match_hl */
5722     int		n;
5723 
5724     /*
5725      * When using a multi-line pattern, start searching at the top
5726      * of the window or just after a closed fold.
5727      * Do this both for search_hl and match_hl.
5728      */
5729     shl = &search_hl;
5730     for (;;)
5731     {
5732 	if (shl->rm.regprog != NULL
5733 		&& shl->lnum == 0
5734 		&& re_multiline(shl->rm.regprog))
5735 	{
5736 	    if (shl->first_lnum == 0)
5737 	    {
5738 # ifdef FEAT_FOLDING
5739 		for (shl->first_lnum = lnum;
5740 			   shl->first_lnum > wp->w_topline; --shl->first_lnum)
5741 		    if (hasFoldingWin(wp, shl->first_lnum - 1,
5742 						      NULL, NULL, TRUE, NULL))
5743 			break;
5744 # else
5745 		shl->first_lnum = wp->w_topline;
5746 # endif
5747 	    }
5748 	    n = 0;
5749 	    while (shl->first_lnum < lnum && shl->rm.regprog != NULL)
5750 	    {
5751 		next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n);
5752 		if (shl->lnum != 0)
5753 		{
5754 		    shl->first_lnum = shl->lnum
5755 				    + shl->rm.endpos[0].lnum
5756 				    - shl->rm.startpos[0].lnum;
5757 		    n = shl->rm.endpos[0].col;
5758 		}
5759 		else
5760 		{
5761 		    ++shl->first_lnum;
5762 		    n = 0;
5763 		}
5764 	    }
5765 	}
5766 	if (shl == &match_hl)
5767 	    break;
5768 	shl = &match_hl;
5769     }
5770 }
5771 
5772 /*
5773  * Search for a next 'searchl' or ":match" match.
5774  * Uses shl->buf.
5775  * Sets shl->lnum and shl->rm contents.
5776  * Note: Assumes a previous match is always before "lnum", unless
5777  * shl->lnum is zero.
5778  * Careful: Any pointers for buffer lines will become invalid.
5779  */
5780     static void
5781 next_search_hl(win, shl, lnum, mincol)
5782     win_T	*win;
5783     match_T	*shl;		/* points to search_hl or match_hl */
5784     linenr_T	lnum;
5785     colnr_T	mincol;		/* minimal column for a match */
5786 {
5787     linenr_T	l;
5788     colnr_T	matchcol;
5789     long	nmatched;
5790 
5791     if (shl->lnum != 0)
5792     {
5793 	/* Check for three situations:
5794 	 * 1. If the "lnum" is below a previous match, start a new search.
5795 	 * 2. If the previous match includes "mincol", use it.
5796 	 * 3. Continue after the previous match.
5797 	 */
5798 	l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
5799 	if (lnum > l)
5800 	    shl->lnum = 0;
5801 	else if (lnum < l || shl->rm.endpos[0].col > mincol)
5802 	    return;
5803     }
5804 
5805     /*
5806      * Repeat searching for a match until one is found that includes "mincol"
5807      * or none is found in this line.
5808      */
5809     called_emsg = FALSE;
5810     for (;;)
5811     {
5812 	/* Three situations:
5813 	 * 1. No useful previous match: search from start of line.
5814 	 * 2. Not Vi compatible or empty match: continue at next character.
5815 	 *    Break the loop if this is beyond the end of the line.
5816 	 * 3. Vi compatible searching: continue at end of previous match.
5817 	 */
5818 	if (shl->lnum == 0)
5819 	    matchcol = 0;
5820 	else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
5821 		|| (shl->rm.endpos[0].lnum == 0
5822 		    && shl->rm.endpos[0].col == shl->rm.startpos[0].col))
5823 	{
5824 	    matchcol = shl->rm.startpos[0].col + 1;
5825 	    if (ml_get_buf(shl->buf, lnum, FALSE)[matchcol - 1] == NUL)
5826 	    {
5827 		shl->lnum = 0;
5828 		break;
5829 	    }
5830 	}
5831 	else
5832 	    matchcol = shl->rm.endpos[0].col;
5833 
5834 	shl->lnum = lnum;
5835 	nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, matchcol);
5836 	if (called_emsg)
5837 	{
5838 	    /* Error while handling regexp: stop using this regexp. */
5839 	    vim_free(shl->rm.regprog);
5840 	    shl->rm.regprog = NULL;
5841 	    no_hlsearch = TRUE;
5842 	    break;
5843 	}
5844 	if (nmatched == 0)
5845 	{
5846 	    shl->lnum = 0;		/* no match found */
5847 	    break;
5848 	}
5849 	if (shl->rm.startpos[0].lnum > 0
5850 		|| shl->rm.startpos[0].col >= mincol
5851 		|| nmatched > 1
5852 		|| shl->rm.endpos[0].col > mincol)
5853 	{
5854 	    shl->lnum += shl->rm.startpos[0].lnum;
5855 	    break;			/* useful match found */
5856 	}
5857     }
5858 }
5859 #endif
5860 
5861       static void
5862 screen_start_highlight(attr)
5863       int	attr;
5864 {
5865     attrentry_T *aep = NULL;
5866 
5867     screen_attr = attr;
5868     if (full_screen
5869 #ifdef WIN3264
5870 		    && termcap_active
5871 #endif
5872 				       )
5873     {
5874 #ifdef FEAT_GUI
5875 	if (gui.in_use)
5876 	{
5877 	    char	buf[20];
5878 
5879 	    sprintf(buf, IF_EB("\033|%dh", ESC_STR "|%dh"), attr);		/* internal GUI code */
5880 	    OUT_STR(buf);
5881 	}
5882 	else
5883 #endif
5884 	{
5885 	    if (attr > HL_ALL)				/* special HL attr. */
5886 	    {
5887 		if (t_colors > 1)
5888 		    aep = syn_cterm_attr2entry(attr);
5889 		else
5890 		    aep = syn_term_attr2entry(attr);
5891 		if (aep == NULL)	    /* did ":syntax clear" */
5892 		    attr = 0;
5893 		else
5894 		    attr = aep->ae_attr;
5895 	    }
5896 	    if ((attr & HL_BOLD) && T_MD != NULL)	/* bold */
5897 		out_str(T_MD);
5898 	    if ((attr & HL_STANDOUT) && T_SO != NULL)	/* standout */
5899 		out_str(T_SO);
5900 	    if ((attr & HL_UNDERLINE) && T_US != NULL)	/* underline */
5901 		out_str(T_US);
5902 	    if ((attr & HL_ITALIC) && T_CZH != NULL)	/* italic */
5903 		out_str(T_CZH);
5904 	    if ((attr & HL_INVERSE) && T_MR != NULL)	/* inverse (reverse) */
5905 		out_str(T_MR);
5906 
5907 	    /*
5908 	     * Output the color or start string after bold etc., in case the
5909 	     * bold etc. override the color setting.
5910 	     */
5911 	    if (aep != NULL)
5912 	    {
5913 		if (t_colors > 1)
5914 		{
5915 		    if (aep->ae_u.cterm.fg_color)
5916 			term_fg_color(aep->ae_u.cterm.fg_color - 1);
5917 		    if (aep->ae_u.cterm.bg_color)
5918 			term_bg_color(aep->ae_u.cterm.bg_color - 1);
5919 		}
5920 		else
5921 		{
5922 		    if (aep->ae_u.term.start != NULL)
5923 			out_str(aep->ae_u.term.start);
5924 		}
5925 	    }
5926 	}
5927     }
5928 }
5929 
5930       void
5931 screen_stop_highlight()
5932 {
5933     int	    do_ME = FALSE;	    /* output T_ME code */
5934 
5935     if (screen_attr != 0
5936 #ifdef WIN3264
5937 			&& termcap_active
5938 #endif
5939 					   )
5940     {
5941 #ifdef FEAT_GUI
5942 	if (gui.in_use)
5943 	{
5944 	    char	buf[20];
5945 
5946 	    /* use internal GUI code */
5947 	    sprintf(buf, IF_EB("\033|%dH", ESC_STR "|%dH"), screen_attr);
5948 	    OUT_STR(buf);
5949 	}
5950 	else
5951 #endif
5952 	{
5953 	    if (screen_attr > HL_ALL)			/* special HL attr. */
5954 	    {
5955 		attrentry_T *aep;
5956 
5957 		if (t_colors > 1)
5958 		{
5959 		    /*
5960 		     * Assume that t_me restores the original colors!
5961 		     */
5962 		    aep = syn_cterm_attr2entry(screen_attr);
5963 		    if (aep != NULL && (aep->ae_u.cterm.fg_color
5964 						 || aep->ae_u.cterm.bg_color))
5965 			do_ME = TRUE;
5966 		}
5967 		else
5968 		{
5969 		    aep = syn_term_attr2entry(screen_attr);
5970 		    if (aep != NULL && aep->ae_u.term.stop != NULL)
5971 		    {
5972 			if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
5973 			    do_ME = TRUE;
5974 			else
5975 			    out_str(aep->ae_u.term.stop);
5976 		    }
5977 		}
5978 		if (aep == NULL)	    /* did ":syntax clear" */
5979 		    screen_attr = 0;
5980 		else
5981 		    screen_attr = aep->ae_attr;
5982 	    }
5983 
5984 	    /*
5985 	     * Often all ending-codes are equal to T_ME.  Avoid outputting the
5986 	     * same sequence several times.
5987 	     */
5988 	    if (screen_attr & HL_STANDOUT)
5989 	    {
5990 		if (STRCMP(T_SE, T_ME) == 0)
5991 		    do_ME = TRUE;
5992 		else
5993 		    out_str(T_SE);
5994 	    }
5995 	    if (screen_attr & HL_UNDERLINE)
5996 	    {
5997 		if (STRCMP(T_UE, T_ME) == 0)
5998 		    do_ME = TRUE;
5999 		else
6000 		    out_str(T_UE);
6001 	    }
6002 	    if (screen_attr & HL_ITALIC)
6003 	    {
6004 		if (STRCMP(T_CZR, T_ME) == 0)
6005 		    do_ME = TRUE;
6006 		else
6007 		    out_str(T_CZR);
6008 	    }
6009 	    if (do_ME || (screen_attr & (HL_BOLD | HL_INVERSE)))
6010 		out_str(T_ME);
6011 
6012 	    if (t_colors > 1)
6013 	    {
6014 		/* set Normal cterm colors */
6015 		if (cterm_normal_fg_color != 0)
6016 		    term_fg_color(cterm_normal_fg_color - 1);
6017 		if (cterm_normal_bg_color != 0)
6018 		    term_bg_color(cterm_normal_bg_color - 1);
6019 		if (cterm_normal_fg_bold)
6020 		    out_str(T_MD);
6021 	    }
6022 	}
6023     }
6024     screen_attr = 0;
6025 }
6026 
6027 /*
6028  * Reset the colors for a cterm.  Used when leaving Vim.
6029  * The machine specific code may override this again.
6030  */
6031     void
6032 reset_cterm_colors()
6033 {
6034     if (t_colors > 1)
6035     {
6036 	/* set Normal cterm colors */
6037 	if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0)
6038 	{
6039 	    out_str(T_OP);
6040 	    screen_attr = -1;
6041 	}
6042 	if (cterm_normal_fg_bold)
6043 	{
6044 	    out_str(T_ME);
6045 	    screen_attr = -1;
6046 	}
6047     }
6048 }
6049 
6050 /*
6051  * Put character ScreenLines["off"] on the screen at position "row" and "col",
6052  * using the attributes from ScreenAttrs["off"].
6053  */
6054     static void
6055 screen_char(off, row, col)
6056     unsigned	off;
6057     int		row;
6058     int		col;
6059 {
6060     int		attr;
6061 
6062     /* Check for illegal values, just in case (could happen just after
6063      * resizing). */
6064     if (row >= screen_Rows || col >= screen_Columns)
6065 	return;
6066 
6067     /* Outputting the last character on the screen may scrollup the screen.
6068      * Don't to it!  Mark the character invalid (update it when scrolled up) */
6069     if (row == screen_Rows - 1 && col == screen_Columns - 1
6070 #ifdef FEAT_RIGHTLEFT
6071 	    /* account for first command-line character in rightleft mode */
6072 	    && !cmdmsg_rl
6073 #endif
6074        )
6075     {
6076 	ScreenAttrs[off] = (sattr_T)-1;
6077 	return;
6078     }
6079 
6080     /*
6081      * Stop highlighting first, so it's easier to move the cursor.
6082      */
6083 #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)
6084     if (screen_char_attr != 0)
6085 	attr = screen_char_attr;
6086     else
6087 #endif
6088 	attr = ScreenAttrs[off];
6089     if (screen_attr != attr)
6090 	screen_stop_highlight();
6091 
6092     windgoto(row, col);
6093 
6094     if (screen_attr != attr)
6095 	screen_start_highlight(attr);
6096 
6097 #ifdef FEAT_MBYTE
6098     if (enc_utf8 && ScreenLinesUC[off] != 0)
6099     {
6100 	char_u	    buf[MB_MAXBYTES + 1];
6101 
6102 	/* Convert UTF-8 character to bytes and write it. */
6103 
6104 	buf[utfc_char2bytes(off, buf)] = NUL;
6105 
6106 	out_str(buf);
6107 	if (utf_char2cells(ScreenLinesUC[off]) > 1)
6108 	    ++screen_cur_col;
6109     }
6110     else
6111 #endif
6112     {
6113 #ifdef FEAT_MBYTE
6114 	out_flush_check();
6115 #endif
6116 	out_char(ScreenLines[off]);
6117 #ifdef FEAT_MBYTE
6118 	/* double-byte character in single-width cell */
6119 	if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
6120 	    out_char(ScreenLines2[off]);
6121 #endif
6122     }
6123 
6124     screen_cur_col++;
6125 }
6126 
6127 #ifdef FEAT_MBYTE
6128 
6129 /*
6130  * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
6131  * on the screen at position 'row' and 'col'.
6132  * The attributes of the first byte is used for all.  This is required to
6133  * output the two bytes of a double-byte character with nothing in between.
6134  */
6135     static void
6136 screen_char_2(off, row, col)
6137     unsigned	off;
6138     int		row;
6139     int		col;
6140 {
6141     /* Check for illegal values (could be wrong when screen was resized). */
6142     if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
6143 	return;
6144 
6145     /* Outputting the last character on the screen may scrollup the screen.
6146      * Don't to it!  Mark the character invalid (update it when scrolled up) */
6147     if (row == screen_Rows - 1 && col >= screen_Columns - 2)
6148     {
6149 	ScreenAttrs[off] = (sattr_T)-1;
6150 	return;
6151     }
6152 
6153     /* Output the first byte normally (positions the cursor), then write the
6154      * second byte directly. */
6155     screen_char(off, row, col);
6156     out_char(ScreenLines[off + 1]);
6157     ++screen_cur_col;
6158 }
6159 #endif
6160 
6161 #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT) || defined(PROTO)
6162 /*
6163  * Draw a rectangle of the screen, inverted when "invert" is TRUE.
6164  * This uses the contents of ScreenLines[] and doesn't change it.
6165  */
6166     void
6167 screen_draw_rectangle(row, col, height, width, invert)
6168     int		row;
6169     int		col;
6170     int		height;
6171     int		width;
6172     int		invert;
6173 {
6174     int		r, c;
6175     int		off;
6176 
6177     if (invert)
6178 	screen_char_attr = HL_INVERSE;
6179     for (r = row; r < row + height; ++r)
6180     {
6181 	off = LineOffset[r];
6182 	for (c = col; c < col + width; ++c)
6183 	{
6184 #ifdef FEAT_MBYTE
6185 	    if (enc_dbcs != 0 && dbcs_off2cells(off + c) > 1)
6186 	    {
6187 		screen_char_2(off + c, r, c);
6188 		++c;
6189 	    }
6190 	    else
6191 #endif
6192 	    {
6193 		screen_char(off + c, r, c);
6194 #ifdef FEAT_MBYTE
6195 		if (utf_off2cells(off + c) > 1)
6196 		    ++c;
6197 #endif
6198 	    }
6199 	}
6200     }
6201     screen_char_attr = 0;
6202 }
6203 #endif
6204 
6205 #ifdef FEAT_VERTSPLIT
6206 /*
6207  * Redraw the characters for a vertically split window.
6208  */
6209     static void
6210 redraw_block(row, end, wp)
6211     int		row;
6212     int		end;
6213     win_T	*wp;
6214 {
6215     int		col;
6216     int		width;
6217 
6218 # ifdef FEAT_CLIPBOARD
6219     clip_may_clear_selection(row, end - 1);
6220 # endif
6221 
6222     if (wp == NULL)
6223     {
6224 	col = 0;
6225 	width = Columns;
6226     }
6227     else
6228     {
6229 	col = wp->w_wincol;
6230 	width = wp->w_width;
6231     }
6232     screen_draw_rectangle(row, col, end - row, width, FALSE);
6233 }
6234 #endif
6235 
6236 /*
6237  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
6238  * with character 'c1' in first column followed by 'c2' in the other columns.
6239  * Use attributes 'attr'.
6240  */
6241     void
6242 screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
6243     int	    start_row, end_row;
6244     int	    start_col, end_col;
6245     int	    c1, c2;
6246     int	    attr;
6247 {
6248     int		    row;
6249     int		    col;
6250     int		    off;
6251     int		    end_off;
6252     int		    did_delete;
6253     int		    c;
6254     int		    norm_term;
6255 #if defined(FEAT_GUI) || defined(UNIX)
6256     int		    force_next = FALSE;
6257 #endif
6258 
6259     if (end_row > screen_Rows)		/* safety check */
6260 	end_row = screen_Rows;
6261     if (end_col > screen_Columns)	/* safety check */
6262 	end_col = screen_Columns;
6263     if (ScreenLines == NULL
6264 	    || start_row >= end_row
6265 	    || start_col >= end_col)	/* nothing to do */
6266 	return;
6267 
6268     /* it's a "normal" terminal when not in a GUI or cterm */
6269     norm_term = (
6270 #ifdef FEAT_GUI
6271 	    !gui.in_use &&
6272 #endif
6273 			    t_colors <= 1);
6274     for (row = start_row; row < end_row; ++row)
6275     {
6276 	/*
6277 	 * Try to use delete-line termcap code, when no attributes or in a
6278 	 * "normal" terminal, where a bold/italic space is just a
6279 	 * space.
6280 	 */
6281 	did_delete = FALSE;
6282 	if (c2 == ' '
6283 		&& end_col == Columns
6284 		&& can_clear(T_CE)
6285 		&& (attr == 0
6286 		    || (norm_term
6287 			&& attr <= HL_ALL
6288 			&& ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
6289 	{
6290 	    /*
6291 	     * check if we really need to clear something
6292 	     */
6293 	    col = start_col;
6294 	    if (c1 != ' ')			/* don't clear first char */
6295 		++col;
6296 
6297 	    off = LineOffset[row] + col;
6298 	    end_off = LineOffset[row] + end_col;
6299 
6300 	    /* skip blanks (used often, keep it fast!) */
6301 #ifdef FEAT_MBYTE
6302 	    if (enc_utf8)
6303 		while (off < end_off && ScreenLines[off] == ' '
6304 			  && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
6305 		    ++off;
6306 	    else
6307 #endif
6308 		while (off < end_off && ScreenLines[off] == ' '
6309 						     && ScreenAttrs[off] == 0)
6310 		    ++off;
6311 	    if (off < end_off)		/* something to be cleared */
6312 	    {
6313 		col = off - LineOffset[row];
6314 		screen_stop_highlight();
6315 		term_windgoto(row, col);/* clear rest of this screen line */
6316 		out_str(T_CE);
6317 		screen_start();		/* don't know where cursor is now */
6318 		col = end_col - col;
6319 		while (col--)		/* clear chars in ScreenLines */
6320 		{
6321 		    ScreenLines[off] = ' ';
6322 #ifdef FEAT_MBYTE
6323 		    if (enc_utf8)
6324 			ScreenLinesUC[off] = 0;
6325 #endif
6326 		    ScreenAttrs[off] = 0;
6327 		    ++off;
6328 		}
6329 	    }
6330 	    did_delete = TRUE;		/* the chars are cleared now */
6331 	}
6332 
6333 	off = LineOffset[row] + start_col;
6334 	c = c1;
6335 	for (col = start_col; col < end_col; ++col)
6336 	{
6337 	    if (ScreenLines[off] != c
6338 #ifdef FEAT_MBYTE
6339 		    || (enc_utf8 && ScreenLinesUC[off] != (c >= 0x80 ? c : 0))
6340 #endif
6341 		    || ScreenAttrs[off] != attr
6342 #if defined(FEAT_GUI) || defined(UNIX)
6343 		    || force_next
6344 #endif
6345 		    )
6346 	    {
6347 #if defined(FEAT_GUI) || defined(UNIX)
6348 		/* The bold trick may make a single row of pixels appear in
6349 		 * the next character.  When a bold character is removed, the
6350 		 * next character should be redrawn too.  This happens for our
6351 		 * own GUI and for some xterms.  */
6352 		if (
6353 # ifdef FEAT_GUI
6354 			gui.in_use
6355 # endif
6356 # if defined(FEAT_GUI) && defined(UNIX)
6357 			||
6358 # endif
6359 # ifdef UNIX
6360 			term_is_xterm
6361 # endif
6362 		   )
6363 		{
6364 		    if (ScreenLines[off] != ' '
6365 			    && (ScreenAttrs[off] > HL_ALL
6366 				|| ScreenAttrs[off] & HL_BOLD))
6367 			force_next = TRUE;
6368 		    else
6369 			force_next = FALSE;
6370 		}
6371 #endif
6372 		ScreenLines[off] = c;
6373 #ifdef FEAT_MBYTE
6374 		if (enc_utf8)
6375 		{
6376 		    if (c >= 0x80)
6377 		    {
6378 			ScreenLinesUC[off] = c;
6379 			ScreenLinesC1[off] = 0;
6380 			ScreenLinesC2[off] = 0;
6381 		    }
6382 		    else
6383 			ScreenLinesUC[off] = 0;
6384 		}
6385 #endif
6386 		ScreenAttrs[off] = attr;
6387 		if (!did_delete || c != ' ')
6388 		    screen_char(off, row, col);
6389 	    }
6390 	    ++off;
6391 	    if (col == start_col)
6392 	    {
6393 		if (did_delete)
6394 		    break;
6395 		c = c2;
6396 	    }
6397 	}
6398 	if (end_col == Columns)
6399 	    LineWraps[row] = FALSE;
6400 	if (row == Rows - 1)		/* overwritten the command line */
6401 	{
6402 	    redraw_cmdline = TRUE;
6403 	    if (c1 == ' ' && c2 == ' ')
6404 		clear_cmdline = FALSE;	/* command line has been cleared */
6405 	}
6406     }
6407 }
6408 
6409 /*
6410  * Check if there should be a delay.  Used before clearing or redrawing the
6411  * screen or the command line.
6412  */
6413     void
6414 check_for_delay(check_msg_scroll)
6415     int	    check_msg_scroll;
6416 {
6417     if ((emsg_on_display || (check_msg_scroll && msg_scroll))
6418 	    && !did_wait_return
6419 	    && emsg_silent == 0)
6420     {
6421 	out_flush();
6422 	ui_delay(1000L, TRUE);
6423 	emsg_on_display = FALSE;
6424 	if (check_msg_scroll)
6425 	    msg_scroll = FALSE;
6426     }
6427 }
6428 
6429 /*
6430  * screen_valid -  allocate screen buffers if size changed
6431  *   If "clear" is TRUE: clear screen if it has been resized.
6432  *	Returns TRUE if there is a valid screen to write to.
6433  *	Returns FALSE when starting up and screen not initialized yet.
6434  */
6435     int
6436 screen_valid(clear)
6437     int	    clear;
6438 {
6439     screenalloc(clear);	    /* allocate screen buffers if size changed */
6440     return (ScreenLines != NULL);
6441 }
6442 
6443 /*
6444  * Resize the shell to Rows and Columns.
6445  * Allocate ScreenLines[] and associated items.
6446  *
6447  * There may be some time between setting Rows and Columns and (re)allocating
6448  * ScreenLines[].  This happens when starting up and when (manually) changing
6449  * the shell size.  Always use screen_Rows and screen_Columns to access items
6450  * in ScreenLines[].  Use Rows and Columns for positioning text etc. where the
6451  * final size of the shell is needed.
6452  */
6453     void
6454 screenalloc(clear)
6455     int	    clear;
6456 {
6457     int		    new_row, old_row;
6458 #ifdef FEAT_GUI
6459     int		    old_Rows;
6460 #endif
6461     win_T	    *wp;
6462     int		    outofmem = FALSE;
6463     int		    len;
6464     schar_T	    *new_ScreenLines;
6465 #ifdef FEAT_MBYTE
6466     u8char_T	    *new_ScreenLinesUC = NULL;
6467     u8char_T	    *new_ScreenLinesC1 = NULL;
6468     u8char_T	    *new_ScreenLinesC2 = NULL;
6469     schar_T	    *new_ScreenLines2 = NULL;
6470 #endif
6471     sattr_T	    *new_ScreenAttrs;
6472     unsigned	    *new_LineOffset;
6473     char_u	    *new_LineWraps;
6474     static int	    entered = FALSE;		/* avoid recursiveness */
6475 
6476     /*
6477      * Allocation of the screen buffers is done only when the size changes and
6478      * when Rows and Columns have been set and we have started doing full
6479      * screen stuff.
6480      */
6481     if ((ScreenLines != NULL
6482 		&& Rows == screen_Rows
6483 		&& Columns == screen_Columns
6484 #ifdef FEAT_MBYTE
6485 		&& enc_utf8 == (ScreenLinesUC != NULL)
6486 		&& (enc_dbcs == DBCS_JPNU) == (ScreenLines2 != NULL)
6487 #endif
6488 		)
6489 	    || Rows == 0
6490 	    || Columns == 0
6491 	    || (!full_screen && ScreenLines == NULL))
6492 	return;
6493 
6494     /*
6495      * It's possible that we produce an out-of-memory message below, which
6496      * will cause this function to be called again.  To break the loop, just
6497      * return here.
6498      */
6499     if (entered)
6500 	return;
6501     entered = TRUE;
6502 
6503     win_new_shellsize();    /* fit the windows in the new sized shell */
6504 
6505 #ifdef FEAT_GUI_BEOS
6506     vim_lock_screen();  /* be safe, put it here */
6507 #endif
6508 
6509     comp_col();		/* recompute columns for shown command and ruler */
6510 
6511     /*
6512      * We're changing the size of the screen.
6513      * - Allocate new arrays for ScreenLines and ScreenAttrs.
6514      * - Move lines from the old arrays into the new arrays, clear extra
6515      *	 lines (unless the screen is going to be cleared).
6516      * - Free the old arrays.
6517      *
6518      * If anything fails, make ScreenLines NULL, so we don't do anything!
6519      * Continuing with the old ScreenLines may result in a crash, because the
6520      * size is wrong.
6521      */
6522 #ifdef FEAT_WINDOWS
6523     for (wp = firstwin; wp; wp = wp->w_next)
6524 	win_free_lsize(wp);
6525 #else
6526 	win_free_lsize(curwin);
6527 #endif
6528 
6529     new_ScreenLines = (schar_T *)lalloc((long_u)(
6530 			      (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
6531 #ifdef FEAT_MBYTE
6532     if (enc_utf8)
6533     {
6534 	new_ScreenLinesUC = (u8char_T *)lalloc((long_u)(
6535 			     (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
6536 	new_ScreenLinesC1 = (u8char_T *)lalloc((long_u)(
6537 			     (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
6538 	new_ScreenLinesC2 = (u8char_T *)lalloc((long_u)(
6539 			     (Rows + 1) * Columns * sizeof(u8char_T)), FALSE);
6540     }
6541     if (enc_dbcs == DBCS_JPNU)
6542 	new_ScreenLines2 = (schar_T *)lalloc((long_u)(
6543 			     (Rows + 1) * Columns * sizeof(schar_T)), FALSE);
6544 #endif
6545     new_ScreenAttrs = (sattr_T *)lalloc((long_u)(
6546 			      (Rows + 1) * Columns * sizeof(sattr_T)), FALSE);
6547     new_LineOffset = (unsigned *)lalloc((long_u)(
6548 					 Rows * sizeof(unsigned)), FALSE);
6549     new_LineWraps = (char_u *)lalloc((long_u)(Rows * sizeof(char_u)), FALSE);
6550 
6551     FOR_ALL_WINDOWS(wp)
6552     {
6553 	if (win_alloc_lines(wp) == FAIL)
6554 	{
6555 	    outofmem = TRUE;
6556 #ifdef FEAT_WINDOWS
6557 	    break;
6558 #endif
6559 	}
6560     }
6561 
6562     if (new_ScreenLines == NULL
6563 #ifdef FEAT_MBYTE
6564 	    || (enc_utf8 && (new_ScreenLinesUC == NULL
6565 		   || new_ScreenLinesC1 == NULL || new_ScreenLinesC2 == NULL))
6566 	    || (enc_dbcs == DBCS_JPNU && new_ScreenLines2 == NULL)
6567 #endif
6568 	    || new_ScreenAttrs == NULL
6569 	    || new_LineOffset == NULL
6570 	    || new_LineWraps == NULL
6571 	    || outofmem)
6572     {
6573 	do_outofmem_msg((long_u)((Rows + 1) * Columns));    /* guess the size */
6574 	vim_free(new_ScreenLines);
6575 	new_ScreenLines = NULL;
6576 #ifdef FEAT_MBYTE
6577 	vim_free(new_ScreenLinesUC);
6578 	new_ScreenLinesUC = NULL;
6579 	vim_free(new_ScreenLinesC1);
6580 	new_ScreenLinesC1 = NULL;
6581 	vim_free(new_ScreenLinesC2);
6582 	new_ScreenLinesC2 = NULL;
6583 	vim_free(new_ScreenLines2);
6584 	new_ScreenLines2 = NULL;
6585 #endif
6586 	vim_free(new_ScreenAttrs);
6587 	new_ScreenAttrs = NULL;
6588 	vim_free(new_LineOffset);
6589 	new_LineOffset = NULL;
6590 	vim_free(new_LineWraps);
6591 	new_LineWraps = NULL;
6592     }
6593     else
6594     {
6595 	for (new_row = 0; new_row < Rows; ++new_row)
6596 	{
6597 	    new_LineOffset[new_row] = new_row * Columns;
6598 	    new_LineWraps[new_row] = FALSE;
6599 
6600 	    /*
6601 	     * If the screen is not going to be cleared, copy as much as
6602 	     * possible from the old screen to the new one and clear the rest
6603 	     * (used when resizing the window at the "--more--" prompt or when
6604 	     * executing an external command, for the GUI).
6605 	     */
6606 	    if (!clear)
6607 	    {
6608 		(void)vim_memset(new_ScreenLines + new_row * Columns,
6609 				      ' ', (size_t)Columns * sizeof(schar_T));
6610 #ifdef FEAT_MBYTE
6611 		if (enc_utf8)
6612 		{
6613 		    (void)vim_memset(new_ScreenLinesUC + new_row * Columns,
6614 				       0, (size_t)Columns * sizeof(u8char_T));
6615 		    (void)vim_memset(new_ScreenLinesC1 + new_row * Columns,
6616 				       0, (size_t)Columns * sizeof(u8char_T));
6617 		    (void)vim_memset(new_ScreenLinesC2 + new_row * Columns,
6618 				       0, (size_t)Columns * sizeof(u8char_T));
6619 		}
6620 		if (enc_dbcs == DBCS_JPNU)
6621 		    (void)vim_memset(new_ScreenLines2 + new_row * Columns,
6622 				       0, (size_t)Columns * sizeof(schar_T));
6623 #endif
6624 		(void)vim_memset(new_ScreenAttrs + new_row * Columns,
6625 					0, (size_t)Columns * sizeof(sattr_T));
6626 		old_row = new_row + (screen_Rows - Rows);
6627 		if (old_row >= 0)
6628 		{
6629 		    if (screen_Columns < Columns)
6630 			len = screen_Columns;
6631 		    else
6632 			len = Columns;
6633 		    mch_memmove(new_ScreenLines + new_LineOffset[new_row],
6634 			    ScreenLines + LineOffset[old_row],
6635 			    (size_t)len * sizeof(schar_T));
6636 #ifdef FEAT_MBYTE
6637 		    if (enc_utf8 && ScreenLinesUC != NULL)
6638 		    {
6639 			mch_memmove(new_ScreenLinesUC + new_LineOffset[new_row],
6640 				ScreenLinesUC + LineOffset[old_row],
6641 				(size_t)len * sizeof(u8char_T));
6642 			mch_memmove(new_ScreenLinesC1 + new_LineOffset[new_row],
6643 				ScreenLinesC1 + LineOffset[old_row],
6644 				(size_t)len * sizeof(u8char_T));
6645 			mch_memmove(new_ScreenLinesC2 + new_LineOffset[new_row],
6646 				ScreenLinesC2 + LineOffset[old_row],
6647 				(size_t)len * sizeof(u8char_T));
6648 		    }
6649 		    if (enc_dbcs == DBCS_JPNU && ScreenLines2 != NULL)
6650 			mch_memmove(new_ScreenLines2 + new_LineOffset[new_row],
6651 				ScreenLines2 + LineOffset[old_row],
6652 				(size_t)len * sizeof(schar_T));
6653 #endif
6654 		    mch_memmove(new_ScreenAttrs + new_LineOffset[new_row],
6655 			    ScreenAttrs + LineOffset[old_row],
6656 			    (size_t)len * sizeof(sattr_T));
6657 		}
6658 	    }
6659 	}
6660 	/* Use the last line of the screen for the current line. */
6661 	current_ScreenLine = new_ScreenLines + Rows * Columns;
6662     }
6663 
6664     vim_free(ScreenLines);
6665 #ifdef FEAT_MBYTE
6666     vim_free(ScreenLinesUC);
6667     vim_free(ScreenLinesC1);
6668     vim_free(ScreenLinesC2);
6669     vim_free(ScreenLines2);
6670 #endif
6671     vim_free(ScreenAttrs);
6672     vim_free(LineOffset);
6673     vim_free(LineWraps);
6674     ScreenLines = new_ScreenLines;
6675 #ifdef FEAT_MBYTE
6676     ScreenLinesUC = new_ScreenLinesUC;
6677     ScreenLinesC1 = new_ScreenLinesC1;
6678     ScreenLinesC2 = new_ScreenLinesC2;
6679     ScreenLines2 = new_ScreenLines2;
6680 #endif
6681     ScreenAttrs = new_ScreenAttrs;
6682     LineOffset = new_LineOffset;
6683     LineWraps = new_LineWraps;
6684 
6685     /* It's important that screen_Rows and screen_Columns reflect the actual
6686      * size of ScreenLines[].  Set them before calling anything. */
6687 #ifdef FEAT_GUI
6688     old_Rows = screen_Rows;
6689 #endif
6690     screen_Rows = Rows;
6691     screen_Columns = Columns;
6692 
6693     must_redraw = CLEAR;	/* need to clear the screen later */
6694     if (clear)
6695 	screenclear2();
6696 
6697 #ifdef FEAT_GUI
6698     else if (gui.in_use
6699 	    && !gui.starting
6700 	    && ScreenLines != NULL
6701 	    && old_Rows != Rows)
6702     {
6703 	(void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
6704 	/*
6705 	 * Adjust the position of the cursor, for when executing an external
6706 	 * command.
6707 	 */
6708 	if (msg_row >= Rows)		/* Rows got smaller */
6709 	    msg_row = Rows - 1;		/* put cursor at last row */
6710 	else if (Rows > old_Rows)	/* Rows got bigger */
6711 	    msg_row += Rows - old_Rows; /* put cursor in same place */
6712 	if (msg_col >= Columns)		/* Columns got smaller */
6713 	    msg_col = Columns - 1;	/* put cursor at last column */
6714     }
6715 #endif
6716 
6717 #ifdef FEAT_GUI_BEOS
6718     vim_unlock_screen();
6719 #endif
6720     entered = FALSE;
6721 }
6722 
6723     void
6724 screenclear()
6725 {
6726     check_for_delay(FALSE);
6727     screenalloc(FALSE);	    /* allocate screen buffers if size changed */
6728     screenclear2();	    /* clear the screen */
6729 }
6730 
6731     static void
6732 screenclear2()
6733 {
6734     int	    i;
6735 
6736     if (starting == NO_SCREEN || ScreenLines == NULL
6737 #ifdef FEAT_GUI
6738 	    || (gui.in_use && gui.starting)
6739 #endif
6740 	    )
6741 	return;
6742 
6743 #ifdef FEAT_GUI
6744     if (!gui.in_use)
6745 #endif
6746 	screen_attr = -1;	/* force setting the Normal colors */
6747     screen_stop_highlight();	/* don't want highlighting here */
6748 
6749 #ifdef FEAT_CLIPBOARD
6750     /* disable selection without redrawing it */
6751     clip_scroll_selection(9999);
6752 #endif
6753 
6754     /* blank out ScreenLines */
6755     for (i = 0; i < Rows; ++i)
6756     {
6757 	lineclear(LineOffset[i], (int)Columns);
6758 	LineWraps[i] = FALSE;
6759     }
6760 
6761     if (can_clear(T_CL))
6762     {
6763 	out_str(T_CL);		/* clear the display */
6764 	clear_cmdline = FALSE;
6765     }
6766     else
6767     {
6768 	/* can't clear the screen, mark all chars with invalid attributes */
6769 	for (i = 0; i < Rows; ++i)
6770 	    lineinvalid(LineOffset[i], (int)Columns);
6771 	clear_cmdline = TRUE;
6772     }
6773 
6774     screen_cleared = TRUE;	/* can use contents of ScreenLines now */
6775 
6776     win_rest_invalid(firstwin);
6777     redraw_cmdline = TRUE;
6778     if (must_redraw == CLEAR)	/* no need to clear again */
6779 	must_redraw = NOT_VALID;
6780     compute_cmdrow();
6781     msg_row = cmdline_row;	/* put cursor on last line for messages */
6782     msg_col = 0;
6783     screen_start();		/* don't know where cursor is now */
6784     msg_scrolled = 0;		/* can't scroll back */
6785     msg_didany = FALSE;
6786     msg_didout = FALSE;
6787 }
6788 
6789 /*
6790  * Clear one line in ScreenLines.
6791  */
6792     static void
6793 lineclear(off, width)
6794     unsigned	off;
6795     int		width;
6796 {
6797     (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
6798 #ifdef FEAT_MBYTE
6799     if (enc_utf8)
6800 	(void)vim_memset(ScreenLinesUC + off, 0,
6801 					  (size_t)width * sizeof(u8char_T));
6802 #endif
6803     (void)vim_memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
6804 }
6805 
6806 /*
6807  * Mark one line in ScreenLines invalid by setting the attributes to an
6808  * invalid value.
6809  */
6810     static void
6811 lineinvalid(off, width)
6812     unsigned	off;
6813     int		width;
6814 {
6815     (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T));
6816 }
6817 
6818 #ifdef FEAT_VERTSPLIT
6819 /*
6820  * Copy part of a Screenline for vertically split window "wp".
6821  */
6822     static void
6823 linecopy(to, from, wp)
6824     int		to;
6825     int		from;
6826     win_T	*wp;
6827 {
6828     unsigned	off_to = LineOffset[to] + wp->w_wincol;
6829     unsigned	off_from = LineOffset[from] + wp->w_wincol;
6830 
6831     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
6832 	    wp->w_width * sizeof(schar_T));
6833 # ifdef FEAT_MBYTE
6834     if (enc_utf8)
6835     {
6836 	mch_memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
6837 		wp->w_width * sizeof(u8char_T));
6838 	mch_memmove(ScreenLinesC1 + off_to, ScreenLinesC1 + off_from,
6839 		wp->w_width * sizeof(u8char_T));
6840 	mch_memmove(ScreenLinesC2 + off_to, ScreenLinesC2 + off_from,
6841 		wp->w_width * sizeof(u8char_T));
6842     }
6843     if (enc_dbcs == DBCS_JPNU)
6844 	mch_memmove(ScreenLines2 + off_to, ScreenLines2 + off_from,
6845 		wp->w_width * sizeof(schar_T));
6846 # endif
6847     mch_memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
6848 	    wp->w_width * sizeof(sattr_T));
6849 }
6850 #endif
6851 
6852 /*
6853  * Return TRUE if clearing with term string "p" would work.
6854  * It can't work when the string is empty or it won't set the right background.
6855  */
6856     int
6857 can_clear(p)
6858     char_u	*p;
6859 {
6860     return (*p != NUL && (t_colors <= 1
6861 #ifdef FEAT_GUI
6862 		|| gui.in_use
6863 #endif
6864 		|| cterm_normal_bg_color == 0 || *T_UT != NUL));
6865 }
6866 
6867 /*
6868  * Reset cursor position. Use whenever cursor was moved because of outputting
6869  * something directly to the screen (shell commands) or a terminal control
6870  * code.
6871  */
6872     void
6873 screen_start()
6874 {
6875     screen_cur_row = screen_cur_col = 9999;
6876 }
6877 
6878 /*
6879  * Note that the cursor has gone down to the next line, column 0.
6880  * Used for Ex mode.
6881  */
6882     void
6883 screen_down()
6884 {
6885     screen_cur_col = 0;
6886     if (screen_cur_row < Rows - 1)
6887 	++screen_cur_row;
6888 }
6889 
6890 /*
6891  * Move the cursor to position "row","col" in the screen.
6892  * This tries to find the most efficient way to move, minimizing the number of
6893  * characters sent to the terminal.
6894  */
6895     void
6896 windgoto(row, col)
6897     int	    row;
6898     int	    col;
6899 {
6900     char_u	    *p;
6901     int		    i;
6902     int		    plan;
6903     int		    cost;
6904     int		    wouldbe_col;
6905     int		    noinvcurs;
6906     char_u	    *bs;
6907     int		    goto_cost;
6908     int		    attr;
6909 
6910 #define GOTO_COST   7	/* asssume a term_windgoto() takes about 7 chars */
6911 #define HIGHL_COST  5	/* assume unhighlight takes 5 chars */
6912 
6913 #define PLAN_LE	    1
6914 #define PLAN_CR	    2
6915 #define PLAN_NL	    3
6916 #define PLAN_WRITE  4
6917     /* Can't use ScreenLines unless initialized */
6918     if (ScreenLines == NULL)
6919 	return;
6920 
6921     if (col != screen_cur_col || row != screen_cur_row)
6922     {
6923 	/* Check for valid position. */
6924 	if (row < 0)	/* window without text lines? */
6925 	    row = 0;
6926 	if (row >= screen_Rows)
6927 	    row = screen_Rows - 1;
6928 	if (col >= screen_Columns)
6929 	    col = screen_Columns - 1;
6930 
6931 	/* check if no cursor movement is allowed in highlight mode */
6932 	if (screen_attr && *T_MS == NUL)
6933 	    noinvcurs = HIGHL_COST;
6934 	else
6935 	    noinvcurs = 0;
6936 	goto_cost = GOTO_COST + noinvcurs;
6937 
6938 	/*
6939 	 * Plan how to do the positioning:
6940 	 * 1. Use CR to move it to column 0, same row.
6941 	 * 2. Use T_LE to move it a few columns to the left.
6942 	 * 3. Use NL to move a few lines down, column 0.
6943 	 * 4. Move a few columns to the right with T_ND or by writing chars.
6944 	 *
6945 	 * Don't do this if the cursor went beyond the last column, the cursor
6946 	 * position is unknown then (some terminals wrap, some don't )
6947 	 *
6948 	 * First check if the highlighting attibutes allow us to write
6949 	 * characters to move the cursor to the right.
6950 	 */
6951 	if (row >= screen_cur_row && screen_cur_col < Columns)
6952 	{
6953 	    /*
6954 	     * If the cursor is in the same row, bigger col, we can use CR
6955 	     * or T_LE.
6956 	     */
6957 	    bs = NULL;			    /* init for GCC */
6958 	    attr = screen_attr;
6959 	    if (row == screen_cur_row && col < screen_cur_col)
6960 	    {
6961 		/* "le" is preferred over "bc", because "bc" is obsolete */
6962 		if (*T_LE)
6963 		    bs = T_LE;		    /* "cursor left" */
6964 		else
6965 		    bs = T_BC;		    /* "backspace character (old) */
6966 		if (*bs)
6967 		    cost = (screen_cur_col - col) * (int)STRLEN(bs);
6968 		else
6969 		    cost = 999;
6970 		if (col + 1 < cost)	    /* using CR is less characters */
6971 		{
6972 		    plan = PLAN_CR;
6973 		    wouldbe_col = 0;
6974 		    cost = 1;		    /* CR is just one character */
6975 		}
6976 		else
6977 		{
6978 		    plan = PLAN_LE;
6979 		    wouldbe_col = col;
6980 		}
6981 		if (noinvcurs)		    /* will stop highlighting */
6982 		{
6983 		    cost += noinvcurs;
6984 		    attr = 0;
6985 		}
6986 	    }
6987 
6988 	    /*
6989 	     * If the cursor is above where we want to be, we can use CR LF.
6990 	     */
6991 	    else if (row > screen_cur_row)
6992 	    {
6993 		plan = PLAN_NL;
6994 		wouldbe_col = 0;
6995 		cost = (row - screen_cur_row) * 2;  /* CR LF */
6996 		if (noinvcurs)		    /* will stop highlighting */
6997 		{
6998 		    cost += noinvcurs;
6999 		    attr = 0;
7000 		}
7001 	    }
7002 
7003 	    /*
7004 	     * If the cursor is in the same row, smaller col, just use write.
7005 	     */
7006 	    else
7007 	    {
7008 		plan = PLAN_WRITE;
7009 		wouldbe_col = screen_cur_col;
7010 		cost = 0;
7011 	    }
7012 
7013 	    /*
7014 	     * Check if any characters that need to be written have the
7015 	     * correct attributes.  Also avoid UTF-8 characters.
7016 	     */
7017 	    i = col - wouldbe_col;
7018 	    if (i > 0)
7019 		cost += i;
7020 	    if (cost < goto_cost && i > 0)
7021 	    {
7022 		/*
7023 		 * Check if the attributes are correct without additionally
7024 		 * stopping highlighting.
7025 		 */
7026 		p = ScreenAttrs + LineOffset[row] + wouldbe_col;
7027 		while (i && *p++ == attr)
7028 		    --i;
7029 		if (i != 0)
7030 		{
7031 		    /*
7032 		     * Try if it works when highlighting is stopped here.
7033 		     */
7034 		    if (*--p == 0)
7035 		    {
7036 			cost += noinvcurs;
7037 			while (i && *p++ == 0)
7038 			    --i;
7039 		    }
7040 		    if (i != 0)
7041 			cost = 999;	/* different attributes, don't do it */
7042 		}
7043 #ifdef FEAT_MBYTE
7044 		if (enc_utf8)
7045 		{
7046 		    /* Don't use an UTF-8 char for positioning, it's slow. */
7047 		    for (i = wouldbe_col; i < col; ++i)
7048 			if (ScreenLinesUC[LineOffset[row] + i] != 0)
7049 			{
7050 			    cost = 999;
7051 			    break;
7052 			}
7053 		}
7054 #endif
7055 	    }
7056 
7057 	    /*
7058 	     * We can do it without term_windgoto()!
7059 	     */
7060 	    if (cost < goto_cost)
7061 	    {
7062 		if (plan == PLAN_LE)
7063 		{
7064 		    if (noinvcurs)
7065 			screen_stop_highlight();
7066 		    while (screen_cur_col > col)
7067 		    {
7068 			out_str(bs);
7069 			--screen_cur_col;
7070 		    }
7071 		}
7072 		else if (plan == PLAN_CR)
7073 		{
7074 		    if (noinvcurs)
7075 			screen_stop_highlight();
7076 		    out_char('\r');
7077 		    screen_cur_col = 0;
7078 		}
7079 		else if (plan == PLAN_NL)
7080 		{
7081 		    if (noinvcurs)
7082 			screen_stop_highlight();
7083 		    while (screen_cur_row < row)
7084 		    {
7085 			out_char('\n');
7086 			++screen_cur_row;
7087 		    }
7088 		    screen_cur_col = 0;
7089 		}
7090 
7091 		i = col - screen_cur_col;
7092 		if (i > 0)
7093 		{
7094 		    /*
7095 		     * Use cursor-right if it's one character only.  Avoids
7096 		     * removing a line of pixels from the last bold char, when
7097 		     * using the bold trick in the GUI.
7098 		     */
7099 		    if (T_ND[0] != NUL && T_ND[1] == NUL)
7100 		    {
7101 			while (i-- > 0)
7102 			    out_char(*T_ND);
7103 		    }
7104 		    else
7105 		    {
7106 			int	off;
7107 
7108 			off = LineOffset[row] + screen_cur_col;
7109 			while (i-- > 0)
7110 			{
7111 			    if (ScreenAttrs[off] != screen_attr)
7112 				screen_stop_highlight();
7113 #ifdef FEAT_MBYTE
7114 			    out_flush_check();
7115 #endif
7116 			    out_char(ScreenLines[off]);
7117 #ifdef FEAT_MBYTE
7118 			    if (enc_dbcs == DBCS_JPNU
7119 						  && ScreenLines[off] == 0x8e)
7120 				out_char(ScreenLines2[off]);
7121 #endif
7122 			    ++off;
7123 			}
7124 		    }
7125 		}
7126 	    }
7127 	}
7128 	else
7129 	    cost = 999;
7130 
7131 	if (cost >= goto_cost)
7132 	{
7133 	    if (noinvcurs)
7134 		screen_stop_highlight();
7135 	    if (row == screen_cur_row && (col > screen_cur_col) &&
7136 								*T_CRI != NUL)
7137 		term_cursor_right(col - screen_cur_col);
7138 	    else
7139 		term_windgoto(row, col);
7140 	}
7141 	screen_cur_row = row;
7142 	screen_cur_col = col;
7143     }
7144 }
7145 
7146 /*
7147  * Set cursor to its position in the current window.
7148  */
7149     void
7150 setcursor()
7151 {
7152     if (redrawing())
7153     {
7154 	validate_cursor();
7155 	windgoto(W_WINROW(curwin) + curwin->w_wrow,
7156 		W_WINCOL(curwin) + (
7157 #ifdef FEAT_RIGHTLEFT
7158 		curwin->w_p_rl ? ((int)W_WIDTH(curwin) - curwin->w_wcol - (
7159 # ifdef FEAT_MBYTE
7160 			has_mbyte ? (*mb_ptr2cells)(ml_get_cursor()) :
7161 # endif
7162 			1)) :
7163 #endif
7164 							    curwin->w_wcol));
7165     }
7166 }
7167 
7168 
7169 /*
7170  * insert 'line_count' lines at 'row' in window 'wp'
7171  * if 'invalid' is TRUE the wp->w_lines[].wl_lnum is invalidated.
7172  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
7173  * scrolling.
7174  * Returns FAIL if the lines are not inserted, OK for success.
7175  */
7176     int
7177 win_ins_lines(wp, row, line_count, invalid, mayclear)
7178     win_T	*wp;
7179     int		row;
7180     int		line_count;
7181     int		invalid;
7182     int		mayclear;
7183 {
7184     int		did_delete;
7185     int		nextrow;
7186     int		lastrow;
7187     int		retval;
7188 
7189     if (invalid)
7190 	wp->w_lines_valid = 0;
7191 
7192     if (wp->w_height < 5)
7193 	return FAIL;
7194 
7195     if (line_count > wp->w_height - row)
7196 	line_count = wp->w_height - row;
7197 
7198     retval = win_do_lines(wp, row, line_count, mayclear, FALSE);
7199     if (retval != MAYBE)
7200 	return retval;
7201 
7202     /*
7203      * If there is a next window or a status line, we first try to delete the
7204      * lines at the bottom to avoid messing what is after the window.
7205      * If this fails and there are following windows, don't do anything to avoid
7206      * messing up those windows, better just redraw.
7207      */
7208     did_delete = FALSE;
7209 #ifdef FEAT_WINDOWS
7210     if (wp->w_next != NULL || wp->w_status_height)
7211     {
7212 	if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
7213 				    line_count, (int)Rows, FALSE, NULL) == OK)
7214 	    did_delete = TRUE;
7215 	else if (wp->w_next)
7216 	    return FAIL;
7217     }
7218 #endif
7219     /*
7220      * if no lines deleted, blank the lines that will end up below the window
7221      */
7222     if (!did_delete)
7223     {
7224 #ifdef FEAT_WINDOWS
7225 	wp->w_redr_status = TRUE;
7226 #endif
7227 	redraw_cmdline = TRUE;
7228 	nextrow = W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp);
7229 	lastrow = nextrow + line_count;
7230 	if (lastrow > Rows)
7231 	    lastrow = Rows;
7232 	screen_fill(nextrow - line_count, lastrow - line_count,
7233 		  W_WINCOL(wp), (int)W_ENDCOL(wp),
7234 		  ' ', ' ', 0);
7235     }
7236 
7237     if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, NULL)
7238 								      == FAIL)
7239     {
7240 	    /* deletion will have messed up other windows */
7241 	if (did_delete)
7242 	{
7243 #ifdef FEAT_WINDOWS
7244 	    wp->w_redr_status = TRUE;
7245 #endif
7246 	    win_rest_invalid(W_NEXT(wp));
7247 	}
7248 	return FAIL;
7249     }
7250 
7251     return OK;
7252 }
7253 
7254 /*
7255  * delete "line_count" window lines at "row" in window "wp"
7256  * If "invalid" is TRUE curwin->w_lines[] is invalidated.
7257  * If "mayclear" is TRUE the screen will be cleared if it is faster than
7258  * scrolling
7259  * Return OK for success, FAIL if the lines are not deleted.
7260  */
7261     int
7262 win_del_lines(wp, row, line_count, invalid, mayclear)
7263     win_T	*wp;
7264     int		row;
7265     int		line_count;
7266     int		invalid;
7267     int		mayclear;
7268 {
7269     int		retval;
7270 
7271     if (invalid)
7272 	wp->w_lines_valid = 0;
7273 
7274     if (line_count > wp->w_height - row)
7275 	line_count = wp->w_height - row;
7276 
7277     retval = win_do_lines(wp, row, line_count, mayclear, TRUE);
7278     if (retval != MAYBE)
7279 	return retval;
7280 
7281     if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
7282 					      (int)Rows, FALSE, NULL) == FAIL)
7283 	return FAIL;
7284 
7285 #ifdef FEAT_WINDOWS
7286     /*
7287      * If there are windows or status lines below, try to put them at the
7288      * correct place. If we can't do that, they have to be redrawn.
7289      */
7290     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
7291     {
7292 	if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
7293 					 line_count, (int)Rows, NULL) == FAIL)
7294 	{
7295 	    wp->w_redr_status = TRUE;
7296 	    win_rest_invalid(wp->w_next);
7297 	}
7298     }
7299     /*
7300      * If this is the last window and there is no status line, redraw the
7301      * command line later.
7302      */
7303     else
7304 #endif
7305 	redraw_cmdline = TRUE;
7306     return OK;
7307 }
7308 
7309 /*
7310  * Common code for win_ins_lines() and win_del_lines().
7311  * Returns OK or FAIL when the work has been done.
7312  * Returns MAYBE when not finished yet.
7313  */
7314     static int
7315 win_do_lines(wp, row, line_count, mayclear, del)
7316     win_T	*wp;
7317     int		row;
7318     int		line_count;
7319     int		mayclear;
7320     int		del;
7321 {
7322     int		retval;
7323 
7324     if (!redrawing() || line_count <= 0)
7325 	return FAIL;
7326 
7327     /* only a few lines left: redraw is faster */
7328     if (mayclear && Rows - line_count < 5
7329 #ifdef FEAT_VERTSPLIT
7330 	    && wp->w_width == Columns
7331 #endif
7332 	    )
7333     {
7334 	screenclear();	    /* will set wp->w_lines_valid to 0 */
7335 	return FAIL;
7336     }
7337 
7338     /*
7339      * Delete all remaining lines
7340      */
7341     if (row + line_count >= wp->w_height)
7342     {
7343 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
7344 		W_WINCOL(wp), (int)W_ENDCOL(wp),
7345 		' ', ' ', 0);
7346 	return OK;
7347     }
7348 
7349     /*
7350      * when scrolling, the message on the command line should be cleared,
7351      * otherwise it will stay there forever.
7352      */
7353     clear_cmdline = TRUE;
7354 
7355     /*
7356      * If the terminal can set a scroll region, use that.
7357      * Always do this in a vertically split window.  This will redraw from
7358      * ScreenLines[] when t_CV isn't defined.  That's faster than using
7359      * win_line().
7360      * Don't use a scroll region when we are going to redraw the text, writing
7361      * a character in the lower right corner of the scroll region causes a
7362      * scroll-up in the DJGPP version.
7363      */
7364     if (scroll_region
7365 #ifdef FEAT_VERTSPLIT
7366 	    || W_WIDTH(wp) != Columns
7367 #endif
7368 	    )
7369     {
7370 #ifdef FEAT_VERTSPLIT
7371 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
7372 #endif
7373 	    scroll_region_set(wp, row);
7374 	if (del)
7375 	    retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
7376 					       wp->w_height - row, FALSE, wp);
7377 	else
7378 	    retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
7379 						      wp->w_height - row, wp);
7380 #ifdef FEAT_VERTSPLIT
7381 	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
7382 #endif
7383 	    scroll_region_reset();
7384 	return retval;
7385     }
7386 
7387 #ifdef FEAT_WINDOWS
7388     if (wp->w_next != NULL && p_tf) /* don't delete/insert on fast terminal */
7389 	return FAIL;
7390 #endif
7391 
7392     return MAYBE;
7393 }
7394 
7395 /*
7396  * window 'wp' and everything after it is messed up, mark it for redraw
7397  */
7398     static void
7399 win_rest_invalid(wp)
7400     win_T	*wp;
7401 {
7402 #ifdef FEAT_WINDOWS
7403     while (wp != NULL)
7404 #else
7405     if (wp != NULL)
7406 #endif
7407     {
7408 	redraw_win_later(wp, NOT_VALID);
7409 #ifdef FEAT_WINDOWS
7410 	wp->w_redr_status = TRUE;
7411 	wp = wp->w_next;
7412 #endif
7413     }
7414     redraw_cmdline = TRUE;
7415 }
7416 
7417 /*
7418  * The rest of the routines in this file perform screen manipulations. The
7419  * given operation is performed physically on the screen. The corresponding
7420  * change is also made to the internal screen image. In this way, the editor
7421  * anticipates the effect of editing changes on the appearance of the screen.
7422  * That way, when we call screenupdate a complete redraw isn't usually
7423  * necessary. Another advantage is that we can keep adding code to anticipate
7424  * screen changes, and in the meantime, everything still works.
7425  */
7426 
7427 /*
7428  * types for inserting or deleting lines
7429  */
7430 #define USE_T_CAL   1
7431 #define USE_T_CDL   2
7432 #define USE_T_AL    3
7433 #define USE_T_CE    4
7434 #define USE_T_DL    5
7435 #define USE_T_SR    6
7436 #define USE_NL	    7
7437 #define USE_T_CD    8
7438 #define USE_REDRAW  9
7439 
7440 /*
7441  * insert lines on the screen and update ScreenLines[]
7442  * 'end' is the line after the scrolled part. Normally it is Rows.
7443  * When scrolling region used 'off' is the offset from the top for the region.
7444  * 'row' and 'end' are relative to the start of the region.
7445  *
7446  * return FAIL for failure, OK for success.
7447  */
7448     static int
7449 screen_ins_lines(off, row, line_count, end, wp)
7450     int		off;
7451     int		row;
7452     int		line_count;
7453     int		end;
7454     win_T	*wp;	    /* NULL or window to use width from */
7455 {
7456     int		i;
7457     int		j;
7458     unsigned	temp;
7459     int		cursor_row;
7460     int		type;
7461     int		result_empty;
7462     int		can_ce = can_clear(T_CE);
7463 
7464     /*
7465      * FAIL if
7466      * - there is no valid screen
7467      * - the screen has to be redrawn completely
7468      * - the line count is less than one
7469      * - the line count is more than 'ttyscroll'
7470      */
7471     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
7472 	return FAIL;
7473 
7474     /*
7475      * There are seven ways to insert lines:
7476      * 0. When in a vertically split window and t_CV isn't set, redraw the
7477      *    characters from ScreenLines[].
7478      * 1. Use T_CD (clear to end of display) if it exists and the result of
7479      *	  the insert is just empty lines
7480      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
7481      *	  present or line_count > 1. It looks better if we do all the inserts
7482      *	  at once.
7483      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
7484      *	  insert is just empty lines and T_CE is not present or line_count >
7485      *	  1.
7486      * 4. Use T_AL (insert line) if it exists.
7487      * 5. Use T_CE (erase line) if it exists and the result of the insert is
7488      *	  just empty lines.
7489      * 6. Use T_DL (delete line) if it exists and the result of the insert is
7490      *	  just empty lines.
7491      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
7492      *	  the 'da' flag is not set or we have clear line capability.
7493      * 8. redraw the characters from ScreenLines[].
7494      *
7495      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
7496      * the scrollbar for the window. It does have insert line, use that if it
7497      * exists.
7498      */
7499     result_empty = (row + line_count >= end);
7500 #ifdef FEAT_VERTSPLIT
7501     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
7502 	type = USE_REDRAW;
7503     else
7504 #endif
7505     if (can_clear(T_CD) && result_empty)
7506 	type = USE_T_CD;
7507     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
7508 	type = USE_T_CAL;
7509     else if (*T_CDL != NUL && result_empty && (line_count > 1 || !can_ce))
7510 	type = USE_T_CDL;
7511     else if (*T_AL != NUL)
7512 	type = USE_T_AL;
7513     else if (can_ce && result_empty)
7514 	type = USE_T_CE;
7515     else if (*T_DL != NUL && result_empty)
7516 	type = USE_T_DL;
7517     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || can_ce))
7518 	type = USE_T_SR;
7519     else
7520 	return FAIL;
7521 
7522     /*
7523      * For clearing the lines screen_del_lines() is used. This will also take
7524      * care of t_db if necessary.
7525      */
7526     if (type == USE_T_CD || type == USE_T_CDL ||
7527 					 type == USE_T_CE || type == USE_T_DL)
7528 	return screen_del_lines(off, row, line_count, end, FALSE, wp);
7529 
7530     /*
7531      * If text is retained below the screen, first clear or delete as many
7532      * lines at the bottom of the window as are about to be inserted so that
7533      * the deleted lines won't later surface during a screen_del_lines.
7534      */
7535     if (*T_DB)
7536 	screen_del_lines(off, end - line_count, line_count, end, FALSE, wp);
7537 
7538 #ifdef FEAT_CLIPBOARD
7539     /* Remove a modeless selection when inserting lines halfway the screen
7540      * or not the full width of the screen. */
7541     if (off + row > 0
7542 # ifdef FEAT_VERTSPLIT
7543 	    || (wp != NULL && wp->w_width != Columns)
7544 # endif
7545        )
7546 	clip_clear_selection();
7547     else
7548 	clip_scroll_selection(-line_count);
7549 #endif
7550 
7551 #ifdef FEAT_GUI_BEOS
7552     vim_lock_screen();
7553 #endif
7554 #ifdef FEAT_GUI
7555     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
7556      * scrolling is actually carried out. */
7557     gui_dont_update_cursor();
7558 #endif
7559 
7560     if (*T_CCS != NUL)	   /* cursor relative to region */
7561 	cursor_row = row;
7562     else
7563 	cursor_row = row + off;
7564 
7565     /*
7566      * Shift LineOffset[] line_count down to reflect the inserted lines.
7567      * Clear the inserted lines in ScreenLines[].
7568      */
7569     row += off;
7570     end += off;
7571     for (i = 0; i < line_count; ++i)
7572     {
7573 #ifdef FEAT_VERTSPLIT
7574 	if (wp != NULL && wp->w_width != Columns)
7575 	{
7576 	    /* need to copy part of a line */
7577 	    j = end - 1 - i;
7578 	    while ((j -= line_count) >= row)
7579 		linecopy(j + line_count, j, wp);
7580 	    j += line_count;
7581 	    if (can_clear((char_u *)" "))
7582 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
7583 	    else
7584 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
7585 	    LineWraps[j] = FALSE;
7586 	}
7587 	else
7588 #endif
7589 	{
7590 	    j = end - 1 - i;
7591 	    temp = LineOffset[j];
7592 	    while ((j -= line_count) >= row)
7593 	    {
7594 		LineOffset[j + line_count] = LineOffset[j];
7595 		LineWraps[j + line_count] = LineWraps[j];
7596 	    }
7597 	    LineOffset[j + line_count] = temp;
7598 	    LineWraps[j + line_count] = FALSE;
7599 	    if (can_clear((char_u *)" "))
7600 		lineclear(temp, (int)Columns);
7601 	    else
7602 		lineinvalid(temp, (int)Columns);
7603 	}
7604     }
7605 #ifdef FEAT_GUI_BEOS
7606     vim_unlock_screen();
7607 #endif
7608 
7609     screen_stop_highlight();
7610     windgoto(cursor_row, 0);
7611 
7612 #ifdef FEAT_VERTSPLIT
7613     /* redraw the characters */
7614     if (type == USE_REDRAW)
7615 	redraw_block(row, end, wp);
7616     else
7617 #endif
7618 	if (type == USE_T_CAL)
7619     {
7620 	term_append_lines(line_count);
7621 	screen_start();		/* don't know where cursor is now */
7622     }
7623     else
7624     {
7625 	for (i = 0; i < line_count; i++)
7626 	{
7627 	    if (type == USE_T_AL)
7628 	    {
7629 		if (i && cursor_row != 0)
7630 		    windgoto(cursor_row, 0);
7631 		out_str(T_AL);
7632 	    }
7633 	    else  /* type == USE_T_SR */
7634 		out_str(T_SR);
7635 	    screen_start();	    /* don't know where cursor is now */
7636 	}
7637     }
7638 
7639     /*
7640      * With scroll-reverse and 'da' flag set we need to clear the lines that
7641      * have been scrolled down into the region.
7642      */
7643     if (type == USE_T_SR && *T_DA)
7644     {
7645 	for (i = 0; i < line_count; ++i)
7646 	{
7647 	    windgoto(off + i, 0);
7648 	    out_str(T_CE);
7649 	    screen_start();	    /* don't know where cursor is now */
7650 	}
7651     }
7652 
7653 #ifdef FEAT_GUI
7654     gui_can_update_cursor();
7655     if (gui.in_use)
7656 	out_flush();	/* always flush after a scroll */
7657 #endif
7658     return OK;
7659 }
7660 
7661 /*
7662  * delete lines on the screen and update ScreenLines[]
7663  * 'end' is the line after the scrolled part. Normally it is Rows.
7664  * When scrolling region used 'off' is the offset from the top for the region.
7665  * 'row' and 'end' are relative to the start of the region.
7666  *
7667  * Return OK for success, FAIL if the lines are not deleted.
7668  */
7669 /*ARGSUSED*/
7670     int
7671 screen_del_lines(off, row, line_count, end, force, wp)
7672     int		off;
7673     int		row;
7674     int		line_count;
7675     int		end;
7676     int		force;		/* even when line_count > p_ttyscroll */
7677     win_T	*wp;		/* NULL or window to use width from */
7678 {
7679     int		j;
7680     int		i;
7681     unsigned	temp;
7682     int		cursor_row;
7683     int		cursor_end;
7684     int		result_empty;	/* result is empty until end of region */
7685     int		can_delete;	/* deleting line codes can be used */
7686     int		type;
7687 
7688     /*
7689      * FAIL if
7690      * - there is no valid screen
7691      * - the screen has to be redrawn completely
7692      * - the line count is less than one
7693      * - the line count is more than 'ttyscroll'
7694      */
7695     if (!screen_valid(TRUE) || line_count <= 0 ||
7696 					 (!force && line_count > p_ttyscroll))
7697 	return FAIL;
7698 
7699     /*
7700      * Check if the rest of the current region will become empty.
7701      */
7702     result_empty = row + line_count >= end;
7703 
7704     /*
7705      * We can delete lines only when 'db' flag not set or when 'ce' option
7706      * available.
7707      */
7708     can_delete = (*T_DB == NUL || can_clear(T_CE));
7709 
7710     /*
7711      * There are six ways to delete lines:
7712      * 0. When in a vertically split window and t_CV isn't set, redraw the
7713      *    characters from ScreenLines[].
7714      * 1. Use T_CD if it exists and the result is empty.
7715      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
7716      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
7717      *	  none of the other ways work.
7718      * 4. Use T_CE (erase line) if the result is empty.
7719      * 5. Use T_DL (delete line) if it exists.
7720      * 6. redraw the characters from ScreenLines[].
7721      */
7722 #ifdef FEAT_VERTSPLIT
7723     if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
7724 	type = USE_REDRAW;
7725     else
7726 #endif
7727     if (can_clear(T_CD) && result_empty)
7728 	type = USE_T_CD;
7729 #if defined(__BEOS__) && defined(BEOS_DR8)
7730     /*
7731      * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
7732      * its internal termcap... this works okay for tests which test *T_DB !=
7733      * NUL.  It has the disadvantage that the user cannot use any :set t_*
7734      * command to get T_DB (back) to empty_option, only :set term=... will do
7735      * the trick...
7736      * Anyway, this hack will hopefully go away with the next OS release.
7737      * (Olaf Seibert)
7738      */
7739     else if (row == 0 && T_DB == empty_option
7740 					&& (line_count == 1 || *T_CDL == NUL))
7741 #else
7742     else if (row == 0 && (
7743 #ifndef AMIGA
7744 	/* On the Amiga, somehow '\n' on the last line doesn't always scroll
7745 	 * up, so use delete-line command */
7746 			    line_count == 1 ||
7747 #endif
7748 						*T_CDL == NUL))
7749 #endif
7750 	type = USE_NL;
7751     else if (*T_CDL != NUL && line_count > 1 && can_delete)
7752 	type = USE_T_CDL;
7753     else if (can_clear(T_CE) && result_empty
7754 #ifdef FEAT_VERTSPLIT
7755 	    && (wp == NULL || wp->w_width == Columns)
7756 #endif
7757 	    )
7758 	type = USE_T_CE;
7759     else if (*T_DL != NUL && can_delete)
7760 	type = USE_T_DL;
7761     else if (*T_CDL != NUL && can_delete)
7762 	type = USE_T_CDL;
7763     else
7764 	return FAIL;
7765 
7766 #ifdef FEAT_CLIPBOARD
7767     /* Remove a modeless selection when deleting lines halfway the screen or
7768      * not the full width of the screen. */
7769     if (off + row > 0
7770 # ifdef FEAT_VERTSPLIT
7771 	    || (wp != NULL && wp->w_width != Columns)
7772 # endif
7773        )
7774 	clip_clear_selection();
7775     else
7776 	clip_scroll_selection(line_count);
7777 #endif
7778 
7779 #ifdef FEAT_GUI_BEOS
7780     vim_lock_screen();
7781 #endif
7782 #ifdef FEAT_GUI
7783     /* Don't update the GUI cursor here, ScreenLines[] is invalid until the
7784      * scrolling is actually carried out. */
7785     gui_dont_update_cursor();
7786 #endif
7787 
7788     if (*T_CCS != NUL)	    /* cursor relative to region */
7789     {
7790 	cursor_row = row;
7791 	cursor_end = end;
7792     }
7793     else
7794     {
7795 	cursor_row = row + off;
7796 	cursor_end = end + off;
7797     }
7798 
7799     /*
7800      * Now shift LineOffset[] line_count up to reflect the deleted lines.
7801      * Clear the inserted lines in ScreenLines[].
7802      */
7803     row += off;
7804     end += off;
7805     for (i = 0; i < line_count; ++i)
7806     {
7807 #ifdef FEAT_VERTSPLIT
7808 	if (wp != NULL && wp->w_width != Columns)
7809 	{
7810 	    /* need to copy part of a line */
7811 	    j = row + i;
7812 	    while ((j += line_count) <= end - 1)
7813 		linecopy(j - line_count, j, wp);
7814 	    j -= line_count;
7815 	    if (can_clear((char_u *)" "))
7816 		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
7817 	    else
7818 		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
7819 	    LineWraps[j] = FALSE;
7820 	}
7821 	else
7822 #endif
7823 	{
7824 	    /* whole width, moving the line pointers is faster */
7825 	    j = row + i;
7826 	    temp = LineOffset[j];
7827 	    while ((j += line_count) <= end - 1)
7828 	    {
7829 		LineOffset[j - line_count] = LineOffset[j];
7830 		LineWraps[j - line_count] = LineWraps[j];
7831 	    }
7832 	    LineOffset[j - line_count] = temp;
7833 	    LineWraps[j - line_count] = FALSE;
7834 	    if (can_clear((char_u *)" "))
7835 		lineclear(temp, (int)Columns);
7836 	    else
7837 		lineinvalid(temp, (int)Columns);
7838 	}
7839     }
7840 #ifdef FEAT_GUI_BEOS
7841     vim_unlock_screen();
7842 #endif
7843 
7844     screen_stop_highlight();
7845 
7846 #ifdef FEAT_VERTSPLIT
7847     /* redraw the characters */
7848     if (type == USE_REDRAW)
7849 	redraw_block(row, end, wp);
7850     else
7851 #endif
7852 	if (type == USE_T_CD)	/* delete the lines */
7853     {
7854 	windgoto(cursor_row, 0);
7855 	out_str(T_CD);
7856 	screen_start();			/* don't know where cursor is now */
7857     }
7858     else if (type == USE_T_CDL)
7859     {
7860 	windgoto(cursor_row, 0);
7861 	term_delete_lines(line_count);
7862 	screen_start();			/* don't know where cursor is now */
7863     }
7864     /*
7865      * Deleting lines at top of the screen or scroll region: Just scroll
7866      * the whole screen (scroll region) up by outputting newlines on the
7867      * last line.
7868      */
7869     else if (type == USE_NL)
7870     {
7871 	windgoto(cursor_end - 1, 0);
7872 	for (i = line_count; --i >= 0; )
7873 	    out_char('\n');		/* cursor will remain on same line */
7874     }
7875     else
7876     {
7877 	for (i = line_count; --i >= 0; )
7878 	{
7879 	    if (type == USE_T_DL)
7880 	    {
7881 		windgoto(cursor_row, 0);
7882 		out_str(T_DL);		/* delete a line */
7883 	    }
7884 	    else /* type == USE_T_CE */
7885 	    {
7886 		windgoto(cursor_row + i, 0);
7887 		out_str(T_CE);		/* erase a line */
7888 	    }
7889 	    screen_start();		/* don't know where cursor is now */
7890 	}
7891     }
7892 
7893     /*
7894      * If the 'db' flag is set, we need to clear the lines that have been
7895      * scrolled up at the bottom of the region.
7896      */
7897     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
7898     {
7899 	for (i = line_count; i > 0; --i)
7900 	{
7901 	    windgoto(cursor_end - i, 0);
7902 	    out_str(T_CE);		/* erase a line */
7903 	    screen_start();		/* don't know where cursor is now */
7904 	}
7905     }
7906 
7907 #ifdef FEAT_GUI
7908     gui_can_update_cursor();
7909     if (gui.in_use)
7910 	out_flush();	/* always flush after a scroll */
7911 #endif
7912 
7913     return OK;
7914 }
7915 
7916 /*
7917  * show the current mode and ruler
7918  *
7919  * If clear_cmdline is TRUE, clear the rest of the cmdline.
7920  * If clear_cmdline is FALSE there may be a message there that needs to be
7921  * cleared only if a mode is shown.
7922  * Return the length of the message (0 if no message).
7923  */
7924     int
7925 showmode()
7926 {
7927     int		need_clear;
7928     int		length = 0;
7929     int		do_mode;
7930     int		attr;
7931     int		nwr_save;
7932 #ifdef FEAT_INS_EXPAND
7933     int		sub_attr;
7934 #endif
7935 
7936     do_mode = (p_smd && ((State & INSERT) || restart_edit
7937 #ifdef FEAT_VISUAL
7938 		|| VIsual_active
7939 #endif
7940 		));
7941     if (do_mode || Recording)
7942     {
7943 	/*
7944 	 * Don't show mode right now, when not redrawing or inside a mapping.
7945 	 * Call char_avail() only when we are going to show something, because
7946 	 * it takes a bit of time.
7947 	 */
7948 	if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0)
7949 	{
7950 	    redraw_cmdline = TRUE;		/* show mode later */
7951 	    return 0;
7952 	}
7953 
7954 	nwr_save = need_wait_return;
7955 
7956 	/* wait a bit before overwriting an important message */
7957 	check_for_delay(FALSE);
7958 
7959 	/* if the cmdline is more than one line high, erase top lines */
7960 	need_clear = clear_cmdline;
7961 	if (clear_cmdline && cmdline_row < Rows - 1)
7962 	    msg_clr_cmdline();			/* will reset clear_cmdline */
7963 
7964 	/* Position on the last line in the window, column 0 */
7965 	msg_pos_mode();
7966 	cursor_off();
7967 	attr = hl_attr(HLF_CM);			/* Highlight mode */
7968 	if (do_mode)
7969 	{
7970 	    MSG_PUTS_ATTR("--", attr);
7971 #if defined(FEAT_XIM)
7972 	    if (xic != NULL && im_get_status() && !p_imdisable
7973 					&& curbuf->b_p_iminsert == B_IMODE_IM)
7974 # ifdef HAVE_GTK2 /* most of the time, it's not XIM being used */
7975 		MSG_PUTS_ATTR(" IM", attr);
7976 # else
7977 		MSG_PUTS_ATTR(" XIM", attr);
7978 # endif
7979 #endif
7980 #if defined(FEAT_HANGULIN) && defined(FEAT_GUI)
7981 	    if (gui.in_use)
7982 	    {
7983 		if (hangul_input_state_get())
7984 		    MSG_PUTS_ATTR(" �ѱ�", attr);   /* HANGUL */
7985 	    }
7986 #endif
7987 #ifdef FEAT_INS_EXPAND
7988 	    if (edit_submode != NULL)		/* CTRL-X in Insert mode */
7989 	    {
7990 		/* These messages can get long, avoid a wrap in a narrow
7991 		 * window.  Prefer showing edit_submode_extra. */
7992 		length = (Rows - msg_row) * Columns - 3;
7993 		if (edit_submode_extra != NULL)
7994 		    length -= vim_strsize(edit_submode_extra);
7995 		if (length > 0)
7996 		{
7997 		    if (edit_submode_pre != NULL)
7998 			length -= vim_strsize(edit_submode_pre);
7999 		    if (length - vim_strsize(edit_submode) > 0)
8000 		    {
8001 			if (edit_submode_pre != NULL)
8002 			    msg_puts_attr(edit_submode_pre, attr);
8003 			msg_puts_attr(edit_submode, attr);
8004 		    }
8005 		    if (edit_submode_extra != NULL)
8006 		    {
8007 			MSG_PUTS_ATTR(" ", attr);  /* add a space in between */
8008 			if ((int)edit_submode_highl < (int)HLF_COUNT)
8009 			    sub_attr = hl_attr(edit_submode_highl);
8010 			else
8011 			    sub_attr = attr;
8012 			msg_puts_attr(edit_submode_extra, sub_attr);
8013 		    }
8014 		}
8015 		length = 0;
8016 	    }
8017 	    else
8018 #endif
8019 	    {
8020 #ifdef FEAT_VREPLACE
8021 		if (State & VREPLACE_FLAG)
8022 		    MSG_PUTS_ATTR(_(" VREPLACE"), attr);
8023 		else
8024 #endif
8025 		    if (State & REPLACE_FLAG)
8026 		    MSG_PUTS_ATTR(_(" REPLACE"), attr);
8027 		else if (State & INSERT)
8028 		{
8029 #ifdef FEAT_RIGHTLEFT
8030 		    if (p_ri)
8031 			MSG_PUTS_ATTR(_(" REVERSE"), attr);
8032 #endif
8033 		    MSG_PUTS_ATTR(_(" INSERT"), attr);
8034 		}
8035 		else if (restart_edit == 'I')
8036 		    MSG_PUTS_ATTR(_(" (insert)"), attr);
8037 		else if (restart_edit == 'R')
8038 		    MSG_PUTS_ATTR(_(" (replace)"), attr);
8039 		else if (restart_edit == 'V')
8040 		    MSG_PUTS_ATTR(_(" (vreplace)"), attr);
8041 #ifdef FEAT_RIGHTLEFT
8042 		if (p_hkmap)
8043 		    MSG_PUTS_ATTR(_(" Hebrew"), attr);
8044 # ifdef FEAT_FKMAP
8045 		if (p_fkmap)
8046 		    MSG_PUTS_ATTR(farsi_text_5, attr);
8047 # endif
8048 #endif
8049 #ifdef FEAT_KEYMAP
8050 		if (State & LANGMAP)
8051 		{
8052 # ifdef FEAT_ARABIC
8053 		    if (curwin->w_p_arab)
8054 			MSG_PUTS_ATTR(_(" Arabic"), attr);
8055 		    else
8056 # endif
8057 			MSG_PUTS_ATTR(_(" (lang)"), attr);
8058 		}
8059 #endif
8060 		if ((State & INSERT) && p_paste)
8061 		    MSG_PUTS_ATTR(_(" (paste)"), attr);
8062 
8063 #ifdef FEAT_VISUAL
8064 		if (VIsual_active)
8065 		{
8066 		    char *p;
8067 
8068 		    /* Don't concatenate separate words to avoid translation
8069 		     * problems. */
8070 		    switch ((VIsual_select ? 4 : 0)
8071 			    + (VIsual_mode == Ctrl_V) * 2
8072 			    + (VIsual_mode == 'V'))
8073 		    {
8074 			case 0:	p = N_(" VISUAL"); break;
8075 			case 1: p = N_(" VISUAL LINE"); break;
8076 			case 2: p = N_(" VISUAL BLOCK"); break;
8077 			case 4: p = N_(" SELECT"); break;
8078 			case 5: p = N_(" SELECT LINE"); break;
8079 			default: p = N_(" SELECT BLOCK"); break;
8080 		    }
8081 		    MSG_PUTS_ATTR(_(p), attr);
8082 		}
8083 #endif
8084 		MSG_PUTS_ATTR(" --", attr);
8085 	    }
8086 	    need_clear = TRUE;
8087 	}
8088 	if (Recording
8089 #ifdef FEAT_INS_EXPAND
8090 		&& edit_submode == NULL	    /* otherwise it gets too long */
8091 #endif
8092 		)
8093 	{
8094 	    MSG_PUTS_ATTR(_("recording"), attr);
8095 	    need_clear = TRUE;
8096 	}
8097 	if (need_clear || clear_cmdline)
8098 	    msg_clr_eos();
8099 	msg_didout = FALSE;		/* overwrite this message */
8100 	length = msg_col;
8101 	msg_col = 0;
8102 	need_wait_return = nwr_save;	/* never ask for hit-return for this */
8103     }
8104     else if (clear_cmdline && msg_silent == 0)
8105 	/* Clear the whole command line.  Will reset "clear_cmdline". */
8106 	msg_clr_cmdline();
8107 
8108 #ifdef FEAT_CMDL_INFO
8109 # ifdef FEAT_VISUAL
8110     /* In Visual mode the size of the selected area must be redrawn. */
8111     if (VIsual_active)
8112 	clear_showcmd();
8113 # endif
8114 
8115     /* If the last window has no status line, the ruler is after the mode
8116      * message and must be redrawn */
8117     if (redrawing()
8118 # ifdef FEAT_WINDOWS
8119 	    && lastwin->w_status_height == 0
8120 # endif
8121        )
8122 	win_redr_ruler(lastwin, TRUE);
8123 #endif
8124     redraw_cmdline = FALSE;
8125     clear_cmdline = FALSE;
8126 
8127     return length;
8128 }
8129 
8130 /*
8131  * Position for a mode message.
8132  */
8133     static void
8134 msg_pos_mode()
8135 {
8136     msg_col = 0;
8137     msg_row = Rows - 1;
8138 }
8139 
8140 /*
8141  * Delete mode message.  Used when ESC is typed which is expected to end
8142  * Insert mode (but Insert mode didn't end yet!).
8143  */
8144     void
8145 unshowmode(force)
8146     int	    force;
8147 {
8148     /*
8149      * Don't delete it right now, when not redrawing or insided a mapping.
8150      */
8151     if (!redrawing() || (!force && char_avail() && !KeyTyped))
8152 	redraw_cmdline = TRUE;		/* delete mode later */
8153     else
8154     {
8155 	msg_pos_mode();
8156 	if (Recording)
8157 	    MSG_PUTS_ATTR(_("recording"), hl_attr(HLF_CM));
8158 	msg_clr_eos();
8159     }
8160 }
8161 
8162 #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)
8163 /*
8164  * Get the character to use in a status line.  Get its attributes in "*attr".
8165  */
8166     static int
8167 fillchar_status(attr, is_curwin)
8168     int		*attr;
8169     int		is_curwin;
8170 {
8171     int fill;
8172     if (is_curwin)
8173     {
8174 	*attr = hl_attr(HLF_S);
8175 	fill = fill_stl;
8176     }
8177     else
8178     {
8179 	*attr = hl_attr(HLF_SNC);
8180 	fill = fill_stlnc;
8181     }
8182     /* Use fill when there is highlighting, and highlighting of current
8183      * window differs, or the fillchars differ, or this is not the
8184      * current window */
8185     if (*attr != 0 && ((hl_attr(HLF_S) != hl_attr(HLF_SNC)
8186 			|| !is_curwin || firstwin == lastwin)
8187 		    || (fill_stl != fill_stlnc)))
8188 	return fill;
8189     if (is_curwin)
8190 	return '^';
8191     return '=';
8192 }
8193 #endif
8194 
8195 #ifdef FEAT_VERTSPLIT
8196 /*
8197  * Get the character to use in a separator between vertically split windows.
8198  * Get its attributes in "*attr".
8199  */
8200     static int
8201 fillchar_vsep(attr)
8202     int	    *attr;
8203 {
8204     *attr = hl_attr(HLF_C);
8205     if (*attr == 0 && fill_vert == ' ')
8206 	return '|';
8207     else
8208 	return fill_vert;
8209 }
8210 #endif
8211 
8212 /*
8213  * Return TRUE if redrawing should currently be done.
8214  */
8215     int
8216 redrawing()
8217 {
8218     return (!RedrawingDisabled
8219 		       && !(p_lz && char_avail() && !KeyTyped && !do_redraw));
8220 }
8221 
8222 /*
8223  * Return TRUE if printing messages should currently be done.
8224  */
8225     int
8226 messaging()
8227 {
8228     return (!(p_lz && char_avail() && !KeyTyped));
8229 }
8230 
8231 /*
8232  * Show current status info in ruler and various other places
8233  * If always is FALSE, only show ruler if position has changed.
8234  */
8235     void
8236 showruler(always)
8237     int	    always;
8238 {
8239     if (!always && !redrawing())
8240 	return;
8241 #if defined(FEAT_STL_OPT) && defined(FEAT_WINDOWS)
8242     if (*p_stl && curwin->w_status_height)
8243 	win_redr_custom(curwin, FALSE);
8244     else
8245 #endif
8246 #ifdef FEAT_CMDL_INFO
8247 	win_redr_ruler(curwin, always);
8248 #endif
8249 
8250 #ifdef FEAT_TITLE
8251     if (need_maketitle
8252 # ifdef FEAT_STL_OPT
8253 	    || (p_icon && (stl_syntax & STL_IN_ICON))
8254 	    || (p_title && (stl_syntax & STL_IN_TITLE))
8255 # endif
8256        )
8257 	maketitle();
8258 #endif
8259 }
8260 
8261 #ifdef FEAT_CMDL_INFO
8262     static void
8263 win_redr_ruler(wp, always)
8264     win_T	*wp;
8265     int		always;
8266 {
8267     char_u	buffer[70];
8268     int		row;
8269     int		fillchar;
8270     int		attr;
8271     int		empty_line = FALSE;
8272     colnr_T	virtcol;
8273     int		i;
8274     int		o;
8275 #ifdef FEAT_VERTSPLIT
8276     int		this_ru_col;
8277     int		off = 0;
8278     int		width = Columns;
8279 # define WITH_OFF(x) x
8280 # define WITH_WIDTH(x) x
8281 #else
8282 # define WITH_OFF(x) 0
8283 # define WITH_WIDTH(x) Columns
8284 # define this_ru_col ru_col
8285 #endif
8286 
8287     /* If 'ruler' off or redrawing disabled, don't do anything */
8288     if (!p_ru)
8289 	return;
8290 
8291     /*
8292      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
8293      * after deleting lines, before cursor.lnum is corrected.
8294      */
8295     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
8296 	return;
8297 
8298 #ifdef FEAT_INS_EXPAND
8299     /* Don't draw the ruler while doing insert-completion, it might overwrite
8300      * the (long) mode message. */
8301 # ifdef FEAT_WINDOWS
8302     if (wp == lastwin && lastwin->w_status_height == 0)
8303 # endif
8304 	if (edit_submode != NULL)
8305 	    return;
8306 #endif
8307 
8308 #ifdef FEAT_STL_OPT
8309     if (*p_ruf)
8310     {
8311 	win_redr_custom(wp, TRUE);
8312 	return;
8313     }
8314 #endif
8315 
8316     /*
8317      * Check if not in Insert mode and the line is empty (will show "0-1").
8318      */
8319     if (!(State & INSERT)
8320 		&& *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
8321 	empty_line = TRUE;
8322 
8323     /*
8324      * Only draw the ruler when something changed.
8325      */
8326     validate_virtcol_win(wp);
8327     if (       redraw_cmdline
8328 	    || always
8329 	    || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
8330 	    || wp->w_cursor.col != wp->w_ru_cursor.col
8331 	    || wp->w_virtcol != wp->w_ru_virtcol
8332 #ifdef FEAT_VIRTUALEDIT
8333 	    || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
8334 #endif
8335 	    || wp->w_topline != wp->w_ru_topline
8336 	    || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
8337 #ifdef FEAT_DIFF
8338 	    || wp->w_topfill != wp->w_ru_topfill
8339 #endif
8340 	    || empty_line != wp->w_ru_empty)
8341     {
8342 	cursor_off();
8343 #ifdef FEAT_WINDOWS
8344 	if (wp->w_status_height)
8345 	{
8346 	    row = W_WINROW(wp) + wp->w_height;
8347 	    fillchar = fillchar_status(&attr, wp == curwin);
8348 # ifdef FEAT_VERTSPLIT
8349 	    off = W_WINCOL(wp);
8350 	    width = W_WIDTH(wp);
8351 # endif
8352 	}
8353 	else
8354 #endif
8355 	{
8356 	    row = Rows - 1;
8357 	    fillchar = ' ';
8358 	    attr = 0;
8359 #ifdef FEAT_VERTSPLIT
8360 	    width = Columns;
8361 	    off = 0;
8362 #endif
8363 	}
8364 
8365 	/* In list mode virtcol needs to be recomputed */
8366 	virtcol = wp->w_virtcol;
8367 	if (wp->w_p_list && lcs_tab1 == NUL)
8368 	{
8369 	    wp->w_p_list = FALSE;
8370 	    getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
8371 	    wp->w_p_list = TRUE;
8372 	}
8373 
8374 	/*
8375 	 * Some sprintfs return the length, some return a pointer.
8376 	 * To avoid portability problems we use strlen() here.
8377 	 */
8378 	sprintf((char *)buffer, "%ld,",
8379 		(wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
8380 		    ? 0L
8381 		    : (long)(wp->w_cursor.lnum));
8382 	col_print(buffer + STRLEN(buffer),
8383 			empty_line ? 0 : (int)wp->w_cursor.col + 1,
8384 			(int)virtcol + 1);
8385 
8386 	/*
8387 	 * Add a "50%" if there is room for it.
8388 	 * On the last line, don't print in the last column (scrolls the
8389 	 * screen up on some terminals).
8390 	 */
8391 	i = (int)STRLEN(buffer);
8392 	get_rel_pos(wp, buffer + i + 1);
8393 	o = i + vim_strsize(buffer + i + 1);
8394 #ifdef FEAT_WINDOWS
8395 	if (wp->w_status_height == 0)	/* can't use last char of screen */
8396 #endif
8397 	    ++o;
8398 #ifdef FEAT_VERTSPLIT
8399 	this_ru_col = ru_col - (Columns - width);
8400 	if (this_ru_col < 0)
8401 	    this_ru_col = 0;
8402 #endif
8403 	/* Never use more than half the window/screen width, leave the other
8404 	 * half for the filename. */
8405 	if (this_ru_col < (WITH_WIDTH(width) + 1) / 2)
8406 	    this_ru_col = (WITH_WIDTH(width) + 1) / 2;
8407 	if (this_ru_col + o < WITH_WIDTH(width))
8408 	{
8409 	    while (this_ru_col + o < WITH_WIDTH(width))
8410 	    {
8411 #ifdef FEAT_MBYTE
8412 		if (has_mbyte)
8413 		    i += (*mb_char2bytes)(fillchar, buffer + i);
8414 		else
8415 #endif
8416 		    buffer[i++] = fillchar;
8417 		++o;
8418 	    }
8419 	    get_rel_pos(wp, buffer + i);
8420 	}
8421 	/* Truncate at window boundary. */
8422 #ifdef FEAT_MBYTE
8423 	if (has_mbyte)
8424 	{
8425 	    o = 0;
8426 	    for (i = 0; buffer[i] != NUL; i += (*mb_ptr2len_check)(buffer + i))
8427 	    {
8428 		o += (*mb_ptr2cells)(buffer + i);
8429 		if (this_ru_col + o > WITH_WIDTH(width))
8430 		{
8431 		    buffer[i] = NUL;
8432 		    break;
8433 		}
8434 	    }
8435 	}
8436 	else
8437 #endif
8438 	if (this_ru_col + (int)STRLEN(buffer) > WITH_WIDTH(width))
8439 	    buffer[WITH_WIDTH(width) - this_ru_col] = NUL;
8440 
8441 	screen_puts(buffer, row, this_ru_col + WITH_OFF(off), attr);
8442 	i = redraw_cmdline;
8443 	screen_fill(row, row + 1,
8444 		this_ru_col + WITH_OFF(off) + (int)STRLEN(buffer),
8445 		(int)(WITH_OFF(off) + WITH_WIDTH(width)),
8446 		fillchar, fillchar, attr);
8447 	/* don't redraw the cmdline because of showing the ruler */
8448 	redraw_cmdline = i;
8449 	wp->w_ru_cursor = wp->w_cursor;
8450 	wp->w_ru_virtcol = wp->w_virtcol;
8451 	wp->w_ru_empty = empty_line;
8452 	wp->w_ru_topline = wp->w_topline;
8453 	wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
8454 #ifdef FEAT_DIFF
8455 	wp->w_ru_topfill = wp->w_topfill;
8456 #endif
8457     }
8458 }
8459 #endif
8460