home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-29  |  200.9 KB  |  8,318 lines

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