home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / move.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  63.5 KB  |  2,790 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9. /*
  10.  * move.c: Functions for moving the cursor and scrolling text.
  11.  *
  12.  * There are two ways to move the cursor:
  13.  * 1. Move the cursor directly, the text is scrolled to keep the cursor in the
  14.  *    window.
  15.  * 2. Scroll the text, the cursor is moved into the text visible in the
  16.  *    window.
  17.  * The 'scrolloff' option makes this a bit complicated.
  18.  */
  19.  
  20. #include "vim.h"
  21.  
  22. static void comp_botline __ARGS((win_T *wp));
  23. static int check_top_offset __ARGS((void));
  24. static void curs_rows __ARGS((win_T *wp, int do_botline));
  25. static void validate_botline_win __ARGS((win_T *wp));
  26. static void validate_cheight __ARGS((void));
  27.  
  28. typedef struct
  29. {
  30.     linenr_T        lnum;    /* line number */
  31. #ifdef FEAT_DIFF
  32.     int            fill;    /* filler lines */
  33. #endif
  34.     int            height;    /* height of added line */
  35. } lineoff_T;
  36.  
  37. static void topline_back __ARGS((lineoff_T *lp));
  38. static void botline_forw __ARGS((lineoff_T *lp));
  39. #ifdef FEAT_DIFF
  40. static void botline_topline __ARGS((lineoff_T *lp));
  41. static void topline_botline __ARGS((lineoff_T *lp));
  42. static void max_topfill __ARGS((void));
  43. #endif
  44.  
  45. /*
  46.  * Compute wp->w_botline for the current wp->w_topline.  Can be called after
  47.  * wp->w_topline changed.
  48.  */
  49.     static void
  50. comp_botline(wp)
  51.     win_T    *wp;
  52. {
  53.     int        n;
  54.     linenr_T    lnum;
  55.     int        done;
  56. #ifdef FEAT_FOLDING
  57.     linenr_T    last;
  58.     int        folded;
  59. #endif
  60.  
  61.     /*
  62.      * If w_cline_row is valid, start there.
  63.      * Otherwise have to start at w_topline.
  64.      */
  65.     check_cursor_moved(wp);
  66.     if (wp->w_valid & VALID_CROW)
  67.     {
  68.     lnum = wp->w_cursor.lnum;
  69.     done = wp->w_cline_row;
  70.     }
  71.     else
  72.     {
  73.     lnum = wp->w_topline;
  74.     done = 0;
  75.     }
  76.  
  77.     for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
  78.     {
  79. #ifdef FEAT_FOLDING
  80.     last = lnum;
  81.     folded = FALSE;
  82.     if (hasFoldingWin(wp, lnum, NULL, &last, TRUE, NULL))
  83.     {
  84.         n = 1;
  85.         folded = TRUE;
  86.     }
  87.     else
  88. #endif
  89. #ifdef FEAT_DIFF
  90.         if (lnum == wp->w_topline)
  91.         n = plines_win_nofill(wp, lnum, TRUE) + wp->w_topfill;
  92.         else
  93. #endif
  94.         n = plines_win(wp, lnum, TRUE);
  95.     if (
  96. #ifdef FEAT_FOLDING
  97.         lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum
  98. #else
  99.         lnum == wp->w_cursor.lnum
  100. #endif
  101.        )
  102.     {
  103.         wp->w_cline_row = done;
  104.         wp->w_cline_height = n;
  105. #ifdef FEAT_FOLDING
  106.         wp->w_cline_folded = folded;
  107. #endif
  108.         wp->w_valid |= (VALID_CROW|VALID_CHEIGHT);
  109.     }
  110.     if (done + n > wp->w_height)
  111.         break;
  112.     done += n;
  113. #ifdef FEAT_FOLDING
  114.     lnum = last;
  115. #endif
  116.     }
  117.  
  118.     /* wp->w_botline is the line that is just below the window */
  119.     wp->w_botline = lnum;
  120.     wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  121.  
  122.     set_empty_rows(wp, done);
  123. }
  124.  
  125. /*
  126.  * Update curwin->w_topline and redraw if necessary.
  127.  * Used to update the screen before printing a message.
  128.  */
  129.     void
  130. update_topline_redraw()
  131. {
  132.     update_topline();
  133.     if (must_redraw)
  134.     update_screen(0);
  135. }
  136.  
  137. /*
  138.  * Update curwin->w_topline to move the cursor onto the screen.
  139.  */
  140.     void
  141. update_topline()
  142. {
  143.     long    line_count;
  144.     int        halfheight;
  145.     int        n;
  146.     linenr_T    old_topline;
  147. #ifdef FEAT_DIFF
  148.     int        old_topfill;
  149. #endif
  150. #ifdef FEAT_FOLDING
  151.     linenr_T    lnum;
  152. #endif
  153.     int        check_topline = FALSE;
  154.     int        check_botline = FALSE;
  155. #ifdef FEAT_MOUSE
  156.     int        save_so = p_so;
  157. #endif
  158.  
  159.     if (!screen_valid(TRUE))
  160.     return;
  161.  
  162.     check_cursor_moved(curwin);
  163.     if (curwin->w_valid & VALID_TOPLINE)
  164.     return;
  165.  
  166. #ifdef FEAT_MOUSE
  167.     /* When dragging with the mouse, don't scroll that quickly */
  168.     if (mouse_dragging)
  169.     p_so = mouse_dragging - 1;
  170. #endif
  171.  
  172.     old_topline = curwin->w_topline;
  173. #ifdef FEAT_DIFF
  174.     old_topfill = curwin->w_topfill;
  175. #endif
  176.  
  177.     /*
  178.      * If the buffer is empty, always set topline to 1.
  179.      */
  180.     if (bufempty())        /* special case - file is empty */
  181.     {
  182.     if (curwin->w_topline != 1)
  183.         redraw_later(NOT_VALID);
  184.     curwin->w_topline = 1;
  185. #ifdef FEAT_DIFF
  186.     curwin->w_topfill = 0;
  187. #endif
  188.     curwin->w_botline = 2;
  189.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  190. #ifdef FEAT_SCROLLBIND
  191.     curwin->w_scbind_pos = 1;
  192. #endif
  193.     }
  194.  
  195.     /*
  196.      * If the cursor is above or near the top of the window, scroll the window
  197.      * to show the line the cursor is in, with 'scrolloff' context.
  198.      */
  199.     else
  200.     {
  201.     if (curwin->w_topline > 1)
  202.     {
  203.         /* If the cursor is above topline, scrolling is always needed.
  204.          * If the cursor is far below topline and there is no folding,
  205.          * scrolling down is never needed. */
  206.         if (curwin->w_cursor.lnum < curwin->w_topline)
  207.         check_topline = TRUE;
  208.         else if (check_top_offset())
  209.         check_topline = TRUE;
  210. #ifdef FEAT_DIFF
  211.         /* Check if there are more filler lines than allowed. */
  212.         else if (curwin->w_topfill > diff_check_fill(curwin,
  213.                                curwin->w_topline))
  214.         check_topline = TRUE;
  215. #endif
  216.     }
  217.  
  218.     if (check_topline)
  219.     {
  220.         halfheight = curwin->w_height / 2 - 1;
  221.         if (halfheight < 2)
  222.         halfheight = 2;
  223.  
  224. #ifdef FEAT_FOLDING
  225.         if (hasAnyFolding(curwin))
  226.         {
  227.         /* Count the number of logical lines between the cursor and
  228.          * topline + p_so (approximation of how much will be
  229.          * scrolled). */
  230.         n = 0;
  231.         for (lnum = curwin->w_cursor.lnum;
  232.                       lnum < curwin->w_topline + p_so; ++lnum)
  233.         {
  234.             ++n;
  235.             /* stop at end of file or when we know we are far off */
  236.             if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight)
  237.             break;
  238.             (void)hasFolding(lnum, NULL, &lnum);
  239.         }
  240.         }
  241.         else
  242. #endif
  243.         n = curwin->w_topline + p_so - curwin->w_cursor.lnum;
  244.  
  245.         /* If we weren't very close to begin with, we scroll to put the
  246.          * cursor in the middle of the window.  Otherwise put the cursor
  247.          * near the top of the window. */
  248.         if (n >= halfheight)
  249.         scroll_cursor_halfway(FALSE);
  250.         else
  251.         {
  252.         scroll_cursor_top((int)p_sj, FALSE);
  253.         check_botline = TRUE;
  254.         }
  255.     }
  256.  
  257.     else
  258.     {
  259. #ifdef FEAT_FOLDING
  260.         /* Make sure topline is the first line of a fold. */
  261.         (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  262. #endif
  263.         check_botline = TRUE;
  264.     }
  265.     }
  266.  
  267.     /*
  268.      * If the cursor is below the bottom of the window, scroll the window
  269.      * to put the cursor on the window.
  270.      * When w_botline is invalid, recompute it first, to avoid a redraw later.
  271.      * If w_botline was approximated, we might need a redraw later in a few
  272.      * cases, but we don't want to spend (a lot of) time recomputing w_botline
  273.      * for every small change.
  274.      */
  275.     if (check_botline)
  276.     {
  277.     if (!(curwin->w_valid & VALID_BOTLINE_AP))
  278.         validate_botline();
  279.  
  280.     if (curwin->w_botline <= curbuf->b_ml.ml_line_count)
  281.     {
  282.         if (curwin->w_cursor.lnum < curwin->w_botline
  283.             && ((long)curwin->w_cursor.lnum
  284.                          >= (long)curwin->w_botline - p_so
  285. #ifdef FEAT_FOLDING
  286.             || hasAnyFolding(curwin)
  287. #endif
  288.             ))
  289.         {
  290.         lineoff_T    loff;
  291.  
  292.         /* Cursor is above botline, check if there are 'scrolloff'
  293.          * window lines below the cursor.  If not, need to scroll. */
  294.         n = curwin->w_empty_rows;
  295.         loff.lnum = curwin->w_cursor.lnum;
  296. #ifdef FEAT_FOLDING
  297.         /* In a fold go to its last line. */
  298.         (void)hasFolding(loff.lnum, NULL, &loff.lnum);
  299. #endif
  300. #ifdef FEAT_DIFF
  301.         loff.fill = 0;
  302.         n += curwin->w_filler_rows;
  303. #endif
  304.         loff.height = 0;
  305.         while (loff.lnum < curwin->w_botline
  306. #ifdef FEAT_DIFF
  307.             && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0)
  308. #endif
  309.             )
  310.         {
  311.             n += loff.height;
  312.             if (n >= p_so)
  313.             break;
  314.             botline_forw(&loff);
  315.         }
  316.         if (n >= p_so)
  317.             /* sufficient context, no need to scroll */
  318.             check_botline = FALSE;
  319.         }
  320.         if (check_botline)
  321.         {
  322. #ifdef FEAT_FOLDING
  323.         if (hasAnyFolding(curwin))
  324.         {
  325.             /* Count the number of logical lines between the cursor and
  326.              * botline - p_so (approximation of how much will be
  327.              * scrolled). */
  328.             line_count = 0;
  329.             for (lnum = curwin->w_cursor.lnum;
  330.                      lnum >= curwin->w_botline - p_so; --lnum)
  331.             {
  332.             ++line_count;
  333.             /* stop at end of file or when we know we are far off */
  334.             if (lnum <= 0 || line_count > curwin->w_height + 1)
  335.                 break;
  336.             (void)hasFolding(lnum, &lnum, NULL);
  337.             }
  338.         }
  339.         else
  340. #endif
  341.             line_count = curwin->w_cursor.lnum - curwin->w_botline
  342.                                    + 1 + p_so;
  343.         if (line_count <= curwin->w_height + 1)
  344.             scroll_cursor_bot((int)p_sj, FALSE);
  345.         else
  346.             scroll_cursor_halfway(FALSE);
  347.         }
  348.     }
  349.     }
  350.     curwin->w_valid |= VALID_TOPLINE;
  351.  
  352.     /*
  353.      * Need to redraw when topline changed.
  354.      */
  355.     if (curwin->w_topline != old_topline
  356. #ifdef FEAT_DIFF
  357.         || curwin->w_topfill != old_topfill
  358. #endif
  359.         )
  360.     {
  361.     dollar_vcol = 0;
  362.     if (curwin->w_skipcol)
  363.     {
  364.         curwin->w_skipcol = 0;
  365.         redraw_later(NOT_VALID);
  366.     }
  367.     else
  368.         redraw_later(VALID);
  369.     /* May need to set w_skipcol when cursor in w_topline. */
  370.     if (curwin->w_cursor.lnum == curwin->w_topline)
  371.         validate_cursor();
  372.     }
  373.  
  374. #ifdef FEAT_MOUSE
  375.     p_so = save_so;
  376. #endif
  377. }
  378.  
  379. /*
  380.  * Return TRUE when there are not 'scrolloff' lines above the cursor for the
  381.  * current window.
  382.  */
  383.     static int
  384. check_top_offset()
  385. {
  386.     lineoff_T    loff;
  387.     int        n;
  388.  
  389.     if (curwin->w_cursor.lnum < curwin->w_topline + p_so
  390. #ifdef FEAT_FOLDING
  391.             || hasAnyFolding(curwin)
  392. #endif
  393.         )
  394.     {
  395.     loff.lnum = curwin->w_cursor.lnum;
  396. #ifdef FEAT_DIFF
  397.     loff.fill = 0;
  398.     n = curwin->w_topfill;        /* always have this context */
  399. #else
  400.     n = 0;
  401. #endif
  402.     /* Count the visible screen lines above the cursor line. */
  403.     while (n < p_so)
  404.     {
  405.         topline_back(&loff);
  406.         /* Stop when included a line above the window. */
  407.         if (loff.lnum < curwin->w_topline
  408. #ifdef FEAT_DIFF
  409.             || (loff.lnum == curwin->w_topline && loff.fill > 0)
  410. #endif
  411.             )
  412.         break;
  413.         n += loff.height;
  414.     }
  415.     if (n < p_so)
  416.         return TRUE;
  417.     }
  418.     return FALSE;
  419. }
  420.  
  421.     void
  422. update_curswant()
  423. {
  424.     if (curwin->w_set_curswant)
  425.     {
  426.     validate_virtcol();
  427.     curwin->w_curswant = curwin->w_virtcol;
  428.     curwin->w_set_curswant = FALSE;
  429.     }
  430. }
  431.  
  432. /*
  433.  * Check if the cursor has moved.  Set the w_valid flag accordingly.
  434.  */
  435.     void
  436. check_cursor_moved(wp)
  437.     win_T    *wp;
  438. {
  439.     if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
  440.     {
  441.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  442.                      |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
  443.     wp->w_valid_cursor = wp->w_cursor;
  444.     wp->w_valid_leftcol = wp->w_leftcol;
  445.     }
  446.     else if (wp->w_cursor.col != wp->w_valid_cursor.col
  447.          || wp->w_leftcol != wp->w_valid_leftcol
  448. #ifdef FEAT_VIRTUALEDIT
  449.          || wp->w_cursor.coladd != wp->w_valid_cursor.coladd
  450. #endif
  451.          )
  452.     {
  453.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
  454.     wp->w_valid_cursor.col = wp->w_cursor.col;
  455.     wp->w_valid_leftcol = wp->w_leftcol;
  456. #ifdef FEAT_VIRTUALEDIT
  457.     wp->w_valid_cursor.coladd = wp->w_cursor.coladd;
  458. #endif
  459.     }
  460. }
  461.  
  462. /*
  463.  * Call this function when some window settings have changed, which require
  464.  * the cursor position, botline and topline to be recomputed and the window to
  465.  * be redrawn.  E.g, when changing the 'wrap' option or folding.
  466.  */
  467.     void
  468. changed_window_setting()
  469. {
  470.     curwin->w_lines_valid = 0;
  471.     changed_line_abv_curs();
  472.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP|VALID_TOPLINE);
  473.     redraw_later(NOT_VALID);
  474. }
  475.  
  476. /*
  477.  * Set wp->w_topline to a certain number.
  478.  */
  479.     void
  480. set_topline(wp, lnum)
  481.     win_T    *wp;
  482.     linenr_T    lnum;
  483. {
  484. #ifdef FEAT_FOLDING
  485.     /* go to first of folded lines */
  486.     (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
  487. #endif
  488.     /* Approximate the value of w_botline */
  489.     wp->w_botline += lnum - wp->w_topline;
  490.     wp->w_topline = lnum;
  491. #ifdef FEAT_DIFF
  492.     wp->w_topfill = 0;
  493. #endif
  494.     wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
  495.     /* Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked. */
  496.     redraw_later(VALID);
  497. }
  498.  
  499. /*
  500.  * Call this function when the length of the cursor line (in screen
  501.  * characters) has changed, and the change is before the cursor.
  502.  * Need to take care of w_botline separately!
  503.  */
  504.     void
  505. changed_cline_bef_curs()
  506. {
  507.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  508.                         |VALID_CHEIGHT|VALID_TOPLINE);
  509. }
  510.  
  511.     void
  512. changed_cline_bef_curs_win(wp)
  513.     win_T    *wp;
  514. {
  515.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  516.                         |VALID_CHEIGHT|VALID_TOPLINE);
  517. }
  518.  
  519. #if 0 /* not used */
  520. /*
  521.  * Call this function when the length of the cursor line (in screen
  522.  * characters) has changed, and the position of the cursor doesn't change.
  523.  * Need to take care of w_botline separately!
  524.  */
  525.     void
  526. changed_cline_aft_curs()
  527. {
  528.     curwin->w_valid &= ~VALID_CHEIGHT;
  529. }
  530. #endif
  531.  
  532. /*
  533.  * Call this function when the length of a line (in screen characters) above
  534.  * the cursor have changed.
  535.  * Need to take care of w_botline separately!
  536.  */
  537.     void
  538. changed_line_abv_curs()
  539. {
  540.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
  541.                         |VALID_CHEIGHT|VALID_TOPLINE);
  542. }
  543.  
  544.     void
  545. changed_line_abv_curs_win(wp)
  546.     win_T    *wp;
  547. {
  548.     wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
  549.                         |VALID_CHEIGHT|VALID_TOPLINE);
  550. }
  551.  
  552. /*
  553.  * Make sure the value of curwin->w_botline is valid.
  554.  */
  555.     void
  556. validate_botline()
  557. {
  558.     if (!(curwin->w_valid & VALID_BOTLINE))
  559.     comp_botline(curwin);
  560. }
  561.  
  562. /*
  563.  * Make sure the value of wp->w_botline is valid.
  564.  */
  565.     static void
  566. validate_botline_win(wp)
  567.     win_T    *wp;
  568. {
  569.     if (!(wp->w_valid & VALID_BOTLINE))
  570.     comp_botline(wp);
  571. }
  572.  
  573. /*
  574.  * Mark curwin->w_botline as invalid (because of some change in the buffer).
  575.  */
  576.     void
  577. invalidate_botline()
  578. {
  579.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  580. }
  581.  
  582.     void
  583. invalidate_botline_win(wp)
  584.     win_T    *wp;
  585. {
  586.     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  587. }
  588.  
  589. #if 0 /* never used */
  590. /*
  591.  * Mark curwin->w_botline as approximated (because of some small change in the
  592.  * buffer).
  593.  */
  594.     void
  595. approximate_botline()
  596. {
  597.     curwin->w_valid &= ~VALID_BOTLINE;
  598. }
  599. #endif
  600.  
  601.     void
  602. approximate_botline_win(wp)
  603.     win_T    *wp;
  604. {
  605.     wp->w_valid &= ~VALID_BOTLINE;
  606. }
  607.  
  608. #if 0 /* not used */
  609. /*
  610.  * Return TRUE if curwin->w_botline is valid.
  611.  */
  612.     int
  613. botline_valid()
  614. {
  615.     return (curwin->w_valid & VALID_BOTLINE);
  616. }
  617. #endif
  618.  
  619. #if 0 /* not used */
  620. /*
  621.  * Return TRUE if curwin->w_botline is valid or approximated.
  622.  */
  623.     int
  624. botline_approximated()
  625. {
  626.     return (curwin->w_valid & VALID_BOTLINE_AP);
  627. }
  628. #endif
  629.  
  630. /*
  631.  * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
  632.  */
  633.     int
  634. cursor_valid()
  635. {
  636.     check_cursor_moved(curwin);
  637.     return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
  638.                               (VALID_WROW|VALID_WCOL));
  639. }
  640.  
  641. /*
  642.  * Validate cursor position.  Makes sure w_wrow and w_wcol are valid.
  643.  * w_topline must be valid, you may need to call update_topline() first!
  644.  */
  645.     void
  646. validate_cursor()
  647. {
  648.     check_cursor_moved(curwin);
  649.     if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
  650.     curs_columns(TRUE);
  651. }
  652.  
  653. #if defined(FEAT_GUI) || defined(PROTO)
  654. /*
  655.  * validate w_cline_row.
  656.  */
  657.     void
  658. validate_cline_row()
  659. {
  660.     /*
  661.      * First make sure that w_topline is valid (after moving the cursor).
  662.      */
  663.     update_topline();
  664.     check_cursor_moved(curwin);
  665.     if (!(curwin->w_valid & VALID_CROW))
  666.     curs_rows(curwin, FALSE);
  667. }
  668. #endif
  669.  
  670. /*
  671.  * Compute wp->w_cline_row and wp->w_cline_height, based on the current value
  672.  * of wp->w_topine.
  673.  *
  674.  * Returns OK when cursor is in the window, FAIL when it isn't.
  675.  */
  676.     static void
  677. curs_rows(wp, do_botline)
  678.     win_T    *wp;
  679.     int        do_botline;        /* also compute w_botline */
  680. {
  681.     linenr_T    lnum;
  682.     int        i;
  683.     int        all_invalid;
  684.     int        valid;
  685. #ifdef FEAT_FOLDING
  686.     long    fold_count;
  687. #endif
  688.  
  689.     /* Check if wp->w_lines[].wl_size is invalid */
  690.     all_invalid = (!redrawing()
  691.             || wp->w_lines_valid == 0
  692.             || wp->w_lines[0].wl_lnum > wp->w_topline);
  693.     i = 0;
  694.     wp->w_cline_row = 0;
  695.     for (lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i)
  696.     {
  697.     valid = FALSE;
  698.     if (!all_invalid && i < wp->w_lines_valid)
  699.     {
  700.         if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
  701.         continue;        /* skip changed or deleted lines */
  702.         if (wp->w_lines[i].wl_lnum == lnum)
  703.         {
  704. #ifdef FEAT_FOLDING
  705.         /* Check for newly inserted lines below this row, in which
  706.          * case we need to check for folded lines. */
  707.         if (!wp->w_buffer->b_mod_set
  708.             || wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
  709.             || wp->w_buffer->b_mod_top
  710.                          > wp->w_lines[i].wl_lastlnum + 1)
  711. #endif
  712.         valid = TRUE;
  713.         }
  714.         else if (wp->w_lines[i].wl_lnum > lnum)
  715.         --i;            /* hold at inserted lines */
  716.     }
  717.     if (valid
  718. #ifdef FEAT_DIFF
  719.         && (lnum != wp->w_topline || !wp->w_p_diff)
  720. #endif
  721.         )
  722.     {
  723. #ifdef FEAT_FOLDING
  724.         lnum = wp->w_lines[i].wl_lastlnum + 1;
  725.         /* Cursor inside folded lines, don't count this row */
  726.         if (lnum > wp->w_cursor.lnum)
  727.         break;
  728. #else
  729.         ++lnum;
  730. #endif
  731.         wp->w_cline_row += wp->w_lines[i].wl_size;
  732.     }
  733.     else
  734.     {
  735. #ifdef FEAT_FOLDING
  736.         fold_count = foldedCount(wp, lnum, NULL);
  737.         if (fold_count)
  738.         {
  739.         lnum += fold_count;
  740.         if (lnum > wp->w_cursor.lnum)
  741.             break;
  742.         ++wp->w_cline_row;
  743.         }
  744.         else
  745. #endif
  746. #ifdef FEAT_DIFF
  747.         if (lnum == wp->w_topline)
  748.             wp->w_cline_row += plines_win_nofill(wp, lnum++, TRUE)
  749.             + wp->w_topfill;
  750.         else
  751. #endif
  752.             wp->w_cline_row += plines_win(wp, lnum++, TRUE);
  753.     }
  754.     }
  755.  
  756.     check_cursor_moved(wp);
  757.     if (!(wp->w_valid & VALID_CHEIGHT))
  758.     {
  759.     if (all_invalid
  760.         || i == wp->w_lines_valid
  761.         || (i < wp->w_lines_valid
  762.             && (!wp->w_lines[i].wl_valid
  763.             || wp->w_lines[i].wl_lnum != wp->w_cursor.lnum)))
  764.     {
  765. #ifdef FEAT_DIFF
  766.         if (wp->w_cursor.lnum == wp->w_topline)
  767.         wp->w_cline_height = plines_win_nofill(wp, wp->w_cursor.lnum,
  768.                             TRUE) + wp->w_topfill;
  769.         else
  770. #endif
  771.         wp->w_cline_height = plines_win(wp, wp->w_cursor.lnum, TRUE);
  772. #ifdef FEAT_FOLDING
  773.         wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
  774.                               NULL, NULL, TRUE, NULL);
  775. #endif
  776.     }
  777.     else if (i > wp->w_lines_valid)
  778.     {
  779.         /* a line that is too long to fit on the last screen line */
  780.         wp->w_cline_height = 0;
  781. #ifdef FEAT_FOLDING
  782.         wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum,
  783.                               NULL, NULL, TRUE, NULL);
  784. #endif
  785.     }
  786.     else
  787.     {
  788.         wp->w_cline_height = wp->w_lines[i].wl_size;
  789. #ifdef FEAT_FOLDING
  790.         wp->w_cline_folded = wp->w_lines[i].wl_folded;
  791. #endif
  792.     }
  793.     }
  794.  
  795.     wp->w_valid |= VALID_CROW|VALID_CHEIGHT;
  796.  
  797.     /* validate botline too, if update_screen doesn't do it */
  798.     if (do_botline && all_invalid)
  799.     validate_botline_win(wp);
  800. }
  801.  
  802. /*
  803.  * Validate curwin->w_virtcol only.
  804.  */
  805.     void
  806. validate_virtcol()
  807. {
  808.     validate_virtcol_win(curwin);
  809. }
  810.  
  811. /*
  812.  * Validate wp->w_virtcol only.
  813.  */
  814.     void
  815. validate_virtcol_win(wp)
  816.     win_T    *wp;
  817. {
  818.     check_cursor_moved(wp);
  819.     if (!(wp->w_valid & VALID_VIRTCOL))
  820.     {
  821.     getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
  822.     wp->w_valid |= VALID_VIRTCOL;
  823.     }
  824. }
  825.  
  826. /*
  827.  * Validate curwin->w_cline_height only.
  828.  */
  829.     static void
  830. validate_cheight()
  831. {
  832.     check_cursor_moved(curwin);
  833.     if (!(curwin->w_valid & VALID_CHEIGHT))
  834.     {
  835. #ifdef FEAT_DIFF
  836.     if (curwin->w_cursor.lnum == curwin->w_topline)
  837.         curwin->w_cline_height = plines_nofill(curwin->w_cursor.lnum)
  838.                               + curwin->w_topfill;
  839.     else
  840. #endif
  841.         curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  842. #ifdef FEAT_FOLDING
  843.     curwin->w_cline_folded = hasFolding(curwin->w_cursor.lnum, NULL, NULL);
  844. #endif
  845.     curwin->w_valid |= VALID_CHEIGHT;
  846.     }
  847. }
  848.  
  849. /*
  850.  * validate w_wcol and w_virtcol only.    Only correct when 'wrap' on!
  851.  */
  852.     void
  853. validate_cursor_col()
  854. {
  855.     colnr_T off;
  856.     colnr_T col;
  857.  
  858.     validate_virtcol();
  859.     if (!(curwin->w_valid & VALID_WCOL))
  860.     {
  861.     col = curwin->w_virtcol;
  862.     off = curwin_col_off();
  863.     col += off;
  864.  
  865.     /* long line wrapping, adjust curwin->w_wrow */
  866.     if (curwin->w_p_wrap && col >= (colnr_T)W_WIDTH(curwin)
  867. #ifdef FEAT_VERTSPLIT
  868.         && curwin->w_width != 0
  869. #endif
  870.         )
  871.     {
  872.         col -= W_WIDTH(curwin);
  873.         col = col % (W_WIDTH(curwin) - off + curwin_col_off2());
  874.     }
  875.     curwin->w_wcol = col;
  876.     curwin->w_valid |= VALID_WCOL;
  877.     }
  878. }
  879.  
  880. /*
  881.  * Compute offset of a window, occupied by line number, fold column and sign
  882.  * column (these don't move when scrolling horizontally).
  883.  */
  884.     int
  885. win_col_off(wp)
  886.     win_T    *wp;
  887. {
  888.     return ((wp->w_p_nu ? 8 : 0)
  889. #ifdef FEAT_CMDWIN
  890.         + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
  891. #endif
  892. #ifdef FEAT_FOLDING
  893.         + wp->w_p_fdc
  894. #endif
  895. #ifdef FEAT_SIGNS
  896.         + (
  897. # ifdef FEAT_NETBEANS_INTG
  898.         /* always show glyph gutter in netbeans */
  899.         usingNetbeans ||
  900. # endif
  901.         wp->w_buffer->b_signlist != NULL ? 2 : 0)
  902. #endif
  903.        );
  904. }
  905.  
  906.     int
  907. curwin_col_off()
  908. {
  909.     return win_col_off(curwin);
  910. }
  911.  
  912. /*
  913.  * Return the difference in column offset for the second screen line of a
  914.  * wrapped line.  It's 8 if 'number' is on and 'n' is in 'cpoptions'.
  915.  */
  916.     int
  917. win_col_off2(wp)
  918.     win_T    *wp;
  919. {
  920.     if (wp->w_p_nu && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
  921.     return 8;
  922.     return 0;
  923. }
  924.  
  925.     int
  926. curwin_col_off2()
  927. {
  928.     return win_col_off2(curwin);
  929. }
  930.  
  931. /*
  932.  * compute curwin->w_wcol and curwin->w_virtcol.
  933.  * Also updates curwin->w_wrow and curwin->w_cline_row.
  934.  * Also updates curwin->w_leftcol.
  935.  */
  936.     void
  937. curs_columns(scroll)
  938.     int        scroll;        /* when TRUE, may scroll horizontally */
  939. {
  940.     int        diff;
  941.     int        extra;        /* offset for first screen line */
  942.     int        off_left, off_right;
  943.     int        n;
  944.     int        p_lines;
  945.     int        width = 0;
  946.     int        textwidth;
  947.     int        new_leftcol;
  948.     colnr_T    startcol;
  949.     colnr_T    endcol;
  950.     colnr_T    prev_skipcol;
  951.  
  952.     /*
  953.      * First make sure that w_topline is valid (after moving the cursor).
  954.      */
  955.     update_topline();
  956.  
  957.     /*
  958.      * Next make sure that w_cline_row is valid.
  959.      */
  960.     if (!(curwin->w_valid & VALID_CROW))
  961.     curs_rows(curwin, FALSE);
  962.  
  963.     /*
  964.      * Compute the number of virtual columns.
  965.      */
  966. #ifdef FEAT_FOLDING
  967.     if (curwin->w_cline_folded)
  968.     /* In a folded line the cursor is always in the first column */
  969.     startcol = curwin->w_virtcol = endcol = curwin->w_leftcol;
  970.     else
  971. #endif
  972.     getvvcol(curwin, &curwin->w_cursor,
  973.                 &startcol, &(curwin->w_virtcol), &endcol);
  974.  
  975.     /* remove '$' from change command when cursor moves onto it */
  976.     if (startcol > dollar_vcol)
  977.     dollar_vcol = 0;
  978.  
  979.     extra = curwin_col_off();
  980.     curwin->w_wcol = curwin->w_virtcol + extra;
  981.     endcol += extra;
  982.  
  983.     /*
  984.      * Now compute w_wrow, counting screen lines from w_cline_row.
  985.      */
  986.     curwin->w_wrow = curwin->w_cline_row;
  987.  
  988.     textwidth = W_WIDTH(curwin) - extra;
  989.     if (textwidth <= 0)
  990.     {
  991.     /* No room for text, put cursor in last char of window. */
  992.     curwin->w_wcol = W_WIDTH(curwin) - 1;
  993.     curwin->w_wrow = curwin->w_height - 1;
  994.     }
  995.     else if (curwin->w_p_wrap
  996. #ifdef FEAT_VERTSPLIT
  997.         && curwin->w_width != 0
  998. #endif
  999.         )
  1000.     {
  1001.     width = textwidth + curwin_col_off2();
  1002.  
  1003.     /* long line wrapping, adjust curwin->w_wrow */
  1004.     if (curwin->w_wcol >= W_WIDTH(curwin))
  1005.     {
  1006.         n = (curwin->w_wcol - W_WIDTH(curwin)) / width + 1;
  1007.         curwin->w_wcol -= n * width;
  1008.         curwin->w_wrow += n;
  1009.  
  1010. #ifdef FEAT_LINEBREAK
  1011.         /* When cursor wraps to first char of next line in Insert
  1012.          * mode, the 'showbreak' string isn't shown, backup to first
  1013.          * column */
  1014.         if (*p_sbr && *ml_get_cursor() == NUL
  1015.             && curwin->w_wcol == (int)vim_strsize(p_sbr))
  1016.         curwin->w_wcol = 0;
  1017. #endif
  1018.     }
  1019.     }
  1020.  
  1021.     /* No line wrapping: compute curwin->w_leftcol if scrolling is on and line
  1022.      * is not folded.
  1023.      * If scrolling is off, curwin->w_leftcol is assumed to be 0 */
  1024.     else if (scroll
  1025. #ifdef FEAT_FOLDING
  1026.         && !curwin->w_cline_folded
  1027. #endif
  1028.         )
  1029.     {
  1030.     /*
  1031.      * If Cursor is left of the screen, scroll rightwards.
  1032.      * If Cursor is right of the screen, scroll leftwards
  1033.      * If we get closer to the edge than 'sidescrolloff', scroll a little
  1034.      * extra
  1035.      */
  1036.     off_left = (int)startcol - (int)curwin->w_leftcol - p_siso;
  1037.     off_right = (int)endcol - (int)(curwin->w_leftcol + W_WIDTH(curwin)
  1038.                                 - p_siso) + 1;
  1039.     if (off_left < 0 || off_right > 0)
  1040.     {
  1041.         if (off_left < 0)
  1042.         diff = -off_left;
  1043.         else
  1044.         diff = off_right;
  1045.  
  1046.         /* When far off or not enough room on either side, put cursor in
  1047.          * middle of window. */
  1048.         if (p_ss == 0 || diff >= textwidth / 2 || off_right >= off_left)
  1049.         new_leftcol = curwin->w_wcol - extra - textwidth / 2;
  1050.         else
  1051.         {
  1052.         if (diff < p_ss)
  1053.             diff = p_ss;
  1054.         if (off_left < 0)
  1055.             new_leftcol = curwin->w_leftcol - diff;
  1056.         else
  1057.             new_leftcol = curwin->w_leftcol + diff;
  1058.         }
  1059.         if (new_leftcol < 0)
  1060.         new_leftcol = 0;
  1061.         if (new_leftcol != (int)curwin->w_leftcol)
  1062.         {
  1063.         curwin->w_leftcol = new_leftcol;
  1064.         /* screen has to be redrawn with new curwin->w_leftcol */
  1065.         redraw_later(NOT_VALID);
  1066.         }
  1067.     }
  1068.     curwin->w_wcol -= curwin->w_leftcol;
  1069.     }
  1070.     else if (curwin->w_wcol > (int)curwin->w_leftcol)
  1071.     curwin->w_wcol -= curwin->w_leftcol;
  1072.     else
  1073.     curwin->w_wcol = 0;
  1074.  
  1075. #ifdef FEAT_DIFF
  1076.     /* Skip over filler lines.  At the top use w_topfill, there
  1077.      * may be some filler lines above the window. */
  1078.     if (curwin->w_cursor.lnum == curwin->w_topline)
  1079.     curwin->w_wrow += curwin->w_topfill;
  1080.     else
  1081.     curwin->w_wrow += diff_check_fill(curwin, curwin->w_cursor.lnum);
  1082. #endif
  1083.  
  1084.     prev_skipcol = curwin->w_skipcol;
  1085.  
  1086.     p_lines = 0;
  1087.     if ((curwin->w_wrow >= curwin->w_height
  1088.         || ((prev_skipcol > 0
  1089.             || curwin->w_wrow + p_so >= curwin->w_height)
  1090.             && (p_lines =
  1091. #ifdef FEAT_DIFF
  1092.             plines_win_nofill
  1093. #else
  1094.             plines_win
  1095. #endif
  1096.             (curwin, curwin->w_cursor.lnum, FALSE))
  1097.                             - 1 >= curwin->w_height))
  1098.         && curwin->w_height != 0
  1099.         && curwin->w_cursor.lnum == curwin->w_topline
  1100.         && width > 0
  1101. #ifdef FEAT_VERTSPLIT
  1102.         && curwin->w_width != 0
  1103. #endif
  1104.         )
  1105.     {
  1106.     /* Cursor past end of screen.  Happens with a single line that does
  1107.      * not fit on screen.  Find a skipcol to show the text around the
  1108.      * cursor.  Avoid scrolling all the time. compute value of "extra":
  1109.      * 1: Less than "p_so" lines above
  1110.      * 2: Less than "p_so" lines below
  1111.      * 3: both of them */
  1112.     extra = 0;
  1113.     if (curwin->w_skipcol + p_so * width > curwin->w_virtcol)
  1114.         extra = 1;
  1115.     /* Compute last display line of the buffer line that we want at the
  1116.      * bottom of the window. */
  1117.     if (p_lines == 0)
  1118.         p_lines = plines_win(curwin, curwin->w_cursor.lnum, FALSE);
  1119.     --p_lines;
  1120.     if (p_lines > curwin->w_wrow + p_so)
  1121.         n = curwin->w_wrow + p_so;
  1122.     else
  1123.         n = p_lines;
  1124.     if ((colnr_T)n >= curwin->w_height + curwin->w_skipcol / width)
  1125.         extra += 2;
  1126.  
  1127.     if (extra == 3 || p_lines < p_so * 2)
  1128.     {
  1129.         /* not enough room for 'scrolloff', put cursor in the middle */
  1130.         n = curwin->w_virtcol / width;
  1131.         if (n > curwin->w_height / 2)
  1132.         n -= curwin->w_height / 2;
  1133.         else
  1134.         n = 0;
  1135.         /* don't skip more than necessary */
  1136.         if (n > p_lines - curwin->w_height + 1)
  1137.         n = p_lines - curwin->w_height + 1;
  1138.         curwin->w_skipcol = n * width;
  1139.     }
  1140.     else if (extra == 1)
  1141.     {
  1142.         /* less then 'scrolloff' lines above, decrease skipcol */
  1143.         extra = (curwin->w_skipcol + p_so * width - curwin->w_virtcol
  1144.                      + width - 1) / width;
  1145.         if (extra > 0)
  1146.         {
  1147.         if ((colnr_T)(extra * width) > curwin->w_skipcol)
  1148.             extra = curwin->w_skipcol / width;
  1149.         curwin->w_skipcol -= extra * width;
  1150.         }
  1151.     }
  1152.     else if (extra == 2)
  1153.     {
  1154.         /* less then 'scrolloff' lines below, increase skipcol */
  1155.         endcol = (n - curwin->w_height + 1) * width;
  1156.         while (endcol > curwin->w_virtcol)
  1157.         endcol -= width;
  1158.         if (endcol > curwin->w_skipcol)
  1159.         curwin->w_skipcol = endcol;
  1160.     }
  1161.  
  1162.     curwin->w_wrow -= curwin->w_skipcol / width;
  1163.     if (curwin->w_wrow >= curwin->w_height)
  1164.     {
  1165.         /* small window, make sure cursor is in it */
  1166.         extra = curwin->w_wrow - curwin->w_height + 1;
  1167.         curwin->w_skipcol += extra * width;
  1168.         curwin->w_wrow -= extra;
  1169.     }
  1170.  
  1171.     extra = ((int)prev_skipcol - (int)curwin->w_skipcol) / width;
  1172.     if (extra > 0)
  1173.         win_ins_lines(curwin, 0, extra, FALSE, FALSE);
  1174.     else if (extra < 0)
  1175.         win_del_lines(curwin, 0, -extra, FALSE, FALSE);
  1176.     }
  1177.     else
  1178.     curwin->w_skipcol = 0;
  1179.     if (prev_skipcol != curwin->w_skipcol)
  1180.     redraw_later(NOT_VALID);
  1181.  
  1182.     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
  1183. }
  1184.  
  1185. /*
  1186.  * Scroll the current window down by "line_count" logical lines.  "CTRL-Y"
  1187.  */
  1188. /*ARGSUSED*/
  1189.     void
  1190. scrolldown(line_count, byfold)
  1191.     long    line_count;
  1192.     int        byfold;        /* TRUE: count a closed fold as one line */
  1193. {
  1194.     long    done = 0;    /* total # of physical lines done */
  1195.     int        wrow;
  1196.     int        moved = FALSE;
  1197.  
  1198. #ifdef FEAT_FOLDING
  1199.     linenr_T    first;
  1200.  
  1201.     /* Make sure w_topline is at the first of a sequence of folded lines. */
  1202.     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  1203. #endif
  1204.     validate_cursor();        /* w_wrow needs to be valid */
  1205.     while (line_count-- > 0)
  1206.     {
  1207. #ifdef FEAT_DIFF
  1208.     if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
  1209.     {
  1210.         ++curwin->w_topfill;
  1211.         ++done;
  1212.     }
  1213.     else
  1214. #endif
  1215.     {
  1216.         if (curwin->w_topline == 1)
  1217.         break;
  1218.         --curwin->w_topline;
  1219. #ifdef FEAT_DIFF
  1220.         curwin->w_topfill = 0;
  1221. #endif
  1222. #ifdef FEAT_FOLDING
  1223.         /* A sequence of folded lines only counts for one logical line */
  1224.         if (hasFolding(curwin->w_topline, &first, NULL))
  1225.         {
  1226.         ++done;
  1227.         if (!byfold)
  1228.             line_count -= curwin->w_topline - first - 1;
  1229.         curwin->w_botline -= curwin->w_topline - first;
  1230.         curwin->w_topline = first;
  1231.         }
  1232.         else
  1233. #endif
  1234. #ifdef FEAT_DIFF
  1235.         done += plines_nofill(curwin->w_topline);
  1236. #else
  1237.         done += plines(curwin->w_topline);
  1238. #endif
  1239.     }
  1240.     --curwin->w_botline;        /* approximate w_botline */
  1241.     invalidate_botline();
  1242.     }
  1243.     curwin->w_wrow += done;        /* keep w_wrow updated */
  1244.     curwin->w_cline_row += done;    /* keep w_cline_row updated */
  1245.  
  1246. #ifdef FEAT_DIFF
  1247.     if (curwin->w_cursor.lnum == curwin->w_topline)
  1248.     curwin->w_cline_row = 0;
  1249.     check_topfill(curwin, TRUE);
  1250. #endif
  1251.  
  1252.     /*
  1253.      * Compute the row number of the last row of the cursor line
  1254.      * and move the cursor onto the displayed part of the window.
  1255.      */
  1256.     wrow = curwin->w_wrow;
  1257.     if (curwin->w_p_wrap
  1258. #ifdef FEAT_VERTSPLIT
  1259.         && curwin->w_width != 0
  1260. #endif
  1261.         )
  1262.     {
  1263.     validate_virtcol();
  1264.     validate_cheight();
  1265.     wrow += curwin->w_cline_height - 1 -
  1266.         curwin->w_virtcol / W_WIDTH(curwin);
  1267.     }
  1268.     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
  1269.     {
  1270. #ifdef FEAT_FOLDING
  1271.     if (hasFolding(curwin->w_cursor.lnum, &first, NULL))
  1272.     {
  1273.         --wrow;
  1274.         if (first == 1)
  1275.         curwin->w_cursor.lnum = 1;
  1276.         else
  1277.         curwin->w_cursor.lnum = first - 1;
  1278.     }
  1279.     else
  1280. #endif
  1281.         wrow -= plines(curwin->w_cursor.lnum--);
  1282.     curwin->w_valid &=
  1283.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1284.     moved = TRUE;
  1285.     }
  1286.     if (moved)
  1287.     {
  1288. #ifdef FEAT_FOLDING
  1289.     /* Move cursor to first line of closed fold. */
  1290.     foldAdjustCursor();
  1291. #endif
  1292.     coladvance(curwin->w_curswant);
  1293.     }
  1294. }
  1295.  
  1296. /*
  1297.  * Scroll the current window up by "line_count" logical lines.  "CTRL-E"
  1298.  */
  1299. /*ARGSUSED*/
  1300.     void
  1301. scrollup(line_count, byfold)
  1302.     long    line_count;
  1303.     int        byfold;        /* TRUE: count a closed fold as one line */
  1304. {
  1305. #if defined(FEAT_FOLDING) || defined(FEAT_DIFF)
  1306.     linenr_T    lnum;
  1307.  
  1308.     if (
  1309. # ifdef FEAT_FOLDING
  1310.         (byfold && hasAnyFolding(curwin))
  1311. #  ifdef FEAT_DIFF
  1312.         ||
  1313. #  endif
  1314. # endif
  1315. # ifdef FEAT_DIFF
  1316.         curwin->w_p_diff
  1317. # endif
  1318.         )
  1319.     {
  1320.     /* count each sequence of folded lines as one logical line */
  1321.     lnum = curwin->w_topline;
  1322.     while (line_count--)
  1323.     {
  1324. # ifdef FEAT_DIFF
  1325.         if (curwin->w_topfill > 0)
  1326.         --curwin->w_topfill;
  1327.         else
  1328. # endif
  1329.         {
  1330. # ifdef FEAT_FOLDING
  1331.         if (byfold)
  1332.             (void)hasFolding(lnum, NULL, &lnum);
  1333. # endif
  1334.         if (lnum >= curbuf->b_ml.ml_line_count)
  1335.             break;
  1336.         ++lnum;
  1337. # ifdef FEAT_DIFF
  1338.         curwin->w_topfill = diff_check_fill(curwin, lnum);
  1339. # endif
  1340.         }
  1341.     }
  1342.     /* approximate w_botline */
  1343.     curwin->w_botline += lnum - curwin->w_topline;
  1344.     curwin->w_topline = lnum;
  1345.     }
  1346.     else
  1347. #endif
  1348.     {
  1349.     curwin->w_topline += line_count;
  1350.     curwin->w_botline += line_count;    /* approximate w_botline */
  1351.     }
  1352.  
  1353.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  1354.     curwin->w_topline = curbuf->b_ml.ml_line_count;
  1355.     if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
  1356.     curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
  1357.  
  1358. #ifdef FEAT_DIFF
  1359.     check_topfill(curwin, FALSE);
  1360. #endif
  1361.  
  1362. #ifdef FEAT_FOLDING
  1363.     if (hasAnyFolding(curwin))
  1364.     /* Make sure w_topline is at the first of a sequence of folded lines. */
  1365.     (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  1366. #endif
  1367.  
  1368.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1369.     if (curwin->w_cursor.lnum < curwin->w_topline)
  1370.     {
  1371.     curwin->w_cursor.lnum = curwin->w_topline;
  1372.     curwin->w_valid &=
  1373.           ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1374.     coladvance(curwin->w_curswant);
  1375.     }
  1376. }
  1377.  
  1378. #ifdef FEAT_DIFF
  1379. /*
  1380.  * Don't end up with too many filler lines in the window.
  1381.  */
  1382.     void
  1383. check_topfill(wp, down)
  1384.     win_T    *wp;
  1385.     int        down;    /* when TRUE scroll down when not enough space */
  1386. {
  1387.     int        n;
  1388.  
  1389.     if (wp->w_topfill > 0)
  1390.     {
  1391.     n = plines_win_nofill(wp, wp->w_topline, TRUE);
  1392.     if (wp->w_topfill + n > wp->w_height)
  1393.     {
  1394.         if (down && wp->w_topline > 1)
  1395.         {
  1396.         --wp->w_topline;
  1397.         wp->w_topfill = 0;
  1398.         }
  1399.         else
  1400.         {
  1401.         wp->w_topfill = wp->w_height - n;
  1402.         if (wp->w_topfill < 0)
  1403.             wp->w_topfill = 0;
  1404.         }
  1405.     }
  1406.     }
  1407. }
  1408.  
  1409. /*
  1410.  * Use as many filler lines as possible for w_topline.  Make sure w_topline
  1411.  * is still visible.
  1412.  */
  1413.     static void
  1414. max_topfill()
  1415. {
  1416.     int        n;
  1417.  
  1418.     n = plines_nofill(curwin->w_topline);
  1419.     if (n >= curwin->w_height)
  1420.     curwin->w_topfill = 0;
  1421.     else
  1422.     {
  1423.     curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  1424.     if (curwin->w_topfill + n > curwin->w_height)
  1425.         curwin->w_topfill = curwin->w_height - n;
  1426.     }
  1427. }
  1428. #endif
  1429.  
  1430. #if defined(FEAT_INS_EXPAND) || defined(PROTO)
  1431. /*
  1432.  * Scroll the screen one line down, but don't do it if it would move the
  1433.  * cursor off the screen.
  1434.  */
  1435.     void
  1436. scrolldown_clamp()
  1437. {
  1438.     int        end_row;
  1439. #ifdef FEAT_DIFF
  1440.     int        can_fill = (curwin->w_topfill
  1441.                 < diff_check_fill(curwin, curwin->w_topline));
  1442. #endif
  1443.  
  1444.     if (curwin->w_topline <= 1
  1445. #ifdef FEAT_DIFF
  1446.         && !can_fill
  1447. #endif
  1448.         )
  1449.     return;
  1450.  
  1451.     validate_cursor();        /* w_wrow needs to be valid */
  1452.  
  1453.     /*
  1454.      * Compute the row number of the last row of the cursor line
  1455.      * and make sure it doesn't go off the screen. Make sure the cursor
  1456.      * doesn't go past 'scrolloff' lines from the screen end.
  1457.      */
  1458.     end_row = curwin->w_wrow;
  1459. #ifdef FEAT_DIFF
  1460.     if (can_fill)
  1461.     ++end_row;
  1462.     else
  1463.     end_row += plines_nofill(curwin->w_topline - 1);
  1464. #else
  1465.     end_row += plines(curwin->w_topline - 1);
  1466. #endif
  1467.     if (curwin->w_p_wrap
  1468. #ifdef FEAT_VERTSPLIT
  1469.         && curwin->w_width != 0
  1470. #endif
  1471.         )
  1472.     {
  1473.     validate_cheight();
  1474.     validate_virtcol();
  1475.     end_row += curwin->w_cline_height - 1 -
  1476.         curwin->w_virtcol / W_WIDTH(curwin);
  1477.     }
  1478.     if (end_row < curwin->w_height - p_so)
  1479.     {
  1480. #ifdef FEAT_DIFF
  1481.     if (can_fill)
  1482.     {
  1483.         ++curwin->w_topfill;
  1484.         check_topfill(curwin, TRUE);
  1485.     }
  1486.     else
  1487.     {
  1488.         --curwin->w_topline;
  1489.         curwin->w_topfill = 0;
  1490.     }
  1491. #else
  1492.     --curwin->w_topline;
  1493. #endif
  1494. #ifdef FEAT_FOLDING
  1495.     hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  1496. #endif
  1497.     --curwin->w_botline;        /* approximate w_botline */
  1498.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1499.     }
  1500. }
  1501.  
  1502. /*
  1503.  * Scroll the screen one line up, but don't do it if it would move the cursor
  1504.  * off the screen.
  1505.  */
  1506.     void
  1507. scrollup_clamp()
  1508. {
  1509.     int        start_row;
  1510.  
  1511.     if (curwin->w_topline == curbuf->b_ml.ml_line_count
  1512. #ifdef FEAT_DIFF
  1513.         && curwin->w_topfill == 0
  1514. #endif
  1515.         )
  1516.     return;
  1517.  
  1518.     validate_cursor();        /* w_wrow needs to be valid */
  1519.  
  1520.     /*
  1521.      * Compute the row number of the first row of the cursor line
  1522.      * and make sure it doesn't go off the screen. Make sure the cursor
  1523.      * doesn't go before 'scrolloff' lines from the screen start.
  1524.      */
  1525. #ifdef FEAT_DIFF
  1526.     start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
  1527.                               - curwin->w_topfill;
  1528. #else
  1529.     start_row = curwin->w_wrow - plines(curwin->w_topline);
  1530. #endif
  1531.     if (curwin->w_p_wrap
  1532. #ifdef FEAT_VERTSPLIT
  1533.         && curwin->w_width != 0
  1534. #endif
  1535.         )
  1536.     {
  1537.     validate_virtcol();
  1538.     start_row -= curwin->w_virtcol / W_WIDTH(curwin);
  1539.     }
  1540.     if (start_row >= p_so)
  1541.     {
  1542. #ifdef FEAT_DIFF
  1543.     if (curwin->w_topfill > 0)
  1544.         --curwin->w_topfill;
  1545.     else
  1546. #endif
  1547.         ++curwin->w_topline;
  1548.     ++curwin->w_botline;        /* approximate w_botline */
  1549.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1550.     }
  1551. }
  1552. #endif /* FEAT_INS_EXPAND */
  1553.  
  1554. /*
  1555.  * Add one line above "lp->lnum".  This can be a filler line, a closed fold or
  1556.  * a (wrapped) text line.  Uses and sets "lp->fill".
  1557.  * Returns the height of the added line in "lp->height".
  1558.  * Lines above the first one are incredibly high.
  1559.  */
  1560.     static void
  1561. topline_back(lp)
  1562.     lineoff_T    *lp;
  1563. {
  1564. #ifdef FEAT_DIFF
  1565.     if (lp->fill < diff_check_fill(curwin, lp->lnum))
  1566.     {
  1567.     /* Add a filler line. */
  1568.     ++lp->fill;
  1569.     lp->height = 1;
  1570.     }
  1571.     else
  1572. #endif
  1573.     {
  1574.     --lp->lnum;
  1575. #ifdef FEAT_DIFF
  1576.     lp->fill = 0;
  1577. #endif
  1578.     if (lp->lnum < 1)
  1579.         lp->height = MAXCOL;
  1580.     else
  1581. #ifdef FEAT_FOLDING
  1582.         if (hasFolding(lp->lnum, &lp->lnum, NULL))
  1583.         /* Add a closed fold */
  1584.         lp->height = 1;
  1585.     else
  1586. #endif
  1587.     {
  1588. #ifdef FEAT_DIFF
  1589.         lp->height = plines_nofill(lp->lnum);
  1590. #else
  1591.         lp->height = plines(lp->lnum);
  1592. #endif
  1593.     }
  1594.     }
  1595. }
  1596.  
  1597. /*
  1598.  * Add one line below "lp->lnum".  This can be a filler line, a closed fold or
  1599.  * a (wrapped) text line.  Uses and sets "lp->fill".
  1600.  * Returns the height of the added line in "lp->height".
  1601.  * Lines below the last one are incredibly high.
  1602.  */
  1603.     static void
  1604. botline_forw(lp)
  1605.     lineoff_T    *lp;
  1606. {
  1607. #ifdef FEAT_DIFF
  1608.     if (lp->fill < diff_check_fill(curwin, lp->lnum + 1))
  1609.     {
  1610.     /* Add a filler line. */
  1611.     ++lp->fill;
  1612.     lp->height = 1;
  1613.     }
  1614.     else
  1615. #endif
  1616.     {
  1617.     ++lp->lnum;
  1618. #ifdef FEAT_DIFF
  1619.     lp->fill = 0;
  1620. #endif
  1621.     if (lp->lnum > curbuf->b_ml.ml_line_count)
  1622.         lp->height = MAXCOL;
  1623.     else
  1624. #ifdef FEAT_FOLDING
  1625.         if (hasFolding(lp->lnum, NULL, &lp->lnum))
  1626.         /* Add a closed fold */
  1627.         lp->height = 1;
  1628.     else
  1629. #endif
  1630.     {
  1631. #ifdef FEAT_DIFF
  1632.         lp->height = plines_nofill(lp->lnum);
  1633. #else
  1634.         lp->height = plines(lp->lnum);
  1635. #endif
  1636.     }
  1637.     }
  1638. }
  1639.  
  1640. #ifdef FEAT_DIFF
  1641. /*
  1642.  * Switch from including filler lines below lp->lnum to including filler
  1643.  * lines above loff.lnum + 1.  This keeps pointing to the same line.
  1644.  * When there are no filler lines nothing changes.
  1645.  */
  1646.     static void
  1647. botline_topline(lp)
  1648.     lineoff_T    *lp;
  1649. {
  1650.     if (lp->fill > 0)
  1651.     {
  1652.     ++lp->lnum;
  1653.     lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
  1654.     }
  1655. }
  1656.  
  1657. /*
  1658.  * Switch from including filler lines above lp->lnum to including filler
  1659.  * lines below loff.lnum - 1.  This keeps pointing to the same line.
  1660.  * When there are no filler lines nothing changes.
  1661.  */
  1662.     static void
  1663. topline_botline(lp)
  1664.     lineoff_T    *lp;
  1665. {
  1666.     if (lp->fill > 0)
  1667.     {
  1668.     lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
  1669.     --lp->lnum;
  1670.     }
  1671. }
  1672. #endif
  1673.  
  1674. /*
  1675.  * Recompute topline to put the cursor at the top of the window.
  1676.  * Scroll at least "min_scroll" lines.
  1677.  * If "always" is TRUE, always set topline (for "zt").
  1678.  */
  1679.     void
  1680. scroll_cursor_top(min_scroll, always)
  1681.     int        min_scroll;
  1682.     int        always;
  1683. {
  1684.     int        scrolled = 0;
  1685.     int        extra = 0;
  1686.     int        used;
  1687.     int        i;
  1688.     linenr_T    top;        /* just above displayed lines */
  1689.     linenr_T    bot;        /* just below displayed lines */
  1690.     linenr_T    old_topline = curwin->w_topline;
  1691. #ifdef FEAT_DIFF
  1692.     linenr_T    old_topfill = curwin->w_topfill;
  1693. #endif
  1694.     linenr_T    new_topline;
  1695.     int        off = p_so;
  1696.  
  1697. #ifdef FEAT_MOUSE
  1698.     if (mouse_dragging > 0)
  1699.     off = mouse_dragging - 1;
  1700. #endif
  1701.  
  1702.     /*
  1703.      * Decrease topline until:
  1704.      * - it has become 1
  1705.      * - (part of) the cursor line is moved off the screen or
  1706.      * - moved at least 'scrolljump' lines and
  1707.      * - at least 'scrolloff' lines above and below the cursor
  1708.      */
  1709.     validate_cheight();
  1710.     used = curwin->w_cline_height;
  1711.     if (curwin->w_cursor.lnum < curwin->w_topline)
  1712.     scrolled = used;
  1713.  
  1714. #ifdef FEAT_FOLDING
  1715.     if (hasFolding(curwin->w_cursor.lnum, &top, &bot))
  1716.     {
  1717.     --top;
  1718.     ++bot;
  1719.     }
  1720.     else
  1721. #endif
  1722.     {
  1723.     top = curwin->w_cursor.lnum - 1;
  1724.     bot = curwin->w_cursor.lnum + 1;
  1725.     }
  1726.     new_topline = top + 1;
  1727.  
  1728. #ifdef FEAT_DIFF
  1729.     /* count filler lines of the cursor window as context */
  1730.     i = diff_check_fill(curwin, curwin->w_cursor.lnum);
  1731.     used += i;
  1732.     extra += i;
  1733. #endif
  1734.  
  1735.     /*
  1736.      * Check if the lines from "top" to "bot" fit in the window.  If they do,
  1737.      * set new_topline and advance "top" and "bot" to include more lines.
  1738.      */
  1739.     while (top > 0)
  1740.     {
  1741. #ifdef FEAT_FOLDING
  1742.     if (hasFolding(top, &top, NULL))
  1743.         /* count one logical line for a sequence of folded lines */
  1744.         i = 1;
  1745.     else
  1746. #endif
  1747.         i = plines(top);
  1748.     used += i;
  1749.     if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
  1750.     {
  1751. #ifdef FEAT_FOLDING
  1752.         if (hasFolding(bot, NULL, &bot))
  1753.         /* count one logical line for a sequence of folded lines */
  1754.         ++used;
  1755.         else
  1756. #endif
  1757.         used += plines(bot);
  1758.     }
  1759.     if (used > curwin->w_height)
  1760.         break;
  1761.     if (top < curwin->w_topline)
  1762.         scrolled += i;
  1763.  
  1764.     /*
  1765.      * If scrolling is needed, scroll at least 'sj' lines.
  1766.      */
  1767.     if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
  1768.         && extra >= off)
  1769.         break;
  1770.  
  1771.     extra += i;
  1772.     new_topline = top;
  1773.     --top;
  1774.     ++bot;
  1775.     }
  1776.  
  1777.     /*
  1778.      * If we don't have enough space, put cursor in the middle.
  1779.      * This makes sure we get the same position when using "k" and "j"
  1780.      * in a small window.
  1781.      */
  1782.     if (used > curwin->w_height)
  1783.     scroll_cursor_halfway(FALSE);
  1784.     else
  1785.     {
  1786.     /*
  1787.      * If "always" is FALSE, only adjust topline to a lower value, higher
  1788.      * value may happen with wrapping lines
  1789.      */
  1790.     if (new_topline < curwin->w_topline || always)
  1791.         curwin->w_topline = new_topline;
  1792.     if (curwin->w_topline > curwin->w_cursor.lnum)
  1793.         curwin->w_topline = curwin->w_cursor.lnum;
  1794. #ifdef FEAT_DIFF
  1795.     curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  1796.     if (curwin->w_topfill > 0 && extra > off)
  1797.     {
  1798.         curwin->w_topfill -= extra - off;
  1799.         if (curwin->w_topfill < 0)
  1800.         curwin->w_topfill = 0;
  1801.     }
  1802.     check_topfill(curwin, FALSE);
  1803. #endif
  1804.     if (curwin->w_topline != old_topline
  1805. #ifdef FEAT_DIFF
  1806.         || curwin->w_topfill != old_topfill
  1807. #endif
  1808.         )
  1809.         curwin->w_valid &=
  1810.               ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  1811.     curwin->w_valid |= VALID_TOPLINE;
  1812.     }
  1813. }
  1814.  
  1815. /*
  1816.  * Set w_empty_rows and w_filler_rows for window "wp", having used up "used"
  1817.  * screen lines for text lines.
  1818.  */
  1819.     void
  1820. set_empty_rows(wp, used)
  1821.     win_T    *wp;
  1822.     int        used;
  1823. {
  1824. #ifdef FEAT_DIFF
  1825.     wp->w_filler_rows = 0;
  1826. #endif
  1827.     if (used == 0)
  1828.     wp->w_empty_rows = 0;    /* single line that doesn't fit */
  1829.     else
  1830.     {
  1831.     wp->w_empty_rows = wp->w_height - used;
  1832. #ifdef FEAT_DIFF
  1833.     if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count)
  1834.     {
  1835.         wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
  1836.         if (wp->w_empty_rows > wp->w_filler_rows)
  1837.         wp->w_empty_rows -= wp->w_filler_rows;
  1838.         else
  1839.         {
  1840.         wp->w_filler_rows = wp->w_empty_rows;
  1841.         wp->w_empty_rows = 0;
  1842.         }
  1843.     }
  1844. #endif
  1845.     }
  1846. }
  1847.  
  1848. /*
  1849.  * Recompute topline to put the cursor at the bottom of the window.
  1850.  * Scroll at least "min_scroll" lines.
  1851.  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
  1852.  * This is messy stuff!!!
  1853.  */
  1854.     void
  1855. scroll_cursor_bot(min_scroll, set_topbot)
  1856.     int        min_scroll;
  1857.     int        set_topbot;
  1858. {
  1859.     int        used;
  1860.     int        scrolled = 0;
  1861.     int        extra = 0;
  1862.     int        i;
  1863.     linenr_T    line_count;
  1864.     linenr_T    old_topline = curwin->w_topline;
  1865.     lineoff_T    loff;
  1866.     lineoff_T    boff;
  1867. #ifdef FEAT_DIFF
  1868.     int        old_topfill = curwin->w_topfill;
  1869.     int        fill_below_window;
  1870. #endif
  1871.     linenr_T    old_botline = curwin->w_botline;
  1872.     linenr_T    old_valid = curwin->w_valid;
  1873.     int        old_empty_rows = curwin->w_empty_rows;
  1874.     linenr_T    cln;            /* Cursor Line Number */
  1875.  
  1876.     cln = curwin->w_cursor.lnum;
  1877.     if (set_topbot)
  1878.     {
  1879.     used = 0;
  1880.     curwin->w_botline = cln + 1;
  1881. #ifdef FEAT_DIFF
  1882.     loff.fill = 0;
  1883. #endif
  1884.     for (curwin->w_topline = curwin->w_botline;
  1885.         curwin->w_topline > 1;
  1886.         curwin->w_topline = loff.lnum)
  1887.     {
  1888.         loff.lnum = curwin->w_topline;
  1889.         topline_back(&loff);
  1890.         if (used + loff.height > curwin->w_height)
  1891.         break;
  1892.         used += loff.height;
  1893. #ifdef FEAT_DIFF
  1894.         curwin->w_topfill = loff.fill;
  1895. #endif
  1896.     }
  1897.     set_empty_rows(curwin, used);
  1898.     curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  1899.     if (curwin->w_topline != old_topline
  1900. #ifdef FEAT_DIFF
  1901.         || curwin->w_topfill != old_topfill
  1902. #endif
  1903.         )
  1904.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  1905.     }
  1906.     else
  1907.     validate_botline();
  1908.  
  1909.     /* The lines of the cursor line itself are always used. */
  1910. #ifdef FEAT_DIFF
  1911.     used = plines_nofill(cln);
  1912. #else
  1913.     validate_cheight();
  1914.     used = curwin->w_cline_height;
  1915. #endif
  1916.  
  1917.     /* If the cursor is below botline, we will at least scroll by the height
  1918.      * of the cursor line.  Correct for empty lines, which are really part of
  1919.      * botline. */
  1920.     if (cln >= curwin->w_botline)
  1921.     {
  1922.     scrolled = used;
  1923.     if (cln == curwin->w_botline)
  1924.         scrolled -= curwin->w_empty_rows;
  1925.     }
  1926.  
  1927.     /*
  1928.      * Stop counting lines to scroll when
  1929.      * - hitting start of the file
  1930.      * - scrolled nothing or at least 'sj' lines
  1931.      * - at least 'so' lines below the cursor
  1932.      * - lines between botline and cursor have been counted
  1933.      */
  1934. #ifdef FEAT_FOLDING
  1935.     if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum))
  1936. #endif
  1937.     {
  1938.     loff.lnum = cln;
  1939.     boff.lnum = cln;
  1940.     }
  1941. #ifdef FEAT_DIFF
  1942.     loff.fill = 0;
  1943.     boff.fill = 0;
  1944.     fill_below_window = diff_check_fill(curwin, curwin->w_botline)
  1945.                               - curwin->w_filler_rows;
  1946. #endif
  1947.  
  1948.     while (loff.lnum > 1)
  1949.     {
  1950.     /* Stop when scrolled nothing or at least "min_scroll", found "extra"
  1951.      * context for 'scrolloff' and counted all lines below the window. */
  1952.     if ((((scrolled <= 0 || scrolled >= min_scroll)
  1953.             && extra >= (
  1954. #ifdef FEAT_MOUSE
  1955.                 mouse_dragging ? mouse_dragging - 1 :
  1956. #endif
  1957.                 p_so))
  1958.             || boff.lnum + 1 > curbuf->b_ml.ml_line_count)
  1959.         && loff.lnum <= curwin->w_botline
  1960. #ifdef FEAT_DIFF
  1961.         && (loff.lnum < curwin->w_botline
  1962.             || loff.fill >= fill_below_window)
  1963. #endif
  1964.         )
  1965.         break;
  1966.  
  1967.     /* Add one line above */
  1968.     topline_back(&loff);
  1969.     used += loff.height;
  1970.     if (used > curwin->w_height)
  1971.         break;
  1972.     if (loff.lnum >= curwin->w_botline
  1973. #ifdef FEAT_DIFF
  1974.         && (loff.lnum > curwin->w_botline
  1975.             || loff.fill <= fill_below_window)
  1976. #endif
  1977.         )
  1978.     {
  1979.         /* Count screen lines that are below the window. */
  1980.         scrolled += loff.height;
  1981.         if (loff.lnum == curwin->w_botline
  1982. #ifdef FEAT_DIFF
  1983.                 && boff.fill == 0
  1984. #endif
  1985.             )
  1986.         scrolled -= curwin->w_empty_rows;
  1987.     }
  1988.  
  1989.     if (boff.lnum < curbuf->b_ml.ml_line_count)
  1990.     {
  1991.         /* Add one line below */
  1992.         botline_forw(&boff);
  1993.         used += boff.height;
  1994.         if (used > curwin->w_height)
  1995.         break;
  1996.         if (extra < (
  1997. #ifdef FEAT_MOUSE
  1998.             mouse_dragging > 0 ? mouse_dragging - 1 :
  1999. #endif
  2000.             p_so) || scrolled < min_scroll)
  2001.         {
  2002.         extra += boff.height;
  2003.         if (boff.lnum >= curwin->w_botline
  2004. #ifdef FEAT_DIFF
  2005.             || (boff.lnum + 1 == curwin->w_botline
  2006.                 && boff.fill > curwin->w_filler_rows)
  2007. #endif
  2008.            )
  2009.         {
  2010.             /* Count screen lines that are below the window. */
  2011.             scrolled += boff.height;
  2012.             if (boff.lnum == curwin->w_botline
  2013. #ifdef FEAT_DIFF
  2014.                 && boff.fill == 0
  2015. #endif
  2016.                 )
  2017.             scrolled -= curwin->w_empty_rows;
  2018.         }
  2019.         }
  2020.     }
  2021.     }
  2022.  
  2023.     /* curwin->w_empty_rows is larger, no need to scroll */
  2024.     if (scrolled <= 0)
  2025.     line_count = 0;
  2026.     /* more than a screenfull, don't scroll but redraw */
  2027.     else if (used > curwin->w_height)
  2028.     line_count = used;
  2029.     /* scroll minimal number of lines */
  2030.     else
  2031.     {
  2032.     line_count = 0;
  2033. #ifdef FEAT_DIFF
  2034.     boff.fill = curwin->w_topfill;
  2035. #endif
  2036.     boff.lnum = curwin->w_topline - 1;
  2037.     for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; )
  2038.     {
  2039.         botline_forw(&boff);
  2040.         i += boff.height;
  2041.         ++line_count;
  2042.     }
  2043.     if (i < scrolled)    /* below curwin->w_botline, don't scroll */
  2044.         line_count = 9999;
  2045.     }
  2046.  
  2047.     /*
  2048.      * Scroll up if the cursor is off the bottom of the screen a bit.
  2049.      * Otherwise put it at 1/2 of the screen.
  2050.      */
  2051.     if (line_count >= curwin->w_height && line_count > min_scroll)
  2052.     scroll_cursor_halfway(FALSE);
  2053.     else
  2054.     scrollup(line_count, TRUE);
  2055.  
  2056.     /*
  2057.      * If topline didn't change we need to restore w_botline and w_empty_rows
  2058.      * (we changed them).
  2059.      * If topline did change, update_screen() will set botline.
  2060.      */
  2061.     if (curwin->w_topline == old_topline && set_topbot)
  2062.     {
  2063.     curwin->w_botline = old_botline;
  2064.     curwin->w_empty_rows = old_empty_rows;
  2065.     curwin->w_valid = old_valid;
  2066.     }
  2067.     curwin->w_valid |= VALID_TOPLINE;
  2068. }
  2069.  
  2070. /*
  2071.  * Recompute topline to put the cursor halfway the window
  2072.  * If "atend" is TRUE, also put it halfway at the end of the file.
  2073.  */
  2074.     void
  2075. scroll_cursor_halfway(atend)
  2076.     int        atend;
  2077. {
  2078.     int        above = 0;
  2079.     linenr_T    topline;
  2080. #ifdef FEAT_DIFF
  2081.     int        topfill = 0;
  2082. #endif
  2083.     int        below = 0;
  2084.     int        used;
  2085.     lineoff_T    loff;
  2086.     lineoff_T    boff;
  2087.  
  2088.     loff.lnum = boff.lnum = curwin->w_cursor.lnum;
  2089. #ifdef FEAT_FOLDING
  2090.     (void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
  2091. #endif
  2092. #ifdef FEAT_DIFF
  2093.     used = plines_nofill(loff.lnum);
  2094.     loff.fill = 0;
  2095.     boff.fill = 0;
  2096. #else
  2097.     used = plines(loff.lnum);
  2098. #endif
  2099.     topline = loff.lnum;
  2100.     while (topline > 1)
  2101.     {
  2102.     if (below <= above)        /* add a line below the cursor first */
  2103.     {
  2104.         if (boff.lnum < curbuf->b_ml.ml_line_count)
  2105.         {
  2106.         botline_forw(&boff);
  2107.         used += boff.height;
  2108.         if (used > curwin->w_height)
  2109.             break;
  2110.         below += boff.height;
  2111.         }
  2112.         else
  2113.         {
  2114.         ++below;        /* count a "~" line */
  2115.         if (atend)
  2116.             ++used;
  2117.         }
  2118.     }
  2119.  
  2120.     if (below > above)        /* add a line above the cursor */
  2121.     {
  2122.         topline_back(&loff);
  2123.         used += loff.height;
  2124.         if (used > curwin->w_height)
  2125.         break;
  2126.         above += loff.height;
  2127.         topline = loff.lnum;
  2128. #ifdef FEAT_DIFF
  2129.         topfill = loff.fill;
  2130. #endif
  2131.     }
  2132.     }
  2133. #ifdef FEAT_FOLDING
  2134.     if (!hasFolding(topline, &curwin->w_topline, NULL))
  2135. #endif
  2136.     curwin->w_topline = topline;
  2137. #ifdef FEAT_DIFF
  2138.     curwin->w_topfill = topfill;
  2139.     check_topfill(curwin, FALSE);
  2140. #endif
  2141.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2142.     curwin->w_valid |= VALID_TOPLINE;
  2143. }
  2144.  
  2145. /*
  2146.  * Correct the cursor position so that it is in a part of the screen at least
  2147.  * 'so' lines from the top and bottom, if possible.
  2148.  * If not possible, put it at the same position as scroll_cursor_halfway().
  2149.  * When called topline must be valid!
  2150.  */
  2151.     void
  2152. cursor_correct()
  2153. {
  2154.     int        above = 0;        /* screen lines above topline */
  2155.     linenr_T    topline;
  2156.     int        below = 0;        /* screen lines below botline */
  2157.     linenr_T    botline;
  2158.     int        above_wanted, below_wanted;
  2159.     linenr_T    cln;            /* Cursor Line Number */
  2160.     int        max_off;
  2161.  
  2162.     /*
  2163.      * How many lines we would like to have above/below the cursor depends on
  2164.      * whether the first/last line of the file is on screen.
  2165.      */
  2166.     above_wanted = p_so;
  2167.     below_wanted = p_so;
  2168. #ifdef FEAT_MOUSE
  2169.     if (mouse_dragging)
  2170.     {
  2171.     above_wanted = mouse_dragging - 1;
  2172.     below_wanted = mouse_dragging - 1;
  2173.     }
  2174. #endif
  2175.     if (curwin->w_topline == 1)
  2176.     {
  2177.     above_wanted = 0;
  2178.     max_off = curwin->w_height / 2;
  2179.     if (below_wanted > max_off)
  2180.         below_wanted = max_off;
  2181.     }
  2182.     validate_botline();
  2183.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1
  2184. #ifdef FEAT_MOUSE
  2185.         && !mouse_dragging
  2186. #endif
  2187.         )
  2188.     {
  2189.     below_wanted = 0;
  2190.     max_off = (curwin->w_height - 1) / 2;
  2191.     if (above_wanted > max_off)
  2192.         above_wanted = max_off;
  2193.     }
  2194.  
  2195.     /*
  2196.      * If there are sufficient file-lines above and below the cursor, we can
  2197.      * return now.
  2198.      */
  2199.     cln = curwin->w_cursor.lnum;
  2200.     if (cln >= curwin->w_topline + above_wanted
  2201.         && cln < curwin->w_botline - below_wanted
  2202. #ifdef FEAT_FOLDING
  2203.         && !hasAnyFolding(curwin)
  2204. #endif
  2205.         )
  2206.     return;
  2207.  
  2208.     /*
  2209.      * Narrow down the area where the cursor can be put by taking lines from
  2210.      * the top and the bottom until:
  2211.      * - the desired context lines are found
  2212.      * - the lines from the top is past the lines from the bottom
  2213.      */
  2214.     topline = curwin->w_topline;
  2215.     botline = curwin->w_botline - 1;
  2216. #ifdef FEAT_DIFF
  2217.     /* count filler lines as context */
  2218.     above = curwin->w_topfill;
  2219.     below = curwin->w_filler_rows;
  2220. #endif
  2221.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  2222.     {
  2223.     if (below < below_wanted && (below <= above || above >= above_wanted))
  2224.     {
  2225. #ifdef FEAT_FOLDING
  2226.         if (hasFolding(botline, &botline, NULL))
  2227.         ++below;
  2228.         else
  2229. #endif
  2230.         below += plines(botline);
  2231.         --botline;
  2232.     }
  2233.     if (above < above_wanted && (above < below || below >= below_wanted))
  2234.     {
  2235. #ifdef FEAT_FOLDING
  2236.         if (hasFolding(topline, NULL, &topline))
  2237.         ++above;
  2238.         else
  2239. #endif
  2240. #ifndef FEAT_DIFF
  2241.         above += plines(topline);
  2242. #else
  2243.         above += plines_nofill(topline);
  2244.  
  2245.         /* Count filler lines below this line as context. */
  2246.         if (topline < botline)
  2247.         above += diff_check_fill(curwin, topline + 1);
  2248. #endif
  2249.         ++topline;
  2250.     }
  2251.     }
  2252.     if (topline == botline || botline == 0)
  2253.     curwin->w_cursor.lnum = topline;
  2254.     else if (topline > botline)
  2255.     curwin->w_cursor.lnum = botline;
  2256.     else
  2257.     {
  2258.     if (cln < topline && curwin->w_topline > 1)
  2259.     {
  2260.         curwin->w_cursor.lnum = topline;
  2261.         curwin->w_valid &=
  2262.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  2263.     }
  2264.     if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2265.     {
  2266.         curwin->w_cursor.lnum = botline;
  2267.         curwin->w_valid &=
  2268.                 ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  2269.     }
  2270.     }
  2271.     curwin->w_valid |= VALID_TOPLINE;
  2272. }
  2273.  
  2274. static void get_scroll_overlap __ARGS((lineoff_T *lp, int dir));
  2275.  
  2276. /*
  2277.  * move screen 'count' pages up or down and update screen
  2278.  *
  2279.  * return FAIL for failure, OK otherwise
  2280.  */
  2281.     int
  2282. onepage(dir, count)
  2283.     int        dir;
  2284.     long    count;
  2285. {
  2286.     long    n;
  2287.     int        retval = OK;
  2288.     lineoff_T    loff;
  2289.     linenr_T    old_topline = curwin->w_topline;
  2290.  
  2291.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  2292.     {
  2293.     beep_flush();
  2294.     return FAIL;
  2295.     }
  2296.  
  2297.     for ( ; count > 0; --count)
  2298.     {
  2299.     validate_botline();
  2300.     /*
  2301.      * It's an error to move a page up when the first line is already on
  2302.      * the screen.    It's an error to move a page down when the last line
  2303.      * is on the screen and the topline is 'scrolloff' lines from the
  2304.      * last line.
  2305.      */
  2306.     if (dir == FORWARD
  2307.         ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so)
  2308.             && curwin->w_botline > curbuf->b_ml.ml_line_count)
  2309.         : (curwin->w_topline == 1
  2310. #ifdef FEAT_DIFF
  2311.             && curwin->w_topfill ==
  2312.                     diff_check_fill(curwin, curwin->w_topline)
  2313. #endif
  2314.             ))
  2315.     {
  2316.         beep_flush();
  2317.         retval = FAIL;
  2318.         break;
  2319.     }
  2320.  
  2321. #ifdef FEAT_DIFF
  2322.     loff.fill = 0;
  2323. #endif
  2324.     if (dir == FORWARD)
  2325.     {
  2326.                     /* at end of file */
  2327.         if (curwin->w_botline > curbuf->b_ml.ml_line_count)
  2328.         {
  2329.         curwin->w_topline = curbuf->b_ml.ml_line_count;
  2330. #ifdef FEAT_DIFF
  2331.         curwin->w_topfill = 0;
  2332. #endif
  2333.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  2334.         }
  2335.         else
  2336.         {
  2337.         /* For the overlap, start with the line just below the window
  2338.          * and go upwards. */
  2339.         loff.lnum = curwin->w_botline;
  2340. #ifdef FEAT_DIFF
  2341.         loff.fill = diff_check_fill(curwin, loff.lnum)
  2342.                               - curwin->w_filler_rows;
  2343. #endif
  2344.         get_scroll_overlap(&loff, -1);
  2345.         curwin->w_topline = loff.lnum;
  2346. #ifdef FEAT_DIFF
  2347.         curwin->w_topfill = loff.fill;
  2348.         check_topfill(curwin, FALSE);
  2349. #endif
  2350.         curwin->w_cursor.lnum = curwin->w_topline;
  2351.         curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
  2352.                    VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2353.         }
  2354.     }
  2355.     else    /* dir == BACKWARDS */
  2356.     {
  2357. #ifdef FEAT_DIFF
  2358.         if (curwin->w_topline == 1)
  2359.         {
  2360.         /* Include max number of filler lines */
  2361.         max_topfill();
  2362.         continue;
  2363.         }
  2364. #endif
  2365.         /* Find the line at the top of the window that is going to be the
  2366.          * line at the bottom of the window.  Make sure this results in
  2367.          * the same line as before doing CTRL-F. */
  2368.         loff.lnum = curwin->w_topline - 1;
  2369. #ifdef FEAT_DIFF
  2370.         loff.fill = diff_check_fill(curwin, loff.lnum + 1)
  2371.                               - curwin->w_topfill;
  2372. #endif
  2373.         get_scroll_overlap(&loff, 1);
  2374.  
  2375.         if (loff.lnum >= curbuf->b_ml.ml_line_count)
  2376.         {
  2377.         loff.lnum = curbuf->b_ml.ml_line_count;
  2378. #ifdef FEAT_DIFF
  2379.         loff.fill = 0;
  2380.         }
  2381.         else
  2382.         {
  2383.         botline_topline(&loff);
  2384. #endif
  2385.         }
  2386.         curwin->w_cursor.lnum = loff.lnum;
  2387.  
  2388.         /* Find the line just above the new topline to get the right line
  2389.          * at the bottom of the window. */
  2390.         n = 0;
  2391.         while (n <= curwin->w_height && loff.lnum >= 1)
  2392.         {
  2393.         topline_back(&loff);
  2394.         n += loff.height;
  2395.         }
  2396.         if (n <= curwin->w_height)            /* at begin of file */
  2397.         {
  2398.         curwin->w_topline = 1;
  2399. #ifdef FEAT_DIFF
  2400.         max_topfill();
  2401. #endif
  2402.         curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2403.         }
  2404.         else
  2405.         {
  2406.         /* Go two lines forward again. */
  2407. #ifdef FEAT_DIFF
  2408.         topline_botline(&loff);
  2409. #endif
  2410.         botline_forw(&loff);
  2411.         botline_forw(&loff);
  2412. #ifdef FEAT_DIFF
  2413.         botline_topline(&loff);
  2414. #endif
  2415. #ifdef FEAT_FOLDING
  2416.         /* We're at the wrong end of a fold now. */
  2417.         (void)hasFolding(loff.lnum, &loff.lnum, NULL);
  2418. #endif
  2419.  
  2420.         /* Always scroll at least one line.  Avoid getting stuck on
  2421.          * very long lines. */
  2422.         if (loff.lnum >= curwin->w_topline
  2423. #ifdef FEAT_DIFF
  2424.             && (loff.lnum > curwin->w_topline
  2425.                 || loff.fill >= curwin->w_topfill)
  2426. #endif
  2427.             )
  2428.         {
  2429. #ifdef FEAT_DIFF
  2430.             /* First try using the maximum number of filler lines.  If
  2431.              * that's not enough, backup one line. */
  2432.             loff.fill = curwin->w_topfill;
  2433.             if (curwin->w_topfill < diff_check_fill(curwin,
  2434.                                curwin->w_topline))
  2435.             max_topfill();
  2436.             if (curwin->w_topfill == loff.fill)
  2437. #endif
  2438.             {
  2439.             --curwin->w_topline;
  2440. #ifdef FEAT_DIFF
  2441.             curwin->w_topfill = 0;
  2442. #endif
  2443.             }
  2444.             comp_botline(curwin);
  2445.             curwin->w_cursor.lnum = curwin->w_botline - 1;
  2446.             curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|
  2447.                 VALID_WROW|VALID_CROW);
  2448.         }
  2449.         else
  2450.         {
  2451.             curwin->w_topline = loff.lnum;
  2452. #ifdef FEAT_DIFF
  2453.             curwin->w_topfill = loff.fill;
  2454.             check_topfill(curwin, FALSE);
  2455. #endif
  2456.             curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2457.         }
  2458.         }
  2459.     }
  2460.     }
  2461. #ifdef FEAT_FOLDING
  2462.     foldAdjustCursor();
  2463. #endif
  2464.     cursor_correct();
  2465.     beginline(BL_SOL | BL_FIX);
  2466.     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
  2467.  
  2468.     /*
  2469.      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
  2470.      * But make sure we scroll at least one line (happens with mix of long
  2471.      * wrapping lines and non-wrapping line).
  2472.      */
  2473.     if (retval == OK && dir == FORWARD && check_top_offset())
  2474.     {
  2475.     scroll_cursor_top(1, FALSE);
  2476.     if (curwin->w_topline <= old_topline
  2477.                   && old_topline < curbuf->b_ml.ml_line_count)
  2478.     {
  2479.         curwin->w_topline = old_topline + 1;
  2480. #ifdef FEAT_FOLDING
  2481.         (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  2482. #endif
  2483.     }
  2484.     }
  2485.  
  2486.     redraw_later(VALID);
  2487.     return retval;
  2488. }
  2489.  
  2490. /*
  2491.  * Decide how much overlap to use for page-up or page-down scrolling.
  2492.  * This is symmetric, so that doing both keeps the same lines displayed.
  2493.  * Three lines are examined:
  2494.  *
  2495.  *  before CTRL-F        after CTRL-F / before CTRL-B
  2496.  *     etc.            l1
  2497.  *  l1 last but one line    ------------
  2498.  *  l2 last text line        l2 top text line
  2499.  *  -------------        l3 second text line
  2500.  *  l3                   etc.
  2501.  */
  2502.     static void
  2503. get_scroll_overlap(lp, dir)
  2504.     lineoff_T    *lp;
  2505.     int        dir;
  2506. {
  2507.     int        h1, h2, h3, h4;
  2508.     int        min_height = curwin->w_height - 2;
  2509.     lineoff_T    loff0, loff1, loff2;
  2510.  
  2511. #ifdef FEAT_DIFF
  2512.     if (lp->fill > 0)
  2513.     lp->height = 1;
  2514.     else
  2515.     lp->height = plines_nofill(lp->lnum);
  2516. #else
  2517.     lp->height = plines(lp->lnum);
  2518. #endif
  2519.     h1 = lp->height;
  2520.     if (h1 > min_height)
  2521.     return;        /* no overlap */
  2522.  
  2523.     loff0 = *lp;
  2524.     if (dir > 0)
  2525.     botline_forw(lp);
  2526.     else
  2527.     topline_back(lp);
  2528.     h2 = lp->height;
  2529.     if (h2 + h1 > min_height)
  2530.     {
  2531.     *lp = loff0;    /* no overlap */
  2532.     return;
  2533.     }
  2534.  
  2535.     loff1 = *lp;
  2536.     if (dir > 0)
  2537.     botline_forw(lp);
  2538.     else
  2539.     topline_back(lp);
  2540.     h3 = lp->height;
  2541.     if (h3 + h2 > min_height)
  2542.     {
  2543.     *lp = loff0;    /* no overlap */
  2544.     return;
  2545.     }
  2546.  
  2547.     loff2 = *lp;
  2548.     if (dir > 0)
  2549.     botline_forw(lp);
  2550.     else
  2551.     topline_back(lp);
  2552.     h4 = lp->height;
  2553.     if (h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
  2554.     *lp = loff1;    /* 1 line overlap */
  2555.     else
  2556.     *lp = loff2;    /* 2 lines overlap */
  2557.     return;
  2558. }
  2559.  
  2560. /* #define KEEP_SCREEN_LINE */
  2561. /*
  2562.  * Scroll 'scroll' lines up or down.
  2563.  */
  2564.     void
  2565. halfpage(flag, Prenum)
  2566.     int        flag;
  2567.     linenr_T    Prenum;
  2568. {
  2569.     long    scrolled = 0;
  2570.     int        i;
  2571.     int        n;
  2572.     int        room;
  2573.  
  2574.     if (Prenum)
  2575.     curwin->w_p_scr = (Prenum > curwin->w_height) ?
  2576.                         curwin->w_height : Prenum;
  2577.     n = (curwin->w_p_scr <= curwin->w_height) ?
  2578.                     curwin->w_p_scr : curwin->w_height;
  2579.  
  2580.     validate_botline();
  2581.     room = curwin->w_empty_rows;
  2582. #ifdef FEAT_DIFF
  2583.     room += curwin->w_filler_rows;
  2584. #endif
  2585.     if (flag)
  2586.     {
  2587.     /*
  2588.      * scroll the text up
  2589.      */
  2590.     while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2591.     {
  2592. #ifdef FEAT_DIFF
  2593.         if (curwin->w_topfill > 0)
  2594.         {
  2595.         i = 1;
  2596.         if (--n < 0 && scrolled > 0)
  2597.             break;
  2598.         --curwin->w_topfill;
  2599.         }
  2600.         else
  2601. #endif
  2602.         {
  2603. #ifdef FEAT_DIFF
  2604.         i = plines_nofill(curwin->w_topline);
  2605. #else
  2606.         i = plines(curwin->w_topline);
  2607. #endif
  2608.         n -= i;
  2609.         if (n < 0 && scrolled > 0)
  2610.             break;
  2611. #ifdef FEAT_FOLDING
  2612.         (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
  2613. #endif
  2614.         ++curwin->w_topline;
  2615. #ifdef FEAT_DIFF
  2616.         curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
  2617. #endif
  2618.  
  2619. #ifndef KEEP_SCREEN_LINE
  2620.         if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  2621.         {
  2622.             ++curwin->w_cursor.lnum;
  2623.             curwin->w_valid &=
  2624.                     ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2625.         }
  2626. #endif
  2627.         }
  2628.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
  2629.         scrolled += i;
  2630.  
  2631.         /*
  2632.          * Correct w_botline for changed w_topline.
  2633.          * Won't work when there are filler lines.
  2634.          */
  2635. #ifdef FEAT_DIFF
  2636.         if (curwin->w_p_diff)
  2637.         curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  2638.         else
  2639. #endif
  2640.         {
  2641.         room += i;
  2642.         do
  2643.         {
  2644.             i = plines(curwin->w_botline);
  2645.             if (i > room)
  2646.             break;
  2647. #ifdef FEAT_FOLDING
  2648.             (void)hasFolding(curwin->w_botline, NULL,
  2649.                               &curwin->w_botline);
  2650. #endif
  2651.             ++curwin->w_botline;
  2652.             room -= i;
  2653.         } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
  2654.         }
  2655.     }
  2656.  
  2657. #ifndef KEEP_SCREEN_LINE
  2658.     /*
  2659.      * When hit bottom of the file: move cursor down.
  2660.      */
  2661.     if (n > 0)
  2662.     {
  2663. # ifdef FEAT_FOLDING
  2664.         if (hasAnyFolding(curwin))
  2665.         {
  2666.         while (--n >= 0
  2667.             && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  2668.         {
  2669.             (void)hasFolding(curwin->w_cursor.lnum, NULL,
  2670.                               &curwin->w_cursor.lnum);
  2671.             ++curwin->w_cursor.lnum;
  2672.         }
  2673.         }
  2674.         else
  2675. # endif
  2676.         curwin->w_cursor.lnum += n;
  2677.         check_cursor_lnum();
  2678.     }
  2679. #else
  2680.     /* try to put the cursor in the same screen line */
  2681.     while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
  2682.                  && curwin->w_cursor.lnum < curwin->w_botline - 1)
  2683.     {
  2684.         scrolled -= plines(curwin->w_cursor.lnum);
  2685.         if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
  2686.         break;
  2687. # ifdef FEAT_FOLDING
  2688.         (void)hasFolding(curwin->w_cursor.lnum, NULL,
  2689.                               &curwin->w_cursor.lnum);
  2690. # endif
  2691.         ++curwin->w_cursor.lnum;
  2692.     }
  2693. #endif
  2694.     }
  2695.     else
  2696.     {
  2697.     /*
  2698.      * scroll the text down
  2699.      */
  2700.     while (n > 0 && curwin->w_topline > 1)
  2701.     {
  2702. #ifdef FEAT_DIFF
  2703.         if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline))
  2704.         {
  2705.         i = 1;
  2706.         if (--n < 0 && scrolled > 0)
  2707.             break;
  2708.         ++curwin->w_topfill;
  2709.         }
  2710.         else
  2711. #endif
  2712.         {
  2713. #ifdef FEAT_DIFF
  2714.         i = plines_nofill(curwin->w_topline - 1);
  2715. #else
  2716.         i = plines(curwin->w_topline - 1);
  2717. #endif
  2718.         n -= i;
  2719.         if (n < 0 && scrolled > 0)
  2720.             break;
  2721.         --curwin->w_topline;
  2722. #ifdef FEAT_FOLDING
  2723.         (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
  2724. #endif
  2725. #ifdef FEAT_DIFF
  2726.         curwin->w_topfill = 0;
  2727. #endif
  2728.         }
  2729.         curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
  2730.                           VALID_BOTLINE|VALID_BOTLINE_AP);
  2731.         scrolled += i;
  2732. #ifndef KEEP_SCREEN_LINE
  2733.         if (curwin->w_cursor.lnum > 1)
  2734.         {
  2735.         --curwin->w_cursor.lnum;
  2736.         curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2737.         }
  2738. #endif
  2739.     }
  2740. #ifndef KEEP_SCREEN_LINE
  2741.     /*
  2742.      * When hit top of the file: move cursor up.
  2743.      */
  2744.     if (n > 0)
  2745.     {
  2746.         if (curwin->w_cursor.lnum <= (linenr_T)n)
  2747.         curwin->w_cursor.lnum = 1;
  2748.         else
  2749. # ifdef FEAT_FOLDING
  2750.         if (hasAnyFolding(curwin))
  2751.         {
  2752.         while (--n >= 0 && curwin->w_cursor.lnum > 1)
  2753.         {
  2754.             --curwin->w_cursor.lnum;
  2755.             (void)hasFolding(curwin->w_cursor.lnum,
  2756.                         &curwin->w_cursor.lnum, NULL);
  2757.         }
  2758.         }
  2759.         else
  2760. # endif
  2761.         curwin->w_cursor.lnum -= n;
  2762.     }
  2763. #else
  2764.     /* try to put the cursor in the same screen line */
  2765.     scrolled += n;        /* move cursor when topline is 1 */
  2766.     while (curwin->w_cursor.lnum > curwin->w_topline
  2767.           && (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
  2768.     {
  2769.         scrolled -= plines(curwin->w_cursor.lnum - 1);
  2770.         if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
  2771.         break;
  2772.         --curwin->w_cursor.lnum;
  2773. # ifdef FEAT_FOLDING
  2774.         foldAdjustCursor();
  2775. # endif
  2776.     }
  2777. #endif
  2778.     }
  2779. # ifdef FEAT_FOLDING
  2780.     /* Move cursor to first line of closed fold. */
  2781.     foldAdjustCursor();
  2782. # endif
  2783. #ifdef FEAT_DIFF
  2784.     check_topfill(curwin, !flag);
  2785. #endif
  2786.     cursor_correct();
  2787.     beginline(BL_SOL | BL_FIX);
  2788.     redraw_later(VALID);
  2789. }
  2790.