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 <luukvbaal@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 7602bd3..344571f 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
Binary files differ
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 2ec7cde..c81c244 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -1294,15 +1294,15 @@
   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 @@
   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 @@
   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 b180637..dd2f2be 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -130,7 +130,7 @@
   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 @@
   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 @@
   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 @@
   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 3467760..2480495 100644
--- a/src/testdir/test_scroll_opt.vim
+++ b/src/testdir/test_scroll_opt.vim
@@ -829,7 +829,7 @@
   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 @@
   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