screen.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:133k
源码类别:

编辑器/阅读器

开发平台:

DOS

  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.  */
  8. /*
  9.  * screen.c: code for displaying on the screen
  10.  */
  11. #include "vim.h"
  12. /*
  13.  * The attributes that are actually active for writing to the screen.
  14.  */
  15. static int screen_attr = 0;
  16. /*
  17.  * Positioning the cursor is reduced by remembering the last position.
  18.  * Mostly used by windgoto() and screen_char().
  19.  */
  20. static int screen_cur_row, screen_cur_col; /* last known cursor position */
  21. #ifdef EXTRA_SEARCH
  22. /*
  23.  * When highlighting matches for the last use search pattern:
  24.  * - search_hl_prog points to the regexp program for it
  25.  * - search_hl_attr contains the attributes to be used
  26.  * - search_hl_ic is the value for "reg_ic" for this search
  27.  */
  28. vim_regexp *search_hl_prog = NULL;
  29. int search_hl_attr;
  30. int search_hl_ic;
  31. #endif
  32. /*
  33.  * Flags for w_valid.
  34.  * These are suppose to be used only in screen.c.  From other files, use the
  35.  * functions that set or reset them.
  36.  *
  37.  * VALID_BOTLINE    VALID_BOTLINE_AP
  38.  *     on on w_botline valid
  39.  *     off on w_botline approximated
  40.  *     off off w_botline not valid
  41.  *     on off not possible
  42.  */
  43. #define VALID_WROW 0x01 /* w_wrow (window row) is valid */
  44. #define VALID_WCOL 0x02 /* w_wcol (window col) is valid */
  45. #define VALID_VIRTCOL 0x04 /* w_virtcol (file col) is valid */
  46. #define VALID_CHEIGHT 0x08 /* w_cline_height is valid */
  47. #define VALID_CROW 0x10 /* w_cline_row is valid */
  48. #define VALID_BOTLINE 0x20 /* w_botine and w_empty_rows are valid */
  49. #define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */
  50. /*
  51.  * Buffer for one screen line.
  52.  */
  53. static char_u *current_LinePointer;
  54. static void win_update __ARGS((WIN *wp));
  55. static int win_line __ARGS((WIN *, linenr_t, int, int));
  56. #ifdef RIGHTLEFT
  57. static void screen_line __ARGS((int row, int endcol, int clear_rest, int rlflag));
  58. #define SCREEN_LINE(r, e, c, rl)    screen_line((r), (e), (c), (rl))
  59. #else
  60. static void screen_line __ARGS((int row, int endcol, int clear_rest));
  61. #define SCREEN_LINE(r, e, c, rl)    screen_line((r), (e), (c))
  62. #endif
  63. #ifdef EXTRA_SEARCH
  64. static void start_search_hl __ARGS((void));
  65. static void end_search_hl __ARGS((void));
  66. #endif
  67. static void screen_start_highlight __ARGS((int attr));
  68. static void comp_botline __ARGS((void));
  69. static void screen_char __ARGS((char_u *, int, int));
  70. static void screenclear2 __ARGS((void));
  71. static void lineclear __ARGS((char_u *p));
  72. static void check_cursor_moved __ARGS((WIN *wp));
  73. static void curs_rows __ARGS((int do_botline));
  74. static void validate_virtcol_win __ARGS((WIN *wp));
  75. static int screen_ins_lines __ARGS((int, int, int, int));
  76. static int highlight_status __ARGS((int *attr, int is_curwin));
  77. static void win_redr_ruler __ARGS((WIN *wp, int always));
  78. static void intro_message __ARGS((void));
  79. /*
  80.  * update_screenline() - like update_screen() but only for cursor line
  81.  *
  82.  * Must only be called when something in the cursor line has changed (e.g.
  83.  * character inserted or deleted).
  84.  *
  85.  * Check if the size of the cursor line has changed since the last screen
  86.  * update.  If it did change, lines below the cursor will move up or down and
  87.  * we need to call the routine update_screen() to examine the entire screen.
  88.  */
  89.     void
  90. update_screenline()
  91. {
  92.     int row;
  93.     int old_cline_height;
  94.     if (!screen_valid(TRUE))
  95. return;
  96.     if (must_redraw) /* must redraw whole screen */
  97.     {
  98. update_screen(must_redraw);
  99. return;
  100.     }
  101.     if (!redrawing())
  102.     {
  103. redraw_later(NOT_VALID); /* remember to update later */
  104. return;
  105.     }
  106.     /*
  107.      * If the screen has scrolled, or some lines after the cursor line have
  108.      * been invalidated, call update_screen().
  109.      */
  110.     if (curwin->w_lsize_valid <= curwin->w_cursor.lnum - curwin->w_topline ||
  111. curwin->w_lsize_lnum[0] != curwin->w_topline)
  112.     {
  113. update_screen(VALID_TO_CURSCHAR);
  114. return;
  115.     }
  116.     /*
  117.      * Get the current height of the cursor line, as it is on the screen.
  118.      * w_lsize[] must be used here, since w_cline_height might already have
  119.      * been updated to the new height of the line in the buffer.
  120.      */
  121.     old_cline_height = curwin->w_lsize[curwin->w_cursor.lnum
  122.   - curwin->w_topline];
  123.     /*
  124.      * Check if the cursor line is still at the same position. Be aware of
  125.      * the cursor having moved around, w_cline_row may be invalid, use the
  126.      * values from w_lsize[] by calling curs_rows().
  127.      */
  128.     check_cursor_moved(curwin);
  129.     if (!(curwin->w_valid & VALID_CROW))
  130. curs_rows(FALSE);
  131. #ifdef EXTRA_SEARCH
  132.     start_search_hl();
  133. #endif
  134.     /*
  135.      * w_virtcol needs to be valid.
  136.      */
  137.     validate_virtcol();
  138.     cursor_off();
  139.     row = win_line(curwin, curwin->w_cursor.lnum,
  140. curwin->w_cline_row, curwin->w_height);
  141.     display_hint = HINT_NONE;
  142. #ifdef EXTRA_SEARCH
  143.     end_search_hl();
  144. #endif
  145.     if (row == curwin->w_height + 1) /* line too long for window */
  146.     {
  147. if (curwin->w_topline < curwin->w_cursor.lnum)
  148. {
  149.     /*
  150.      * Window needs to be scrolled up to show the cursor line.
  151.      * We know w_botline was valid before the change, so it should now
  152.      * be one less.  This removes the need to recompute w_botline in
  153.      * update_topline().
  154.      */
  155.     --curwin->w_botline;
  156.     curwin->w_valid |= VALID_BOTLINE_AP;
  157. }
  158. update_topline();
  159. update_screen(VALID_TO_CURSCHAR);
  160.     }
  161.     else if (!dollar_vcol)
  162.     {
  163. /*
  164.  * If the cursor line changed size, delete or insert screen lines and
  165.  * redraw the rest of the window.
  166.  */
  167. if (old_cline_height != curwin->w_cline_height)
  168. {
  169.     if (curwin->w_cline_height < old_cline_height)
  170. win_del_lines(curwin, row,
  171.       old_cline_height - curwin->w_cline_height, FALSE, TRUE);
  172.     else
  173. win_ins_lines(curwin,
  174.  curwin->w_cline_row + curwin->w_cline_height,
  175.       curwin->w_cline_height - old_cline_height, FALSE, TRUE);
  176.     update_screen(VALID_TO_CURSCHAR);
  177. }
  178. #ifdef SYNTAX_HL
  179. /*
  180.  * If syntax lost its sync, have to redraw the following lines.
  181.  */
  182. else if (syntax_present(curbuf) && row < cmdline_row
  183.    && syntax_check_changed(curwin->w_cursor.lnum + 1))
  184.     update_screen(VALID_TO_CURSCHAR);
  185. #endif
  186. else if (clear_cmdline || redraw_cmdline)
  187.     showmode();     /* clear cmdline, show mode and ruler */
  188.     }
  189. }
  190. /*
  191.  * Redraw the current window later, with UpdateScreen(type).
  192.  * Set must_redraw only of not already set to a higher value.
  193.  * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
  194.  */
  195.     void
  196. redraw_later(type)
  197.     int     type;
  198. {
  199.     if (curwin->w_redr_type < type)
  200. curwin->w_redr_type = type;
  201.     if (must_redraw < type) /* must_redraw is the maximum of all windows */
  202. must_redraw = type;
  203. }
  204. /*
  205.  * Mark all windows to be redrawn later.
  206.  */
  207.     void
  208. redraw_all_later(type)
  209.     int type;
  210. {
  211.     WIN     *wp;
  212.     for (wp = firstwin; wp; wp = wp->w_next)
  213. if (wp->w_redr_type < type)
  214.     wp->w_redr_type = type;
  215.     redraw_later(type);
  216. }
  217. /*
  218.  * Mark all windows that are editing the current buffer to be udpated later.
  219.  */
  220.     void
  221. redraw_curbuf_later(type)
  222.     int type;
  223. {
  224.     WIN     *wp;
  225.     for (wp = firstwin; wp; wp = wp->w_next)
  226. if (wp->w_redr_type < type && wp->w_buffer == curbuf)
  227.     wp->w_redr_type = type;
  228.     redraw_later(type);
  229. }
  230. /*
  231.  * update all windows that are editing the current buffer
  232.  */
  233.     void
  234. update_curbuf(type)
  235.     int type;
  236. {
  237.     redraw_curbuf_later(type);
  238.     update_screen(type);
  239. }
  240. /*
  241.  * update_screen()
  242.  *
  243.  * Based on the current value of curwin->w_topline, transfer a screenfull
  244.  * of stuff from Filemem to NextScreen, and update curwin->w_botline.
  245.  */
  246.     void
  247. update_screen(type)
  248.     int     type;
  249. {
  250.     WIN     *wp;
  251.     static int     did_intro = FALSE;
  252.     if (!screen_valid(TRUE))
  253. return;
  254.     dollar_vcol = 0;
  255.     if (must_redraw)
  256.     {
  257. if (type < must_redraw)     /* use maximal type */
  258.     type = must_redraw;
  259. must_redraw = 0;
  260.     }
  261.     if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
  262. type = NOT_VALID;
  263.     if (!redrawing())
  264.     {
  265. redraw_later(type); /* remember type for next time */
  266. curwin->w_redr_type = type;
  267. curwin->w_lsize_valid = 0; /* don't use w_lsize[] now */
  268. return;
  269.     }
  270.     /*
  271.      * if the screen was scrolled up when displaying a message, scroll it down
  272.      */
  273.     if (msg_scrolled)
  274.     {
  275. clear_cmdline = TRUE;
  276. if (msg_scrolled > Rows - 5)     /* clearing is faster */
  277.     type = CLEAR;
  278. else if (type != CLEAR)
  279. {
  280.     check_for_delay(FALSE);
  281.     if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
  282. type = CLEAR;
  283.     win_rest_invalid(firstwin);     /* should do only first/last few */
  284. }
  285. msg_scrolled = 0;
  286. need_wait_return = FALSE;
  287.     }
  288.     /* reset cmdline_row now (may have been changed temporarily) */
  289.     compute_cmdrow();
  290.     /* Check for changed highlighting */
  291.     if (need_highlight_changed)
  292. highlight_changed();
  293.     if (type == CLEAR) /* first clear screen */
  294.     {
  295. screenclear(); /* will reset clear_cmdline */
  296. type = NOT_VALID;
  297.     }
  298.     if (clear_cmdline) /* first clear cmdline */
  299.     {
  300. check_for_delay(FALSE);
  301. msg_clr_cmdline(); /* will reset clear_cmdline */
  302.     }
  303.     /*
  304.      * Only start redrawing if there is really something to do.
  305.      */
  306.     if (type == INVERTED)
  307. update_curswant();
  308.     if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0])
  309.     || (type == INVERTED
  310. && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
  311. && (curwin->w_valid & VALID_VIRTCOL)
  312. && curwin->w_old_curswant == curwin->w_curswant)))
  313.     {
  314. /*
  315.  * go from top to bottom through the windows, redrawing the ones that
  316.  * need it
  317.  */
  318. curwin->w_redr_type = type;
  319. cursor_off();
  320. #ifdef EXTRA_SEARCH
  321. start_search_hl();
  322. #endif
  323. for (wp = firstwin; wp; wp = wp->w_next)
  324. {
  325.     if (wp->w_redr_type)
  326. win_update(wp);
  327.     if (wp->w_redr_status)
  328. win_redr_status(wp);
  329. }
  330. #ifdef EXTRA_SEARCH
  331. end_search_hl();
  332. #endif
  333.     }
  334.     if (redraw_cmdline)
  335. showmode();
  336.     display_hint = HINT_NONE;
  337.     /* May put up an introductory message when not editing a file */
  338.     if (!did_intro && bufempty()
  339.     && curbuf->b_fname == NULL
  340.     && firstwin->w_next == NULL
  341.     && vim_strchr(p_shm, SHM_INTRO) == NULL)
  342. intro_message();
  343.     did_intro = TRUE;
  344. }
  345. #ifdef USE_GUI
  346. /*
  347.  * Update a single window, its status line and maybe the command line msg.
  348.  * Used for the GUI scrollbar.
  349.  */
  350.     void
  351. updateWindow(wp)
  352.     WIN     *wp;
  353. {
  354.     cursor_off();
  355. #ifdef EXTRA_SEARCH
  356.     start_search_hl();
  357. #endif
  358.     win_update(wp);
  359.     if (wp->w_redr_status || p_ru)
  360. win_redr_status(wp);
  361.     if (redraw_cmdline)
  362. showmode();
  363. #ifdef EXTRA_SEARCH
  364.     end_search_hl();
  365. #endif
  366. }
  367. #endif
  368. /*
  369.  * Update all windows for the current buffer, except curwin.
  370.  * Used after modifying text, to update the other windows on the same buffer.
  371.  */
  372.     void
  373. update_other_win()
  374. {
  375.     WIN     *wp;
  376.     int     first = TRUE;
  377.     for (wp = firstwin; wp; wp = wp->w_next)
  378. if (wp != curwin && wp->w_buffer == curbuf)
  379. {
  380.     if (first)
  381.     {
  382. cursor_off();
  383. #ifdef EXTRA_SEARCH
  384. start_search_hl();
  385. #endif
  386. first = FALSE;
  387.     }
  388.     wp->w_redr_type = NOT_VALID;
  389.     /*
  390.      * don't do the actual redraw if wait_return() has just been
  391.      * called and the user typed a ":"
  392.      */
  393.     if (!skip_redraw)
  394. win_update(wp);
  395. }
  396. #ifdef EXTRA_SEARCH
  397.     end_search_hl();
  398. #endif
  399. }
  400. /*
  401.  * Update a single window.
  402.  *
  403.  * This may cause the windows below it also to be redrawn.
  404.  */
  405.     static void
  406. win_update(wp)
  407.     WIN     *wp;
  408. {
  409.     int     type;
  410.     int     row;
  411.     int     endrow;
  412.     linenr_t     lnum;
  413.     linenr_t     lastline;     /* only valid if endrow != Rows -1 */
  414.     int     done;     /* if TRUE, we hit the end of the file */
  415.     int     didline;     /* if TRUE, we finished the last line */
  416.     int     srow = 0;     /* starting row of the current line */
  417.     int     idx;
  418.     int     i;
  419.     long     j;
  420.     static int     recursive = FALSE; /* being called recursively */
  421.     int     old_botline = wp->w_botline;
  422.     int     must_start_top = FALSE; /* update must start at top row */
  423.     int     must_end_bot = FALSE;   /* update must end at bottom row */
  424.     type = wp->w_redr_type;
  425.     if (type == NOT_VALID)
  426.     {
  427. wp->w_redr_status = TRUE;
  428. wp->w_lsize_valid = 0;
  429.     }
  430.     wp->w_redr_type = 0; /* reset it now, may be set again later */
  431.     idx = 0;
  432.     row = 0;
  433.     lnum = wp->w_topline;
  434.     validate_virtcol_win(wp);
  435.     /* The number of rows shown is w_height. */
  436.     /* The default last row is the status/command line. */
  437.     endrow = wp->w_height;
  438.     /*
  439.      * If there are no changes on the screen, handle two special cases:
  440.      * 1: we are off the top of the screen by a few lines: scroll down
  441.      * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
  442.      */
  443.     if (type == VALID || type == VALID_TO_CURSCHAR ||
  444.     type == VALID_BEF_CURSCHAR || type == INVERTED)
  445.     {
  446. if (wp->w_topline < wp->w_lsize_lnum[0])    /* may scroll down */
  447. {
  448.     j = wp->w_lsize_lnum[0] - wp->w_topline;
  449.     if (j < wp->w_height - 2     /* not too far off */
  450.     && (type != VALID_TO_CURSCHAR
  451.        || wp->w_lsize_lnum[0] < curwin->w_cursor.lnum)
  452.     && (type != VALID_BEF_CURSCHAR
  453.   || wp->w_lsize_lnum[0] < curwin->w_cursor.lnum - 1))
  454.     {
  455. lastline = wp->w_lsize_lnum[0] - 1;
  456. i = plines_m_win(wp, wp->w_topline, lastline);
  457. if (i < wp->w_height - 2) /* less than a screen off */
  458. {
  459.     /*
  460.      * Try to insert the correct number of lines.
  461.      * If not the last window, delete the lines at the bottom.
  462.      * win_ins_lines may fail.
  463.      */
  464.     if (i > 0)
  465. check_for_delay(FALSE);
  466.     if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK
  467.  && wp->w_lsize_valid)
  468.     {
  469. must_start_top = TRUE;
  470. endrow = i;
  471. /* If there are changes, must redraw the rest too */
  472. if (type == VALID_TO_CURSCHAR
  473. || type == VALID_BEF_CURSCHAR)
  474.     wp->w_redr_type = type;
  475. if ((wp->w_lsize_valid += j) > wp->w_height)
  476.     wp->w_lsize_valid = wp->w_height;
  477. for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
  478. {
  479.     wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
  480.     wp->w_lsize[idx] = wp->w_lsize[idx - j];
  481. }
  482. idx = 0;
  483.     }
  484. }
  485. else if (lastwin == firstwin)
  486. {
  487.     screenclear();  /* far off: clearing the screen is faster */
  488.     must_start_top = TRUE;
  489.     must_end_bot = TRUE;
  490. }
  491.     }
  492.     else if (lastwin == firstwin)
  493.     {
  494. screenclear();     /* far off: clearing the screen is faster */
  495. must_start_top = TRUE;
  496. must_end_bot = TRUE;
  497.     }
  498. }
  499. else /* may scroll up */
  500. {
  501.     j = -1;
  502. /* try to find wp->w_topline in wp->w_lsize_lnum[] */
  503.     for (i = 0; i < wp->w_lsize_valid; i++)
  504.     {
  505. if (wp->w_lsize_lnum[i] == wp->w_topline)
  506. {
  507.     j = i;
  508.     break;
  509. }
  510. row += wp->w_lsize[i];
  511.     }
  512.     if (j == -1)    /* wp->w_topline is not in wp->w_lsize_lnum */
  513.     {
  514. row = 0;    /* start at the first row */
  515. if (lastwin == firstwin)
  516. {
  517.     screenclear();  /* far off: clearing the screen is faster */
  518.     must_start_top = TRUE;
  519.     must_end_bot = TRUE;
  520. }
  521.     }
  522.     else
  523.     {
  524. /*
  525.  * Try to delete the correct number of lines.
  526.  * wp->w_topline is at wp->w_lsize_lnum[i].
  527.  */
  528. if (row)
  529. {
  530.     check_for_delay(FALSE);
  531.     if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
  532. must_end_bot = TRUE;
  533. }
  534. if ((row == 0 || must_end_bot) && wp->w_lsize_valid)
  535. {
  536.     /*
  537.      * Skip the lines (below the deleted lines) that are still
  538.      * valid and don't need redrawing. Copy their info
  539.      * upwards, to compensate for the deleted lines.  Leave
  540.      * row and lnum on the first line that needs redrawing.
  541.      */
  542.     srow = row;
  543.     row = 0;
  544.     for (;;)
  545.     {
  546. if ((type == VALID_TO_CURSCHAR &&
  547.  lnum == wp->w_cursor.lnum) ||
  548. (type == VALID_BEF_CURSCHAR &&
  549.        lnum == wp->w_cursor.lnum - 1))
  550. {
  551.     wp->w_lsize_valid = idx;
  552.     break;
  553. }
  554. wp->w_lsize[idx] = wp->w_lsize[j];
  555. wp->w_lsize_lnum[idx] = lnum;
  556. if (row + srow + (int)wp->w_lsize[j] > wp->w_height)
  557. {
  558.     wp->w_lsize_valid = idx + 1;
  559.     break;
  560. }
  561. ++lnum;
  562. row += wp->w_lsize[idx++];
  563. if ((int)++j >= wp->w_lsize_valid)
  564. {
  565.     wp->w_lsize_valid = idx;
  566.     break;
  567. }
  568.     }
  569. }
  570. else
  571.     row = 0;     /* update all lines */
  572.     }
  573. }
  574. if (endrow == wp->w_height && idx == 0)     /* no scrolling */
  575.     wp->w_lsize_valid = 0;
  576.     }
  577.     done = didline = FALSE;
  578.     if (VIsual_active)     /* check if we are updating the inverted part */
  579.     {
  580. linenr_t    from, to;
  581. /*
  582.  * Find the line numbers that need to be updated: The lines between
  583.  * the old cursor position and the current cursor position.  Also
  584.  * check if the Visual position changed.
  585.  */
  586. if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
  587. {
  588.     from = curwin->w_cursor.lnum;
  589.     to = wp->w_old_cursor_lnum;
  590. }
  591. else
  592. {
  593.     from = wp->w_old_cursor_lnum;
  594.     to = curwin->w_cursor.lnum;
  595. }
  596. if (VIsual.lnum != wp->w_old_visual_lnum)
  597. {
  598.     if (wp->w_old_visual_lnum < from)
  599. from = wp->w_old_visual_lnum;
  600.     if (wp->w_old_visual_lnum > to)
  601. to = wp->w_old_visual_lnum;
  602.     if (VIsual.lnum < from)
  603. from = VIsual.lnum;
  604.     if (VIsual.lnum > to)
  605. to = VIsual.lnum;
  606. }
  607. /*
  608.  * If in block mode and changed column or curwin->w_curswant: update
  609.  * all lines.
  610.  * First compute the actual start and end column.
  611.  */
  612. if (VIsual_mode == Ctrl('V'))
  613. {
  614.     colnr_t from1, from2, to1, to2;
  615.     if (lt(VIsual, curwin->w_cursor))
  616.     {
  617. getvcol(wp, &VIsual, &from1, NULL, &to1);
  618. getvcol(wp, &curwin->w_cursor, &from2, NULL, &to2);
  619.     }
  620.     else
  621.     {
  622. getvcol(wp, &curwin->w_cursor, &from1, NULL, &to1);
  623. getvcol(wp, &VIsual, &from2, NULL, &to2);
  624.     }
  625.     if (from2 < from1)
  626. from1 = from2;
  627.     if (to2 > to1)
  628.     {
  629. if (*p_sel == 'e' && from2 - 1 >= to1)
  630.     to1 = from2 - 1;
  631. else
  632.     to1 = to2;
  633.     }
  634.     ++to1;
  635.     if (curwin->w_curswant == MAXCOL)
  636. to1 = MAXCOL;
  637.     if (from1 != wp->w_old_cursor_fcol || to1 != wp->w_old_cursor_lcol)
  638.     {
  639. if (from > VIsual.lnum)
  640.     from = VIsual.lnum;
  641. if (to < VIsual.lnum)
  642.     to = VIsual.lnum;
  643.     }
  644.     wp->w_old_cursor_fcol = from1;
  645.     wp->w_old_cursor_lcol = to1;
  646. }
  647. /*
  648.  * There is no need to update lines above the top of the window.
  649.  * If "must_start_top" is set, always start at w_topline.
  650.  */
  651. if (from < wp->w_topline || must_start_top)
  652.     from = wp->w_topline;
  653. /*
  654.  * If we know the value of w_botline, use it to restrict the update to
  655.  * the lines that are visible in the window.
  656.  */
  657. if (wp->w_valid & VALID_BOTLINE)
  658. {
  659.     if (from >= wp->w_botline)
  660. from = wp->w_botline - 1;
  661.     if (to >= wp->w_botline)
  662. to = wp->w_botline - 1;
  663. }
  664. /*
  665.  * Find the minimal part to be updated.
  666.  *
  667.  * If "lnum" is past "from" already, start at w_topline (can
  668.  * happen when scrolling).
  669.  */
  670. if (lnum > from)
  671. {
  672.     lnum = wp->w_topline;
  673.     idx = 0;
  674.     row = 0;
  675. }
  676. while (lnum < from && idx < wp->w_lsize_valid)     /* find start */
  677. {
  678.     row += wp->w_lsize[idx++];
  679.     ++lnum;
  680. }
  681. if (!must_end_bot && !must_start_top)
  682. {
  683.     srow = row;
  684.     for (j = idx; j < wp->w_lsize_valid; ++j)     /* find end */
  685.     {
  686. if (wp->w_lsize_lnum[j] == to + 1)
  687. {
  688.     endrow = srow;
  689.     break;
  690. }
  691. srow += wp->w_lsize[j];
  692.     }
  693. }
  694. else
  695. {
  696.     /* Redraw until the end, otherwise we could miss something when
  697.      * doing CTRL-U. */
  698.     endrow = wp->w_height;
  699. }
  700. wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
  701. wp->w_old_visual_lnum = VIsual.lnum;
  702. wp->w_old_curswant = curwin->w_curswant;
  703.     }
  704.     else
  705.     {
  706. wp->w_old_cursor_lnum = 0;
  707. wp->w_old_visual_lnum = 0;
  708.     }
  709.     /*
  710.      * Update the screen rows from "row" to "endrow".
  711.      * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
  712.      */
  713.     for (;;)
  714.     {
  715. if (row == endrow)
  716. {
  717.     didline = TRUE;
  718.     break;
  719. }
  720. if (lnum > wp->w_buffer->b_ml.ml_line_count)
  721. {
  722.     done = TRUE; /* hit the end of the file */
  723.     break;
  724. }
  725. srow = row;
  726. row = win_line(wp, lnum, srow, endrow);
  727. if (row > endrow) /* past end of screen */
  728. {
  729.     /* we may need the size of that too long line later on */
  730.     wp->w_lsize[idx] = plines_win(wp, lnum);
  731.     wp->w_lsize_lnum[idx++] = lnum;
  732.     break;
  733. }
  734. wp->w_lsize[idx] = row - srow;
  735. wp->w_lsize_lnum[idx++] = lnum;
  736. if (++lnum > wp->w_buffer->b_ml.ml_line_count)
  737. {
  738.     done = TRUE;
  739.     break;
  740. }
  741.     }
  742.     if (idx > wp->w_lsize_valid)
  743. wp->w_lsize_valid = idx;
  744.     /* Do we have to do off the top of the screen processing ? */
  745.     if (endrow != wp->w_height)
  746.     {
  747. row = 0;
  748. for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
  749.     row += wp->w_lsize[idx];
  750. if (row < wp->w_height)
  751. {
  752.     done = TRUE;
  753. }
  754. else if (row > wp->w_height) /* Need to blank out the last line */
  755. {
  756.     lnum = wp->w_lsize_lnum[idx - 1];
  757.     srow = row - wp->w_lsize[idx - 1];
  758.     didline = FALSE;
  759. }
  760. else
  761. {
  762.     lnum = wp->w_lsize_lnum[idx - 1] + 1;
  763.     didline = TRUE;
  764. }
  765.     }
  766.     wp->w_empty_rows = 0;
  767.     /*
  768.      * If we didn't hit the end of the file, and we didn't finish the last
  769.      * line we were working on, then the line didn't fit.
  770.      */
  771.     if (!done && !didline)
  772.     {
  773. if (lnum == wp->w_topline)
  774. {
  775. #if 0
  776.     /*
  777.      * Single line that does not fit!
  778.      * Fill last line with '@' characters.
  779.      */
  780.     screen_fill(wp->w_winpos + wp->w_height - 1,
  781.     wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@',
  782.     hl_attr(HLF_AT));
  783. #endif
  784.     wp->w_botline = lnum + 1;
  785. }
  786. else
  787. {
  788.     /*
  789.      * Clear the rest of the screen and mark the unused lines.
  790.      */
  791. #ifdef RIGHTLEFT
  792.     if (wp->w_p_rl)
  793.     {
  794. screen_fill(wp->w_winpos + srow,
  795. wp->w_winpos + wp->w_height, 0, (int)Columns - 1,
  796. ' ', ' ', hl_attr(HLF_AT));
  797. screen_fill(wp->w_winpos + srow,
  798. wp->w_winpos + wp->w_height, (int)Columns - 1,
  799. (int)Columns, '@', ' ', hl_attr(HLF_AT));
  800.     }
  801.     else
  802. #endif
  803. screen_fill(wp->w_winpos + srow,
  804. wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ',
  805. hl_attr(HLF_AT));
  806.     wp->w_botline = lnum;
  807.     wp->w_empty_rows = wp->w_height - srow;
  808. }
  809.     }
  810.     else
  811.     {
  812. /* make sure the rest of the screen is blank */
  813. /* put '~'s on rows that aren't part of the file. */
  814. #ifdef RIGHTLEFT
  815. if (wp->w_p_rl)
  816. {
  817.     screen_fill(wp->w_winpos + row,
  818.     wp->w_winpos + wp->w_height, 0, (int)Columns - 1,
  819.     ' ', ' ', hl_attr(HLF_AT));
  820.     screen_fill(wp->w_winpos + row,
  821.     wp->w_winpos + wp->w_height, (int)Columns - 1,
  822.     (int)Columns, '~', ' ', hl_attr(HLF_AT));
  823. }
  824. else
  825. #endif
  826.     screen_fill(wp->w_winpos + row,
  827. wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ',
  828. hl_attr(HLF_AT));
  829. wp->w_empty_rows = wp->w_height - row;
  830. if (done) /* we hit the end of the file */
  831.     wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
  832. else
  833.     wp->w_botline = lnum;
  834.     }
  835.     /*
  836.      * There is a trick with w_botline.  If we invalidate it on each change
  837.      * that might modify it, this will cause a lot of expensive calls to
  838.      * plines() in update_topline() each time. Therefore the value of
  839.      * w_botline is often approximated, and this value is used to compute the
  840.      * value of w_topline.  If the value of w_botline was wrong, check that
  841.      * the value of w_topline is correct (cursor is on the visible part of the
  842.      * text).  If it's not, we need to redraw again.  Mostly this just means
  843.      * scrolling up a few lines, so it doesn't look too bad.  Only do this for
  844.      * the current window (where changes are relevant).
  845.      */
  846.     wp->w_valid |= VALID_BOTLINE;
  847.     if (wp == curwin && wp->w_botline != old_botline && !recursive)
  848.     {
  849. recursive = TRUE;
  850. update_topline(); /* may invalidate w_botline again */
  851. if (must_redraw)
  852. {
  853.     win_update(wp);
  854.     must_redraw = 0;
  855. }
  856. recursive = FALSE;
  857.     }
  858.     /* When insering lines at top, these have been redrawn now.  Still need to
  859.      * redraw other lines with changes */
  860.     if (wp->w_redr_type && !recursive)
  861.     {
  862. recursive = TRUE;
  863. win_update(wp);
  864. recursive = FALSE;
  865.     }
  866. }
  867. /*
  868.  * Display line "lnum" of window 'wp' on the screen.
  869.  * Start at row "startrow", stop when "endrow" is reached.
  870.  * wp->w_virtcol needs to be valid.
  871.  *
  872.  * Return the number of last row the line occupies.
  873.  */
  874.     static int
  875. win_line(wp, lnum, startrow, endrow)
  876.     WIN     *wp;
  877.     linenr_t     lnum;
  878.     int     startrow;
  879.     int     endrow;
  880. {
  881.     char_u     *screenp;
  882.     int     c = 0; /* init for GCC */
  883.     int     col; /* visual column on screen */
  884.     long     vcol; /* visual column for tabs */
  885.     long     v;
  886. #ifdef SYNTAX_HL
  887.     int     rcol; /* real column in the line */
  888. #endif
  889.     int     row; /* row in the window, excl w_winpos */
  890.     int     screen_row; /* row on the screen, incl w_winpos */
  891.     char_u     *ptr;
  892. #ifdef SYNTAX_HL
  893.     char_u     *line;
  894. #endif
  895.     char_u     extra[16]; /* "%ld" must fit in here */
  896.     int     n_extra = 0; /* number of extra chars */
  897.     char_u     *p_extra = NULL; /* string of extra chars */
  898.     int     c_extra = NUL; /* extra chars, all the same */
  899.     char_u     *showbreak = NULL;
  900.     int     n_attr = 0; /* chars with current attr */
  901.     int     n_skip = 0; /* nr of chars to skip for 'nowrap' */
  902.     int     n_number = 0; /* chars for 'number' */
  903.     int     fromcol, tocol; /* start/end of inverting */
  904.     int     noinvcur = FALSE; /* don't invert the cursor */
  905.     FPOS     *top, *bot;
  906.     int     area_highlighting; /* Visual or incsearch highlighting in
  907.    this line */
  908.     int     attr; /* attributes for area highlighting */
  909.     int     area_attr = 0; /* attributes desired by highlighting */
  910.     int     search_attr = 0; /* attributes sesired by 'searchhl' */
  911. #ifdef SYNTAX_HL
  912.     int     syntax_attr = 0; /* attributes desired by syntax */
  913.     int     has_syntax = FALSE; /* this buffer has syntax highl. */
  914. #endif
  915.     int     extra_check; /* has syntax or linebreak */
  916.     int     char_attr; /* attributes for next character */
  917.     int     saved_attr1 = 0; /* char_attr saved for showbreak */
  918.     int     saved_attr2 = 0; /* char_attr saved for listtabstring */
  919.     int     extra_attr = 0;
  920. #ifdef EXTRA_SEARCH
  921.     char_u     *matchp;
  922.     char_u     *search_hl_start = NULL;
  923.     char_u     *search_hl_end = NULL;
  924. #endif
  925. #ifdef MULTI_BYTE
  926.     int     bCharacter = 0;
  927.     char_u     *line_head;
  928. #endif
  929.     char_u     *trail = NULL; /* start of trailing spaces */
  930.     if (startrow > endrow) /* past the end already! */
  931. return startrow;
  932.     row = startrow;
  933.     screen_row = row + wp->w_winpos;
  934.     attr = hl_attr(HLF_V);
  935.     /*
  936.      * To speed up the loop below, set extra_check when there is linebreak,
  937.      * trailing white spcae and/or syntax processing to be done.
  938.      */
  939.     extra_check = wp->w_p_lbr;
  940. #ifdef SYNTAX_HL
  941.     if (syntax_present(wp->w_buffer))
  942.     {
  943. syntax_start(wp, lnum);
  944. has_syntax = TRUE;
  945. extra_check = TRUE;
  946.     }
  947. #endif
  948.     col = 0;
  949.     vcol = 0;
  950.     fromcol = -10;
  951.     tocol = MAXCOL;
  952.     area_highlighting = FALSE;
  953.     char_attr = 0;
  954.     /*
  955.      * handle visual active in this window
  956.      */
  957.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  958.     {
  959. /* Visual is after curwin->w_cursor */
  960. if (ltoreq(curwin->w_cursor, VIsual))
  961. {
  962.     top = &curwin->w_cursor;
  963.     bot = &VIsual;
  964. }
  965. else /* Visual is before curwin->w_cursor */
  966. {
  967.     top = &VIsual;
  968.     bot = &curwin->w_cursor;
  969. }
  970. if (VIsual_mode == Ctrl('V')) /* block mode */
  971. {
  972.     if (lnum >= top->lnum && lnum <= bot->lnum)
  973.     {
  974. fromcol = wp->w_old_cursor_fcol;
  975. tocol = wp->w_old_cursor_lcol;
  976.     }
  977. }
  978. else /* non-block mode */
  979. {
  980.     if (lnum > top->lnum && lnum <= bot->lnum)
  981. fromcol = 0;
  982.     else if (lnum == top->lnum)
  983.     {
  984. if (VIsual_mode == 'V') /* linewise */
  985.     fromcol = 0;
  986. else
  987.     getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
  988.     }
  989.     if (VIsual_mode != 'V' && lnum == bot->lnum)
  990.     {
  991. if (*p_sel == 'e' && bot->col == 0)
  992. {
  993.     fromcol = -10;
  994.     tocol = MAXCOL;
  995. }
  996. else
  997. {
  998.     FPOS pos;
  999.     pos = *bot;
  1000.     if (*p_sel == 'e')
  1001. --pos.col;
  1002.     getvcol(wp, &pos, NULL, NULL, (colnr_t *)&tocol);
  1003.     ++tocol;
  1004. }
  1005.     }
  1006. }
  1007. #ifndef MSDOS
  1008. /* Check if the character under the cursor should not be inverted */
  1009. if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin
  1010. # ifdef USE_GUI
  1011. && !gui.in_use
  1012. # endif
  1013. )
  1014.     noinvcur = TRUE;
  1015. #endif
  1016. /*
  1017.  * 'nowrap': adjust for when the inverted text is left of the screen,
  1018.  * and when the start of the inverted text is left of the screen.
  1019.  */
  1020. if (!wp->w_p_wrap)
  1021. {
  1022.     if (tocol <= (int)wp->w_leftcol)
  1023. fromcol = 0;
  1024.     else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
  1025. fromcol = wp->w_leftcol;
  1026. }
  1027. /* if inverting in this line, can't optimize cursor positioning */
  1028. if (fromcol >= 0)
  1029.     area_highlighting = TRUE;
  1030.     }
  1031.     /*
  1032.      * handle incremental search position highlighting
  1033.      */
  1034.     else if (highlight_match && wp == curwin && search_match_len)
  1035.     {
  1036. if (lnum == curwin->w_cursor.lnum)
  1037. {
  1038.     getvcol(curwin, &(curwin->w_cursor),
  1039.     (colnr_t *)&fromcol, NULL, NULL);
  1040.     curwin->w_cursor.col += search_match_len;
  1041.     getvcol(curwin, &(curwin->w_cursor),
  1042.     (colnr_t *)&tocol, NULL, NULL);
  1043.     curwin->w_cursor.col -= search_match_len;
  1044.     area_highlighting = TRUE;
  1045.     attr = hl_attr(HLF_I);
  1046.     if (fromcol == tocol) /* do at least one character */
  1047. tocol = fromcol + 1; /* happens when past end of line */
  1048. }
  1049.     }
  1050.     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
  1051. #ifdef EXTRA_SEARCH
  1052.     matchp = ptr;
  1053. #endif
  1054. #ifdef SYNTAX_HL
  1055.     line = ptr;
  1056.     rcol = 0;
  1057. #endif
  1058. #ifdef MULTI_BYTE
  1059.     line_head = ptr;
  1060. #endif
  1061.     /* find start of trailing whitespace */
  1062.     if (wp->w_p_list && lcs_trail)
  1063.     {
  1064. trail = ptr + STRLEN(ptr);
  1065. while (trail > ptr && vim_iswhite(trail[-1]))
  1066.     --trail;
  1067. extra_check = TRUE;
  1068.     }
  1069.     /*
  1070.      * 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
  1071.      * first character to be displayed.
  1072.      */
  1073.     if (!wp->w_p_wrap || wp->w_skipcol)
  1074.     {
  1075. if (wp->w_p_wrap)
  1076.     v = wp->w_skipcol;
  1077. else
  1078.     v = wp->w_leftcol;
  1079. while (vcol < v && *ptr)
  1080. {
  1081.     c = win_chartabsize(wp, *ptr++, (colnr_t)vcol);
  1082.     vcol += c;
  1083. #ifdef SYNTAX_HL
  1084.     ++rcol;
  1085. #endif
  1086. }
  1087. /* handle a character that's not completely on the screen */
  1088. if (vcol > v)
  1089. {
  1090.     vcol -= c;
  1091.     --ptr;
  1092. #ifdef SYNTAX_HL
  1093.     --rcol;
  1094. #endif
  1095.     n_skip = v - vcol;
  1096. }
  1097.     }
  1098. #ifdef EXTRA_SEARCH
  1099.     /*
  1100.      * Handle highlighting the last used search pattern.
  1101.      */
  1102.     if (search_hl_prog != NULL)
  1103.     {
  1104. reg_ic = search_hl_ic;
  1105. for (;;)
  1106. {
  1107.     if (vim_regexec(search_hl_prog, matchp, TRUE))
  1108.     {
  1109. search_hl_start = search_hl_prog->startp[0];
  1110. search_hl_end = search_hl_prog->endp[0];
  1111. if (search_hl_end <= ptr)    /* match before leftcol */
  1112. {
  1113.     if (matchp == search_hl_end) /* empty match */
  1114. ++matchp;
  1115.     else
  1116. matchp = search_hl_end;
  1117.     continue;
  1118. }
  1119. if (search_hl_start < ptr)  /* match at leftcol */
  1120.     search_attr = search_hl_attr;
  1121.     }
  1122.     else
  1123.     {
  1124. search_hl_start = NULL;
  1125. search_hl_end = NULL;
  1126.     }
  1127.     break;
  1128. }
  1129. if (search_hl_start != NULL)
  1130.     area_highlighting = TRUE;
  1131.     }
  1132. #endif
  1133.     screenp = current_LinePointer;
  1134. #ifdef RIGHTLEFT
  1135.     if (wp->w_p_rl)
  1136.     {
  1137. col = Columns - 1;     /* col follows screenp here */
  1138. screenp += Columns - 1;
  1139.     }
  1140. #endif
  1141.     /* add a line number if 'number' is set */
  1142.     if (wp->w_p_nu)
  1143.     {
  1144. sprintf((char *)extra, "%7ld ", (long)lnum);
  1145. #ifdef RIGHTLEFT
  1146. if (wp->w_p_rl)     /* reverse line numbers */
  1147. {
  1148.     char_u *c1, *c2, t;
  1149.     for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
  1150.    c1++, c2--)
  1151.     {
  1152. t = *c1;
  1153. *c1 = *c2;
  1154. *c2 = t;
  1155.     }
  1156. }
  1157. #endif
  1158. n_number = 8;
  1159. n_extra = 8;
  1160. p_extra = extra;
  1161. c_extra = NUL;
  1162. vcol -= 8; /* so vcol is right when line number has been printed */
  1163. n_attr = 8;
  1164. extra_attr = hl_attr(HLF_N);
  1165. saved_attr2 = 0;
  1166.     }
  1167.     /*
  1168.      * Repeat for the whole displayed line.
  1169.      */
  1170.     for (;;)
  1171.     {
  1172. /* handle Visual or match highlighting in this line (but not when
  1173.  * still in the line number) */
  1174. if (area_highlighting && n_number <= 0)
  1175. {
  1176.     if (((vcol == fromcol
  1177.     && !(noinvcur
  1178. && (colnr_t)vcol == wp->w_virtcol))
  1179. || (noinvcur
  1180.     && (colnr_t)vcol == wp->w_virtcol + 1
  1181.     && vcol >= fromcol))
  1182.     && vcol < tocol)
  1183. area_attr = attr;     /* start highlighting */
  1184.     else if (area_attr
  1185.     && (vcol == tocol
  1186. || (noinvcur
  1187.     && (colnr_t)vcol == wp->w_virtcol)))
  1188. area_attr = 0;     /* stop highlighting */
  1189. #ifdef EXTRA_SEARCH
  1190.     /*
  1191.      * Check for start/end of search pattern match.
  1192.      * After end, check for start/end of next match.
  1193.      * When another match, have to check for start again.
  1194.      * Watch out for matching an empty string!
  1195.      */
  1196.     if (!n_extra)
  1197.     {
  1198. for (;;)
  1199. {
  1200.     if (ptr == search_hl_start)
  1201. search_attr = search_hl_attr;
  1202.     if (ptr == search_hl_end)
  1203.     {
  1204. search_attr = 0;
  1205. reg_ic = search_hl_ic;
  1206. if (vim_regexec(search_hl_prog, ptr, FALSE))
  1207. {
  1208.     search_hl_start = search_hl_prog->startp[0];
  1209.     search_hl_end = search_hl_prog->endp[0];
  1210.     if (search_hl_start != search_hl_end)
  1211. continue;
  1212.     ++search_hl_end; /* try again after empty match */
  1213. }
  1214.     }
  1215.     break;
  1216. }
  1217.     }
  1218. #endif
  1219.     if (area_attr)
  1220. char_attr = area_attr;
  1221. #ifdef SYNTAX_HL
  1222.     else if (!search_attr && has_syntax)
  1223. char_attr = syntax_attr;
  1224. #endif
  1225.     else
  1226. char_attr = search_attr;
  1227. }
  1228.     /*
  1229.      * Get the next character to put on the screen.
  1230.      */
  1231. /*
  1232.  * If 'showbreak' is set it contains the characters to put at the
  1233.  * start of each broken line.
  1234.  */
  1235. if (*p_sbr != 0)
  1236. {
  1237.     if (
  1238. #ifdef RIGHTLEFT
  1239.     (wp->w_p_rl ? col == -1 : col == Columns)
  1240. #else
  1241.     col == Columns
  1242. #endif
  1243.     && (*ptr != NUL
  1244. || (wp->w_p_list && lcs_eol != NUL)
  1245. || (n_extra && (c_extra != NUL || *p_extra != NUL)))
  1246.     && vcol != 0)
  1247.     {
  1248. showbreak = p_sbr;
  1249. saved_attr1 = char_attr; /* save current attributes */
  1250.     }
  1251.     if (showbreak != NULL)
  1252.     {
  1253. if (*showbreak == NUL)
  1254. {
  1255.     showbreak = NULL;
  1256.     char_attr = saved_attr1; /* restore attributes */
  1257. }
  1258. else
  1259. {
  1260.     c = *showbreak++;
  1261.     char_attr = hl_attr(HLF_AT);
  1262. }
  1263.     }
  1264. }
  1265. if (showbreak == NULL)
  1266. {
  1267.     /*
  1268.      * The 'extra' array contains the extra stuff that is inserted to
  1269.      * represent special characters (non-printable stuff).  When all
  1270.      * characters are the same, c_extra is used.
  1271.      * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
  1272.      */
  1273.     if (n_extra)
  1274.     {
  1275. if (c_extra)
  1276.     c = c_extra;
  1277. else
  1278.     c = *p_extra++;
  1279. --n_extra;
  1280.     }
  1281.     else
  1282.     {
  1283. c = *ptr++;
  1284. #ifdef MULTI_BYTE
  1285. bCharacter = 1;
  1286. #endif
  1287. if (extra_check)
  1288. {
  1289. #ifdef SYNTAX_HL
  1290.     if (has_syntax)
  1291.     {
  1292. syntax_attr = get_syntax_attr(rcol++, line);
  1293. if (!area_attr && !search_attr)
  1294.     char_attr = syntax_attr;
  1295.     }
  1296. #endif
  1297.     /*
  1298.      * Found last space before word: check for line break
  1299.      */
  1300.     if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
  1301.   && !wp->w_p_list)
  1302.     {
  1303. n_extra = win_lbr_chartabsize(wp, ptr - 1,
  1304. (colnr_t)vcol, NULL) - 1;
  1305. c_extra = ' ';
  1306. if (vim_iswhite(c))
  1307.     c = ' ';
  1308.     }
  1309.     if (trail != NULL && ptr > trail && c == ' ')
  1310.     {
  1311. c = lcs_trail;
  1312. if (!area_attr && !search_attr)
  1313. {
  1314.     n_attr = 1;
  1315.     extra_attr = hl_attr(HLF_AT);
  1316.     saved_attr2 = char_attr; /* save current attr */
  1317. }
  1318.     }
  1319. }
  1320. /*
  1321.  * Handling of non-printable characters.
  1322.  */
  1323. if (!safe_vim_isprintc(c))
  1324. {
  1325.     /*
  1326.      * when getting a character from the file, we may have to
  1327.      * turn it into something else on the way to putting it
  1328.      * into 'NextScreen'.
  1329.      */
  1330.     if (c == TAB && (!wp->w_p_list || lcs_tab1))
  1331.     {
  1332. /* tab amount depends on current column */
  1333. n_extra = (int)wp->w_buffer->b_p_ts -
  1334.  vcol % (int)wp->w_buffer->b_p_ts - 1;
  1335. if (wp->w_p_list)
  1336. {
  1337.     c = lcs_tab1;
  1338.     c_extra = lcs_tab2;
  1339.     if (!area_attr && !search_attr)
  1340.     {
  1341. n_attr = n_extra + 1;
  1342. extra_attr = hl_attr(HLF_AT);
  1343. saved_attr2 = char_attr; /* save current attr */
  1344.     }
  1345. }
  1346. else
  1347. {
  1348.     c_extra = ' ';
  1349.     c = ' ';
  1350. }
  1351.     }
  1352.     else if (c == NUL && wp->w_p_list && lcs_eol != NUL)
  1353.     {
  1354. p_extra = (char_u *)"";
  1355. n_extra = 1;
  1356. c_extra = NUL;
  1357. c = lcs_eol;
  1358. --ptr;     /* put it back at the NUL */
  1359. char_attr = hl_attr(HLF_AT);
  1360.     }
  1361.     else if (c != NUL)
  1362.     {
  1363. p_extra = transchar(c);
  1364. n_extra = charsize(c) - 1;
  1365. c_extra = NUL;
  1366. c = *p_extra++;
  1367.     }
  1368. }
  1369.     }
  1370.     if (n_attr)
  1371. char_attr = extra_attr;
  1372. }
  1373. /*
  1374.  * At end of the text line.
  1375.  */
  1376. if (c == NUL)
  1377. {
  1378.     if (area_attr)
  1379.     {
  1380. /* invert at least one char, used for Visual and empty line or
  1381.  * highlight match at end of line. If it's beyond the last
  1382.  * char on the screen, just overwrite that one (tricky!) */
  1383. if (vcol == fromcol)
  1384. {
  1385. #ifdef RIGHTLEFT
  1386.     if (wp->w_p_rl)
  1387.     {
  1388. if (col < 0)
  1389. {
  1390.     ++screenp;
  1391.     ++col;
  1392. }
  1393.     }
  1394.     else
  1395. #endif
  1396.     {
  1397. if (col >= Columns)
  1398. {
  1399.     --screenp;
  1400.     --col;
  1401. }
  1402.     }
  1403.     *screenp = ' ';
  1404.     *(screenp + Columns) = char_attr;
  1405. #ifdef RIGHTLEFT
  1406.     if (wp->w_p_rl)
  1407. --col;
  1408.     else
  1409. #endif
  1410. ++col;
  1411. }
  1412.     }
  1413.     SCREEN_LINE(screen_row, col, TRUE, wp->w_p_rl);
  1414.     row++;
  1415.     /*
  1416.      * Update w_cline_height if we can (saves a call to plines()
  1417.      * later).
  1418.      */
  1419.     if (wp == curwin && lnum == curwin->w_cursor.lnum)
  1420.     {
  1421. curwin->w_cline_row = startrow;
  1422. curwin->w_cline_height = row - startrow;
  1423. curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW);
  1424.     }
  1425.     break;
  1426. }
  1427. /*
  1428.  * At end of screen line.
  1429.  */
  1430. if (
  1431. #ifdef RIGHTLEFT
  1432.     wp->w_p_rl ? (col < 0) :
  1433. #endif
  1434.     (col >= Columns))
  1435. {
  1436.     SCREEN_LINE(screen_row, col, TRUE, wp->w_p_rl);
  1437.     col = 0;
  1438.     ++row;
  1439.     ++screen_row;
  1440.     if (!wp->w_p_wrap)
  1441. break;
  1442.     if (row == endrow)     /* line got too long for screen */
  1443.     {
  1444. ++row;
  1445. break;
  1446.     }
  1447.     /*
  1448.      * Special trick to make copy/paste of wrapped lines work with
  1449.      * xterm/screen: write an extra character beyond the end of the
  1450.      * line. This will work with all terminal types (regardless of the
  1451.      * xn,am settings).
  1452.      * Only do this on a fast tty.
  1453.      * Only do this if the cursor is on the current line (something
  1454.      * has been written in it).
  1455.      * Don't do this for the GUI.
  1456.      */
  1457.     if (p_tf && screen_cur_row == screen_row - 1
  1458. #ifdef USE_GUI
  1459.      && !gui.in_use
  1460. #endif
  1461. )
  1462.     {
  1463. if (screen_cur_col != Columns)
  1464.     screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1465.   screen_row - 1, (int)(Columns - 1));
  1466. screen_char(LinePointers[screen_row],
  1467. screen_row - 1, (int)Columns);
  1468. screen_start(); /* don't know where cursor is now */
  1469.     }
  1470.     screenp = current_LinePointer;
  1471. #ifdef RIGHTLEFT
  1472.     if (wp->w_p_rl)
  1473.     {
  1474. col = Columns - 1; /* col is not used if breaking! */
  1475. screenp += Columns - 1;
  1476.     }
  1477. #endif
  1478. }
  1479. /* line continues beyond line end */
  1480. if (lcs_ext
  1481. && !wp->w_p_wrap
  1482. && (
  1483. #ifdef RIGHTLEFT
  1484.     wp->w_p_rl ? col == 0 :
  1485. #endif
  1486.     col == Columns - 1)
  1487. && (*ptr != NUL
  1488.     || (wp->w_p_list && lcs_eol != NUL)
  1489.     || (n_extra && (c_extra != NUL || *p_extra != NUL))))
  1490. {
  1491.     c = lcs_ext;
  1492.     char_attr = hl_attr(HLF_AT);
  1493. }
  1494. #ifdef MULTI_BYTE
  1495. if (is_dbcs)
  1496. {
  1497.     /* if an mult-byte character splits by line edge,
  1498.        lead or trail byte is substituted by '~' */
  1499.     if (col == 0 && bCharacter)
  1500.     {
  1501. if (IsTrailByte(line_head, ptr-1))
  1502.     c = '~';
  1503.     }
  1504.     if (
  1505. # ifdef RIGHTLEFT
  1506.     wp->w_p_rl ? (col <= 0) :
  1507. # endif
  1508.     (col >= Columns-1))
  1509.     {
  1510. if (bCharacter && IsLeadByte(*(ptr-1))
  1511. && IsTrailByte(line_head, ptr))
  1512.     c = '~';
  1513.     }
  1514.     bCharacter = 0;
  1515. }
  1516. #endif
  1517. /* Skip characters that are left of the screen for 'nowrap' */
  1518. if (n_number > 0 || n_skip <= 0)
  1519. {
  1520.     /*
  1521.      * Store the character.
  1522.      */
  1523.     *screenp = c;
  1524.     *(screenp + Columns) = char_attr;
  1525. #ifdef RIGHTLEFT
  1526.     if (wp->w_p_rl)
  1527.     {
  1528. --screenp;
  1529. --col;
  1530.     }
  1531.     else
  1532. #endif
  1533.     {
  1534. ++screenp;
  1535. ++col;
  1536.     }
  1537.     --n_number;
  1538. }
  1539. else
  1540.     --n_skip;
  1541. ++vcol;
  1542. /* restore attributes after last 'listchars' or 'number' char */
  1543. if (n_attr && --n_attr == 0)
  1544.     char_attr = saved_attr2;
  1545. /* When still displaying '$' of change command, stop at cursor */
  1546. if (dollar_vcol && wp == curwin && vcol >= (long)wp->w_virtcol)
  1547. {
  1548.     SCREEN_LINE(screen_row, col, FALSE, wp->w_p_rl);
  1549.     break;
  1550. }
  1551.     }
  1552.     return (row);
  1553. }
  1554. /*
  1555.  * Move one "cooked" screen line to the screen, but only the characters that
  1556.  * have actually changed.  Handle insert/delete character.
  1557.  * 'endcol' gives the columns where valid characters are.
  1558.  * 'clear_rest' is TRUE if the rest of the line needs to be cleared.
  1559.  * 'rlflag' is TRUE in a rightleft window:
  1560.  * When TRUE and clear_rest, line is cleared in 0 -- endcol.
  1561.  * When FALSE and clear_rest, line is cleared in endcol -- Columns-1.
  1562.  */
  1563.     static void
  1564. screen_line(row, endcol, clear_rest
  1565. #ifdef RIGHTLEFT
  1566.     , rlflag
  1567. #endif
  1568. )
  1569.     int     row;
  1570.     int     endcol;
  1571.     int     clear_rest;
  1572. #ifdef RIGHTLEFT
  1573.     int     rlflag;
  1574. #endif
  1575. {
  1576.     char_u     *screenp_from;
  1577.     char_u     *screenp_to;
  1578.     int     col = 0;
  1579.     int     force = FALSE; /* force update rest of the line */
  1580.     screenp_from = current_LinePointer;
  1581.     screenp_to = LinePointers[row];
  1582. #ifdef RIGHTLEFT
  1583.     if (rlflag)
  1584.     {
  1585. if (clear_rest)
  1586. {
  1587.     while (col <= endcol && *screenp_to == ' '
  1588.       && *(screenp_to + Columns) == 0)
  1589.     {
  1590. ++screenp_to;
  1591. ++col;
  1592.     }
  1593.     if (col <= endcol)
  1594. screen_fill(row, row + 1, col, endcol + 1, ' ', ' ', 0);
  1595. }
  1596. col = endcol + 1;
  1597. screenp_to = LinePointers[row] + col;
  1598. screenp_from += col;
  1599.     }
  1600.     while (rlflag ? (col < Columns) : (col < endcol))
  1601. #else
  1602.     while (col < endcol)
  1603. #endif
  1604.     {
  1605. if (
  1606. #if defined(MULTI_BYTE)
  1607. /* a multi byte ch. is misprinted when right/left scrolling. */
  1608. is_dbcs ||
  1609. #endif
  1610.    force
  1611. || *screenp_from != *screenp_to
  1612. || *(screenp_from + Columns) != *(screenp_to + Columns)
  1613.    )
  1614. {
  1615.     /*
  1616.      * Special handling when 'xs' termcap flag set (hpterm):
  1617.      * Attributes for characters are stored at the position where the
  1618.      * cursor is when writing the highlighting code.  The
  1619.      * start-highlighting code must be written with the cursor on the
  1620.      * first highlighted character.  The stop-highlighting code must
  1621.      * be written with the cursor just after the last highlighted
  1622.      * character.
  1623.      * Overwriting a character doesn't remove it's highlighting.  Need
  1624.      * to clear the rest of the line, and force redrawing it
  1625.      * completely.
  1626.      */
  1627.     if (       p_wiv
  1628.     && !force
  1629. #ifdef USE_GUI
  1630.     && !gui.in_use
  1631. #endif
  1632.     && *(screenp_to + Columns)
  1633.     && *(screenp_from + Columns) != *(screenp_to + Columns))
  1634.     {
  1635. /*
  1636.  * Need to remove highlighting attributes here.
  1637.  */
  1638. windgoto(row, col);
  1639. out_str(T_CE); /* clear rest of this screen line */
  1640. screen_start(); /* don't know where cursor is now */
  1641. force = TRUE; /* force redraw of rest of the line */
  1642. /*
  1643.  * If the previous character was highlighted, need to stop
  1644.  * highlighting at this character.
  1645.  */
  1646. if (col > 0 && *(screenp_to + Columns - 1))
  1647. {
  1648.     screen_attr = *(screenp_to + Columns - 1);
  1649.     term_windgoto(row, col);
  1650.     screen_stop_highlight();
  1651. }
  1652. else
  1653.     screen_attr = 0;     /* highlighting has stopped */
  1654.     }
  1655.     *screenp_to = *screenp_from;
  1656. #if defined(USE_GUI) || defined(UNIX)
  1657.     /* The bold trick makes a single row of pixels appear in the next
  1658.      * character.  When a bold character is removed, the next
  1659.      * character should be redrawn too.  This happens for our own GUI
  1660.      * and for some xterms. */
  1661.     if (
  1662. # ifdef USE_GUI
  1663.     gui.in_use
  1664. # endif
  1665. # if defined(USE_GUI) && defined(UNIX)
  1666.     ||
  1667. # endif
  1668. # ifdef UNIX
  1669.     vim_is_xterm(T_NAME)
  1670. # endif
  1671.     )
  1672.     {
  1673. int n;
  1674. n = *(screenp_to + Columns);
  1675. if (col + 1 < Columns && (n > HL_ALL || (n & HL_BOLD)))
  1676.     *(screenp_to + 1) = 0;
  1677.     }
  1678. #endif
  1679.     *(screenp_to + Columns) = *(screenp_from + Columns);
  1680.     screen_char(screenp_to, row, col);
  1681. }
  1682. else if (  p_wiv
  1683. #ifdef USE_GUI
  1684. && !gui.in_use
  1685. #endif
  1686. && col > 0)
  1687. {
  1688.     if (*(screenp_to + Columns) == *(screenp_to + Columns - 1))
  1689.     {
  1690. /*
  1691.  * Don't output stop-highlight when moving the cursor, it will
  1692.  * stop the highlighting when it should continue.
  1693.  */
  1694. screen_attr = 0;
  1695.     }
  1696.     else if (screen_attr)
  1697.     {
  1698. screen_stop_highlight();
  1699.     }
  1700. }
  1701. ++screenp_to;
  1702. ++screenp_from;
  1703. ++col;
  1704.     }
  1705.     if (clear_rest
  1706. #ifdef RIGHTLEFT
  1707.     && !rlflag
  1708. #endif
  1709.    )
  1710.     {
  1711. /* blank out the rest of the line */
  1712. while (col < Columns && *screenp_to == ' ' &&
  1713. *(screenp_to + Columns) == 0)
  1714. {
  1715.     ++screenp_to;
  1716.     ++col;
  1717. }
  1718. if (col < Columns)
  1719.     screen_fill(row, row + 1, col, (int)Columns, ' ', ' ', 0);
  1720.     }
  1721. }
  1722. /*
  1723.  * mark all status lines for redraw; used after first :cd
  1724.  */
  1725.     void
  1726. status_redraw_all()
  1727. {
  1728.     WIN     *wp;
  1729.     for (wp = firstwin; wp; wp = wp->w_next)
  1730. if (wp->w_status_height)
  1731. {
  1732.     wp->w_redr_status = TRUE;
  1733.     redraw_later(NOT_VALID);
  1734. }
  1735. }
  1736. /*
  1737.  * Redraw all status lines that need to be redrawn.
  1738.  */
  1739.     void
  1740. redraw_statuslines()
  1741. {
  1742.     WIN     *wp;
  1743.     for (wp = firstwin; wp; wp = wp->w_next)
  1744. if (wp->w_redr_status)
  1745.     win_redr_status(wp);
  1746. }
  1747. /*
  1748.  * Redraw the status line of window wp.
  1749.  *
  1750.  * If inversion is possible we use it. Else '=' characters are used.
  1751.  */
  1752.     void
  1753. win_redr_status(wp)
  1754.     WIN     *wp;
  1755. {
  1756.     int     row;
  1757.     char_u  *p;
  1758.     int     len;
  1759.     int     fillchar;
  1760.     int     attr;
  1761.     if (wp->w_status_height) /* if there is a status line */
  1762.     {
  1763. fillchar = highlight_status(&attr, wp == curwin);
  1764. p = wp->w_buffer->b_fname;
  1765. if (p == NULL)
  1766.     STRCPY(NameBuff, "[No File]");
  1767. else
  1768. {
  1769.     home_replace(wp->w_buffer, p, NameBuff, MAXPATHL, TRUE);
  1770.     trans_characters(NameBuff, MAXPATHL);
  1771. }
  1772. p = NameBuff;
  1773. len = STRLEN(p);
  1774. if (wp->w_buffer->b_help || buf_changed(wp->w_buffer) ||
  1775.  wp->w_buffer->b_p_ro)
  1776.     *(p + len++) = ' ';
  1777. if (wp->w_buffer->b_help)
  1778. {
  1779.     STRCPY(p + len, "[help]");
  1780.     len += 6;
  1781. }
  1782. if (buf_changed(wp->w_buffer))
  1783. {
  1784.     STRCPY(p + len, "[+]");
  1785.     len += 3;
  1786. }
  1787. if (wp->w_buffer->b_p_ro)
  1788. {
  1789.     STRCPY(p + len, "[RO]");
  1790.     len += 4;
  1791. }
  1792. if (len > ru_col - 1)
  1793. {
  1794.     p += len - (ru_col - 1);
  1795.     *p = '<';
  1796.     len = ru_col - 1;
  1797. }
  1798. row = wp->w_winpos + wp->w_height;
  1799. screen_puts(p, row, 0, attr);
  1800. screen_fill(row, row + 1, len, ru_col, fillchar, fillchar, attr);
  1801. win_redr_ruler(wp, TRUE);
  1802.     }
  1803.     else    /* no status line, can only be last window */
  1804. redraw_cmdline = TRUE;
  1805.     wp->w_redr_status = FALSE;
  1806. }
  1807. /*
  1808.  * Output a single character directly to the screen and update NextScreen.
  1809.  */
  1810.     void
  1811. screen_putchar(c, row, col, attr)
  1812.     int     c;
  1813.     int     row, col;
  1814.     int     attr;
  1815. {
  1816.     char_u buf[2];
  1817.     buf[0] = c;
  1818.     buf[1] = NUL;
  1819.     screen_puts(buf, row, col, attr);
  1820. }
  1821. /*
  1822.  * Put string '*text' on the screen at position 'row' and 'col', with
  1823.  * attributes 'attr', and update NextScreen.
  1824.  * Note: only outputs within one row, message is truncated at screen boundary!
  1825.  * Note: if NextScreen, row and/or col is invalid, nothing is done.
  1826.  */
  1827.     void
  1828. screen_puts(text, row, col, attr)
  1829.     char_u  *text;
  1830.     int     row;
  1831.     int     col;
  1832.     int     attr;
  1833. {
  1834.     char_u  *screenp;
  1835.     if (NextScreen != NULL && row < Rows)     /* safety check */
  1836.     {
  1837. screenp = LinePointers[row] + col;
  1838. while (*text && col < Columns)
  1839. {
  1840.     if (*screenp != *text || *(screenp + Columns) != attr ||
  1841. exmode_active)
  1842.     {
  1843. *screenp = *text;
  1844. *(screenp + Columns) = attr;
  1845. screen_char(screenp, row, col);
  1846.     }
  1847.     ++screenp;
  1848.     ++col;
  1849.     ++text;
  1850. }
  1851.     }
  1852. }
  1853. #ifdef EXTRA_SEARCH
  1854. /*
  1855.  * Prepare for 'searchhl' highlighting.
  1856.  */
  1857.     static void
  1858. start_search_hl()
  1859. {
  1860.     if (p_hls && !no_hlsearch)
  1861.     {
  1862. search_hl_prog = last_pat_prog();
  1863. search_hl_attr = hl_attr(HLF_L);
  1864. search_hl_ic = reg_ic;
  1865.     }
  1866. }
  1867. /*
  1868.  * Clean up for 'searchhl' highlighting.
  1869.  */
  1870.     static void
  1871. end_search_hl()
  1872. {
  1873.     if (search_hl_prog != NULL)
  1874.     {
  1875. vim_free(search_hl_prog);
  1876. search_hl_prog = NULL;
  1877.     }
  1878. }
  1879. #endif
  1880. /*
  1881.  * Reset cursor position. Use whenever cursor was moved because of outputting
  1882.  * something directly to the screen (shell commands) or a terminal control
  1883.  * code.
  1884.  */
  1885.     void
  1886. screen_start()
  1887. {
  1888.     screen_cur_row = screen_cur_col = 9999;
  1889. }
  1890. /*
  1891.  * Note that the cursor has gone down to the next line, column 0.
  1892.  * Used for Ex mode.
  1893.  */
  1894.     void
  1895. screen_down()
  1896. {
  1897.     screen_cur_col = 0;
  1898.     if (screen_cur_row < Rows - 1)
  1899. ++screen_cur_row;
  1900. }
  1901.       static void
  1902. screen_start_highlight(attr)
  1903.       int attr;
  1904. {
  1905.     struct attr_entry *aep = NULL;
  1906.     screen_attr = attr;
  1907.     if (full_screen
  1908. #ifdef WIN32
  1909.     && termcap_active
  1910. #endif
  1911.        )
  1912.     {
  1913. #ifdef USE_GUI
  1914. if (gui.in_use)
  1915. {
  1916.     char buf[20];
  1917.     sprintf(buf, "33|%dh", attr); /* internal GUI code */
  1918.     OUT_STR(buf);
  1919. }
  1920. else
  1921. #endif
  1922. {
  1923.     if (attr > HL_ALL) /* special HL attr. */
  1924.     {
  1925. if (*T_CCO != NUL)
  1926.     aep = syn_cterm_attr2entry(attr);
  1927. else
  1928.     aep = syn_term_attr2entry(attr);
  1929. if (aep == NULL)     /* did ":syntax clear" */
  1930.     attr = 0;
  1931. else
  1932.     attr = aep->ae_attr;
  1933.     }
  1934.     if ((attr & HL_BOLD) && T_MD != NULL) /* bold */
  1935. out_str(T_MD);
  1936.     if ((attr & HL_STANDOUT) && T_SO != NULL) /* standout */
  1937. out_str(T_SO);
  1938.     if ((attr & HL_UNDERLINE) && T_US != NULL) /* underline */
  1939. out_str(T_US);
  1940.     if ((attr & HL_ITALIC) && T_CZH != NULL) /* italic */
  1941. out_str(T_CZH);
  1942.     if ((attr & HL_INVERSE) && T_MR != NULL) /* inverse (reverse) */
  1943. out_str(T_MR);
  1944.     /*
  1945.      * Output the color or start string after bold etc., in case the
  1946.      * bold etc. override the color setting.
  1947.      */
  1948.     if (aep != NULL)
  1949.     {
  1950. if (*T_CCO != NUL)
  1951. {
  1952.     if (aep->ae_u.cterm.fg_color)
  1953. term_fg_color(aep->ae_u.cterm.fg_color - 1);
  1954.     if (aep->ae_u.cterm.bg_color)
  1955. term_bg_color(aep->ae_u.cterm.bg_color - 1);
  1956. }
  1957. else
  1958. {
  1959.     if (aep->ae_u.term.start != NULL)
  1960. out_str(aep->ae_u.term.start);
  1961. }
  1962.     }
  1963. }
  1964.     }
  1965. }
  1966.       void
  1967. screen_stop_highlight()
  1968. {
  1969.     int     do_ME = FALSE;     /* output T_ME code */
  1970.     if (screen_attr
  1971. #ifdef WIN32
  1972. && termcap_active
  1973. #endif
  1974.    )
  1975.     {
  1976. #ifdef USE_GUI
  1977. if (gui.in_use)
  1978. {
  1979.     char buf[20];
  1980.     sprintf(buf, "33|%dH", screen_attr); /* internal GUI code */
  1981.     OUT_STR(buf);
  1982. }
  1983. else
  1984. #endif
  1985. {
  1986.     if (screen_attr > HL_ALL) /* special HL attr. */
  1987.     {
  1988. struct attr_entry *aep;
  1989. if (*T_CCO != NUL)
  1990. {
  1991.     /*
  1992.      * Assume that t_me restores the original colors!
  1993.      */
  1994.     aep = syn_cterm_attr2entry(screen_attr);
  1995.     if (aep != NULL && (aep->ae_u.cterm.fg_color ||
  1996.     aep->ae_u.cterm.bg_color))
  1997. do_ME = TRUE;
  1998. }
  1999. else
  2000. {
  2001.     aep = syn_term_attr2entry(screen_attr);
  2002.     if (aep != NULL && aep->ae_u.term.stop != NULL)
  2003.     {
  2004. if (STRCMP(aep->ae_u.term.stop, T_ME) == 0)
  2005.     do_ME = TRUE;
  2006. else
  2007.     out_str(aep->ae_u.term.stop);
  2008.     }
  2009. }
  2010. if (aep == NULL)     /* did ":syntax clear" */
  2011.     screen_attr = 0;
  2012. else
  2013.     screen_attr = aep->ae_attr;
  2014.     }
  2015.     /*
  2016.      * Often all ending-codes are equal to T_ME.  Avoid outputting the
  2017.      * same sequence several times.
  2018.      */
  2019.     if (screen_attr & HL_STANDOUT)
  2020.     {
  2021. if (STRCMP(T_SE, T_ME) == 0)
  2022.     do_ME = TRUE;
  2023. else
  2024.     out_str(T_SE);
  2025.     }
  2026.     if (screen_attr & HL_UNDERLINE)
  2027.     {
  2028. if (STRCMP(T_UE, T_ME) == 0)
  2029.     do_ME = TRUE;
  2030. else
  2031.     out_str(T_UE);
  2032.     }
  2033.     if (screen_attr & HL_ITALIC)
  2034.     {
  2035. if (STRCMP(T_CZR, T_ME) == 0)
  2036.     do_ME = TRUE;
  2037. else
  2038.     out_str(T_CZR);
  2039.     }
  2040.     if (do_ME || (screen_attr & HL_BOLD) || (screen_attr & HL_INVERSE))
  2041. out_str(T_ME);
  2042.     if (*T_CCO != NUL)
  2043.     {
  2044. /* set Normal cterm colors */
  2045. if (cterm_normal_fg_color)
  2046.     term_fg_color(cterm_normal_fg_color - 1);
  2047. if (cterm_normal_bg_color)
  2048.     term_bg_color(cterm_normal_bg_color - 1);
  2049. if (cterm_normal_fg_bold)
  2050.     out_str(T_MD);
  2051.     }
  2052. }
  2053.     }
  2054.     screen_attr = 0;
  2055. }
  2056. /*
  2057.  * Reset the colors for a cterm.  Used when leaving Vim.
  2058.  */
  2059.     void
  2060. reset_cterm_colors()
  2061. {
  2062.     if (*T_CCO != NUL)
  2063.     {
  2064. /* set Normal cterm colors */
  2065. if (cterm_normal_fg_color || cterm_normal_bg_color)
  2066.     out_str(T_OP);
  2067. if (cterm_normal_fg_bold)
  2068.     out_str(T_ME);
  2069.     }
  2070. }
  2071. /*
  2072.  * put character '*p' on the screen at position 'row' and 'col'
  2073.  */
  2074.     static void
  2075. screen_char(p, row, col)
  2076.     char_u  *p;
  2077.     int     row;
  2078.     int     col;
  2079. {
  2080.     /*
  2081.      * Outputting the last character on the screen may scrollup the screen.
  2082.      * Don't to it!
  2083.      */
  2084.     if (col == Columns - 1 && row == Rows - 1)
  2085. return;
  2086.     /*
  2087.      * Stop highlighting first, so it's easier to move the cursor.
  2088.      */
  2089.     if (screen_attr != *(p + Columns))
  2090. screen_stop_highlight();
  2091.     windgoto(row, col);
  2092.     if (screen_attr != *(p + Columns))
  2093. screen_start_highlight(*(p + Columns));
  2094.     out_char(*p);
  2095.     screen_cur_col++;
  2096. }
  2097. /*
  2098.  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
  2099.  * with character 'c1' in first column followed by 'c2' in the other columns.
  2100.  * Use attributes 'attr'.
  2101.  */
  2102.     void
  2103. screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
  2104.     int     start_row, end_row;
  2105.     int     start_col, end_col;
  2106.     int     c1, c2;
  2107.     int     attr;
  2108. {
  2109.     int     row;
  2110.     int     col;
  2111.     char_u     *screenp;
  2112.     char_u     *attrp;
  2113.     int     did_delete;
  2114.     int     c;
  2115.     int     norm_term;
  2116.     if (end_row > Rows)     /* safety check */
  2117. end_row = Rows;
  2118.     if (end_col > Columns)     /* safety check */
  2119. end_col = Columns;
  2120.     if (NextScreen == NULL ||
  2121.     start_row >= end_row || start_col >= end_col)   /* nothing to do */
  2122. return;
  2123.     /* it's a "normal" terminal when not in a GUI or cterm */
  2124.     norm_term = (
  2125. #ifdef USE_GUI
  2126.     !gui.in_use &&
  2127. #endif
  2128.     *T_CCO == NUL);
  2129.     for (row = start_row; row < end_row; ++row)
  2130.     {
  2131. /*
  2132.  * Try to use delete-line termcap code, when no attributes or in a
  2133.  * "normal" terminal, where a bold/italic space is just a
  2134.  * space.
  2135.  */
  2136. did_delete = FALSE;
  2137. if (c2 == ' ' && end_col == Columns && *T_CE != NUL
  2138. && (attr == 0 || (norm_term && attr <= HL_ALL
  2139.     && ((attr & ~(HL_BOLD | HL_ITALIC)) == 0))))
  2140. {
  2141.     /*
  2142.      * check if we really need to clear something
  2143.      */
  2144.     col = start_col;
  2145.     screenp = LinePointers[row] + start_col;
  2146.     if (c1 != ' ') /* don't clear first char */
  2147.     {
  2148. ++col;
  2149. ++screenp;
  2150.     }
  2151.     /* skip blanks (used often, keep it fast!) */
  2152.     attrp = screenp + Columns;
  2153.     while (col < end_col && *screenp == ' ' && *attrp == 0)
  2154.     {
  2155. ++col;
  2156. ++screenp;
  2157. ++attrp;
  2158.     }
  2159.     if (col < end_col) /* something to be cleared */
  2160.     {
  2161. screen_stop_highlight();
  2162. term_windgoto(row, col);/* clear rest of this screen line */
  2163. out_str(T_CE);
  2164. screen_start(); /* don't know where cursor is now */
  2165. col = end_col - col;
  2166. while (col--) /* clear chars in NextScreen */
  2167. {
  2168.     *attrp++ = 0;
  2169.     *screenp++ = ' ';
  2170. }
  2171.     }
  2172.     did_delete = TRUE; /* the chars are cleared now */
  2173. }
  2174. screenp = LinePointers[row] + start_col;
  2175. c = c1;
  2176. for (col = start_col; col < end_col; ++col)
  2177. {
  2178.     if (*screenp != c || *(screenp + Columns) != attr)
  2179.     {
  2180. *screenp = c;
  2181. *(screenp + Columns) = attr;
  2182. if (!did_delete || c != ' ')
  2183.     screen_char(screenp, row, col);
  2184.     }
  2185.     ++screenp;
  2186.     if (col == start_col)
  2187.     {
  2188. if (did_delete)
  2189.     break;
  2190. c = c2;
  2191.     }
  2192. }
  2193. if (row == Rows - 1) /* overwritten the command line */
  2194. {
  2195.     redraw_cmdline = TRUE;
  2196.     if (c1 == ' ' && c2 == ' ')
  2197. clear_cmdline = FALSE; /* command line has been cleared */
  2198. }
  2199.     }
  2200. }
  2201. /*
  2202.  * compute wp->w_botline. Can be called after wp->w_topline changed.
  2203.  */
  2204.     static void
  2205. comp_botline()
  2206. {
  2207.     int n;
  2208.     linenr_t lnum;
  2209.     int done;
  2210.     /*
  2211.      * If w_cline_row is valid, start there.
  2212.      * Otherwise have to start at w_topline.
  2213.      */
  2214.     check_cursor_moved(curwin);
  2215.     if (curwin->w_valid & VALID_CROW)
  2216.     {
  2217. lnum = curwin->w_cursor.lnum;
  2218. done = curwin->w_cline_row;
  2219.     }
  2220.     else
  2221.     {
  2222. lnum = curwin->w_topline;
  2223. done = 0;
  2224.     }
  2225.     for ( ; lnum <= curwin->w_buffer->b_ml.ml_line_count; ++lnum)
  2226.     {
  2227. n = plines(lnum);
  2228. if (lnum == curwin->w_cursor.lnum)
  2229. {
  2230.     curwin->w_cline_row = done;
  2231.     curwin->w_cline_height = n;
  2232.     curwin->w_valid |= (VALID_CROW|VALID_CHEIGHT);
  2233. }
  2234. if (done + n > curwin->w_height)
  2235.     break;
  2236. done += n;
  2237.     }
  2238.     /* curwin->w_botline is the line that is just below the window */
  2239.     curwin->w_botline = lnum;
  2240.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  2241.     /*
  2242.      * Also set curwin->w_empty_rows, otherwise scroll_cursor_bot() won't work
  2243.      */
  2244.     if (done == 0)
  2245. curwin->w_empty_rows = 0; /* single line that doesn't fit */
  2246.     else
  2247. curwin->w_empty_rows = curwin->w_height - done;
  2248. }
  2249.     void
  2250. screenalloc(clear)
  2251.     int     clear;
  2252. {
  2253.     int     new_row, old_row;
  2254.     WIN     *wp;
  2255.     int     outofmem = FALSE;
  2256.     int     len;
  2257.     char_u     *new_NextScreen;
  2258.     char_u     **new_LinePointers;
  2259.     static int     entered = FALSE; /* avoid recursiveness */
  2260.     /*
  2261.      * Allocation of the screen buffers is done only when the size changes
  2262.      * and when Rows and Columns have been set and we have started doing full
  2263.      * screen stuff.
  2264.      */
  2265.     if ((NextScreen != NULL &&
  2266.   Rows == screen_Rows && Columns == screen_Columns) ||
  2267.     Rows == 0 || Columns == 0 || (!full_screen && NextScreen == NULL))
  2268. return;
  2269.     /*
  2270.      * It's possible that we produce an out-of-memory message below, which
  2271.      * will cause this function to be called again.  To break the loop, just
  2272.      * return here.
  2273.      */
  2274.     if (entered)
  2275. return;
  2276.     entered = TRUE;
  2277. #ifdef USE_GUI_BEOS
  2278.     vim_lock_screen();  /* be safe, put it here */
  2279. #endif
  2280.     comp_col(); /* recompute columns for shown command and ruler */
  2281.     /*
  2282.      * We're changing the size of the screen.
  2283.      * - Allocate new arrays for NextScreen.
  2284.      * - Move lines from the old arrays into the new arrays, clear extra
  2285.      *  lines (unless the screen is going to be cleared).
  2286.      * - Free the old arrays.
  2287.      *
  2288.      * If anything fails, make NextScreen NULL, so we don't do anything!
  2289.      * Continuing with the old NextScreen may result in a crash, because the
  2290.      * size is wrong.
  2291.      */
  2292.     for (wp = firstwin; wp; wp = wp->w_next)
  2293. win_free_lsize(wp);
  2294.     new_NextScreen =
  2295. (char_u *)lalloc((long_u)((Rows + 1) * Columns * 2), FALSE);
  2296.     new_LinePointers =
  2297. (char_u **)lalloc((long_u)(sizeof(char_u *) * Rows), FALSE);
  2298.     for (wp = firstwin; wp; wp = wp->w_next)
  2299.     {
  2300. if (win_alloc_lsize(wp) == FAIL)
  2301. {
  2302.     outofmem = TRUE;
  2303.     break;
  2304. }
  2305.     }
  2306.     if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
  2307.     {
  2308. do_outofmem_msg();
  2309. vim_free(new_NextScreen);
  2310. new_NextScreen = NULL;
  2311. vim_free(new_LinePointers);
  2312. new_LinePointers = NULL;
  2313.     }
  2314.     else
  2315.     {
  2316. for (new_row = 0; new_row < Rows; ++new_row)
  2317. {
  2318.     new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
  2319.     /*
  2320.      * If the screen is not going to be cleared, copy as much as
  2321.      * possible from the old screen to the new one and clear the rest
  2322.      * (used when resizing the window at the "--more--" prompt or when
  2323.      * executing an external command, for the GUI).
  2324.      */
  2325.     if (!clear)
  2326.     {
  2327. lineclear(new_LinePointers[new_row]);
  2328. old_row = new_row + (screen_Rows - Rows);
  2329. if (old_row >= 0)
  2330. {
  2331.     if (screen_Columns < Columns)
  2332. len = screen_Columns;
  2333.     else
  2334. len = Columns;
  2335.     mch_memmove(new_LinePointers[new_row],
  2336.     LinePointers[old_row], (size_t)len);
  2337.     mch_memmove(new_LinePointers[new_row] + Columns,
  2338.     LinePointers[old_row] + screen_Columns,
  2339.  (size_t)len);
  2340. }
  2341.     }
  2342. }
  2343. current_LinePointer = new_NextScreen + Rows * Columns * 2;
  2344.     }
  2345.     vim_free(NextScreen);
  2346.     vim_free(LinePointers);
  2347.     NextScreen = new_NextScreen;
  2348.     LinePointers = new_LinePointers;
  2349.     must_redraw = CLEAR; /* need to clear the screen later */
  2350.     if (clear)
  2351. screenclear2();
  2352. #ifdef USE_GUI
  2353.     else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
  2354.     {
  2355. (void)gui_redraw_block(0, 0, (int)Rows - 1, (int)Columns - 1, 0);
  2356. /*
  2357.  * Adjust the position of the cursor, for when executing an external
  2358.  * command.
  2359.  */
  2360. if (msg_row >= Rows)     /* Rows got smaller */
  2361.     msg_row = Rows - 1;     /* put cursor at last row */
  2362. else if (Rows > screen_Rows)     /* Rows got bigger */
  2363.     msg_row += Rows - screen_Rows;  /* put cursor in same place */
  2364. if (msg_col >= Columns)     /* Columns got smaller */
  2365.     msg_col = Columns - 1;     /* put cursor at last column */
  2366.     }
  2367. #endif
  2368.     screen_Rows = Rows;
  2369.     screen_Columns = Columns;
  2370. #ifdef USE_GUI_BEOS
  2371.     vim_unlock_screen();
  2372. #endif
  2373.     entered = FALSE;
  2374. }
  2375.     void
  2376. screenclear()
  2377. {
  2378.     check_for_delay(FALSE);
  2379.     screenalloc(FALSE);     /* allocate screen buffers if size changed */
  2380.     screenclear2();     /* clear the screen */
  2381. }
  2382.     static void
  2383. screenclear2()
  2384. {
  2385.     int     i;
  2386.     if (starting || NextScreen == NULL)
  2387. return;
  2388.     screen_stop_highlight(); /* don't want highlighting here */
  2389.     out_str(T_CL); /* clear the display */
  2390. /* blank out NextScreen */
  2391.     for (i = 0; i < Rows; ++i)
  2392. lineclear(LinePointers[i]);
  2393.     screen_cleared = TRUE;     /* can use contents of NextScreen now */
  2394.     win_rest_invalid(firstwin);
  2395.     clear_cmdline = FALSE;
  2396.     redraw_cmdline = TRUE;
  2397.     if (must_redraw == CLEAR)     /* no need to clear again */
  2398. must_redraw = NOT_VALID;
  2399.     compute_cmdrow();
  2400.     msg_row = cmdline_row;     /* put cursor on last line for messages */
  2401.     msg_col = 0;
  2402.     screen_start();     /* don't know where cursor is now */
  2403.     msg_scrolled = 0;     /* can't scroll back */
  2404.     msg_didany = FALSE;
  2405.     msg_didout = FALSE;
  2406. }
  2407. /*
  2408.  * Clear one line in NextScreen.
  2409.  */
  2410.     static void
  2411. lineclear(p)
  2412.     char_u  *p;
  2413. {
  2414.     (void)vim_memset(p, ' ', (size_t)Columns);
  2415.     (void)vim_memset(p + Columns, 0, (size_t)Columns);
  2416. }
  2417. /*
  2418.  * Update curwin->w_topline and redraw if necessary.
  2419.  */
  2420.     void
  2421. update_topline_redraw()
  2422. {
  2423.     update_topline();
  2424.     if (must_redraw)
  2425. update_screen(must_redraw);
  2426. }
  2427. /*
  2428.  * Update curwin->w_topline to move the cursor onto the screen.
  2429.  */
  2430.     void
  2431. update_topline()
  2432. {
  2433.     long     line_count;
  2434.     int     temp;
  2435.     linenr_t     old_topline;
  2436.     if (!screen_valid(TRUE))
  2437. return;
  2438.     old_topline = curwin->w_topline;
  2439.     /*
  2440.      * If the buffer is empty, always set topline to 1.
  2441.      */
  2442.     if (bufempty()) /* special case - file is empty */
  2443.     {
  2444. if (curwin->w_topline != 1)
  2445.     redraw_later(NOT_VALID);
  2446. curwin->w_topline = 1;
  2447. curwin->w_botline = 2;
  2448. curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  2449.     }
  2450.     /*
  2451.      * If the cursor is above the top of the window, scroll the window to put
  2452.      * it at the top of the window.
  2453.      * If we weren't very close to begin with, we scroll to put the cursor in
  2454.      * the middle of the window.
  2455.      */
  2456.     else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
  2457. curwin->w_topline > 1)
  2458.     {
  2459. temp = curwin->w_height / 2 - 1;
  2460. if (temp < 2)
  2461.     temp = 2;
  2462. /* not very close, put cursor halfway screen */
  2463. if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
  2464.     scroll_cursor_halfway(FALSE);
  2465. else
  2466.     scroll_cursor_top((int)p_sj, FALSE);
  2467.     }