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 / amiga / vim46src.lha / vim-4.6 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-13  |  79.4 KB  |  3,406 lines

  1. /* vi:set ts=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. /*
  10.  * screen.c: code for displaying on the screen
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17. #include "ops.h"        /* For op_inclusive */
  18.  
  19. char *tgoto __PARMS((char *cm, int col, int line));
  20.  
  21. static int        canopt;            /* TRUE when cursor goto can be optimized */
  22. static int        attributes = 0;    /* current attributes for screen character*/
  23. static int         highlight_attr = 0;    /* attributes when highlighting on */
  24. #ifdef RIGHTLEFT
  25. static int        rightleft = 0;    /* set to 1 for right to left in screen_fill */
  26. #endif
  27.  
  28. static int win_line __ARGS((WIN *, linenr_t, int, int));
  29. static void comp_Botline_sub __ARGS((WIN *wp, linenr_t lnum, int done));
  30. static void screen_char __ARGS((char_u *, int, int));
  31. static void screenclear2 __ARGS((void));
  32. static void lineclear __ARGS((char_u *p));
  33. static int screen_ins_lines __ARGS((int, int, int, int));
  34.  
  35. /*
  36.  * updateline() - like updateScreen() but only for cursor line
  37.  *
  38.  * Check if the size of the cursor line has changed.  If it did change, lines
  39.  * below the cursor will move up or down and we need to call the routine
  40.  * updateScreen() to examine the entire screen.
  41.  */
  42.     void
  43. updateline()
  44. {
  45.     int         row;
  46.     int         n;
  47.  
  48.     if (!screen_valid(TRUE))
  49.         return;
  50.  
  51.     if (must_redraw)                    /* must redraw whole screen */
  52.     {
  53.         updateScreen(must_redraw);
  54.         return;
  55.     }
  56.  
  57.     if (RedrawingDisabled)
  58.     {
  59.         must_redraw = NOT_VALID;        /* remember to update later */
  60.         return;
  61.     }
  62.  
  63.     cursor_off();
  64.  
  65.     (void)set_highlight('v');
  66.     row = win_line(curwin, curwin->w_cursor.lnum,
  67.                                        curwin->w_cline_row, curwin->w_height);
  68.  
  69.     if (row == curwin->w_height + 1)    /* line too long for window */
  70.     {
  71.             /* window needs to be scrolled up to show the cursor line */
  72.         if (curwin->w_topline < curwin->w_cursor.lnum)
  73.             ++curwin->w_topline;
  74.         updateScreen(VALID_TO_CURSCHAR);
  75.         cursupdate();
  76.     }
  77.     else if (!dollar_vcol)
  78.     {
  79.         n = row - curwin->w_cline_row;
  80.         if (n != curwin->w_cline_height)        /* line changed size */
  81.         {
  82.             if (n < curwin->w_cline_height)     /* got smaller: delete lines */
  83.                 win_del_lines(curwin, row,
  84.                                      curwin->w_cline_height - n, FALSE, TRUE);
  85.             else                                /* got bigger: insert lines */
  86.                 win_ins_lines(curwin,
  87.                                  curwin->w_cline_row + curwin->w_cline_height,
  88.                                      n - curwin->w_cline_height, FALSE, TRUE);
  89.             updateScreen(VALID_TO_CURSCHAR);
  90.         }
  91.         else if (clear_cmdline || redraw_cmdline)
  92.             showmode();                /* clear cmdline, show mode and ruler */
  93.     }
  94. }
  95.  
  96. /*
  97.  * update all windows that are editing the current buffer
  98.  */
  99.     void
  100. update_curbuf(type)
  101.     int            type;
  102. {
  103.     WIN                *wp;
  104.  
  105.     for (wp = firstwin; wp; wp = wp->w_next)
  106.         if (wp->w_buffer == curbuf && wp->w_redr_type < type)
  107.             wp->w_redr_type = type;
  108.     updateScreen(type);
  109. }
  110.  
  111. /*
  112.  * updateScreen()
  113.  *
  114.  * Based on the current value of curwin->w_topline, transfer a screenfull
  115.  * of stuff from Filemem to NextScreen, and update curwin->w_botline.
  116.  */
  117.  
  118.     void
  119. updateScreen(type)
  120.     int             type;
  121. {
  122.     WIN                *wp;
  123.  
  124.     if (!screen_valid(TRUE))
  125.         return;
  126.  
  127.     dollar_vcol = 0;
  128.  
  129.     if (must_redraw)
  130.     {
  131.         if (type < must_redraw)        /* use maximal type */
  132.             type = must_redraw;
  133.         must_redraw = 0;
  134.     }
  135.  
  136.     if (type == CURSUPD)        /* update cursor and then redraw NOT_VALID */
  137.     {
  138.         curwin->w_lsize_valid = 0;
  139.         cursupdate();                    /* may call updateScreen() */
  140.         if (curwin->w_lsize_valid != 0)    /* did call updateScreen() */
  141.             return;
  142.         type = NOT_VALID;
  143.     }
  144.     else if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
  145.         type = NOT_VALID;
  146.  
  147.      if (RedrawingDisabled)
  148.     {
  149.         must_redraw = type;        /* remember type for next time */
  150.         curwin->w_redr_type = type;
  151.         curwin->w_lsize_valid = 0;        /* don't use w_lsize[] now */
  152.         return;
  153.     }
  154.  
  155.     /*
  156.      * if the screen was scrolled up when displaying a message, scroll it down
  157.      */
  158.     if (msg_scrolled)
  159.     {
  160.         clear_cmdline = TRUE;
  161.         if (msg_scrolled > Rows - 5)        /* clearing is faster */
  162.             type = CLEAR;
  163.         else if (type != CLEAR)
  164.         {
  165.             if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
  166.                 type = CLEAR;
  167.             win_rest_invalid(firstwin);        /* should do only first/last few */
  168.         }
  169.         msg_scrolled = 0;
  170.         need_wait_return = FALSE;
  171.     }
  172.  
  173.     /*
  174.      * reset cmdline_row now (may have been changed temporarily)
  175.      */
  176.     compute_cmdrow();
  177.  
  178.     if (type == CLEAR)            /* first clear screen */
  179.     {
  180.         screenclear();            /* will reset clear_cmdline */
  181.         type = NOT_VALID;
  182.     }
  183.  
  184.     if (clear_cmdline)            /* first clear cmdline */
  185.     {
  186.         if (emsg_on_display)
  187.         {
  188.             mch_delay(1000L, TRUE);
  189.             emsg_on_display = FALSE;
  190.         }
  191.         msg_row = cmdline_row;
  192.         msg_col = 0;
  193.         msg_clr_eos();            /* will reset clear_cmdline */
  194.     }
  195.  
  196. /* return if there is nothing to do */
  197.     if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0]) ||
  198.             (type == INVERTED &&
  199.                     curwin->w_old_cursor_lnum == curwin->w_cursor.lnum &&
  200.                     curwin->w_old_cursor_vcol == curwin->w_virtcol &&
  201.                     curwin->w_old_curswant == curwin->w_curswant)))
  202.     {
  203.         /*
  204.          * go from top to bottom through the windows, redrawing the ones that
  205.          * need it
  206.          */
  207.         curwin->w_redr_type = type;
  208.         cursor_off();
  209.         for (wp = firstwin; wp; wp = wp->w_next)
  210.         {
  211.             if (wp->w_redr_type)
  212.                 win_update(wp);
  213.             if (wp->w_redr_status)
  214.                 win_redr_status(wp);
  215.         }
  216.     }
  217.     if (redraw_cmdline)
  218.         showmode();
  219. }
  220.  
  221. #ifdef USE_GUI
  222. /*
  223.  * Update a single window, its status line and maybe the command line msg.
  224.  * Used for the GUI scrollbar.
  225.  */
  226.     void
  227. updateWindow(wp)
  228.     WIN        *wp;
  229. {
  230.     win_update(wp);
  231.     if (wp->w_redr_status)
  232.         win_redr_status(wp);
  233.     if (redraw_cmdline)
  234.         showmode();
  235. }
  236. #endif
  237.  
  238. /*
  239.  * update a single window
  240.  *
  241.  * This may cause the windows below it also to be redrawn
  242.  */
  243.     void
  244. win_update(wp)
  245.     WIN        *wp;
  246. {
  247.     int                type = wp->w_redr_type;
  248.     register int    row;
  249.     register int    endrow;
  250.     linenr_t        lnum;
  251.     linenr_t        lastline = 0;    /* only valid if endrow != Rows -1 */
  252.     int                done;            /* if TRUE, we hit the end of the file */
  253.     int                didline;        /* if TRUE, we finished the last line */
  254.     int             srow = 0;        /* starting row of the current line */
  255.     int             idx;
  256.     int             i;
  257.     long             j;
  258.  
  259.     if (type == NOT_VALID)
  260.     {
  261.         wp->w_redr_status = TRUE;
  262.         wp->w_lsize_valid = 0;
  263.     }
  264.  
  265.     idx = 0;
  266.     row = 0;
  267.     lnum = wp->w_topline;
  268.  
  269.     /* The number of rows shown is w_height. */
  270.     /* The default last row is the status/command line. */
  271.     endrow = wp->w_height;
  272.  
  273.     if (type == VALID || type == VALID_TO_CURSCHAR)
  274.     {
  275.         /*
  276.          * We handle two special cases:
  277.          * 1: we are off the top of the screen by a few lines: scroll down
  278.          * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
  279.          */
  280.         if (wp->w_topline < wp->w_lsize_lnum[0])    /* may scroll down */
  281.         {
  282.             j = wp->w_lsize_lnum[0] - wp->w_topline;
  283.             if (j < wp->w_height - 2)                /* not too far off */
  284.             {
  285.                 lastline = wp->w_lsize_lnum[0] - 1;
  286.                 i = plines_m_win(wp, wp->w_topline, lastline);
  287.                 if (i < wp->w_height - 2)        /* less than a screen off */
  288.                 {
  289.                     /*
  290.                      * Try to insert the correct number of lines.
  291.                      * If not the last window, delete the lines at the bottom.
  292.                      * win_ins_lines may fail.
  293.                      */
  294.                     if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK &&
  295.                                                     wp->w_lsize_valid)
  296.                     {
  297.                         endrow = i;
  298.  
  299.                         if ((wp->w_lsize_valid += j) > wp->w_height)
  300.                             wp->w_lsize_valid = wp->w_height;
  301.                         for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
  302.                         {
  303.                             wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
  304.                             wp->w_lsize[idx] = wp->w_lsize[idx - j];
  305.                         }
  306.                         idx = 0;
  307.                     }
  308.                 }
  309.                 else if (lastwin == firstwin)
  310.                     screenclear();    /* far off: clearing the screen is faster */
  311.             }
  312.             else if (lastwin == firstwin)
  313.                 screenclear();        /* far off: clearing the screen is faster */
  314.         }
  315.         else                            /* may scroll up */
  316.         {
  317.             j = -1;
  318.                         /* try to find wp->w_topline in wp->w_lsize_lnum[] */
  319.             for (i = 0; i < wp->w_lsize_valid; i++)
  320.             {
  321.                 if (wp->w_lsize_lnum[i] == wp->w_topline)
  322.                 {
  323.                     j = i;
  324.                     break;
  325.                 }
  326.                 row += wp->w_lsize[i];
  327.             }
  328.             if (j == -1)    /* wp->w_topline is not in wp->w_lsize_lnum */
  329.             {
  330.                 row = 0;
  331.                 if (lastwin == firstwin)
  332.                     screenclear();    /* far off: clearing the screen is faster */
  333.             }
  334.             else
  335.             {
  336.                 /*
  337.                  * Try to delete the correct number of lines.
  338.                  * wp->w_topline is at wp->w_lsize_lnum[i].
  339.                  */
  340.                 if ((row == 0 || win_del_lines(wp, 0, row,
  341.                             FALSE, wp == firstwin) == OK) && wp->w_lsize_valid)
  342.                 {
  343.                     srow = row;
  344.                     row = 0;
  345.                     for (;;)
  346.                     {
  347.                         if (type == VALID_TO_CURSCHAR &&
  348.                                                     lnum == wp->w_cursor.lnum)
  349.                                 break;
  350.                         if (row + srow + (int)wp->w_lsize[j] >= wp->w_height)
  351.                                 break;
  352.                         wp->w_lsize[idx] = wp->w_lsize[j];
  353.                         wp->w_lsize_lnum[idx] = lnum++;
  354.  
  355.                         row += wp->w_lsize[idx++];
  356.                         if ((int)++j >= wp->w_lsize_valid)
  357.                             break;
  358.                     }
  359.                     wp->w_lsize_valid = idx;
  360.                 }
  361.                 else
  362.                     row = 0;        /* update all lines */
  363.             }
  364.         }
  365.         if (endrow == wp->w_height && idx == 0)     /* no scrolling */
  366.                 wp->w_lsize_valid = 0;
  367.     }
  368.  
  369.     done = didline = FALSE;
  370.  
  371.     if (VIsual_active)        /* check if we are updating the inverted part */
  372.     {
  373.         linenr_t    from, to;
  374.  
  375.     /* find the line numbers that need to be updated */
  376.         if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
  377.         {
  378.             from = curwin->w_cursor.lnum;
  379.             to = wp->w_old_cursor_lnum;
  380.         }
  381.         else
  382.         {
  383.             from = wp->w_old_cursor_lnum;
  384.             to = curwin->w_cursor.lnum;
  385.         }
  386.             /* if VIsual changed, update the maximal area */
  387.         if (VIsual.lnum != wp->w_old_visual_lnum)
  388.         {
  389.             if (wp->w_old_visual_lnum < from)
  390.                 from = wp->w_old_visual_lnum;
  391.             if (wp->w_old_visual_lnum > to)
  392.                 to = wp->w_old_visual_lnum;
  393.             if (VIsual.lnum < from)
  394.                 from = VIsual.lnum;
  395.             if (VIsual.lnum > to)
  396.                 to = VIsual.lnum;
  397.         }
  398.     /* if in block mode and changed column or wp->w_curswant: update all
  399.      * lines */
  400.         if (VIsual_mode == Ctrl('V') &&
  401.                         (curwin->w_virtcol != wp->w_old_cursor_vcol ||
  402.                         wp->w_curswant != wp->w_old_curswant))
  403.         {
  404.             if (from > VIsual.lnum)
  405.                 from = VIsual.lnum;
  406.             if (to < VIsual.lnum)
  407.                 to = VIsual.lnum;
  408.         }
  409.  
  410.         if (from < wp->w_topline)
  411.             from = wp->w_topline;
  412.         if (from >= wp->w_botline)
  413.             from = wp->w_botline - 1;
  414.         if (to >= wp->w_botline)
  415.             to = wp->w_botline - 1;
  416.  
  417.     /* find the minimal part to be updated */
  418.         if (type == INVERTED)
  419.         {
  420.             while (lnum < from)                        /* find start */
  421.             {
  422.                 row += wp->w_lsize[idx++];
  423.                 ++lnum;
  424.             }
  425.             srow = row;
  426.             for (j = idx; j < wp->w_lsize_valid; ++j)    /* find end */
  427.             {
  428.                 if (wp->w_lsize_lnum[j] == to + 1)
  429.                 {
  430.                     endrow = srow;
  431.                     break;
  432.                 }
  433.                 srow += wp->w_lsize[j];
  434.             }
  435.         }
  436.  
  437.     /* if we update the lines between from and to set old_cursor */
  438.         if (type == INVERTED || (lnum <= from &&
  439.                                   (endrow == wp->w_height || lastline >= to)))
  440.         {
  441.             wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
  442.             wp->w_old_cursor_vcol = curwin->w_virtcol;
  443.             wp->w_old_visual_lnum = VIsual.lnum;
  444.             wp->w_old_curswant = wp->w_curswant;
  445.         }
  446.     }
  447.     else
  448.     {
  449.         wp->w_old_cursor_lnum = 0;
  450.         wp->w_old_visual_lnum = 0;
  451.     }
  452.  
  453.     (void)set_highlight('v');
  454.  
  455.     /*
  456.      * Update the screen rows from "row" to "endrow".
  457.      * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
  458.      */
  459.     for (;;)
  460.     {
  461.         if (lnum > wp->w_buffer->b_ml.ml_line_count)
  462.         {
  463.             done = TRUE;        /* hit the end of the file */
  464.             break;
  465.         }
  466.         srow = row;
  467.         row = win_line(wp, lnum, srow, endrow);
  468.         if (row > endrow)        /* past end of screen */
  469.         {                        /* we may need the size of that */
  470.             wp->w_lsize[idx] = plines_win(wp, lnum);
  471.             wp->w_lsize_lnum[idx++] = lnum;        /* too long line later on */
  472.             break;
  473.         }
  474.  
  475.         wp->w_lsize[idx] = row - srow;
  476.         wp->w_lsize_lnum[idx++] = lnum;
  477.         if (++lnum > wp->w_buffer->b_ml.ml_line_count)
  478.         {
  479.             done = TRUE;
  480.             break;
  481.         }
  482.  
  483.         if (row == endrow)
  484.         {
  485.             didline = TRUE;
  486.             break;
  487.         }
  488.     }
  489.     if (idx > wp->w_lsize_valid)
  490.         wp->w_lsize_valid = idx;
  491.  
  492.     /* Do we have to do off the top of the screen processing ? */
  493.     if (endrow != wp->w_height)
  494.     {
  495.         row = 0;
  496.         for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
  497.             row += wp->w_lsize[idx];
  498.  
  499.         if (row < wp->w_height)
  500.         {
  501.             done = TRUE;
  502.         }
  503.         else if (row > wp->w_height)    /* Need to blank out the last line */
  504.         {
  505.             lnum = wp->w_lsize_lnum[idx - 1];
  506.             srow = row - wp->w_lsize[idx - 1];
  507.             didline = FALSE;
  508.         }
  509.         else
  510.         {
  511.             lnum = wp->w_lsize_lnum[idx - 1] + 1;
  512.             didline = TRUE;
  513.         }
  514.     }
  515.  
  516.     wp->w_empty_rows = 0;
  517.     /*
  518.      * If we didn't hit the end of the file, and we didn't finish the last
  519.      * line we were working on, then the line didn't fit.
  520.      */
  521.     if (!done && !didline)
  522.     {
  523.         if (lnum == wp->w_topline)
  524.         {
  525.             /*
  526.              * Single line that does not fit!
  527.              * Fill last line with '@' characters.
  528.              */
  529.             screen_fill(wp->w_winpos + wp->w_height - 1,
  530.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@');
  531.             wp->w_botline = lnum + 1;
  532.         }
  533.         else
  534.         {
  535.             /*
  536.              * Clear the rest of the screen and mark the unused lines.
  537.              */
  538. #ifdef RIGHTLEFT
  539.             if (wp->w_p_rl)
  540.                 rightleft = 1;
  541. #endif
  542.             screen_fill(wp->w_winpos + srow,
  543.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ');
  544. #ifdef RIGHTLEFT
  545.             rightleft = 0;
  546. #endif
  547.             wp->w_botline = lnum;
  548.             wp->w_empty_rows = wp->w_height - srow;
  549.         }
  550.     }
  551.     else
  552.     {
  553.         /* make sure the rest of the screen is blank */
  554.         /* put '~'s on rows that aren't part of the file. */
  555. #ifdef RIGHTLEFT
  556.         if (wp->w_p_rl)
  557.             rightleft = 1;
  558. #endif
  559.         screen_fill(wp->w_winpos + row,
  560.                     wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ');
  561. #ifdef RIGHTLEFT
  562.         rightleft = 0;
  563. #endif
  564.         wp->w_empty_rows = wp->w_height - row;
  565.  
  566.         if (done)                /* we hit the end of the file */
  567.             wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
  568.         else
  569.             wp->w_botline = lnum;
  570.     }
  571.  
  572.     wp->w_redr_type = 0;
  573. }
  574.  
  575. /*
  576.  * mark all status lines for redraw; used after first :cd
  577.  */
  578.     void
  579. status_redraw_all()
  580. {
  581.     WIN        *wp;
  582.  
  583.     for (wp = firstwin; wp; wp = wp->w_next)
  584.         wp->w_redr_status = TRUE;
  585.     updateScreen(NOT_VALID);
  586. }
  587.  
  588. /*
  589.  * Redraw the status line of window wp.
  590.  *
  591.  * If inversion is possible we use it. Else '=' characters are used.
  592.  */
  593.     void
  594. win_redr_status(wp)
  595.     WIN        *wp;
  596. {
  597.     int        row;
  598.     char_u    *p;
  599.     int        len;
  600.     int        fillchar;
  601.  
  602.     if (wp->w_status_height)                    /* if there is a status line */
  603.     {
  604.         if (set_highlight('s') == OK)            /* can highlight */
  605.         {
  606.             fillchar = ' ';
  607.             start_highlight();
  608.         }
  609.         else                                    /* can't highlight, use '=' */
  610.             fillchar = '=';
  611.  
  612.         p = wp->w_buffer->b_xfilename;
  613.         if (p == NULL)
  614.             STRCPY(NameBuff, "[No File]");
  615.         else
  616.         {
  617.             home_replace(wp->w_buffer, p, NameBuff, MAXPATHL);
  618.             trans_characters(NameBuff, MAXPATHL);
  619.         }
  620.         p = NameBuff;
  621.         len = STRLEN(p);
  622.  
  623.         if (wp->w_buffer->b_help || wp->w_buffer->b_changed ||
  624.                                                          wp->w_buffer->b_p_ro)
  625.             *(p + len++) = ' ';
  626.         if (wp->w_buffer->b_help)
  627.         {
  628.             STRCPY(p + len, "[help]");
  629.             len += 6;
  630.         }
  631.         if (wp->w_buffer->b_changed)
  632.         {
  633.             STRCPY(p + len, "[+]");
  634.             len += 3;
  635.         }
  636.         if (wp->w_buffer->b_p_ro)
  637.         {
  638.             STRCPY(p + len, "[RO]");
  639.             len += 4;
  640.         }
  641.  
  642.         if (len > ru_col - 1)
  643.         {
  644.             p += len - (ru_col - 1);
  645.             *p = '<';
  646.             len = ru_col - 1;
  647.         }
  648.  
  649.         row = wp->w_winpos + wp->w_height;
  650.         screen_msg(p, row, 0);
  651.         screen_fill(row, row + 1, len, ru_col, fillchar, fillchar);
  652.  
  653.         stop_highlight();
  654.         win_redr_ruler(wp, TRUE);
  655.     }
  656.     else    /* no status line, can only be last window */
  657.         redraw_cmdline = TRUE;
  658.     wp->w_redr_status = FALSE;
  659. }
  660.  
  661. /*
  662.  * display line "lnum" of window 'wp' on the screen
  663.  * Start at row "startrow", stop when "endrow" is reached.
  664.  * Return the number of last row the line occupies.
  665.  */
  666.  
  667.     static int
  668. win_line(wp, lnum, startrow, endrow)
  669.     WIN                *wp;
  670.     linenr_t        lnum;
  671.     int             startrow;
  672.     int             endrow;
  673. {
  674.     char_u             *screenp;
  675.     int                c;
  676.     int                col;                /* visual column on screen */
  677.     long            vcol;                /* visual column for tabs */
  678.     int                row;                /* row in the window, excl w_winpos */
  679.     int                screen_row;            /* row on the screen, incl w_winpos */
  680.     char_u            *ptr;
  681.     char_u            extra[16];            /* "%ld" must fit in here */
  682.     char_u            *p_extra;
  683.     char_u            *showbreak = NULL;
  684.     int             n_extra;
  685.     int                n_spaces = 0;
  686.  
  687.     int                fromcol, tocol;        /* start/end of inverting */
  688.     int                noinvcur = FALSE;    /* don't invert the cursor */
  689.     FPOS            *top, *bot;
  690.  
  691.     if (startrow > endrow)                /* past the end already! */
  692.         return startrow;
  693.  
  694.     row = startrow;
  695.     screen_row = row + wp->w_winpos;
  696.     col = 0;
  697.     vcol = 0;
  698.     fromcol = -10;
  699.     tocol = MAXCOL;
  700.     canopt = TRUE;
  701.  
  702.     /*
  703.      * handle visual active in this window
  704.      */
  705.     if (VIsual_active && wp->w_buffer == curwin->w_buffer)
  706.     {
  707.                                         /* Visual is after curwin->w_cursor */
  708.         if (ltoreq(curwin->w_cursor, VIsual))
  709.         {
  710.             top = &curwin->w_cursor;
  711.             bot = &VIsual;
  712.         }
  713.         else                            /* Visual is before curwin->w_cursor */
  714.         {
  715.             top = &VIsual;
  716.             bot = &curwin->w_cursor;
  717.         }
  718.         if (VIsual_mode == Ctrl('V'))    /* block mode */
  719.         {
  720.             if (lnum >= top->lnum && lnum <= bot->lnum)
  721.             {
  722.                 colnr_t        from, to;
  723.  
  724.                 getvcol(wp, top, (colnr_t *)&fromcol, NULL, (colnr_t *)&tocol);
  725.                 getvcol(wp, bot, &from, NULL, &to);
  726.                 if ((int)from < fromcol)
  727.                     fromcol = from;
  728.                 if ((int)to > tocol)
  729.                     tocol = to;
  730.                 ++tocol;
  731.  
  732.                 if (wp->w_curswant == MAXCOL)
  733.                     tocol = MAXCOL;
  734.             }
  735.         }
  736.         else                            /* non-block mode */
  737.         {
  738.             if (lnum > top->lnum && lnum <= bot->lnum)
  739.                 fromcol = 0;
  740.             else if (lnum == top->lnum)
  741.                 getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
  742.             if (lnum == bot->lnum)
  743.             {
  744.                 getvcol(wp, bot, NULL, NULL, (colnr_t *)&tocol);
  745.                 ++tocol;
  746.             }
  747.  
  748.             if (VIsual_mode == 'V')        /* linewise */
  749.             {
  750.                 if (fromcol > 0)
  751.                     fromcol = 0;
  752.                 tocol = MAXCOL;
  753.             }
  754.         }
  755.             /* if the cursor can't be switched off, don't invert the
  756.              * character where the cursor is */
  757. #ifndef MSDOS
  758.         if (!highlight_match && *T_VI == NUL &&
  759.                             lnum == curwin->w_cursor.lnum && wp == curwin)
  760.             noinvcur = TRUE;
  761. #endif
  762.  
  763.         if (tocol <= (int)wp->w_leftcol)    /* inverting is left of screen */
  764.             fromcol = 0;
  765.                                         /* start of invert is left of screen */
  766.         else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
  767.             fromcol = wp->w_leftcol;
  768.  
  769.         /* if inverting in this line, can't optimize cursor positioning */
  770.         if (fromcol >= 0)
  771.             canopt = FALSE;
  772.     }
  773.     /*
  774.      * handle incremental search position highlighting
  775.      */
  776.     else if (highlight_match && wp == curwin && search_match_len)
  777.     {
  778.         if (lnum == curwin->w_cursor.lnum)
  779.         {
  780.             getvcol(curwin, &(curwin->w_cursor),
  781.                                             (colnr_t *)&fromcol, NULL, NULL);
  782.             curwin->w_cursor.col += search_match_len;
  783.             getvcol(curwin, &(curwin->w_cursor),
  784.                                             (colnr_t *)&tocol, NULL, NULL);
  785.             curwin->w_cursor.col -= search_match_len;
  786.             canopt = FALSE;
  787.             if (fromcol == tocol)        /* do at least one character */
  788.                 tocol = fromcol + 1;    /* happens when past end of line */
  789.         }
  790.     }
  791.  
  792.     ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
  793.     if (!wp->w_p_wrap)        /* advance to first character to be displayed */
  794.     {
  795.         while ((colnr_t)vcol < wp->w_leftcol && *ptr)
  796.             vcol += win_chartabsize(wp, *ptr++, (colnr_t)vcol);
  797.         if ((colnr_t)vcol > wp->w_leftcol)
  798.         {
  799.             n_spaces = vcol - wp->w_leftcol;    /* begin with some spaces */
  800.             vcol = wp->w_leftcol;
  801.         }
  802.     }
  803.     screenp = LinePointers[screen_row];
  804. #ifdef RIGHTLEFT
  805.     if (wp->w_p_rl)
  806.     {
  807.         col = Columns - 1;                    /* col follows screenp here */
  808.         screenp += Columns - 1;
  809.     }
  810. #endif
  811.     if (wp->w_p_nu)
  812.     {
  813. #ifdef RIGHTLEFT
  814.         if (wp->w_p_rl)                        /* reverse line numbers */
  815.         {
  816.             char_u *c1, *c2, t;
  817.  
  818.             sprintf((char *)extra, " %-7ld", (long)lnum);
  819.             for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
  820.                                                                    c1++, c2--)
  821.             {
  822.                 t = *c1;
  823.                 *c1 = *c2;
  824.                 *c2 = t;
  825.             }
  826.         }
  827.         else
  828. #endif
  829.             sprintf((char *)extra, "%7ld ", (long)lnum);
  830.         p_extra = extra;
  831.         n_extra = 8;
  832.         vcol -= 8;        /* so vcol is 0 when line number has been printed */
  833.     }
  834.     else
  835.     {
  836.         p_extra = NULL;
  837.         n_extra = 0;
  838.     }
  839.     for (;;)
  840.     {
  841.         if (!canopt)    /* Visual or match highlighting in this line */
  842.         {
  843.             if (((vcol == fromcol && !(noinvcur &&
  844.                                            (colnr_t)vcol == wp->w_virtcol)) ||
  845.                     (noinvcur && (colnr_t)vcol == wp->w_virtcol + 1 &&
  846.                             vcol >= fromcol)) && vcol < tocol)
  847.                 start_highlight();        /* start highlighting */
  848.             else if (attributes && (vcol == tocol ||
  849.                                 (noinvcur && (colnr_t)vcol == wp->w_virtcol)))
  850.                 stop_highlight();        /* stop highlighting */
  851.         }
  852.  
  853.     /* Get the next character to put on the screen. */
  854.  
  855.         /*
  856.          * if 'showbreak' is set it contains the characters to put at the
  857.          * start of each broken line
  858.          */
  859.         if (
  860. #ifdef RIGHTLEFT
  861.             (wp->w_p_rl ? col == -1 : col == Columns)
  862. #else
  863.             col == Columns
  864. #endif
  865.             && (*ptr != NUL || (wp->w_p_list && n_extra == 0) ||
  866.                                         (n_extra && *p_extra) || n_spaces) &&
  867.                                               vcol != 0 && STRLEN(p_sbr) != 0)
  868.             showbreak = p_sbr;
  869.         if (showbreak != NULL)
  870.         {
  871.             c = *showbreak++;
  872.             if (*showbreak == NUL)
  873.                 showbreak = NULL;
  874.         }
  875.         /*
  876.          * The 'extra' array contains the extra stuff that is inserted to
  877.          * represent special characters (non-printable stuff).
  878.          */
  879.         else if (n_extra)
  880.         {
  881.             c = *p_extra++;
  882.             n_extra--;
  883.         }
  884.         else if (n_spaces)
  885.         {
  886.             c = ' ';
  887.             n_spaces--;
  888.         }
  889.         else
  890.         {
  891.             c = *ptr++;
  892.             /*
  893.              * Found last space before word: check for line break
  894.              */
  895.             if (wp->w_p_lbr && isbreak(c) && !isbreak(*ptr) && !wp->w_p_list)
  896.             {
  897.                 n_spaces = win_lbr_chartabsize(wp, ptr - 1,
  898.                                                      (colnr_t)vcol, NULL) - 1;
  899.                 if (vim_iswhite(c))
  900.                     c = ' ';
  901.             }
  902.             else if (!isprintchar(c))
  903.             {
  904.                 /*
  905.                  * when getting a character from the file, we may have to turn
  906.                  * it into something else on the way to putting it into
  907.                  * 'NextScreen'.
  908.                  */
  909.                 if (c == TAB && !wp->w_p_list)
  910.                 {
  911.                     /* tab amount depends on current column */
  912.                     n_spaces = (int)wp->w_buffer->b_p_ts -
  913.                                     vcol % (int)wp->w_buffer->b_p_ts - 1;
  914.                     c = ' ';
  915.                 }
  916.                 else if (c == NUL && wp->w_p_list)
  917.                 {
  918.                     p_extra = (char_u *)"";
  919.                     n_extra = 1;
  920.                     c = '$';
  921.                     --ptr;            /* put it back at the NUL */
  922.                 }
  923.                 else if (c != NUL)
  924.                 {
  925.                     p_extra = transchar(c);
  926.                     n_extra = charsize(c) - 1;
  927.                     c = *p_extra++;
  928.                 }
  929.             }
  930.         }
  931.  
  932.         if (c == NUL)
  933.         {
  934.             if (attributes)
  935.             {
  936.                 /* invert at least one char, used for Visual and empty line or
  937.                  * highlight match at end of line. If it's beyond the last
  938.                  * char on the screen, just overwrite that one (tricky!) */
  939.                 if (vcol == fromcol)
  940.                 {
  941. #ifdef RIGHTLEFT
  942.                     if (wp->w_p_rl)
  943.                     {
  944.                         if (col < 0)
  945.                         {
  946.                             ++screenp;
  947.                             ++col;
  948.                         }
  949.                     }
  950.                     else
  951. #endif
  952.                     {
  953.                         if (col >= Columns)
  954.                         {
  955.                             --screenp;
  956.                             --col;
  957.                         }
  958.                     }
  959.                     if (*screenp != ' ' || *(screenp + Columns) != attributes)
  960.                     {
  961.                             *screenp = ' ';
  962.                             *(screenp + Columns) = attributes;
  963.                             screen_char(screenp, screen_row, col);
  964.                     }
  965. #ifdef RIGHTLEFT
  966.                     if (wp->w_p_rl)
  967.                     {
  968.                         --screenp;
  969.                         --col;
  970.                     }
  971.                     else
  972. #endif
  973.                     {
  974.                         ++screenp;
  975.                         ++col;
  976.                     }
  977.                 }
  978.                 stop_highlight();
  979.             }
  980.             /* 
  981.              * blank out the rest of this row, if necessary
  982.              */
  983. #ifdef RIGHTLEFT
  984.             if (wp->w_p_rl)
  985.             {
  986.                 while (col >= 0 && *screenp == ' ' &&
  987.                                                     *(screenp + Columns) == 0)
  988.                 {
  989.                     --screenp;
  990.                     --col;
  991.                 }
  992.                 if (col >= 0)
  993.                     screen_fill(screen_row, screen_row + 1,
  994.                                                         0, col + 1, ' ', ' ');
  995.             }
  996.             else
  997. #endif
  998.             {
  999.                 while (col < Columns && *screenp == ' ' &&
  1000.                                                     *(screenp + Columns) == 0)
  1001.                 {
  1002.                     ++screenp;
  1003.                     ++col;
  1004.                 }
  1005.                 if (col < Columns)
  1006.                     screen_fill(screen_row, screen_row + 1,
  1007.                                                 col, (int)Columns, ' ', ' ');
  1008.             }
  1009.             row++;
  1010.             break;
  1011.         }
  1012.         if (
  1013. #ifdef RIGHTLEFT
  1014.             wp->w_p_rl ? (col < 0) : 
  1015. #endif
  1016.                                     (col >= Columns)
  1017.                                                     )
  1018.         {
  1019.             col = 0;
  1020.             ++row;
  1021.             ++screen_row;
  1022.             if (!wp->w_p_wrap)
  1023.                 break;
  1024.             if (row == endrow)        /* line got too long for screen */
  1025.             {
  1026.                 ++row;
  1027.                 break;
  1028.             }
  1029.             screenp = LinePointers[screen_row];
  1030. #ifdef RIGHTLEFT
  1031.             if (wp->w_p_rl)
  1032.             {
  1033.                 col = Columns - 1;        /* col is not used if breaking! */
  1034.                 screenp += Columns - 1;
  1035.             }
  1036. #endif
  1037.         }
  1038.  
  1039.         /*
  1040.          * Store the character in NextScreen.
  1041.          */
  1042.         if (*screenp != c || *(screenp + Columns) != attributes)
  1043.         {
  1044.             /*
  1045.              * Special trick to make copy/paste of wrapped lines work with
  1046.              * xterm/screen:
  1047.              *   If the first column is to be written, write the preceding
  1048.              *   char twice.  This will work with all terminal types
  1049.              *   (regardless of the xn,am settings).
  1050.              * Only do this on a fast tty.
  1051.              */
  1052.             if (p_tf && row > startrow && col == 0 &&
  1053.                     LinePointers[screen_row - 1][Columns - 1 + Columns] ==
  1054.                         attributes)
  1055.             {
  1056.                 if (screen_cur_row != screen_row - 1 ||
  1057.                                                     screen_cur_col != Columns)
  1058.                     screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1059.                                           screen_row - 1, (int)(Columns - 1));
  1060.                 screen_char(LinePointers[screen_row - 1] + Columns - 1,
  1061.                                                 screen_row - 1, (int)Columns);    
  1062.                 screen_start();
  1063.             }
  1064.  
  1065.             *screenp = c;
  1066.             *(screenp + Columns) = attributes;
  1067.             screen_char(screenp, screen_row, col);
  1068.         }
  1069. #ifdef RIGHTLEFT
  1070.         if (wp->w_p_rl)
  1071.         {
  1072.             --screenp;
  1073.             --col;
  1074.         }
  1075.         else
  1076. #endif
  1077.         {
  1078.             ++screenp;
  1079.             ++col;
  1080.         }
  1081.         ++vcol;
  1082.             /* stop before '$' of change command */
  1083.         if (wp == curwin && dollar_vcol && vcol >= (long)wp->w_virtcol)
  1084.             break;
  1085.     }
  1086.  
  1087.     stop_highlight();
  1088.     return (row);
  1089. }
  1090.  
  1091. /*
  1092.  * Called when p_dollar is set: display a '$' at the end of the changed text
  1093.  * Only works when cursor is in the line that changes.
  1094.  */
  1095.     void
  1096. display_dollar(col)
  1097.     colnr_t        col;
  1098. {
  1099.     colnr_t    save_col;
  1100.  
  1101.     if (RedrawingDisabled)
  1102.         return;
  1103.  
  1104.     cursor_off();
  1105.     save_col = curwin->w_cursor.col;
  1106.     curwin->w_cursor.col = col;
  1107.     curs_columns(FALSE);
  1108.     if (!curwin->w_p_wrap)
  1109.         curwin->w_col -= curwin->w_leftcol;
  1110.     if (curwin->w_col < Columns)
  1111.     {
  1112.         screen_msg((char_u *)"$", curwin->w_winpos + curwin->w_row,
  1113. #ifdef RIGHTLEFT
  1114.                 curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
  1115. #endif
  1116.                                                                curwin->w_col);
  1117.         dollar_vcol = curwin->w_virtcol;
  1118.     }
  1119.     curwin->w_cursor.col = save_col;
  1120. }
  1121.  
  1122. /*
  1123.  * Call this function before moving the cursor from the normal insert position
  1124.  * in insert mode.
  1125.  */
  1126.     void
  1127. undisplay_dollar()
  1128. {
  1129.     if (dollar_vcol)
  1130.     {
  1131.         dollar_vcol = 0;
  1132.         updateline();
  1133.     }
  1134. }
  1135.  
  1136. /*
  1137.  * output a single character directly to the screen
  1138.  * update NextScreen
  1139.  */
  1140.     void
  1141. screen_outchar(c, row, col)
  1142.     int        c;
  1143.     int        row, col;
  1144. {
  1145.     char_u        buf[2];
  1146.  
  1147.     buf[0] = c;
  1148.     buf[1] = NUL;
  1149.     screen_msg(buf, row, col);
  1150. }
  1151.     
  1152. /*
  1153.  * put string '*text' on the screen at position 'row' and 'col'
  1154.  * update NextScreen
  1155.  * Note: only outputs within one row, message is truncated at screen boundary!
  1156.  * Note: if NextScreen, row and/or col is invalid, nothing is done.
  1157.  */
  1158.     void
  1159. screen_msg(text, row, col)
  1160.     char_u    *text;
  1161.     int        row;
  1162.     int        col;
  1163. {
  1164.     char_u    *screenp;
  1165.  
  1166.     if (NextScreen != NULL && row < Rows)            /* safety check */
  1167.     {
  1168.         screenp = LinePointers[row] + col;
  1169.         while (*text && col < Columns)
  1170.         {
  1171.             if (*screenp != *text || *(screenp + Columns) != attributes)
  1172.             {
  1173.                 *screenp = *text;
  1174.                 *(screenp + Columns) = attributes;
  1175.                 screen_char(screenp, row, col);
  1176.             }
  1177.             ++screenp;
  1178.             ++col;
  1179.             ++text;
  1180.         }
  1181.     }
  1182. }
  1183.  
  1184. /*
  1185.  * Reset cursor position. Use whenever cursor was moved because of outputting
  1186.  * something directly to the screen (shell commands) or a terminal control
  1187.  * code.
  1188.  */
  1189.     void
  1190. screen_start()
  1191. {
  1192.     screen_cur_row = screen_cur_col = 9999;
  1193. }
  1194.  
  1195. /*
  1196.  * set_highlight - set highlight depending on 'highlight' option and context.
  1197.  *
  1198.  * return FAIL if highlighting is not possible, OK otherwise
  1199.  */
  1200.     int
  1201. set_highlight(context)
  1202.     int        context;
  1203. {
  1204.     int        i;
  1205.     int        mode;
  1206.     char_u    *p;
  1207.  
  1208.     /*
  1209.      * Try to find the mode in the 'highlight' option.
  1210.      * If not found, try the default for the 'highlight' option.
  1211.      * If still not found, use 'r' (should not happen).
  1212.      */
  1213.     mode = 'r';
  1214.     for (i = 0; i < 2; ++i)
  1215.     {
  1216.         if (i)
  1217.             p = get_highlight_default();
  1218.         else
  1219.             p = p_hl;
  1220.         if (p == NULL)
  1221.             continue;
  1222.  
  1223.         while (*p)
  1224.         {
  1225.             if (*p == context)                /* found what we are looking for */
  1226.                 break;
  1227.             while (*p && *p != ',')            /* skip to comma */
  1228.                 ++p;
  1229.             p = skip_to_option_part(p);        /* skip comma and spaces */
  1230.         }
  1231.         if (p[0] && p[1])
  1232.         {
  1233.             mode = p[1];
  1234.             break;
  1235.         }
  1236.     }
  1237.  
  1238.     switch (mode)
  1239.     {
  1240.         case 'b':    highlight = T_MD;        /* bold */
  1241.                     unhighlight = T_ME;
  1242.                     highlight_attr = CHAR_BOLD;
  1243.                     break;
  1244.         case 's':    highlight = T_SO;        /* standout */
  1245.                     unhighlight = T_SE;
  1246.                     highlight_attr = CHAR_STDOUT;
  1247.                     break;
  1248.         case 'n':    highlight = NULL;        /* no highlighting */
  1249.                     unhighlight = NULL;
  1250.                     highlight_attr = 0;
  1251.                     break;
  1252.         case 'u':    highlight = T_US;        /* underline */
  1253.                     unhighlight = T_UE;
  1254.                     highlight_attr = CHAR_UNDERL;
  1255.                     break;
  1256.         case 'i':    highlight = T_CZH;        /* italic */
  1257.                     unhighlight = T_CZR;
  1258.                     highlight_attr = CHAR_ITALIC;
  1259.                     break;
  1260.         default:    highlight = T_MR;        /* reverse (invert) */
  1261.                     unhighlight = T_ME;
  1262.                     highlight_attr = CHAR_INVERT;
  1263.                     break;
  1264.     }
  1265.     if (highlight == NULL || *highlight == NUL ||
  1266.                         unhighlight == NULL || *unhighlight == NUL)
  1267.     {
  1268.         highlight = NULL;
  1269.         return FAIL;
  1270.     }
  1271.     return OK;
  1272. }
  1273.  
  1274.     void
  1275. start_highlight()
  1276. {
  1277.     if (full_screen &&
  1278. #ifdef WIN32
  1279.                         termcap_active &&
  1280. #endif
  1281.                                             highlight != NULL)
  1282.     {
  1283.         outstr(highlight);
  1284.         attributes = highlight_attr;
  1285.     }
  1286. }
  1287.  
  1288.     void
  1289. stop_highlight()
  1290. {
  1291.     if (attributes)
  1292.     {
  1293.         outstr(unhighlight);
  1294.         attributes = 0;
  1295.     }
  1296. }
  1297.  
  1298. /*
  1299.  * variables used for one level depth of highlighting
  1300.  * Used for "-- More --" message.
  1301.  */
  1302.  
  1303. static char_u    *old_highlight = NULL;
  1304. static char_u    *old_unhighlight = NULL;
  1305. static int        old_highlight_attr = 0;
  1306.  
  1307.     void
  1308. remember_highlight()
  1309. {
  1310.     old_highlight = highlight;
  1311.     old_unhighlight = unhighlight;
  1312.     old_highlight_attr = highlight_attr;
  1313. }
  1314.  
  1315.     void
  1316. recover_old_highlight()
  1317. {
  1318.     highlight = old_highlight;
  1319.     unhighlight = old_unhighlight;
  1320.     highlight_attr = old_highlight_attr;
  1321. }
  1322.  
  1323. /*
  1324.  * put character '*p' on the screen at position 'row' and 'col'
  1325.  */
  1326.     static void
  1327. screen_char(p, row, col)
  1328.     char_u    *p;
  1329.     int     row;
  1330.     int     col;
  1331. {
  1332.     int            c;
  1333.     int            noinvcurs;
  1334.  
  1335.     /*
  1336.      * Outputting the last character on the screen may scrollup the screen.
  1337.      * Don't to it!
  1338.      */
  1339.     if (col == Columns - 1 && row == Rows - 1)
  1340.         return;
  1341.     if (screen_cur_col != col || screen_cur_row != row)
  1342.     {
  1343.         /* check if no cursor movement is allowed in standout mode */
  1344.         if (attributes && !p_wiv && *T_MS == NUL)
  1345.             noinvcurs = 7;
  1346.         else
  1347.             noinvcurs = 0;
  1348.  
  1349.         /*
  1350.          * If we're on the same row (which happens a lot!), try to
  1351.          * avoid a windgoto().
  1352.          * If we are only a few characters off, output the
  1353.          * characters. That is faster than cursor positioning.
  1354.          * This can't be used when switching between inverting and not
  1355.          * inverting.
  1356.          */
  1357.         if (screen_cur_row == row && screen_cur_col < col)
  1358.         {
  1359.             register int i;
  1360.  
  1361.             i = col - screen_cur_col;
  1362.             if (i <= 4 + noinvcurs)
  1363.             {
  1364.                 /* stop at the first character that has different attributes
  1365.                  * from the ones that are active */
  1366.                 while (i && *(p - i + Columns) == attributes)
  1367.                 {
  1368.                     c = *(p - i--);
  1369.                     outchar(c);
  1370.                 }
  1371.             }
  1372.             if (i)
  1373.             {
  1374.                 if (noinvcurs)
  1375.                     stop_highlight();
  1376.             
  1377.                 if (*T_CRI != NUL)    /* use tgoto interface! jw */
  1378.                     OUTSTR(tgoto((char *)T_CRI, 0, i));
  1379.                 else
  1380.                     windgoto(row, col);
  1381.             
  1382.                 if (noinvcurs)
  1383.                     start_highlight();
  1384.             }
  1385.         }
  1386.         /*
  1387.          * If the cursor is at the line above where we want to be, use CR LF,
  1388.          * this is quicker than windgoto().
  1389.          * Don't do this if the cursor went beyond the last column, the cursor
  1390.          * position is unknown then (some terminals wrap, some don't )
  1391.          */
  1392.         else if (screen_cur_row + 1 == row && col == 0 &&
  1393.                                                      screen_cur_col < Columns)
  1394.         {
  1395.             if (noinvcurs)
  1396.                 stop_highlight();
  1397.             outchar('\n');
  1398.             if (noinvcurs)
  1399.                 start_highlight();
  1400.         }
  1401.         else
  1402.         {
  1403.             if (noinvcurs)
  1404.                 stop_highlight();
  1405.             windgoto(row, col);
  1406.             if (noinvcurs)
  1407.                 start_highlight();
  1408.         }
  1409.         screen_cur_row = row;
  1410.         screen_cur_col = col;
  1411.     }
  1412.  
  1413.     /*
  1414.      * For weird invert mechanism: output (un)highlight before every char
  1415.      * Lots of extra output, but works.
  1416.      */
  1417.     if (p_wiv)
  1418.     {
  1419.         if (attributes)                                      
  1420.             outstr(highlight);                            
  1421.         else if (full_screen)                                            
  1422.             outstr(unhighlight);
  1423.     }
  1424.     outchar(*p);
  1425.     screen_cur_col++;
  1426. }
  1427.  
  1428. /*
  1429.  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
  1430.  * with character 'c1' in first column followed by 'c2' in the other columns.
  1431.  */
  1432.     void
  1433. screen_fill(start_row, end_row, start_col, end_col, c1, c2)
  1434.     int     start_row, end_row;
  1435.     int        start_col, end_col;
  1436.     int        c1, c2;
  1437. {
  1438.     int                row;
  1439.     int                col;
  1440.     char_u            *screenp;
  1441.     char_u            *attrp;
  1442.     int                did_delete;
  1443.     int                c;
  1444.  
  1445.     if (end_row > Rows)                /* safety check */
  1446.         end_row = Rows;
  1447.     if (end_col > Columns)            /* safety check */
  1448.         end_col = Columns;
  1449.     if (NextScreen == NULL ||
  1450.             start_row >= end_row || start_col >= end_col)    /* nothing to do */
  1451.         return;
  1452.  
  1453.     for (row = start_row; row < end_row; ++row)
  1454.     {
  1455.             /* try to use delete-line termcap code */
  1456.         did_delete = FALSE;
  1457.         if (attributes == 0 && c2 == ' ' && end_col == Columns && *T_CE != NUL
  1458. #ifdef RIGHTLEFT
  1459.                     && !rightleft
  1460. #endif
  1461.                                     )
  1462.         {
  1463.             /*
  1464.              * check if we really need to clear something
  1465.              */
  1466.             col = start_col;
  1467.             screenp = LinePointers[row] + start_col;
  1468.             if (c1 != ' ')                        /* don't clear first char */
  1469.             {
  1470.                 ++col;
  1471.                 ++screenp;
  1472.             }
  1473.  
  1474.             /* skip blanks (used often, keep it fast!) */
  1475.             attrp = screenp + Columns;
  1476.             while (col < end_col && *screenp == ' ' && *attrp == 0)
  1477.             {
  1478.                 ++col;
  1479.                 ++screenp;
  1480.                 ++attrp;
  1481.             }
  1482.             if (col < end_col)            /* something to be cleared */
  1483.             {
  1484.                 windgoto(row, col);        /* clear rest of this screen line */
  1485.                 outstr(T_CE);
  1486.                 screen_start();            /* don't know where cursor is now */
  1487.                 col = end_col - col;
  1488.                 while (col--)            /* clear chars in NextScreen */
  1489.                 {
  1490.                     *attrp++ = 0;
  1491.                     *screenp++ = ' ';
  1492.                 }
  1493.             }
  1494.             did_delete = TRUE;            /* the chars are cleared now */
  1495.         }
  1496.  
  1497.         screenp = LinePointers[row] +
  1498. #ifdef RIGHTLEFT
  1499.             (rightleft ? (int)Columns - 1 - start_col : start_col);
  1500. #else
  1501.                                                     start_col;
  1502. #endif
  1503.         c = c1;
  1504.         for (col = start_col; col < end_col; ++col)
  1505.         {
  1506.             if (*screenp != c || *(screenp + Columns) != attributes)
  1507.             {
  1508.                 *screenp = c;
  1509.                 *(screenp + Columns) = attributes;
  1510.                 if (!did_delete || c != ' ')
  1511.                     screen_char(screenp, row,
  1512. #ifdef RIGHTLEFT
  1513.                             rightleft ? Columns - 1 - col :
  1514. #endif
  1515.                                                             col);
  1516.             }
  1517. #ifdef RIGHTLEFT
  1518.             if (rightleft)
  1519.                 --screenp;
  1520.             else
  1521. #endif
  1522.                 ++screenp;
  1523.             if (col == start_col)
  1524.             {
  1525.                 if (did_delete)
  1526.                     break;
  1527.                 c = c2;
  1528.             }
  1529.         }
  1530.         if (row == Rows - 1)            /* overwritten the command line */
  1531.         {
  1532.             redraw_cmdline = TRUE;
  1533.             if (c1 == ' ' && c2 == ' ')
  1534.                 clear_cmdline = FALSE;    /* command line has been cleared */
  1535.         }
  1536.     }
  1537. }
  1538.  
  1539. /*
  1540.  * recompute all w_botline's. Called after Rows changed.
  1541.  */
  1542.     void
  1543. comp_Botline_all()
  1544. {
  1545.     WIN        *wp;
  1546.  
  1547.     for (wp = firstwin; wp; wp = wp->w_next)
  1548.         comp_Botline(wp);
  1549. }
  1550.  
  1551. /*
  1552.  * compute wp->w_botline. Can be called after wp->w_topline changed.
  1553.  */
  1554.     void
  1555. comp_Botline(wp)
  1556.     WIN            *wp;
  1557. {
  1558.     comp_Botline_sub(wp, wp->w_topline, 0);
  1559. }
  1560.  
  1561. /*
  1562.  * Compute wp->w_botline, may have a start at the cursor position.
  1563.  * Code shared between comp_Botline() and cursupdate().
  1564.  */
  1565.     static void
  1566. comp_Botline_sub(wp, lnum, done)
  1567.     WIN            *wp;
  1568.     linenr_t    lnum;
  1569.     int            done;
  1570. {
  1571.     int            n;
  1572.  
  1573.     for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
  1574.     {
  1575.         n = plines_win(wp, lnum);
  1576.         if (done + n > wp->w_height)
  1577.             break;
  1578.         done += n;
  1579.     }
  1580.  
  1581.     /* wp->w_botline is the line that is just below the window */
  1582.     wp->w_botline = lnum;
  1583.  
  1584.     /* Also set wp->w_empty_rows, otherwise scroll_cursor_bot() won't work */
  1585.     if (done == 0)
  1586.         wp->w_empty_rows = 0;        /* single line that doesn't fit */
  1587.     else
  1588.         wp->w_empty_rows = wp->w_height - done;
  1589. }
  1590.  
  1591.     void
  1592. screenalloc(clear)
  1593.     int        clear;
  1594. {
  1595.     register int    new_row, old_row;
  1596.     WIN                *wp;
  1597.     int                outofmem = FALSE;
  1598.     int                len;
  1599.     char_u            *new_NextScreen;
  1600.     char_u            **new_LinePointers;
  1601.     static int        entered = FALSE;            /* avoid recursiveness */
  1602.  
  1603.     /*
  1604.      * Allocation of the screen buffers is done only when the size changes
  1605.      * and when Rows and Columns have been set and we have started doing full
  1606.      * screen stuff.
  1607.      */
  1608.     if ((NextScreen != NULL &&
  1609.                           Rows == screen_Rows && Columns == screen_Columns) ||
  1610.             Rows == 0 || Columns == 0 || (!full_screen && NextScreen == NULL))
  1611.         return;
  1612.  
  1613.     /*
  1614.      * It's possible that we produce an out-of-memory message below, which
  1615.      * will cause this function to be called again.  To break the loop, just
  1616.      * return here.
  1617.      */
  1618.     if (entered)
  1619.         return;
  1620.     entered = TRUE;
  1621.  
  1622.     comp_col();            /* recompute columns for shown command and ruler */
  1623.  
  1624.     /*
  1625.      * We're changing the size of the screen.
  1626.      * - Allocate new arrays for NextScreen.
  1627.      * - Move lines from the old arrays into the new arrays, clear extra
  1628.      *   lines (unless the screen is going to be cleared).
  1629.      * - Free the old arrays.
  1630.      *
  1631.      * If anything fails, make NextScreen NULL, so we don't do anything!
  1632.      * Continuing with the old NextScreen may result in a crash, because the
  1633.      * size is wrong.
  1634.      */
  1635.     for (wp = firstwin; wp; wp = wp->w_next)
  1636.         win_free_lsize(wp);
  1637.  
  1638.     new_NextScreen = (char_u *)malloc((size_t) (Rows * Columns * 2));
  1639.     new_LinePointers = (char_u **)malloc(sizeof(char_u *) * Rows);
  1640.  
  1641.     for (wp = firstwin; wp; wp = wp->w_next)
  1642.     {
  1643.         if (win_alloc_lsize(wp) == FAIL)
  1644.         {
  1645.             outofmem = TRUE;
  1646.             break;
  1647.         }
  1648.     }
  1649.  
  1650.     if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
  1651.     {
  1652.         do_outofmem_msg();
  1653.         vim_free(new_NextScreen);
  1654.         new_NextScreen = NULL;
  1655.         vim_free(new_LinePointers);
  1656.         new_LinePointers = NULL;
  1657.     }
  1658.     else
  1659.     {
  1660.         for (new_row = 0; new_row < Rows; ++new_row)
  1661.         {
  1662.             new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
  1663.  
  1664.             /*
  1665.              * If the screen is not going to be cleared, copy as much as
  1666.              * possible from the old screen to the new one and clear the rest
  1667.              * (used when resizing the window at the "--more--" prompt or when
  1668.              * executing an external command, for the GUI).
  1669.              */
  1670.             if (!clear)
  1671.             {
  1672.                 lineclear(new_LinePointers[new_row]);
  1673.                 old_row = new_row + (screen_Rows - Rows);
  1674.                 if (old_row >= 0)
  1675.                 {
  1676.                     if (screen_Columns < Columns)
  1677.                         len = screen_Columns;
  1678.                     else
  1679.                         len = Columns;
  1680.                     vim_memmove(new_LinePointers[new_row],
  1681.                             LinePointers[old_row], (size_t)len);
  1682.                     vim_memmove(new_LinePointers[new_row] + Columns,
  1683.                             LinePointers[old_row] + screen_Columns, (size_t)len);
  1684.                 }
  1685.             }
  1686.         }
  1687.     }
  1688.  
  1689.     vim_free(NextScreen);
  1690.     vim_free(LinePointers);
  1691.     NextScreen = new_NextScreen;
  1692.     LinePointers = new_LinePointers;
  1693.  
  1694.     must_redraw = CLEAR;        /* need to clear the screen later */
  1695.     if (clear)
  1696.         screenclear2();
  1697.  
  1698. #ifdef USE_GUI
  1699.     else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
  1700.     {
  1701.         gui_redraw_block(0, 0, Rows - 1, Columns - 1);
  1702.         /*
  1703.          * Adjust the position of the cursor, for when executing an external
  1704.          * command.
  1705.          */
  1706.         if (msg_row >= Rows)                /* Rows got smaller */
  1707.             msg_row = Rows - 1;                /* put cursor at last row */
  1708.         else if (Rows > screen_Rows)        /* Rows got bigger */
  1709.             msg_row += Rows - screen_Rows;    /* put cursor in same place */
  1710.         if (msg_col >= Columns)                /* Columns got smaller */
  1711.             msg_col = Columns - 1;            /* put cursor at last column */
  1712.     }
  1713. #endif
  1714.  
  1715.     screen_Rows = Rows;
  1716.     screen_Columns = Columns;
  1717.     entered = FALSE;
  1718. }
  1719.  
  1720.     void
  1721. screenclear()
  1722. {
  1723.     if (emsg_on_display)
  1724.     {
  1725.         mch_delay(1000L, TRUE);
  1726.         emsg_on_display = FALSE;
  1727.     }
  1728.     screenalloc(FALSE);        /* allocate screen buffers if size changed */
  1729.     screenclear2();            /* clear the screen */
  1730. }
  1731.  
  1732.     static void
  1733. screenclear2()
  1734. {
  1735.     int        i;
  1736.  
  1737.     if (starting || NextScreen == NULL)
  1738.         return;
  1739.  
  1740.     outstr(T_CL);                /* clear the display */
  1741.  
  1742.                                 /* blank out NextScreen */
  1743.     for (i = 0; i < Rows; ++i)
  1744.         lineclear(LinePointers[i]);
  1745.  
  1746.     screen_cleared = TRUE;            /* can use contents of NextScreen now */
  1747.  
  1748.     win_rest_invalid(firstwin);
  1749.     clear_cmdline = FALSE;
  1750.     redraw_cmdline = TRUE;
  1751.     if (must_redraw == CLEAR)        /* no need to clear again */
  1752.         must_redraw = NOT_VALID;
  1753.     compute_cmdrow();
  1754.     msg_pos((int)Rows - 1, 0);        /* put cursor on last line for messages */
  1755.     screen_start();                    /* don't know where cursor is now */
  1756.     msg_scrolled = 0;                /* can't scroll back */
  1757.     msg_didany = FALSE;
  1758.     msg_didout = FALSE;
  1759. }
  1760.  
  1761. /*
  1762.  * Clear one line in NextScreen.
  1763.  */
  1764.     static void
  1765. lineclear(p)
  1766.     char_u    *p;
  1767. {
  1768.     (void)vim_memset(p, ' ', (size_t)Columns);
  1769.     (void)vim_memset(p + Columns, 0, (size_t)Columns);
  1770. }
  1771.  
  1772. /*
  1773.  * check cursor for a valid lnum
  1774.  */
  1775.     void
  1776. check_cursor()
  1777. {
  1778.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1779.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1780.     if (curwin->w_cursor.lnum <= 0)
  1781.         curwin->w_cursor.lnum = 1;
  1782. }
  1783.  
  1784.     void
  1785. cursupdate()
  1786. {
  1787.     linenr_t        lnum;
  1788.     long             line_count;
  1789.     int             sline;
  1790.     int                done;
  1791.     int             temp;
  1792.  
  1793.     if (!screen_valid(TRUE))
  1794.         return;
  1795.  
  1796.     /*
  1797.      * Make sure the cursor is on a valid line number
  1798.      */
  1799.     check_cursor();
  1800.  
  1801.     /*
  1802.      * If the buffer is empty, always set topline to 1.
  1803.      */
  1804.     if (bufempty())             /* special case - file is empty */
  1805.     {
  1806.         curwin->w_topline = 1;
  1807.         curwin->w_cursor.lnum = 1;
  1808.         curwin->w_cursor.col = 0;
  1809.         curwin->w_lsize[0] = 0;
  1810.         if (curwin->w_lsize_valid == 0)    /* don't know about screen contents */
  1811.             updateScreen(NOT_VALID);
  1812.         curwin->w_lsize_valid = 1;
  1813.     }
  1814.  
  1815.     /*
  1816.      * If the cursor is above the top of the window, scroll the window to put
  1817.      * it at the top of the window.
  1818.      * If we weren't very close to begin with, we scroll to put the cursor in
  1819.      * the middle of the window.
  1820.      */
  1821.     else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
  1822.                                                         curwin->w_topline > 1)
  1823.     {
  1824.         lnum = curwin->w_topline;
  1825.         temp = curwin->w_height / 2 - 1;
  1826.         if (temp < 2)
  1827.             temp = 2;
  1828.                                 /* not very close, put cursor halfway screen */
  1829.         if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
  1830.             scroll_cursor_halfway(FALSE);
  1831.         else
  1832.             scroll_cursor_top((int)p_sj, FALSE);
  1833.         /* redraw when scrolled or windows contents has changed */
  1834.         if (lnum != curwin->w_topline || must_redraw > INVERTED)
  1835.             updateScreen(VALID);
  1836.     }
  1837.  
  1838.     /*
  1839.      * If the cursor is below the bottom of the window, scroll the window
  1840.      * to put the cursor on the window. If the cursor is less than a
  1841.      * windowheight down compute the number of lines at the top which have
  1842.      * the same or more rows than the rows of the lines below the bottom.
  1843.      * Note: After curwin->w_botline was computed lines may have been
  1844.      * added or deleted, it may be greater than ml_line_count.
  1845.      */
  1846.     else if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
  1847.                                 curwin->w_botline <= curbuf->b_ml.ml_line_count)
  1848.     {
  1849.         lnum = curwin->w_topline;
  1850.         line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
  1851.         if (line_count <= curwin->w_height + 1)
  1852.             scroll_cursor_bot((int)p_sj, FALSE);
  1853.         else
  1854.             scroll_cursor_halfway(FALSE);
  1855.         /* redraw when scrolled or windows contents has changed */
  1856.         if (lnum != curwin->w_topline || must_redraw > INVERTED)
  1857.             updateScreen(VALID);
  1858.     }
  1859.  
  1860.     /*
  1861.      * If the window contents is unknown, need to update the screen.
  1862.      */
  1863.     else if (curwin->w_lsize_valid == 0)
  1864.         updateScreen(NOT_VALID);
  1865.  
  1866.     /*
  1867.      * Figure out the row number of the cursor line.
  1868.      * This is used often, keep it fast!
  1869.      */
  1870.     curwin->w_row = sline = 0;
  1871.                                             /* curwin->w_lsize[] invalid */
  1872.     if (RedrawingDisabled || curwin->w_lsize_valid == 0)
  1873.     {
  1874.         done = 0;
  1875.         for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
  1876.             done += plines(lnum);
  1877.         curwin->w_row = done;
  1878.  
  1879.         /*
  1880.          * Also need to compute w_botline and w_empty_rows, because
  1881.          * updateScreen() will not have done that.
  1882.          */
  1883.         comp_Botline_sub(curwin, lnum, done);
  1884.     }
  1885.     else
  1886.     {
  1887.         for (done = curwin->w_cursor.lnum - curwin->w_topline; done > 0; --done)
  1888.             curwin->w_row += curwin->w_lsize[sline++];
  1889.     }
  1890.  
  1891.     curwin->w_cline_row = curwin->w_row;
  1892.     curwin->w_col = curwin->w_virtcol = 0;
  1893.     if (!RedrawingDisabled && sline > curwin->w_lsize_valid)
  1894.                                 /* Should only happen with a line that is too */
  1895.                                 /* long to fit on the last screen line. */
  1896.         curwin->w_cline_height = 0;
  1897.     else
  1898.     {
  1899.                             /* curwin->w_lsize[] invalid */
  1900.         if (RedrawingDisabled || curwin->w_lsize_valid == 0)
  1901.             curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  1902.         else
  1903.             curwin->w_cline_height = curwin->w_lsize[sline];
  1904.                             /* compute curwin->w_virtcol and curwin->w_col */
  1905.         curs_columns(!RedrawingDisabled);
  1906.         if (must_redraw)
  1907.             updateScreen(must_redraw);
  1908.     }
  1909.  
  1910.     if (curwin->w_set_curswant)
  1911.     {
  1912.         curwin->w_curswant = curwin->w_virtcol;
  1913.         curwin->w_set_curswant = FALSE;
  1914.     }
  1915. }
  1916.  
  1917. /*
  1918.  * Recompute topline to put the cursor at the top of the window.
  1919.  * Scroll at least "min_scroll" lines.
  1920.  * If "always" is TRUE, always set topline (for "zt").
  1921.  */
  1922.     void
  1923. scroll_cursor_top(min_scroll, always)
  1924.     int        min_scroll;
  1925.     int        always;
  1926. {
  1927.     int        scrolled = 0;
  1928.     int        extra = 0;
  1929.     int        used;
  1930.     int        i;
  1931.     int        sline;        /* screen line for cursor */
  1932.  
  1933.     /*
  1934.      * Decrease topline until:
  1935.      * - it has become 1
  1936.      * - (part of) the cursor line is moved off the screen or
  1937.      * - moved at least 'scrolljump' lines and
  1938.      * - at least 'scrolloff' lines above and below the cursor
  1939.      */
  1940.     used = plines(curwin->w_cursor.lnum);
  1941.     for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
  1942.     {
  1943.         i = plines(curwin->w_cursor.lnum - sline);
  1944.         used += i;
  1945.         extra += i;
  1946.         if (extra <= p_so &&
  1947.                    curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
  1948.             used += plines(curwin->w_cursor.lnum + sline);
  1949.         if (used > curwin->w_height)
  1950.             break;
  1951.         if (curwin->w_cursor.lnum - sline < curwin->w_topline)
  1952.             scrolled += i;
  1953.  
  1954.         /*
  1955.          * If scrolling is needed, scroll at least 'sj' lines.
  1956.          */
  1957.         if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
  1958.                                       scrolled >= min_scroll) && extra > p_so)
  1959.             break;
  1960.     }
  1961.  
  1962.     /*
  1963.      * If we don't have enough space, put cursor in the middle.
  1964.      * This makes sure we get the same position when using "k" and "j"
  1965.      * in a small window.
  1966.      */
  1967.     if (used > curwin->w_height)
  1968.         scroll_cursor_halfway(FALSE);
  1969.     else
  1970.     {
  1971.         /*
  1972.          * If "always" is FALSE, only adjust topline to a lower value, higher
  1973.          * value may happen with wrapping lines
  1974.          */
  1975.         if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
  1976.             curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
  1977.         if (curwin->w_topline > curwin->w_cursor.lnum)
  1978.             curwin->w_topline = curwin->w_cursor.lnum;
  1979.     }
  1980. }
  1981.  
  1982. /*
  1983.  * Recompute topline to put the cursor at the bottom of the window.
  1984.  * Scroll at least "min_scroll" lines.
  1985.  * If "set_topline" is TRUE, set topline and botline first (for "zb").
  1986.  * This is messy stuff!!!
  1987.  */
  1988.     void
  1989. scroll_cursor_bot(min_scroll, set_topline)
  1990.     int        min_scroll;
  1991.     int        set_topline;
  1992. {
  1993.     int            used;
  1994.     int            scrolled = 0;
  1995.     int            extra = 0;
  1996.     int            sline;            /* screen line for cursor from bottom */
  1997.     int            i;
  1998.     linenr_t    lnum;
  1999.     linenr_t    line_count;
  2000.     linenr_t    old_topline = curwin->w_topline;
  2001.     linenr_t    old_botline = curwin->w_botline;
  2002.     int            old_empty_rows = curwin->w_empty_rows;
  2003.     linenr_t    cln;                /* Cursor Line Number */
  2004.  
  2005.     cln = curwin->w_cursor.lnum;
  2006.     if (set_topline)
  2007.     {
  2008.         used = 0;
  2009.         curwin->w_botline = cln + 1;
  2010.         for (curwin->w_topline = curwin->w_botline;
  2011.                 curwin->w_topline != 1;
  2012.                 --curwin->w_topline)
  2013.         {
  2014.             i = plines(curwin->w_topline - 1);
  2015.             if (used + i > curwin->w_height)
  2016.                 break;
  2017.             used += i;
  2018.         }
  2019.         curwin->w_empty_rows = curwin->w_height - used;
  2020.     }
  2021.  
  2022.     used = plines(cln);
  2023.     if (cln >= curwin->w_botline)
  2024.     {
  2025.         scrolled = used;
  2026.         if (cln == curwin->w_botline)
  2027.             scrolled -= curwin->w_empty_rows;
  2028.     }
  2029.  
  2030.     /*
  2031.      * Stop counting lines to scroll when
  2032.      * - hitting start of the file
  2033.      * - scrolled nothing or at least 'sj' lines
  2034.      * - at least 'so' lines below the cursor
  2035.      * - lines between botline and cursor have been counted
  2036.      */
  2037.     for (sline = 1; sline < cln; ++sline)
  2038.     {
  2039.         if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
  2040.                 cln + sline > curbuf->b_ml.ml_line_count) &&
  2041.                 cln - sline < curwin->w_botline)
  2042.             break;
  2043.         i = plines(cln - sline);
  2044.         used += i;
  2045.         if (used > curwin->w_height)
  2046.             break;
  2047.         if (cln - sline >= curwin->w_botline)
  2048.         {
  2049.             scrolled += i;
  2050.             if (cln - sline == curwin->w_botline)
  2051.                 scrolled -= curwin->w_empty_rows;
  2052.         }
  2053.         if (cln + sline <= curbuf->b_ml.ml_line_count)
  2054.         {
  2055.             i = plines(cln + sline);
  2056.             used += i;
  2057.             if (used > curwin->w_height)
  2058.                 break;
  2059.             if (extra < p_so || scrolled < min_scroll)
  2060.             {
  2061.                 extra += i;
  2062.                 if (cln + sline >= curwin->w_botline)
  2063.                 {
  2064.                     scrolled += i;
  2065.                     if (cln + sline == curwin->w_botline)
  2066.                         scrolled -= curwin->w_empty_rows;
  2067.                 }
  2068.             }
  2069.         }
  2070.     }
  2071.     /* curwin->w_empty_rows is larger, no need to scroll */
  2072.     if (scrolled <= 0)
  2073.         line_count = 0;
  2074.     /* more than a screenfull, don't scroll but redraw */
  2075.     else if (used > curwin->w_height)
  2076.         line_count = used;
  2077.     /* scroll minimal number of lines */
  2078.     else
  2079.     {
  2080.         for (i = 0, lnum = curwin->w_topline;
  2081.                 i < scrolled && lnum < curwin->w_botline; ++lnum)
  2082.             i += plines(lnum);
  2083.         if (i >= scrolled)        /* it's possible to scroll */
  2084.             line_count = lnum - curwin->w_topline;
  2085.         else                /* below curwin->w_botline, don't scroll */
  2086.             line_count = 9999;
  2087.     }
  2088.  
  2089.     /*
  2090.      * Scroll up if the cursor is off the bottom of the screen a bit.
  2091.      * Otherwise put it at 1/2 of the screen.
  2092.      */
  2093.     if (line_count >= curwin->w_height && line_count > min_scroll)
  2094.         scroll_cursor_halfway(FALSE);
  2095.     else
  2096.         scrollup(line_count);
  2097.  
  2098.     /*
  2099.      * If topline didn't change we need to restore w_botline and w_empty_rows
  2100.      * (we changed them).
  2101.      * If topline did change, updateScreen() will set botline.
  2102.      */
  2103.     if (curwin->w_topline == old_topline && set_topline)
  2104.     {
  2105.         curwin->w_botline = old_botline;
  2106.         curwin->w_empty_rows = old_empty_rows;
  2107.     }
  2108. }
  2109.  
  2110. /*
  2111.  * Recompute topline to put the cursor halfway the window
  2112.  * If "atend" is TRUE, also put it halfway at the end of the file.
  2113.  */
  2114.     void
  2115. scroll_cursor_halfway(atend)
  2116.     int        atend;
  2117. {
  2118.     int            above = 0;
  2119.     linenr_t    topline;
  2120.     int            below = 0;
  2121.     linenr_t    botline;
  2122.     int            used;
  2123.     int            i;
  2124.     linenr_t    cln;                /* Cursor Line Number */
  2125.  
  2126.     topline = botline = cln = curwin->w_cursor.lnum;
  2127.     used = plines(cln);
  2128.     while (topline > 1)
  2129.     {
  2130.         if (below <= above)            /* add a line below the cursor */
  2131.         {
  2132.             if (botline + 1 <= curbuf->b_ml.ml_line_count)
  2133.             {
  2134.                 i = plines(botline + 1);
  2135.                 used += i;
  2136.                 if (used > curwin->w_height)
  2137.                     break;
  2138.                 below += i;
  2139.                 ++botline;
  2140.             }
  2141.             else
  2142.             {
  2143.                 ++below;            /* count a "~" line */
  2144.                 if (atend)
  2145.                     ++used;
  2146.             }
  2147.         }
  2148.  
  2149.         if (below > above)            /* add a line above the cursor */
  2150.         {
  2151.             i = plines(topline - 1);
  2152.             used += i;
  2153.             if (used > curwin->w_height)
  2154.                 break;
  2155.             above += i;
  2156.             --topline;
  2157.         }
  2158.     }
  2159.     curwin->w_topline = topline;
  2160. }
  2161.  
  2162. /*
  2163.  * Correct the cursor position so that it is in a part of the screen at least
  2164.  * 'so' lines from the top and bottom, if possible.
  2165.  * If not possible, put it at the same position as scroll_cursor_halfway().
  2166.  * When called topline and botline must be valid!
  2167.  */
  2168.     void
  2169. cursor_correct()
  2170. {
  2171.     int            above = 0;            /* screen lines above topline */
  2172.     linenr_t    topline;
  2173.     int            below = 0;            /* screen lines below botline */
  2174.     linenr_t    botline;
  2175.     int            above_wanted, below_wanted;
  2176.     linenr_t    cln;                /* Cursor Line Number */
  2177.     int            max_off;
  2178.  
  2179.     /*
  2180.      * How many lines we would like to have above/below the cursor depends on
  2181.      * whether the first/last line of the file is on screen.
  2182.      */
  2183.     above_wanted = p_so;
  2184.     below_wanted = p_so;
  2185.     if (curwin->w_topline == 1)
  2186.     {
  2187.         above_wanted = 0;
  2188.         max_off = curwin->w_height / 2;
  2189.         if (below_wanted > max_off)
  2190.             below_wanted = max_off;
  2191.     }
  2192.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
  2193.     {
  2194.         below_wanted = 0;
  2195.         max_off = (curwin->w_height - 1) / 2;
  2196.         if (above_wanted > max_off)
  2197.             above_wanted = max_off;
  2198.     }
  2199.  
  2200.     /*
  2201.      * If there are sufficient file-lines above and below the cursor, we can
  2202.      * return now.
  2203.      */
  2204.     cln = curwin->w_cursor.lnum;
  2205.     if (cln >= curwin->w_topline + above_wanted && 
  2206.                                       cln < curwin->w_botline - below_wanted)
  2207.         return;
  2208.  
  2209.     /*
  2210.      * Narrow down the area where the cursor can be put by taking lines from
  2211.      * the top and the bottom until:
  2212.      * - the desired context lines are found
  2213.      * - the lines from the top is past the lines from the bottom
  2214.      */
  2215.     topline = curwin->w_topline;
  2216.     botline = curwin->w_botline - 1;
  2217.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  2218.     {
  2219.         if (below < below_wanted && (below <= above || above >= above_wanted))
  2220.         {
  2221.             below += plines(botline);
  2222.             --botline;
  2223.         }
  2224.         if (above < above_wanted && (above < below || below >= below_wanted))
  2225.         {
  2226.             above += plines(topline);
  2227.             ++topline;
  2228.         }
  2229.     }
  2230.     if (topline == botline || botline == 0)
  2231.         curwin->w_cursor.lnum = topline;
  2232.     else if (topline > botline)
  2233.         curwin->w_cursor.lnum = botline;
  2234.     else
  2235.     {
  2236.         if (cln < topline && curwin->w_topline > 1)
  2237.             curwin->w_cursor.lnum = topline;
  2238.         if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2239.             curwin->w_cursor.lnum = botline;
  2240.     }
  2241. }
  2242.  
  2243. /*
  2244.  * Compute curwin->w_row.
  2245.  * Can be called when topline and botline have not been updated.
  2246.  * return OK when cursor is in the window, FAIL when it isn't.
  2247.  */
  2248.     int
  2249. curs_rows()
  2250. {
  2251.     linenr_t    lnum;
  2252.     int            i;
  2253.  
  2254.     if (curwin->w_cursor.lnum < curwin->w_topline ||
  2255.                          curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
  2256.                                    curwin->w_cursor.lnum >= curwin->w_botline)
  2257.         return FAIL;
  2258.  
  2259.     curwin->w_row = i = 0;
  2260.     for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
  2261.         if (RedrawingDisabled)        /* curwin->w_lsize[] invalid */
  2262.             curwin->w_row += plines(lnum);
  2263.         else
  2264.             curwin->w_row += curwin->w_lsize[i++];
  2265.     return OK;
  2266. }
  2267.  
  2268. /*
  2269.  * compute curwin->w_col and curwin->w_virtcol
  2270.  */
  2271.     void
  2272. curs_columns(scroll)
  2273.     int scroll;            /* when TRUE, may scroll horizontally */
  2274. {
  2275.     int        diff;
  2276.     int        extra;
  2277.     int        new_leftcol;
  2278.     colnr_t    startcol;
  2279.     colnr_t endcol;
  2280.  
  2281.     getvcol(curwin, &curwin->w_cursor,
  2282.                                 &startcol, &(curwin->w_virtcol), &endcol);
  2283.  
  2284.         /* remove '$' from change command when cursor moves onto it */
  2285.     if (startcol > dollar_vcol)
  2286.         dollar_vcol = 0;
  2287.  
  2288.     curwin->w_col = curwin->w_virtcol;
  2289.     if (curwin->w_p_nu)
  2290.     {
  2291.         curwin->w_col += 8;
  2292.         endcol += 8;
  2293.     }
  2294.  
  2295.     curwin->w_row = curwin->w_cline_row;
  2296.     if (curwin->w_p_wrap)        /* long line wrapping, adjust curwin->w_row */
  2297.     {
  2298.         while (curwin->w_col >= Columns)
  2299.         {
  2300.             curwin->w_col -= Columns;
  2301.             curwin->w_row++;
  2302.         }
  2303.     }
  2304.     else if (scroll)    /* no line wrapping, compute curwin->w_leftcol if
  2305.                          * scrolling is on.  If scrolling is off,
  2306.                          * curwin->w_leftcol is assumed to be 0 */
  2307.     {
  2308.                         /* If Cursor is left of the screen, scroll rightwards */
  2309.                         /* If Cursor is right of the screen, scroll leftwards */
  2310.         if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
  2311.              (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
  2312.         {
  2313.             if (extra < 0)
  2314.                 diff = -extra;
  2315.             else
  2316.                 diff = extra;
  2317.  
  2318.                 /* far off, put cursor in middle of window */
  2319.             if (p_ss == 0 || diff >= Columns / 2)
  2320.                 new_leftcol = curwin->w_col - Columns / 2;
  2321.             else
  2322.             {
  2323.                 if (diff < p_ss)
  2324.                     diff = p_ss;
  2325.                 if (extra < 0)
  2326.                     new_leftcol = curwin->w_leftcol - diff;
  2327.                 else
  2328.                     new_leftcol = curwin->w_leftcol + diff;
  2329.             }
  2330.             if (new_leftcol < 0)
  2331.                 curwin->w_leftcol = 0;
  2332.             else
  2333.                 curwin->w_leftcol = new_leftcol;
  2334.                     /* screen has to be redrawn with new curwin->w_leftcol */
  2335.             redraw_later(NOT_VALID);
  2336.         }
  2337.         curwin->w_col -= curwin->w_leftcol;
  2338.     }
  2339.         /* Cursor past end of screen */
  2340.         /* happens with line that does not fit on screen */
  2341.     if (curwin->w_row > curwin->w_height - 1)
  2342.         curwin->w_row = curwin->w_height - 1;
  2343. }
  2344.  
  2345.     void
  2346. scrolldown(line_count)
  2347.     long    line_count;
  2348. {
  2349.     register long    done = 0;    /* total # of physical lines done */
  2350.  
  2351.     /* Scroll up 'line_count' lines. */
  2352.     while (line_count--)
  2353.     {
  2354.         if (curwin->w_topline == 1)
  2355.             break;
  2356.         done += plines(--curwin->w_topline);
  2357.     }
  2358.     /*
  2359.      * Compute the row number of the last row of the cursor line
  2360.      * and move it onto the screen.
  2361.      */
  2362.     curwin->w_row += done;
  2363.     if (curwin->w_p_wrap)
  2364.         curwin->w_row += plines(curwin->w_cursor.lnum) -
  2365.                                               1 - curwin->w_virtcol / Columns;
  2366.     while (curwin->w_row >= curwin->w_height && curwin->w_cursor.lnum > 1)
  2367.         curwin->w_row -= plines(curwin->w_cursor.lnum--);
  2368.     comp_Botline(curwin);
  2369. }
  2370.  
  2371.     void
  2372. scrollup(line_count)
  2373.     long    line_count;
  2374. {
  2375.     curwin->w_topline += line_count;
  2376.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  2377.         curwin->w_topline = curbuf->b_ml.ml_line_count;
  2378.     if (curwin->w_cursor.lnum < curwin->w_topline)
  2379.         curwin->w_cursor.lnum = curwin->w_topline;
  2380.     comp_Botline(curwin);
  2381. }
  2382.  
  2383. /*
  2384.  * Scroll the screen one line down, but don't do it if it would move the
  2385.  * cursor off the screen.
  2386.  */
  2387.     void
  2388. scrolldown_clamp()
  2389. {
  2390.     int        end_row;
  2391.  
  2392.     if (curwin->w_topline == 1)
  2393.         return;
  2394.  
  2395.     /*
  2396.      * Compute the row number of the last row of the cursor line
  2397.      * and make sure it doesn't go off the screen. Make sure the cursor
  2398.      * doesn't go past 'scrolloff' lines from the screen end.
  2399.      */
  2400.     end_row = curwin->w_row + plines(curwin->w_topline - 1);
  2401.     if (curwin->w_p_wrap)
  2402.         end_row += plines(curwin->w_cursor.lnum) - 1 -
  2403.                                                   curwin->w_virtcol / Columns;
  2404.     if (end_row < curwin->w_height - p_so)
  2405.         --curwin->w_topline;
  2406. }
  2407.  
  2408. /*
  2409.  * Scroll the screen one line up, but don't do it if it would move the cursor
  2410.  * off the screen.
  2411.  */
  2412.     void
  2413. scrollup_clamp()
  2414. {
  2415.     int        start_row;
  2416.  
  2417.     if (curwin->w_topline == curbuf->b_ml.ml_line_count)
  2418.         return;
  2419.  
  2420.     /*
  2421.      * Compute the row number of the first row of the cursor line
  2422.      * and make sure it doesn't go off the screen. Make sure the cursor
  2423.      * doesn't go before 'scrolloff' lines from the screen start.
  2424.      */
  2425.     start_row = curwin->w_row - plines(curwin->w_topline);
  2426.     if (curwin->w_p_wrap)
  2427.         start_row -= curwin->w_virtcol / Columns;
  2428.     if (start_row >= p_so)
  2429.         ++curwin->w_topline;
  2430. }
  2431.  
  2432. /*
  2433.  * insert 'line_count' lines at 'row' in window 'wp'
  2434.  * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
  2435.  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
  2436.  * scrolling.
  2437.  * Returns FAIL if the lines are not inserted, OK for success.
  2438.  */
  2439.     int
  2440. win_ins_lines(wp, row, line_count, invalid, mayclear)
  2441.     WIN        *wp;
  2442.     int        row;
  2443.     int        line_count;
  2444.     int        invalid;
  2445.     int        mayclear;
  2446. {
  2447.     int        did_delete;
  2448.     int        nextrow;
  2449.     int        lastrow;
  2450.     int        retval;
  2451.  
  2452.     if (invalid)
  2453.         wp->w_lsize_valid = 0;
  2454.  
  2455.     if (RedrawingDisabled || line_count <= 0 || wp->w_height < 5)
  2456.         return FAIL;
  2457.     
  2458.     if (line_count > wp->w_height - row)
  2459.         line_count = wp->w_height - row;
  2460.  
  2461.     if (mayclear && Rows - line_count < 5)    /* only a few lines left: redraw is faster */
  2462.     {
  2463.         screenclear();        /* will set wp->w_lsize_valid to 0 */
  2464.         return FAIL;
  2465.     }
  2466.  
  2467.     /*
  2468.      * Delete all remaining lines
  2469.      */
  2470.     if (row + line_count >= wp->w_height)
  2471.     {
  2472.         screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  2473.                                                    0, (int)Columns, ' ', ' ');
  2474.         return OK;
  2475.     }
  2476.  
  2477.     /*
  2478.      * when scrolling, the message on the command line should be cleared,
  2479.      * otherwise it will stay there forever.
  2480.      */
  2481.     clear_cmdline = TRUE;
  2482.  
  2483.     /*
  2484.      * if the terminal can set a scroll region, use that
  2485.      */
  2486.     if (scroll_region)
  2487.     {
  2488.         scroll_region_set(wp, row);
  2489.         retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
  2490.                                                           wp->w_height - row);
  2491.         scroll_region_reset();
  2492.         return retval;
  2493.     }
  2494.  
  2495.     if (wp->w_next && p_tf)        /* don't delete/insert on fast terminal */
  2496.         return FAIL;
  2497.  
  2498.     /*
  2499.      * If there is a next window or a status line, we first try to delete the
  2500.      * lines at the bottom to avoid messing what is after the window.
  2501.      * If this fails and there are following windows, don't do anything to avoid
  2502.      * messing up those windows, better just redraw.
  2503.      */
  2504.     did_delete = FALSE;
  2505.     if (wp->w_next || wp->w_status_height)
  2506.     {
  2507.         if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
  2508.                                           line_count, (int)Rows, FALSE) == OK)
  2509.             did_delete = TRUE;
  2510.         else if (wp->w_next)
  2511.             return FAIL;
  2512.     }
  2513.     /*
  2514.      * if no lines deleted, blank the lines that will end up below the window
  2515.      */
  2516.     if (!did_delete)
  2517.     {
  2518.         wp->w_redr_status = TRUE;
  2519.         redraw_cmdline = TRUE;
  2520.         nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
  2521.         lastrow = nextrow + line_count;
  2522.         if (lastrow > Rows)
  2523.             lastrow = Rows;
  2524.         screen_fill(nextrow - line_count, lastrow - line_count,
  2525.                                                    0, (int)Columns, ' ', ' ');
  2526.     }
  2527.  
  2528.     if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
  2529.     {
  2530.             /* deletion will have messed up other windows */
  2531.         if (did_delete)
  2532.         {
  2533.             wp->w_redr_status = TRUE;
  2534.             win_rest_invalid(wp->w_next);
  2535.         }
  2536.         return FAIL;
  2537.     }
  2538.  
  2539.     return OK;
  2540. }
  2541.  
  2542. /*
  2543.  * delete 'line_count' lines at 'row' in window 'wp'
  2544.  * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
  2545.  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
  2546.  * scrolling
  2547.  * Return OK for success, FAIL if the lines are not deleted.
  2548.  */
  2549.     int
  2550. win_del_lines(wp, row, line_count, invalid, mayclear)
  2551.     WIN                *wp;
  2552.     int             row;
  2553.     int             line_count;
  2554.     int                invalid;
  2555.     int                mayclear;
  2556. {
  2557.     int            retval;
  2558.  
  2559.     if (invalid)
  2560.         wp->w_lsize_valid = 0;
  2561.  
  2562.     if (RedrawingDisabled || line_count <= 0)
  2563.         return FAIL;
  2564.     
  2565.     if (line_count > wp->w_height - row)
  2566.         line_count = wp->w_height - row;
  2567.  
  2568.     /* only a few lines left: redraw is faster */
  2569.     if (mayclear && Rows - line_count < 5)
  2570.     {
  2571.         screenclear();        /* will set wp->w_lsize_valid to 0 */
  2572.         return FAIL;
  2573.     }
  2574.  
  2575.     /*
  2576.      * Delete all remaining lines
  2577.      */
  2578.     if (row + line_count >= wp->w_height)
  2579.     {
  2580.         screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  2581.                                                    0, (int)Columns, ' ', ' ');
  2582.         return OK;
  2583.     }
  2584.  
  2585.     /*
  2586.      * when scrolling, the message on the command line should be cleared,
  2587.      * otherwise it will stay there forever.
  2588.      */
  2589.     clear_cmdline = TRUE;
  2590.  
  2591.     /*
  2592.      * if the terminal can set a scroll region, use that
  2593.      */
  2594.     if (scroll_region)
  2595.     {
  2596.         scroll_region_set(wp, row);
  2597.         retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
  2598.                                                    wp->w_height - row, FALSE);
  2599.         scroll_region_reset();
  2600.         return retval;
  2601.     }
  2602.  
  2603.     if (wp->w_next && p_tf)        /* don't delete/insert on fast terminal */
  2604.         return FAIL;
  2605.  
  2606.     if (screen_del_lines(0, wp->w_winpos + row, line_count,
  2607.                                                     (int)Rows, FALSE) == FAIL)
  2608.         return FAIL;
  2609.  
  2610.     /*
  2611.      * If there are windows or status lines below, try to put them at the
  2612.      * correct place. If we can't do that, they have to be redrawn.
  2613.      */
  2614.     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
  2615.     {
  2616.         if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
  2617.                                                line_count, (int)Rows) == FAIL)
  2618.         {
  2619.             wp->w_redr_status = TRUE;
  2620.             win_rest_invalid(wp->w_next);
  2621.         }
  2622.     }
  2623.     /*
  2624.      * If this is the last window and there is no status line, redraw the
  2625.      * command line later.
  2626.      */
  2627.     else
  2628.         redraw_cmdline = TRUE;
  2629.     return OK;
  2630. }
  2631.  
  2632. /*
  2633.  * window 'wp' and everything after it is messed up, mark it for redraw
  2634.  */
  2635.     void
  2636. win_rest_invalid(wp)
  2637.     WIN            *wp;
  2638. {
  2639.     while (wp)
  2640.     {
  2641.         wp->w_lsize_valid = 0;
  2642.         wp->w_redr_type = NOT_VALID;
  2643.         wp->w_redr_status = TRUE;
  2644.         wp = wp->w_next;
  2645.     }
  2646.     redraw_cmdline = TRUE;
  2647. }
  2648.  
  2649. /*
  2650.  * The rest of the routines in this file perform screen manipulations. The
  2651.  * given operation is performed physically on the screen. The corresponding
  2652.  * change is also made to the internal screen image. In this way, the editor
  2653.  * anticipates the effect of editing changes on the appearance of the screen.
  2654.  * That way, when we call screenupdate a complete redraw isn't usually
  2655.  * necessary. Another advantage is that we can keep adding code to anticipate
  2656.  * screen changes, and in the meantime, everything still works.
  2657.  */
  2658.  
  2659. /*
  2660.  * types for inserting or deleting lines
  2661.  */
  2662. #define USE_T_CAL    1
  2663. #define USE_T_CDL    2
  2664. #define USE_T_AL    3
  2665. #define USE_T_CE    4
  2666. #define USE_T_DL    5
  2667. #define USE_T_SR    6
  2668. #define USE_NL        7
  2669. #define USE_T_CD    8
  2670.  
  2671. /*
  2672.  * insert lines on the screen and update NextScreen
  2673.  * 'end' is the line after the scrolled part. Normally it is Rows.
  2674.  * When scrolling region used 'off' is the offset from the top for the region.
  2675.  * 'row' and 'end' are relative to the start of the region.
  2676.  *
  2677.  * return FAIL for failure, OK for success.
  2678.  */
  2679.     static int
  2680. screen_ins_lines(off, row, line_count, end)
  2681.     int            off;
  2682.     int         row;
  2683.     int         line_count;
  2684.     int            end;
  2685. {
  2686.     int         i;
  2687.     int         j;
  2688.     char_u        *temp;
  2689.     int            cursor_row;
  2690.     int            type;
  2691.     int            result_empty;
  2692.  
  2693.     /*
  2694.      * FAIL if
  2695.      * - there is no valid screen 
  2696.      * - the screen has to be redrawn completely
  2697.      * - the line count is less than one
  2698.      * - the line count is more than 'ttyscroll'
  2699.      */
  2700.     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
  2701.         return FAIL;
  2702.  
  2703.     /*
  2704.      * There are seven ways to insert lines:
  2705.      * 1. Use T_CD (clear to end of display) if it exists and the result of
  2706.      *      the insert is just empty lines
  2707.      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
  2708.      *    present or line_count > 1. It looks better if we do all the inserts
  2709.      *    at once.
  2710.      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
  2711.      *    insert is just empty lines and T_CE is not present or line_count >
  2712.      *    1.
  2713.      * 4. Use T_AL (insert line) if it exists.
  2714.      * 5. Use T_CE (erase line) if it exists and the result of the insert is
  2715.      *    just empty lines.
  2716.      * 6. Use T_DL (delete line) if it exists and the result of the insert is
  2717.      *    just empty lines.
  2718.      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
  2719.      *    the 'da' flag is not set or we have clear line capability.
  2720.      *
  2721.      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
  2722.      * the scrollbar for the window. It does have insert line, use that if it
  2723.      * exists.
  2724.      */
  2725.     result_empty = (row + line_count >= end);
  2726.     if (*T_CD != NUL && result_empty)
  2727.         type = USE_T_CD;
  2728.     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
  2729.         type = USE_T_CAL;
  2730.     else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
  2731.         type = USE_T_CDL;
  2732.     else if (*T_AL != NUL)
  2733.         type = USE_T_AL;
  2734.     else if (*T_CE != NUL && result_empty)
  2735.         type = USE_T_CE;
  2736.     else if (*T_DL != NUL && result_empty)
  2737.         type = USE_T_DL;
  2738.     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
  2739.         type = USE_T_SR;
  2740.     else
  2741.         return FAIL;
  2742.     
  2743.     /*
  2744.      * For clearing the lines screen_del_lines is used. This will also take
  2745.      * care of t_db if necessary.
  2746.      */
  2747.     if (type == USE_T_CD || type == USE_T_CDL ||
  2748.                                          type == USE_T_CE || type == USE_T_DL)
  2749.         return screen_del_lines(off, row, line_count, end, FALSE);
  2750.  
  2751.     /*
  2752.      * If text is retained below the screen, first clear or delete as many
  2753.      * lines at the bottom of the window as are about to be inserted so that
  2754.      * the deleted lines won't later surface during a screen_del_lines.
  2755.      */
  2756.     if (*T_DB)
  2757.         screen_del_lines(off, end - line_count, line_count, end, FALSE);
  2758.  
  2759.     if (*T_CSC != NUL)     /* cursor relative to region */
  2760.         cursor_row = row;
  2761.     else
  2762.         cursor_row = row + off;
  2763.  
  2764.     /*
  2765.      * Shift LinePointers line_count down to reflect the inserted lines.
  2766.      * Clear the inserted lines in NextScreen.
  2767.      */
  2768.     row += off;
  2769.     end += off;
  2770.     for (i = 0; i < line_count; ++i)
  2771.     {
  2772.         j = end - 1 - i;
  2773.         temp = LinePointers[j];
  2774.         while ((j -= line_count) >= row)
  2775.             LinePointers[j + line_count] = LinePointers[j];
  2776.         LinePointers[j + line_count] = temp;
  2777.         lineclear(temp);
  2778.     }
  2779.  
  2780.     windgoto(cursor_row, 0);
  2781.     if (type == USE_T_CAL)
  2782.     {
  2783.         OUTSTR(tgoto((char *)T_CAL, 0, line_count));
  2784.         screen_start();            /* don't know where cursor is now */
  2785.     }
  2786.     else
  2787.     {
  2788.         for (i = 0; i < line_count; i++) 
  2789.         {
  2790.             if (type == USE_T_AL)
  2791.             {
  2792.                 if (i && cursor_row != 0)
  2793.                     windgoto(cursor_row, 0);
  2794.                 outstr(T_AL);
  2795.             }
  2796.             else  /* type == USE_T_SR */
  2797.                 outstr(T_SR);
  2798.             screen_start();            /* don't know where cursor is now */
  2799.         }
  2800.     }
  2801.  
  2802.     /*
  2803.      * With scroll-reverse and 'da' flag set we need to clear the lines that
  2804.      * have been scrolled down into the region.
  2805.      */
  2806.     if (type == USE_T_SR && *T_DA)
  2807.     {
  2808.         for (i = 0; i < line_count; ++i) 
  2809.         {
  2810.             windgoto(off + i, 0);
  2811.             outstr(T_CE);
  2812.             screen_start();            /* don't know where cursor is now */
  2813.         }
  2814.     }
  2815.  
  2816.     return OK;
  2817. }
  2818.  
  2819. /*
  2820.  * delete lines on the screen and update NextScreen
  2821.  * 'end' is the line after the scrolled part. Normally it is Rows.
  2822.  * When scrolling region used 'off' is the offset from the top for the region.
  2823.  * 'row' and 'end' are relative to the start of the region.
  2824.  *
  2825.  * Return OK for success, FAIL if the lines are not deleted.
  2826.  */
  2827.     int
  2828. screen_del_lines(off, row, line_count, end, force)
  2829.     int                off;
  2830.     int             row;
  2831.     int             line_count;
  2832.     int                end;
  2833.     int                force;        /* even when line_count > p_ttyscroll */
  2834. {
  2835.     int         j;
  2836.     int         i;
  2837.     char_u        *temp;
  2838.     int            cursor_row;
  2839.     int            cursor_end;
  2840.     int            result_empty;    /* result is empty until end of region */
  2841.     int            can_delete;        /* deleting line codes can be used */
  2842.     int            type;
  2843.  
  2844.     /*
  2845.      * FAIL if
  2846.      * - there is no valid screen 
  2847.      * - the screen has to be redrawn completely
  2848.      * - the line count is less than one
  2849.      * - the line count is more than 'ttyscroll'
  2850.      */
  2851.     if (!screen_valid(TRUE) || line_count <= 0 ||
  2852.                                          (!force && line_count > p_ttyscroll))
  2853.         return FAIL;
  2854.  
  2855.     /*
  2856.      * Check if the rest of the current region will become empty.
  2857.      */
  2858.     result_empty = row + line_count >= end;
  2859.  
  2860.     /*
  2861.      * We can delete lines only when 'db' flag not set or when 'ce' option
  2862.      * available.
  2863.      */
  2864.     can_delete = (*T_DB == NUL || *T_CE);
  2865.  
  2866.     /*
  2867.      * There are four ways to delete lines:
  2868.      * 1. Use T_CD if it exists and the result is empty.
  2869.      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
  2870.      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
  2871.      *    none of the other ways work.
  2872.      * 4. Use T_CE (erase line) if the result is empty.
  2873.      * 5. Use T_DL (delete line) if it exists.
  2874.      */
  2875.     if (*T_CD != NUL && result_empty)
  2876.         type = USE_T_CD;
  2877.     else if (row == 0 && (line_count == 1 || *T_CDL == NUL))
  2878.         type = USE_NL;
  2879.     else if (*T_CDL != NUL && line_count > 1 && can_delete)
  2880.         type = USE_T_CDL;
  2881.     else if (*T_CE != NUL && result_empty)
  2882.         type = USE_T_CE;
  2883.     else if (*T_DL != NUL && can_delete)
  2884.         type = USE_T_DL;
  2885.     else if (*T_CDL != NUL && can_delete)
  2886.         type = USE_T_CDL;
  2887.     else
  2888.         return FAIL;
  2889.  
  2890.     if (*T_CSC != NUL)        /* cursor relative to region */
  2891.     {
  2892.         cursor_row = row;
  2893.         cursor_end = end;
  2894.     }
  2895.     else
  2896.     {
  2897.         cursor_row = row + off;
  2898.         cursor_end = end + off;
  2899.     }
  2900.  
  2901.     /*
  2902.      * Now shift LinePointers line_count up to reflect the deleted lines.
  2903.      * Clear the inserted lines in NextScreen.
  2904.      */
  2905.     row += off;
  2906.     end += off;
  2907.     for (i = 0; i < line_count; ++i)
  2908.     {
  2909.         j = row + i;
  2910.         temp = LinePointers[j];
  2911.         while ((j += line_count) <= end - 1)
  2912.             LinePointers[j - line_count] = LinePointers[j];
  2913.         LinePointers[j - line_count] = temp;
  2914.         lineclear(temp);
  2915.     }
  2916.  
  2917.     /* delete the lines */
  2918.     if (type == USE_T_CD)
  2919.     {
  2920.         windgoto(cursor_row, 0);
  2921.         outstr(T_CD);
  2922.         screen_start();                    /* don't know where cursor is now */
  2923.     }
  2924.     else if (type == USE_T_CDL)
  2925.     {
  2926.         windgoto(cursor_row, 0);
  2927.         OUTSTR(tgoto((char *)T_CDL, 0, line_count));
  2928.         screen_start();                    /* don't know where cursor is now */
  2929.     }
  2930.         /*
  2931.          * Deleting lines at top of the screen or scroll region: Just scroll
  2932.          * the whole screen (scroll region) up by outputting newlines on the
  2933.          * last line.
  2934.          */
  2935.     else if (type == USE_NL)
  2936.     {
  2937.         windgoto(cursor_end - 1, 0);
  2938.         for (i = line_count; --i >= 0; )
  2939.             outchar('\n');                /* cursor will remain on same line */
  2940.     }
  2941.     else
  2942.     {
  2943.         for (i = line_count; --i >= 0; )
  2944.         {
  2945.             if (type == USE_T_DL)
  2946.             {
  2947.                 windgoto(cursor_row, 0);
  2948.                 outstr(T_DL);           /* delete a line */
  2949.             }
  2950.             else /* type == USE_T_CE */
  2951.             {
  2952.                 windgoto(cursor_row + i, 0);
  2953.                 outstr(T_CE);           /* erase a line */
  2954.             }
  2955.             screen_start();                /* don't know where cursor is now */
  2956.         }
  2957.     }
  2958.  
  2959.     /*
  2960.      * If the 'db' flag is set, we need to clear the lines that have been
  2961.      * scrolled up at the bottom of the region.
  2962.      */
  2963.     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
  2964.     {
  2965.         for (i = line_count; i > 0; --i)
  2966.         {
  2967.             windgoto(cursor_end - i, 0);
  2968.             outstr(T_CE);               /* erase a line */
  2969.             screen_start();                /* don't know where cursor is now */
  2970.         }
  2971.     }
  2972.     return OK;
  2973. }
  2974.  
  2975. /*
  2976.  * show the current mode and ruler
  2977.  *
  2978.  * If clear_cmdline is TRUE, clear the rest of the cmdline.
  2979.  * If clear_cmdline is FALSE there may be a message there that needs to be
  2980.  * cleared only if a mode is shown.
  2981.  * Return the lenght of the message (0 if no message).
  2982.  */
  2983.     int
  2984. showmode()
  2985. {
  2986.     int        need_clear = FALSE;
  2987.     int        length = 0;
  2988.     int        do_mode = (p_smd &&
  2989.                          ((State & INSERT) || restart_edit || VIsual_active));
  2990.  
  2991.     if (do_mode || Recording)
  2992.     {
  2993.         if (emsg_on_display)
  2994.         {
  2995.             mch_delay(1000L, TRUE);
  2996.             emsg_on_display = FALSE;
  2997.         }
  2998.         msg_didout = FALSE;                /* never scroll up */
  2999.         msg_col = 0;
  3000.         gotocmdline(FALSE);
  3001.         set_highlight('M');        /* Highlight mode */
  3002.         if (do_mode)
  3003.         {
  3004.             start_highlight();
  3005.             MSG_OUTSTR("--");
  3006. #ifdef INSERT_EXPAND
  3007.             if (edit_submode != NULL)        /* CTRL-X in Insert mode */
  3008.             {
  3009.                 msg_outstr(edit_submode);
  3010.                 if (edit_submode_extra != NULL)
  3011.                 {
  3012.                     msg_outchar(' ');        /* add a space in between */
  3013.                     if (edit_submode_highl != NUL)
  3014.                     {
  3015.                         stop_highlight();
  3016.                         set_highlight(edit_submode_highl);    /* Highlight mode */
  3017.                         start_highlight();
  3018.                     }
  3019.                     msg_outstr(edit_submode_extra);
  3020.                     if (edit_submode_highl != NUL)
  3021.                     {
  3022.                         stop_highlight();
  3023.                         set_highlight('M');        /* Highlight mode */
  3024.                         start_highlight();
  3025.                     }
  3026.                 }
  3027.             }
  3028.             else
  3029. #endif
  3030.             {
  3031.                 if (State == INSERT)
  3032.                 {
  3033. #ifdef RIGHTLEFT
  3034.                     if (p_ri)
  3035.                         MSG_OUTSTR(" REVERSE");
  3036. #endif
  3037.                     MSG_OUTSTR(" INSERT");
  3038.                 }
  3039.                 else if (State == REPLACE)
  3040.                     MSG_OUTSTR(" REPLACE");
  3041.                 else if (restart_edit == 'I')
  3042.                     MSG_OUTSTR(" (insert)");
  3043.                 else if (restart_edit == 'R')
  3044.                     MSG_OUTSTR(" (replace)");
  3045. #ifdef RIGHTLEFT
  3046.                 if (p_hkmap)
  3047.                     MSG_OUTSTR(" Hebrew");
  3048. #endif
  3049.                 if ((State & INSERT) && p_paste)
  3050.                     MSG_OUTSTR(" (paste)");
  3051.                 if (VIsual_active)
  3052.                 {
  3053.                     MSG_OUTSTR(" VISUAL");
  3054.                     if (VIsual_mode == Ctrl('V'))
  3055.                         MSG_OUTSTR(" BLOCK");
  3056.                     else if (VIsual_mode == 'V')
  3057.                         MSG_OUTSTR(" LINE");
  3058.                 }
  3059.             }
  3060.             MSG_OUTSTR(" --");
  3061.             need_clear = TRUE;
  3062.         }
  3063.         if (Recording)
  3064.         {
  3065.             if (!need_clear)
  3066.                 start_highlight();
  3067.             MSG_OUTSTR("recording");
  3068.             need_clear = TRUE;
  3069.         }
  3070.         if (need_clear)
  3071.             stop_highlight();
  3072.         if (need_clear || clear_cmdline)
  3073.             msg_clr_eos();
  3074.         msg_didout = FALSE;                /* overwrite this message */
  3075.         length = msg_col;
  3076.         msg_col = 0;
  3077.     }
  3078.     else if (clear_cmdline)                /* just clear anything */
  3079.     {
  3080.         msg_row = cmdline_row;
  3081.         msg_col = 0;
  3082.         msg_clr_eos();                    /* will reset clear_cmdline */
  3083.     }
  3084.     win_redr_ruler(lastwin, TRUE);
  3085.     redraw_cmdline = FALSE;
  3086.  
  3087.     return length;
  3088. }
  3089.  
  3090. /*
  3091.  * delete mode message
  3092.  */
  3093.     void
  3094. delmode()
  3095. {
  3096.     if (Recording)
  3097.         MSG("recording");
  3098.     else
  3099.         MSG("");
  3100. }
  3101.  
  3102. /*
  3103.  * if ruler option is set: show current cursor position
  3104.  * if always is FALSE, only print if position has changed
  3105.  */
  3106.     void
  3107. showruler(always)
  3108.     int        always;
  3109. {
  3110.     win_redr_ruler(curwin, always);
  3111. }
  3112.  
  3113.     void
  3114. win_redr_ruler(wp, always)
  3115.     WIN        *wp;
  3116.     int        always;
  3117. {
  3118.     static linenr_t    old_lnum = 0;
  3119.     static colnr_t    old_col = 0;
  3120.     char_u            buffer[30];
  3121.     int                row;
  3122.     int                fillchar;
  3123.     int                empty_line = FALSE;
  3124.  
  3125.     if (!p_ru)        /* 'ruler' off, don't do anything */
  3126.         return;
  3127.  
  3128.     /*
  3129.      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
  3130.      * after deleting lines, before cursor.lnum is corrected.
  3131.      */
  3132.     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
  3133.         return;
  3134.  
  3135.     /*
  3136.      * Need to update on an empty line always, since we don't know if there
  3137.      * was a character previously (changing column "1" to "0-1").
  3138.      */
  3139.     if (*ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
  3140.         empty_line = TRUE;
  3141.  
  3142.     if ((redraw_cmdline || always || empty_line ||
  3143.                 wp->w_cursor.lnum != old_lnum || wp->w_virtcol != old_col))
  3144.     {
  3145.         cursor_off();
  3146.         if (wp->w_status_height)
  3147.         {
  3148.             row = wp->w_winpos + wp->w_height;
  3149.             if (set_highlight('s') == OK)        /* can use highlighting */
  3150.             {
  3151.                 fillchar = ' ';
  3152.                 start_highlight();
  3153.             }
  3154.             else
  3155.                 fillchar = '=';
  3156.         }
  3157.         else
  3158.         {
  3159.             row = Rows - 1;
  3160.             fillchar = ' ';
  3161.         }
  3162.         /*
  3163.          * Some sprintfs return the length, some return a pointer.
  3164.          * To avoid portability problems we use strlen() here.
  3165.          */
  3166.         sprintf((char *)buffer, "%ld,",
  3167.                 (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  3168.                     ? 0L
  3169.                     : (long)(wp->w_cursor.lnum));
  3170.         col_print(buffer + STRLEN(buffer),
  3171.                 !(State & INSERT) && empty_line
  3172.                     ? 0
  3173.                     : (int)wp->w_cursor.col + 1,
  3174.                 (int)wp->w_virtcol + 1);
  3175.  
  3176.         screen_msg(buffer, row, ru_col);
  3177.         screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
  3178.                                             (int)Columns, fillchar, fillchar);
  3179.         old_lnum = wp->w_cursor.lnum;
  3180.         old_col = wp->w_virtcol;
  3181.         stop_highlight();
  3182.     }
  3183. }
  3184.  
  3185. /*
  3186.  * screen_valid -  allocate screen buffers if size changed 
  3187.  *   If "clear" is TRUE: clear screen if it has been resized.
  3188.  *        Returns TRUE if there is a valid screen to write to.
  3189.  *        Returns FALSE when starting up and screen not initialized yet.
  3190.  */
  3191.     int
  3192. screen_valid(clear)
  3193.     int        clear;
  3194. {
  3195.     screenalloc(clear);        /* allocate screen buffers if size changed */
  3196.     return (NextScreen != NULL);
  3197. }
  3198.  
  3199. #ifdef USE_MOUSE
  3200. /*
  3201.  * Move the cursor to the specified row and column on the screen.
  3202.  * Change current window if neccesary.  Returns an integer with the
  3203.  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
  3204.  *
  3205.  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
  3206.  * if the mouse is outside the window then the text will scroll, or if the
  3207.  * mouse was previously on a status line, then the status line may be dragged.
  3208.  *
  3209.  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
  3210.  * cursor is moved unless the cursor was on a status line.  Ignoring the
  3211.  * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
  3212.  * IN_STATUS_LINE depending on where the cursor was clicked.
  3213.  *
  3214.  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
  3215.  * the last call.
  3216.  *
  3217.  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
  3218.  * remembered.
  3219.  */
  3220.     int
  3221. jump_to_mouse(flags)
  3222.     int        flags;
  3223. {
  3224.     static int on_status_line = 0;        /* #lines below bottom of window */
  3225.     static int prev_row = -1;
  3226.     static int prev_col = -1;
  3227.  
  3228.     WIN        *wp, *old_curwin;
  3229.     FPOS    old_cursor;
  3230.     int        count;
  3231.     int        first;
  3232.     int        row = mouse_row;
  3233.     int        col = mouse_col;
  3234.  
  3235.     mouse_past_bottom = FALSE;
  3236.     mouse_past_eol = FALSE;
  3237.  
  3238.     if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row &&
  3239.                                                         prev_col == mouse_col)
  3240.         return IN_BUFFER;                /* mouse pointer didn't move */
  3241.  
  3242.     prev_row = mouse_row;
  3243.     prev_col = mouse_col;
  3244.  
  3245.     if ((flags & MOUSE_SETPOS))
  3246.         return IN_BUFFER;                /* mouse pointer didn't move */
  3247.  
  3248.     old_curwin = curwin;
  3249.     old_cursor = curwin->w_cursor;
  3250.  
  3251.     if (!(flags & MOUSE_FOCUS))
  3252.     {
  3253.         if (row < 0 || col < 0)        /* check if it makes sense */
  3254.             return IN_UNKNOWN;
  3255.  
  3256.         /* find the window where the row is in */
  3257.         for (wp = firstwin; wp->w_next; wp = wp->w_next)
  3258.             if (row < wp->w_next->w_winpos)
  3259.                 break;
  3260.         /*
  3261.          * winpos and height may change in win_enter()!
  3262.          */
  3263.         row -= wp->w_winpos;
  3264.         if (row >= wp->w_height)    /* In (or below) status line */
  3265.             on_status_line = row - wp->w_height + 1;
  3266.         else
  3267.             on_status_line = 0;
  3268.         win_enter(wp, TRUE);        /* can make wp invalid! */
  3269.         if (on_status_line)            /* In (or below) status line */
  3270.         {
  3271.             /* Don't use start_arrow() if we're in the same window */
  3272.             if (curwin == old_curwin)
  3273.                 return IN_STATUS_LINE;
  3274.             else
  3275.                 return IN_STATUS_LINE | CURSOR_MOVED;
  3276.         }
  3277.  
  3278.         curwin->w_cursor.lnum = curwin->w_topline;
  3279.     }
  3280.     else if (on_status_line)
  3281.     {
  3282.         /* Drag the status line */
  3283.         count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
  3284.         win_drag_status_line(count);
  3285.         return IN_STATUS_LINE;        /* Cursor didn't move */
  3286.     }
  3287.     else /* keep_window_focus must be TRUE */
  3288.     {
  3289.         row -= curwin->w_winpos;
  3290.  
  3291.         /*
  3292.          * When clicking beyond the end of the window, scroll the screen.
  3293.          * Scroll by however many rows outside the window we are.
  3294.          */
  3295.         if (row < 0)
  3296.         {
  3297.             count = 0;
  3298.             for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
  3299.             {
  3300.                 count += plines(curwin->w_topline - 1);
  3301.                 if (!first && count > -row)
  3302.                     break;
  3303.                 first = FALSE;
  3304.             }
  3305.             redraw_later(VALID);
  3306.             row = 0;
  3307.         }
  3308.         else if (row >= curwin->w_height)
  3309.         {
  3310.             count = 0;
  3311.             for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
  3312.                                                         ++curwin->w_topline)
  3313.             {
  3314.                 count += plines(curwin->w_topline);
  3315.                 if (!first && count > row - curwin->w_height + 1)
  3316.                     break;
  3317.                 first = FALSE;
  3318.             }
  3319.             redraw_later(VALID);
  3320.             row = curwin->w_height - 1;
  3321.         }
  3322.         curwin->w_cursor.lnum = curwin->w_topline;
  3323.     }
  3324.  
  3325. #ifdef RIGHTLEFT
  3326.     if (curwin->w_p_rl)
  3327.         col = Columns - 1 - col;
  3328. #endif
  3329.  
  3330.     if (curwin->w_p_wrap)        /* lines wrap */
  3331.     {
  3332.         while (row)
  3333.         {
  3334.             count = plines(curwin->w_cursor.lnum);
  3335.             if (count > row)
  3336.             {
  3337.                 col += row * Columns;
  3338.                 break;
  3339.             }
  3340.             if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  3341.             {
  3342.                 mouse_past_bottom = TRUE;
  3343.                 break;
  3344.             }
  3345.             row -= count;
  3346.             ++curwin->w_cursor.lnum;
  3347.         }
  3348.     }
  3349.     else                        /* lines don't wrap */
  3350.     {
  3351.         curwin->w_cursor.lnum += row;
  3352.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3353.         {
  3354.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3355.             mouse_past_bottom = TRUE;
  3356.         }
  3357.         col += curwin->w_leftcol;
  3358.     }
  3359.  
  3360.     if (curwin->w_p_nu)            /* skip number in front of the line */
  3361.         if ((col -= 8) < 0)
  3362.             col = 0;
  3363.  
  3364.     curwin->w_curswant = col;
  3365.     curwin->w_set_curswant = FALSE;        /* May still have been TRUE */
  3366.     if (coladvance(col) == FAIL)
  3367.     {
  3368.         /* Mouse click beyond end of line */
  3369.         op_inclusive = TRUE;
  3370.         mouse_past_eol = TRUE;
  3371.     }
  3372.     else
  3373.         op_inclusive = FALSE;
  3374.  
  3375.     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
  3376.     {
  3377.         start_visual_highlight();
  3378.         VIsual = old_cursor;
  3379.         VIsual_active = TRUE;
  3380. #ifdef USE_MOUSE
  3381.         setmouse();
  3382. #endif
  3383.         if (p_smd)
  3384.             redraw_cmdline = TRUE;            /* show visual mode later */
  3385.     }
  3386.  
  3387.     if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
  3388.                                        curwin->w_cursor.col == old_cursor.col)
  3389.         return IN_BUFFER;                /* Cursor has not moved */
  3390.     return IN_BUFFER | CURSOR_MOVED;    /* Cursor has moved */
  3391. }
  3392. #endif /* USE_MOUSE */
  3393.  
  3394. /*
  3395.  * Redraw the screen later, with UpdateScreen(type).
  3396.  * Set must_redraw only of not already set to a higher value.
  3397.  * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
  3398.  */
  3399.     void
  3400. redraw_later(type)
  3401.     int        type;
  3402. {
  3403.     if (must_redraw < type)
  3404.         must_redraw = type;
  3405. }
  3406.