patch 9.1.0211: page-wise scrolling does not support smooth-scrolling

Commit: 
https://github.com/vim/vim/commit/b9f5b95b7bec2414a5a96010514702d99afea18e
Author: Luuk van Baal <luukvb...@gmail.com>
Date:   Tue Mar 26 18:46:45 2024 +0100

    patch 9.1.0211: page-wise scrolling does not support smooth-scrolling
    
    Problem:  Page-wise scrolling with Ctrl-F/Ctrl-B implements
              it's own logic to change the topline and cursor.
              In doing so, skipcol is not handled properly for
              'smoothscroll', and virtual lines.
    Solution: Re-use the logic from Ctrl-E/Ctrl-Y while staying
              backward compatible as much as possible.
    
    closes: #14268
    
    Signed-off-by: Luuk van Baal <luukvb...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index cd425b819..ff7497037 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt*  For Vim version 9.1.  Last change: 2024 Mar 25
+*options.txt*  For Vim version 9.1.  Last change: 2024 Mar 26
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -7502,8 +7502,8 @@ A jump table for the options with a short description can 
be found at |Q_op|.
        highlighted with |hl-NonText|.
        You may also want to add "lastline" to the 'display' option to show as
        much of the last line as possible.
-       NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y
-       and scrolling with the mouse.
+       NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
+       CTRL-B, CTRL-F and scrolling with the mouse.
 
                                        *'softtabstop'* *'sts'*
 'softtabstop' 'sts'    number  (default 0)
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index b94d15764..82482a762 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41554,6 +41554,8 @@ Other improvements                              
*new-other-9.2*
 Changed                                                *changed-9.2*
 -------
 
+- use 'smoothscroll' logic for CTRL-F and CTRL-B for pagewise scrolling
+
 Added                                          *added-9.2*
 -----
 
diff --git a/src/move.c b/src/move.c
index 9ea24c8ed..772b173bc 100644
--- a/src/move.c
+++ b/src/move.c
@@ -2047,26 +2047,6 @@ check_topfill(
        }
     }
 }
-
-/*
- * Use as many filler lines as possible for w_topline.  Make sure w_topline
- * is still visible.
- */
-    static void
-max_topfill(void)
-{
-    int                n;
-
-    n = plines_nofill(curwin->w_topline);
-    if (n >= curwin->w_height)
-       curwin->w_topfill = 0;
-    else
-    {
-       curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
-       if (curwin->w_topfill + n > curwin->w_height)
-           curwin->w_topfill = curwin->w_height - n;
-    }
-}
 #endif
 
 /*
@@ -2269,38 +2249,6 @@ botline_forw(lineoff_T *lp)
     }
 }
 
-#ifdef FEAT_DIFF
-/*
- * Switch from including filler lines below lp->lnum to including filler
- * lines above loff.lnum + 1.  This keeps pointing to the same line.
- * When there are no filler lines nothing changes.
- */
-    static void
-botline_topline(lineoff_T *lp)
-{
-    if (lp->fill > 0)
-    {
-       ++lp->lnum;
-       lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
-    }
-}
-
-/*
- * Switch from including filler lines above lp->lnum to including filler
- * lines below loff.lnum - 1.  This keeps pointing to the same line.
- * When there are no filler lines nothing changes.
- */
-    static void
-topline_botline(lineoff_T *lp)
-{
-    if (lp->fill > 0)
-    {
-       lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
-       --lp->lnum;
-    }
-}
-#endif
-
 /*
  * Recompute topline to put the cursor at the top of the window.
  * Scroll at least "min_scroll" lines.
@@ -3077,8 +3025,6 @@ cursor_correct(void)
     curwin->w_valid |= VALID_TOPLINE;
 }
 
-static void get_scroll_overlap(lineoff_T *lp, int dir);
-
 /*
  * Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
  * and update the screen.
@@ -3088,313 +3034,48 @@ static void get_scroll_overlap(lineoff_T *lp, int dir);
     int
 onepage(int dir, long count)
 {
-    long       n;
-    int                retval = OK;
-    lineoff_T  loff;
-    linenr_T   old_topline = curwin->w_topline;
-    long       so = get_scrolloff_value();
-
-    if (curbuf->b_ml.ml_line_count == 1)    // nothing to do
-    {
-       beep_flush();
-       return FAIL;
-    }
-
-    for ( ; count > 0; --count)
-    {
-       validate_botline();
-       /*
-        * It's an error to move a page up when the first line is already on
-        * the screen.  It's an error to move a page down when the last line
-        * is on the screen and the topline is 'scrolloff' lines from the
-        * last line.
-        */
-       if (dir == FORWARD
-               ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
-                   && curwin->w_botline > curbuf->b_ml.ml_line_count)
-               : (curwin->w_topline == 1
-#ifdef FEAT_DIFF
-                   && curwin->w_topfill ==
-                                   diff_check_fill(curwin, curwin->w_topline)
-#endif
-                   ))
-       {
-           beep_flush();
-           retval = FAIL;
-           break;
-       }
-
-#ifdef FEAT_DIFF
-       loff.fill = 0;
-#endif
-       if (dir == FORWARD)
-       {
-           if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
-           {
-               // Vi compatible scrolling
-               if (p_window <= 2)
-                   ++curwin->w_topline;
-               else
-                   curwin->w_topline += p_window - 2;
-               if (curwin->w_topline > curbuf->b_ml.ml_line_count)
-                   curwin->w_topline = curbuf->b_ml.ml_line_count;
-               curwin->w_cursor.lnum = curwin->w_topline;
-           }
-           else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
-           {
-               // at end of file
-               curwin->w_topline = curbuf->b_ml.ml_line_count;
-#ifdef FEAT_DIFF
-               curwin->w_topfill = 0;
-#endif
-               curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
-           }
-           else
-           {
-               // For the overlap, start with the line just below the window
-               // and go upwards.
-               loff.lnum = curwin->w_botline;
-#ifdef FEAT_DIFF
-               loff.fill = diff_check_fill(curwin, loff.lnum)
-                                                     - curwin->w_filler_rows;
-#endif
-               get_scroll_overlap(&loff, -1);
-               curwin->w_topline = loff.lnum;
-#ifdef FEAT_DIFF
-               curwin->w_topfill = loff.fill;
-               check_topfill(curwin, FALSE);
-#endif
-               curwin->w_cursor.lnum = curwin->w_topline;
-               curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
-                                  VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
-           }
-       }
-       else    // dir == BACKWARDS
-       {
-#ifdef FEAT_DIFF
-           if (curwin->w_topline == 1)
-           {
-               // Include max number of filler lines
-               max_topfill();
-               continue;
-           }
-#endif
-           if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1)
-           {
-               // Vi compatible scrolling (sort of)
-               if (p_window <= 2)
-                   --curwin->w_topline;
-               else
-                   curwin->w_topline -= p_window - 2;
-               if (curwin->w_topline < 1)
-                   curwin->w_topline = 1;
-               curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
-               if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
-                   curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
-               continue;
-           }
-
-           // Find the line at the top of the window that is going to be the
-           // line at the bottom of the window.  Make sure this results in
-           // the same line as before doing CTRL-F.
-           loff.lnum = curwin->w_topline - 1;
-#ifdef FEAT_DIFF
-           loff.fill = diff_check_fill(curwin, loff.lnum + 1)
-                                                         - curwin->w_topfill;
-#endif
-           get_scroll_overlap(&loff, 1);
-
-           if (loff.lnum >= curbuf->b_ml.ml_line_count)
-           {
-               loff.lnum = curbuf->b_ml.ml_line_count;
 #ifdef FEAT_DIFF
-               loff.fill = 0;
-           }
-           else
-           {
-               botline_topline(&loff);
+    int                prev_topfill = curwin->w_topfill;
 #endif
-           }
-           curwin->w_cursor.lnum = loff.lnum;
+    linenr_T   prev_topline = curwin->w_topline;
+    colnr_T    prev_skipcol = curwin->w_skipcol;
 
-           // Find the line just above the new topline to get the right line
-           // at the bottom of the window.
-           n = 0;
-           while (n <= curwin->w_height && loff.lnum >= 1)
-           {
-               topline_back(&loff);
-               if (loff.height == MAXCOL)
-                   n = MAXCOL;
-               else
-                   n += loff.height;
-           }
-           if (loff.lnum < 1)                  // at begin of file
-           {
-               curwin->w_topline = 1;
-#ifdef FEAT_DIFF
-               max_topfill();
-#endif
-               curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
-           }
-           else
-           {
-               // Go two lines forward again.
-#ifdef FEAT_DIFF
-               topline_botline(&loff);
-#endif
-               botline_forw(&loff);
-               botline_forw(&loff);
-#ifdef FEAT_DIFF
-               botline_topline(&loff);
-#endif
-#ifdef FEAT_FOLDING
-               // We're at the wrong end of a fold now.
-               (void)hasFolding(loff.lnum, &loff.lnum, NULL);
-#endif
+    // Scroll 'window' or current window height lines.
+    count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) ?
+                                           p_window : curwin->w_height) - 2;
 
-               // Always scroll at least one line.  Avoid getting stuck on
-               // very long lines.
-               if (loff.lnum >= curwin->w_topline
-#ifdef FEAT_DIFF
-                       && (loff.lnum > curwin->w_topline
-                           || loff.fill >= curwin->w_topfill)
-#endif
-                       )
-               {
-#ifdef FEAT_DIFF
-                   // First try using the maximum number of filler lines.  If
-                   // that's not enough, backup one line.
-                   loff.fill = curwin->w_topfill;
-                   if (curwin->w_topfill < diff_check_fill(curwin,
-                                                          curwin->w_topline))
-                       max_topfill();
-                   if (curwin->w_topfill == loff.fill)
-#endif
-                   {
-                       --curwin->w_topline;
-#ifdef FEAT_DIFF
-                       curwin->w_topfill = 0;
-#endif
-                       curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
-                   }
-                   comp_botline(curwin);
-                   curwin->w_cursor.lnum = curwin->w_botline - 1;
-                   curwin->w_valid &=
-                           ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW);
-               }
-               else
-               {
-                   curwin->w_topline = loff.lnum;
+    if (curwin->w_p_sms)
+       scroll_redraw(dir == FORWARD, count);
+    else
+    {
+       // Scroll at least one full line without 'smoothscroll'.
 #ifdef FEAT_DIFF
-                   curwin->w_topfill = loff.fill;
-                   check_topfill(curwin, FALSE);
-#endif
-                   curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
-               }
-           }
-       }
-    }
-#ifdef FEAT_FOLDING
-    foldAdjustCursor();
+       count -= plines_nofill(curwin->w_topline);
+#else
+       count -= plines(curwin->w_topline);
 #endif
-    cursor_correct();
-    check_cursor_col();
-    if (retval == OK)
-       beginline(BL_SOL | BL_FIX);
-    curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
+       scroll_redraw(dir == FORWARD, 1);
 
-    if (retval == OK && dir == FORWARD)
-    {
-       // Avoid the screen jumping up and down when 'scrolloff' is non-zero.
-       // But make sure we scroll at least one line (happens with mix of long
-       // wrapping lines and non-wrapping line).
-       if (check_top_offset())
-       {
-           scroll_cursor_top(1, FALSE);
-           if (curwin->w_topline <= old_topline
-                                 && old_topline < curbuf->b_ml.ml_line_count)
-           {
-               curwin->w_topline = old_topline + 1;
-#ifdef FEAT_FOLDING
-               (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
-#endif
-           }
-       }
-#ifdef FEAT_FOLDING
-       else if (curwin->w_botline > curbuf->b_ml.ml_line_count)
-           (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
-#endif
+       // Temporarily set 'smoothscroll' so that scrolling count lines
+       // does not skip over parts of the buffer with wrapped lines.
+       curwin->w_p_sms = TRUE;
+       if (count > 0)
+           scroll_redraw(dir == FORWARD, count);
+       curwin->w_p_sms = FALSE;
     }
 
-    redraw_later(UPD_VALID);
-    return retval;
-}
-
-/*
- * Decide how much overlap to use for page-up or page-down scrolling.
- * This is symmetric, so that doing both keeps the same lines displayed.
- * Three lines are examined:
- *
- *  before CTRL-F          after CTRL-F / before CTRL-B
- *     etc.                    l1
- *  l1 last but one line       ------------
- *  l2 last text line          l2 top text line
- *  -------------              l3 second text line
- *  l3                            etc.
- */
-    static void
-get_scroll_overlap(lineoff_T *lp, int dir)
-{
-    int                h1, h2, h3, h4;
-    int                min_height = curwin->w_height - 2;
-    lineoff_T  loff0, loff1, loff2;
-
+    int nochange = curwin->w_topline == prev_topline
 #ifdef FEAT_DIFF
-    if (lp->fill > 0)
-       lp->height = 1;
-    else
-       lp->height = plines_nofill(lp->lnum);
-#else
-    lp->height = plines(lp->lnum);
+       && curwin->w_topfill == prev_topfill
 #endif
-    h1 = lp->height;
-    if (h1 > min_height)
-       return;         // no overlap
+       && curwin->w_skipcol == prev_skipcol;
 
-    loff0 = *lp;
-    if (dir > 0)
-       botline_forw(lp);
-    else
-       topline_back(lp);
-    h2 = lp->height;
-    if (h2 == MAXCOL || h2 + h1 > min_height)
-    {
-       *lp = loff0;    // no overlap
-       return;
-    }
-
-    loff1 = *lp;
-    if (dir > 0)
-       botline_forw(lp);
-    else
-       topline_back(lp);
-    h3 = lp->height;
-    if (h3 == MAXCOL || h3 + h2 > min_height)
-    {
-       *lp = loff0;    // no overlap
-       return;
-    }
+    if (nochange)
+       beep_flush();
+    else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol)
+       beginline(BL_SOL | BL_FIX);
 
-    loff2 = *lp;
-    if (dir > 0)
-       botline_forw(lp);
-    else
-       topline_back(lp);
-    h4 = lp->height;
-    if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
-       *lp = loff1;    // 1 line overlap
-    else
-       *lp = loff2;    // 2 lines overlap
+    return nochange;
 }
 
 /*
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 7602bd374..344571fc1 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
@@ -1647,34 +1647,38 @@ endfunc
 func Test_diff_scroll_many_filler()
   20new
   vnew
-  call setline(1, ['^^^', '^^^', '$$$', '$$$'])
+  call setline(1, range(1, 40))
   diffthis
   setlocal scrolloff=0
   wincmd p
-  call setline(1, ['^^^', '^^^'] + repeat(['###'], 41) + ['$$$', '$$$'])
+  call setline(1, range(1, 20)->reverse() + ['###']->repeat(41) + range(21, 
40)->reverse())
   diffthis
   setlocal scrolloff=0
   wincmd p
   redraw
 
   " Note: need a redraw after each scroll, otherwise the test always passes.
-  normal! G
-  redraw
-  call assert_equal(3, winsaveview().topline)
-  call assert_equal(18, winsaveview().topfill)
-  exe "normal! \<C-B>"
-  redraw
-  call assert_equal(3, winsaveview().topline)
-  call assert_equal(19, winsaveview().topfill)
-  exe "normal! \<C-B>"
-  redraw
-  call assert_equal(2, winsaveview().topline)
-  call assert_equal(0, winsaveview().topfill)
-  exe "normal! \<C-B>"
-  redraw
-  call assert_equal(1, winsaveview().topline)
-  call assert_equal(0, winsaveview().topfill)
+  for _ in range(2)
+    normal! G
+    redraw
+    call assert_equal(40, winsaveview().topline)
+    call assert_equal(19, winsaveview().topfill)
+    exe "normal! \<C-B>"
+    redraw
+    call assert_equal(22, winsaveview().topline)
+    call assert_equal(0, winsaveview().topfill)
+    exe "normal! \<C-B>"
+    redraw
+    call assert_equal(4, winsaveview().topline)
+    call assert_equal(0, winsaveview().topfill)
+    exe "normal! \<C-B>"
+    redraw
+    call assert_equal(1, winsaveview().topline)
+    call assert_equal(0, winsaveview().topfill)
+    set smoothscroll
+  endfor
 
+  set smoothscroll&
   bwipe!
   bwipe!
 endfunc
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 2ec7cde8d..c81c24453 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -1294,15 +1294,15 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("i\<PageDown>\<esc>", 'tnix')
   call assert_equal([0, 30, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 29, 1, 0], getpos('.'))
+  call assert_equal([0, 30, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 21, 1, 0], getpos('.'))
+  call assert_equal([0, 23, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 13, 1, 0], getpos('.'))
+  call assert_equal([0, 15, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 5, 1, 0], getpos('.'))
+  call assert_equal([0, 10, 1, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   " <S-Up> is the same as <PageUp>
   " <S-Down> is the same as <PageDown>
   call cursor(1, 1)
@@ -1317,28 +1317,28 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call feedkeys("i\<S-Down>\<esc>", 'tnix')
   call assert_equal([0, 30, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 29, 1, 0], getpos('.'))
+  call assert_equal([0, 30, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 21, 1, 0], getpos('.'))
+  call assert_equal([0, 23, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 13, 1, 0], getpos('.'))
+  call assert_equal([0, 15, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 5, 1, 0], getpos('.'))
+  call assert_equal([0, 10, 1, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   set nostartofline
   call cursor(30, 11)
   norm! zt
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 29, 11, 0], getpos('.'))
+  call assert_equal([0, 30, 11, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 21, 11, 0], getpos('.'))
+  call assert_equal([0, 23, 11, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 13, 11, 0], getpos('.'))
+  call assert_equal([0, 15, 11, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call feedkeys("A\<PageUp>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call cursor(1, 1)
   call feedkeys("A\<PageDown>\<esc>", 'tnix')
   call assert_equal([0, 9, 11, 0], getpos('.'))
@@ -1355,15 +1355,15 @@ func Test_edit_PAGEUP_PAGEDOWN()
   call cursor(30, 11)
   norm! zt
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 29, 11, 0], getpos('.'))
+  call assert_equal([0, 30, 11, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 21, 11, 0], getpos('.'))
+  call assert_equal([0, 23, 11, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 13, 11, 0], getpos('.'))
+  call assert_equal([0, 15, 11, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call feedkeys("A\<S-Up>\<esc>", 'tnix')
-  call assert_equal([0, 5, 11, 0], getpos('.'))
+  call assert_equal([0, 10, 11, 0], getpos('.'))
   call cursor(1, 1)
   call feedkeys("A\<S-Down>\<esc>", 'tnix')
   call assert_equal([0, 9, 11, 0], getpos('.'))
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index b18063747..dd2f2be2f 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -130,7 +130,7 @@ func Test_normal01_keymodel()
   call assert_equal([0, 1, 1, 0], getpos("'<"))
   call assert_equal([0, 3, 1, 0], getpos("'>"))
   call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt')
-  call assert_equal([0, 2, 1, 0], getpos("'<"))
+  call assert_equal([0, 3, 1, 0], getpos("'<"))
   call assert_equal([0, 3, 8, 0], getpos("'>"))
   " Test for <S-C-Home> and <S-C-End>
   call cursor(2, 12)
@@ -912,12 +912,10 @@ func Test_normal14_page()
   set scrolloff=0
   100
   exe "norm! $\<c-b>"
-  call assert_equal('92', getline('.'))
   call assert_equal([0, 92, 1, 0, 1], getcurpos())
   100
   set nostartofline
   exe "norm! $\<c-b>"
-  call assert_equal('92', getline('.'))
   call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos())
   " cleanup
   set startofline
@@ -3815,11 +3813,11 @@ func Test_normal_vert_scroll_longline()
   call assert_equal(11, line('.'))
   call assert_equal(1, winline())
   exe "normal \<C-B>"
-  call assert_equal(10, line('.'))
-  call assert_equal(3, winline())
+  call assert_equal(11, line('.'))
+  call assert_equal(9, winline())
   exe "normal \<C-B>\<C-B>"
   call assert_equal(5, line('.'))
-  call assert_equal(5, winline())
+  call assert_equal(1, winline())
 
   bwipe!
 endfunc
@@ -4172,20 +4170,30 @@ func Test_normal34_zet_large()
   norm! z9765405999999999999
 endfunc
 
-" Test for { and } paragraph movements in a single line
-func Test_brace_single_line()
-  let text =<< trim [DATA]
-    foobar one two three
-  [DATA]
+" Test for { and } paragraph movements and Ctrl-B in buffer with a single line
+func Test_single_line_scroll()
+  CheckFeature textprop
 
   new
-  call setline(1, text)
+  call setline(1, ['foobar one two three'])
+  let vt = 'virt_above'
+  call prop_type_add(vt, {'highlight': 'IncSearch'})
+  call prop_add(1, 0, {'type': vt, 'text': '---', 'text_align': 'above'})
   1
   norm! 0}
 
   call assert_equal([0, 1, 20, 0], getpos('.'))
   norm! {
   call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  " Ctrl-B scrolls up with hidden "above" virtual text.
+  set smoothscroll
+  exe "normal \<C-E>"
+  call assert_notequal(0, winsaveview().skipcol)
+  exe "normal \<C-B>"
+  call assert_equal(0, winsaveview().skipcol)
+
+  set smoothscroll&
   bw!
 endfunc
 
diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim
index 346776074..24804956f 100644
--- a/src/testdir/test_scroll_opt.vim
+++ b/src/testdir/test_scroll_opt.vim
@@ -829,7 +829,7 @@ func Test_smoothscroll_eob()
   call VerifyScreenDump(buf, 'Test_smooth_eob_1', {})
 
   " cursor is not placed below window
-  call term_sendkeys(buf, ":call setline(92, 'a'->repeat(100))\<CR>\<C-B>G")
+  call term_sendkeys(buf, ":call setline(92, 
'a'->repeat(100))\<CR>\<C-L>\<C-B>G")
   call VerifyScreenDump(buf, 'Test_smooth_eob_2', {})
 
   call StopVimInTerminal(buf)
@@ -998,4 +998,26 @@ func Test_smoothscroll_textoff_small_winwidth()
   set smoothscroll& number&
 endfunc
 
+func Test_smoothscroll_page()
+  set smoothscroll
+
+  10split | 40vsplit
+  call setline(1, 'abcde '->repeat(150))
+
+  exe "norm! \<C-F>"
+  call assert_equal(320, winsaveview().skipcol)
+  exe "norm! \<C-F>"
+  call assert_equal(640, winsaveview().skipcol)
+  exe "norm! \<C-F>"
+  call assert_equal(880, winsaveview().skipcol)
+  exe "norm! \<C-B>"
+  call assert_equal(560, winsaveview().skipcol)
+  exe "norm! \<C-B>"
+  call assert_equal(240, winsaveview().skipcol)
+  exe "norm! \<C-B>"
+  call assert_equal(0, winsaveview().skipcol)
+
+  set smoothscroll&
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 0c053c565..634125972 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    211,
 /**/
     210,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rpB5g-007baf-Uo%40256bit.org.

Raspunde prin e-mail lui