From 4147302f4be3fe8a5dae3f20a336477cb5f507a4 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 26 Mar 2024 19:06:39 +0100 Subject: [PATCH 1/2] vim-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. https://github.com/vim/vim/commit/b9f5b95b7bec2414a5a96010514702d99afea18e --- runtime/doc/options.txt | 4 +- runtime/lua/vim/_meta/options.lua | 4 +- src/nvim/move.c | 298 +++------------------ src/nvim/options.lua | 4 +- test/functional/legacy/scroll_opt_spec.lua | 2 +- test/old/testdir/test_diffmode.vim | 40 +-- test/old/testdir/test_edit.vim | 40 +-- test/old/testdir/test_normal.vim | 32 ++- test/old/testdir/test_scroll_opt.vim | 24 +- 9 files changed, 123 insertions(+), 325 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 3cc5b6af64..043524e976 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5693,8 +5693,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/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index e8e56e86b2..2d78013208 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -6075,8 +6075,8 @@ vim.go.sta = vim.go.smarttab --- 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. --- --- @type boolean vim.o.smoothscroll = false diff --git a/src/nvim/move.c b/src/nvim/move.c index 3c4da7f8ac..ebb27337f7 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -36,6 +36,7 @@ #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/plines.h" @@ -1552,21 +1553,6 @@ void check_topfill(win_T *wp, bool down) win_check_anchored_floats(wp); } -// Use as many filler lines as possible for w_topline. Make sure w_topline -// is still visible. -static void max_topfill(void) -{ - int n = plines_win_nofill(curwin, curwin->w_topline, true); - if (n >= curwin->w_height_inner) { - curwin->w_topfill = 0; - } else { - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - if (curwin->w_topfill + n > curwin->w_height_inner) { - curwin->w_topfill = curwin->w_height_inner - n; - } - } -} - // Scroll the screen one line down, but don't do it if it would move the // cursor off the screen. void scrolldown_clamp(void) @@ -1697,28 +1683,6 @@ static void botline_forw(win_T *wp, lineoff_T *lp) } } -// 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 = win_get_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 = win_get_fill(curwin, lp->lnum) - lp->fill + 1; - lp->lnum--; - } -} - // Recompute topline to put the cursor at the top of the window. // Scroll at least "min_scroll" lines. // If "always" is true, always set topline (for "zt"). @@ -2320,241 +2284,41 @@ void cursor_correct(win_T *wp) /// @return FAIL for failure, OK otherwise. int onepage(Direction dir, int count) { - int retval = OK; - lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - int so = get_scrolloff_value(curwin); + int prev_topfill = curwin->w_topfill; + linenr_T prev_topline = curwin->w_topline; + colnr_T prev_skipcol = curwin->w_skipcol; - if (curbuf->b_ml.ml_line_count == 1) { // nothing to do + // Scroll 'window' or current window height lines. + count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) + ? (int)p_window - 2 : curwin->w_height - 1); + + if (curwin->w_p_sms) { + scroll_redraw(dir == FORWARD, count); + } else { + // Scroll at least one full line without 'smoothscroll'. + count -= plines_win_nofill(curwin, curwin->w_topline, false); + scroll_redraw(dir == FORWARD, 1); + + // 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; + } + + int nochange = curwin->w_topline == prev_topline + && curwin->w_topfill == prev_topfill + && curwin->w_skipcol == prev_skipcol; + + if (nochange) { beep_flush(); - return FAIL; - } - - for (; count > 0; count--) { - validate_botline(curwin); - // 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 - && curwin->w_topfill == win_get_fill(curwin, curwin->w_topline))) { - beep_flush(); - retval = FAIL; - break; - } - - loff.fill = 0; - 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 += (linenr_T)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; - curwin->w_topfill = 0; - 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; - loff.fill = win_get_fill(curwin, loff.lnum) - - curwin->w_filler_rows; - get_scroll_overlap(&loff, -1); - curwin->w_topline = loff.lnum; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - 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 - if (curwin->w_topline == 1) { - // Include max number of filler lines - max_topfill(); - continue; - } - 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 -= (linenr_T)p_window - 2; - } - if (curwin->w_topline < 1) { - curwin->w_topline = 1; - } - curwin->w_cursor.lnum = curwin->w_topline + (linenr_T)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; - loff.fill = win_get_fill(curwin, loff.lnum + 1) - curwin->w_topfill; - get_scroll_overlap(&loff, 1); - - if (loff.lnum >= curbuf->b_ml.ml_line_count) { - loff.lnum = curbuf->b_ml.ml_line_count; - loff.fill = 0; - } else { - botline_topline(&loff); - } - curwin->w_cursor.lnum = loff.lnum; - - // Find the line just above the new topline to get the right line - // at the bottom of the window. - int n = 0; - while (n <= curwin->w_height_inner && loff.lnum >= 1) { - topline_back(curwin, &loff); - if (loff.height == MAXCOL) { - n = MAXCOL; - } else { - n += loff.height; - } - } - if (loff.lnum < 1) { // at begin of file - curwin->w_topline = 1; - max_topfill(); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } else { - // Go two lines forward again. - topline_botline(&loff); - botline_forw(curwin, &loff); - botline_forw(curwin, &loff); - botline_topline(&loff); - // We're at the wrong end of a fold now. - hasFolding(curwin, loff.lnum, &loff.lnum, NULL); - - // Always scroll at least one line. Avoid getting stuck on - // very long lines. - if (loff.lnum >= curwin->w_topline - && (loff.lnum > curwin->w_topline - || loff.fill >= curwin->w_topfill)) { - // 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 < win_get_fill(curwin, curwin->w_topline)) { - max_topfill(); - } - if (curwin->w_topfill == loff.fill) { - curwin->w_topline--; - curwin->w_topfill = 0; - 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; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } - } - } - } - foldAdjustCursor(curwin); - cursor_correct(curwin); - check_cursor_col(curwin); - if (retval == OK) { + } else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) { beginline(BL_SOL | BL_FIX); } - curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); - 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(curwin, 1, false); - if (curwin->w_topline <= old_topline - && old_topline < curbuf->b_ml.ml_line_count) { - curwin->w_topline = old_topline + 1; - hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); - } - } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); - } - } - - redraw_later(curwin, 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 min_height = curwin->w_height_inner - 2; - - if (lp->fill > 0) { - lp->height = 1; - } else { - lp->height = plines_win_nofill(curwin, lp->lnum, true); - } - int h1 = lp->height; - if (h1 > min_height) { - return; // no overlap - } - lineoff_T loff0 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int h2 = lp->height; - if (h2 == MAXCOL || h2 + h1 > min_height) { - *lp = loff0; // no overlap - return; - } - - lineoff_T loff1 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int h3 = lp->height; - if (h3 == MAXCOL || h3 + h2 > min_height) { - *lp = loff0; // no overlap - return; - } - - lineoff_T loff2 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); - } else { - topline_back(curwin, lp); - } - int 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; } // Scroll 'scroll' lines up or down. diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 6bfeee75e6..a7c5a97d02 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7663,8 +7663,8 @@ return { 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. ]=], full_name = 'smoothscroll', pv_name = 'p_sms', diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua index 78028f2f44..c00993f5f7 100644 --- a/test/functional/legacy/scroll_opt_spec.lua +++ b/test/functional/legacy/scroll_opt_spec.lua @@ -740,7 +740,7 @@ describe('smoothscroll', function() | ]]) exec("call setline(92, 'a'->repeat(100))") - feed('G') + feed('G') -- cursor is not placed below window screen:expect([[ {1:<<<}aaaaaaaaaaaaaaaaa | diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim index c1a63a6f88..3e7eabf8f5 100644 --- a/test/old/testdir/test_diffmode.vim +++ b/test/old/testdir/test_diffmode.vim @@ -1632,34 +1632,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! \" - redraw - call assert_equal(3, winsaveview().topline) - call assert_equal(19, winsaveview().topfill) - exe "normal! \" - redraw - call assert_equal(2, winsaveview().topline) - call assert_equal(0, winsaveview().topfill) - exe "normal! \" - 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! \" + redraw + call assert_equal(22, winsaveview().topline) + call assert_equal(0, winsaveview().topfill) + exe "normal! \" + redraw + call assert_equal(4, winsaveview().topline) + call assert_equal(0, winsaveview().topfill) + exe "normal! \" + redraw + call assert_equal(1, winsaveview().topline) + call assert_equal(0, winsaveview().topfill) + set smoothscroll + endfor + set smoothscroll& bwipe! bwipe! endfunc diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim index 8281b3d495..2d4314a276 100644 --- a/test/old/testdir/test_edit.vim +++ b/test/old/testdir/test_edit.vim @@ -1312,15 +1312,15 @@ func Test_edit_PAGEUP_PAGEDOWN() call feedkeys("i\\", 'tnix') call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 29, 1, 0], getpos('.')) + call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 21, 1, 0], getpos('.')) + call assert_equal([0, 23, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 13, 1, 0], getpos('.')) + call assert_equal([0, 15, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 1, 0], getpos('.')) + call assert_equal([0, 10, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 11, 0], getpos('.')) + call assert_equal([0, 10, 11, 0], getpos('.')) " is the same as " is the same as call cursor(1, 1) @@ -1335,28 +1335,28 @@ func Test_edit_PAGEUP_PAGEDOWN() call feedkeys("i\\", 'tnix') call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 29, 1, 0], getpos('.')) + call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 21, 1, 0], getpos('.')) + call assert_equal([0, 23, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 13, 1, 0], getpos('.')) + call assert_equal([0, 15, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 1, 0], getpos('.')) + call assert_equal([0, 10, 1, 0], getpos('.')) call feedkeys("A\\", '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\\", 'tnix') - call assert_equal([0, 29, 11, 0], getpos('.')) + call assert_equal([0, 30, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 21, 11, 0], getpos('.')) + call assert_equal([0, 23, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 13, 11, 0], getpos('.')) + call assert_equal([0, 15, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 11, 0], getpos('.')) + call assert_equal([0, 10, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 11, 0], getpos('.')) + call assert_equal([0, 10, 11, 0], getpos('.')) call cursor(1, 1) call feedkeys("A\\", 'tnix') call assert_equal([0, 9, 11, 0], getpos('.')) @@ -1373,15 +1373,15 @@ func Test_edit_PAGEUP_PAGEDOWN() call cursor(30, 11) norm! zt call feedkeys("A\\", 'tnix') - call assert_equal([0, 29, 11, 0], getpos('.')) + call assert_equal([0, 30, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 21, 11, 0], getpos('.')) + call assert_equal([0, 23, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 13, 11, 0], getpos('.')) + call assert_equal([0, 15, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 11, 0], getpos('.')) + call assert_equal([0, 10, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 5, 11, 0], getpos('.')) + call assert_equal([0, 10, 11, 0], getpos('.')) call cursor(1, 1) call feedkeys("A\\", 'tnix') call assert_equal([0, 9, 11, 0], getpos('.')) diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim index d31ae488d9..644a632413 100644 --- a/test/old/testdir/test_normal.vim +++ b/test/old/testdir/test_normal.vim @@ -131,7 +131,7 @@ func Test_normal01_keymodel() call assert_equal([0, 1, 1, 0], getpos("'<")) call assert_equal([0, 3, 1, 0], getpos("'>")) call feedkeys("Gz\8|\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 and call cursor(2, 12) @@ -915,12 +915,10 @@ func Test_normal14_page() set scrolloff=0 100 exe "norm! $\" - call assert_equal('92', getline('.')) call assert_equal([0, 92, 1, 0, 1], getcurpos()) 100 set nostartofline exe "norm! $\" - call assert_equal('92', getline('.')) call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos()) " cleanup set startofline @@ -3825,11 +3823,11 @@ func Test_normal_vert_scroll_longline() call assert_equal(11, line('.')) call assert_equal(1, winline()) exe "normal \" - call assert_equal(10, line('.')) - call assert_equal(3, winline()) + call assert_equal(11, line('.')) + call assert_equal(9, winline()) exe "normal \\" call assert_equal(5, line('.')) - call assert_equal(5, winline()) + call assert_equal(1, winline()) bwipe! endfunc @@ -4182,20 +4180,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 \" + call assert_notequal(0, winsaveview().skipcol) + exe "normal \" + call assert_equal(0, winsaveview().skipcol) + + set smoothscroll& bw! endfunc diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim index 8130f7a1ac..ebfed77214 100644 --- a/test/old/testdir/test_scroll_opt.vim +++ b/test/old/testdir/test_scroll_opt.vim @@ -832,7 +832,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))\\G") + call term_sendkeys(buf, ":call setline(92, 'a'->repeat(100))\\\G") call VerifyScreenDump(buf, 'Test_smooth_eob_2', {}) call StopVimInTerminal(buf) @@ -1001,4 +1001,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! \" + call assert_equal(320, winsaveview().skipcol) + exe "norm! \" + call assert_equal(640, winsaveview().skipcol) + exe "norm! \" + call assert_equal(880, winsaveview().skipcol) + exe "norm! \" + call assert_equal(560, winsaveview().skipcol) + exe "norm! \" + call assert_equal(240, winsaveview().skipcol) + exe "norm! \" + call assert_equal(0, winsaveview().skipcol) + + set smoothscroll& +endfunc + " vim: shiftwidth=2 sts=2 expandtab From 2f638c0ac6275bebacd12671481642fa43d7ba10 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 28 Mar 2024 10:20:45 +0100 Subject: [PATCH 2/2] vim-patch:9.1.0215: Half-page scrolling does not support smooth-scrolling Problem: Page-wise scrolling with Ctrl-D/Ctrl-U implements it's own logic to change the topline and cursor. More logic than necessary for scrolling with Ctrl-F/Ctrl-B was removed in patch 9.1.0211. Solution: Re-use the logic from Ctrl-E/Ctrl-Y/Ctrl-F/Ctrl-B while staying backward compatible as much as possible. Restore some of the logic that determined how many lines will be scrolled (Luuk van Baal) https://github.com/vim/vim/commit/5a2e3ec9ac72b6e644fea4ebba7e632498296e2f --- runtime/doc/options.txt | 6 +- runtime/lua/vim/_meta/options.lua | 6 +- src/nvim/edit.c | 4 +- src/nvim/mouse.c | 2 +- src/nvim/move.c | 214 ++++++++------------- src/nvim/normal.c | 10 +- src/nvim/options.lua | 6 +- test/functional/legacy/matchparen_spec.lua | 2 +- test/old/testdir/test_edit.vim | 32 +-- test/old/testdir/test_normal.vim | 26 ++- test/old/testdir/test_scroll_opt.vim | 29 ++- 11 files changed, 159 insertions(+), 178 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 043524e976..b0583d306d 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5694,7 +5694,7 @@ A jump table for the options with a short description can be found at |Q_op|. 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, - CTRL-B, CTRL-F and scrolling with the mouse. + CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse. *'softtabstop'* *'sts'* 'softtabstop' 'sts' number (default 0) @@ -7164,8 +7164,8 @@ A jump table for the options with a short description can be found at |Q_op|. will scroll 'window' minus two lines, with a minimum of one. When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll in a much smarter way, taking care of wrapping lines. - When resizing the Vim window, the value is smaller than 1 or more than - or equal to 'lines' it will be set to 'lines' minus 1. + When resizing the Vim window, and the value is smaller than 1 or more + than or equal to 'lines' it will be set to 'lines' minus 1. Note: Do not confuse this with the height of the Vim window, use 'lines' for that. diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 2d78013208..adc42f9659 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -6076,7 +6076,7 @@ vim.go.sta = vim.go.smarttab --- 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, ---- CTRL-B, CTRL-F and scrolling with the mouse. +--- CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse. --- --- @type boolean vim.o.smoothscroll = false @@ -7861,8 +7861,8 @@ vim.wo.winbl = vim.wo.winblend --- will scroll 'window' minus two lines, with a minimum of one. --- When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll --- in a much smarter way, taking care of wrapping lines. ---- When resizing the Vim window, the value is smaller than 1 or more than ---- or equal to 'lines' it will be set to 'lines' minus 1. +--- When resizing the Vim window, and the value is smaller than 1 or more +--- than or equal to 'lines' it will be set to 'lines' minus 1. --- Note: Do not confuse this with the height of the Vim window, use --- 'lines' for that. --- diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 5ae5267364..11c5ba2628 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4193,7 +4193,7 @@ static void ins_pageup(void) } pos_T tpos = curwin->w_cursor; - if (onepage(BACKWARD, 1) == OK) { + if (pagescroll(BACKWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { @@ -4238,7 +4238,7 @@ static void ins_pagedown(void) } pos_T tpos = curwin->w_cursor; - if (onepage(FORWARD, 1) == OK) { + if (pagescroll(FORWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index a2b4042f30..1e70462700 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -1024,7 +1024,7 @@ void do_mousescroll(cmdarg_T *cap) // Vertical scrolling if ((State & MODE_NORMAL) && shift_or_ctrl) { // whole page up or down - onepage(cap->arg ? FORWARD : BACKWARD, 1); + pagescroll(cap->arg ? FORWARD : BACKWARD, 1, false); } else { if (shift_or_ctrl) { // whole page up or down diff --git a/src/nvim/move.c b/src/nvim/move.c index ebb27337f7..52b65c0fef 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -2278,19 +2278,90 @@ void cursor_correct(win_T *wp) wp->w_viewport_invalid = true; } +/// 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 int get_scroll_overlap(Direction dir) +{ + lineoff_T loff; + int min_height = curwin->w_height_inner - 2; + + validate_botline(curwin); + if (dir == FORWARD && curwin->w_botline > curbuf->b_ml.ml_line_count) { + return min_height + 2; // no overlap, still handle 'smoothscroll' + } + + loff.lnum = dir == FORWARD ? curwin->w_botline : curwin->w_topline - 1; + loff.fill = win_get_fill(curwin, loff.lnum + dir == BACKWARD) + - (dir == FORWARD ? curwin->w_filler_rows : curwin->w_topfill); + loff.height = loff.fill > 0 ? 1 : plines_win_nofill(curwin, loff.lnum, true); + + int h1 = loff.height; + if (h1 > min_height) { + return min_height + 2; // no overlap + } + if (dir == FORWARD) { + topline_back(curwin, &loff); + } else { + botline_forw(curwin, &loff); + } + + int h2 = loff.height; + if (h2 == MAXCOL || h2 + h1 > min_height) { + return min_height + 2; // no overlap + } + if (dir == FORWARD) { + topline_back(curwin, &loff); + } else { + botline_forw(curwin, &loff); + } + + int h3 = loff.height; + if (h3 == MAXCOL || h3 + h2 > min_height) { + return min_height + 2; // no overlap + } + if (dir == FORWARD) { + topline_back(curwin, &loff); + } else { + botline_forw(curwin, &loff); + } + + int h4 = loff.height; + if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) { + return min_height + 1; // 1 line overlap + } else { + return min_height; // 2 lines overlap + } +} + /// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD) /// and update the screen. /// /// @return FAIL for failure, OK otherwise. -int onepage(Direction dir, int count) +int pagescroll(Direction dir, int count, bool half) { int prev_topfill = curwin->w_topfill; linenr_T prev_topline = curwin->w_topline; colnr_T prev_skipcol = curwin->w_skipcol; - // Scroll 'window' or current window height lines. - count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) - ? (int)p_window - 2 : curwin->w_height - 1); + if (half) { + // Scroll [count], 'scroll' or current window height lines. + if (count) { + curwin->w_p_scr = MIN(curwin->w_height_inner, count); + } + count = MIN(curwin->w_height_inner, (int)curwin->w_p_scr); + } else { + // Scroll 'window' or current window height lines. + count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) + ? (int)p_window - 2 : get_scroll_overlap(dir)); + } if (curwin->w_p_sms) { scroll_redraw(dir == FORWARD, count); @@ -2307,13 +2378,22 @@ int onepage(Direction dir, int count) } curwin->w_p_sms = false; } + // Move cursor to first line of closed fold. + foldAdjustCursor(curwin); int nochange = curwin->w_topline == prev_topline && curwin->w_topfill == prev_topfill && curwin->w_skipcol == prev_skipcol; + // Error if the viewport did not change and the cursor is already + // at the boundary. if (nochange) { - beep_flush(); + int prev_cursor = curwin->w_cursor.lnum; + curwin->w_cursor.lnum += (count + 1) * (dir == FORWARD ? 1 : -1); + check_cursor(curwin); + if (curwin->w_cursor.lnum == prev_cursor) { + beep_flush(); + } } else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) { beginline(BL_SOL | BL_FIX); } @@ -2321,130 +2401,6 @@ int onepage(Direction dir, int count) return nochange; } -// Scroll 'scroll' lines up or down. -void halfpage(bool flag, linenr_T Prenum) -{ - int scrolled = 0; - int i; - - if (Prenum) { - curwin->w_p_scr = (Prenum > curwin->w_height_inner) ? curwin->w_height_inner - : Prenum; - } - assert(curwin->w_p_scr <= INT_MAX); - int n = curwin->w_p_scr <= curwin->w_height_inner ? (int)curwin->w_p_scr - : curwin->w_height_inner; - - update_topline(curwin); - validate_botline(curwin); - int room = curwin->w_empty_rows + curwin->w_filler_rows; - if (flag) { - // scroll the text up - while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) { - if (curwin->w_topfill > 0) { - i = 1; - n--; - curwin->w_topfill--; - } else { - i = plines_win_nofill(curwin, curwin->w_topline, true); - n -= i; - if (n < 0 && scrolled > 0) { - break; - } - hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline); - curwin->w_topline++; - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - - if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum++; - curwin->w_valid &= - ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } - } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW); - scrolled += i; - - // Correct w_botline for changed w_topline. - // Won't work when there are filler lines. - if (win_may_fill(curwin)) { - curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); - } else { - room += i; - do { - i = plines_win(curwin, curwin->w_botline, true); - if (i > room) { - break; - } - hasFolding(curwin, curwin->w_botline, NULL, &curwin->w_botline); - curwin->w_botline++; - room -= i; - } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); - } - } - - // When hit bottom of the file: move cursor down. - if (n > 0) { - if (hasAnyFolding(curwin)) { - while (--n >= 0 - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - hasFolding(curwin, curwin->w_cursor.lnum, NULL, - &curwin->w_cursor.lnum); - curwin->w_cursor.lnum++; - } - } else { - curwin->w_cursor.lnum += n; - } - check_cursor_lnum(curwin); - } - } else { - // scroll the text down - while (n > 0 && curwin->w_topline > 1) { - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { - i = 1; - n--; - curwin->w_topfill++; - } else { - i = plines_win_nofill(curwin, curwin->w_topline - 1, true); - n -= i; - if (n < 0 && scrolled > 0) { - break; - } - curwin->w_topline--; - hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); - curwin->w_topfill = 0; - } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW| - VALID_BOTLINE|VALID_BOTLINE_AP); - scrolled += i; - if (curwin->w_cursor.lnum > 1) { - curwin->w_cursor.lnum--; - curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } - } - - // When hit top of the file: move cursor up. - if (n > 0) { - if (curwin->w_cursor.lnum <= (linenr_T)n) { - curwin->w_cursor.lnum = 1; - } else if (hasAnyFolding(curwin)) { - while (--n >= 0 && curwin->w_cursor.lnum > 1) { - curwin->w_cursor.lnum--; - hasFolding(curwin, curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); - } - } else { - curwin->w_cursor.lnum -= n; - } - } - } - // Move cursor to first line of closed fold. - foldAdjustCursor(curwin); - check_topfill(curwin, !flag); - cursor_correct(curwin); - beginline(BL_SOL | BL_FIX); - redraw_later(curwin, UPD_VALID); -} - void do_check_cursorbind(void) { static win_T *prev_curwin = NULL; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 12f0bb631e..bbba8069c7 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -2258,7 +2258,7 @@ static void nv_page(cmdarg_T *cap) goto_tabpage(cap->count0); } } else { - onepage(cap->arg, cap->count1); + pagescroll(cap->arg, cap->count1, false); } } @@ -6394,12 +6394,8 @@ static void nv_at(cmdarg_T *cap) /// Handle the CTRL-U and CTRL-D commands. static void nv_halfpage(cmdarg_T *cap) { - if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1) - || (cap->cmdchar == Ctrl_D - && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)) { - clearopbeep(cap->oap); - } else if (!checkclearop(cap->oap)) { - halfpage(cap->cmdchar == Ctrl_D, cap->count0); + if (!checkclearop(cap->oap)) { + pagescroll(cap->cmdchar == Ctrl_D, cap->count0, true); } } diff --git a/src/nvim/options.lua b/src/nvim/options.lua index a7c5a97d02..e7acf6f6ef 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7664,7 +7664,7 @@ return { 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, - CTRL-B, CTRL-F and scrolling with the mouse. + CTRL-D, CTRL-U, CTRL-F, CTRL-B and scrolling with the mouse. ]=], full_name = 'smoothscroll', pv_name = 'p_sms', @@ -9806,8 +9806,8 @@ return { will scroll 'window' minus two lines, with a minimum of one. When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll in a much smarter way, taking care of wrapping lines. - When resizing the Vim window, the value is smaller than 1 or more than - or equal to 'lines' it will be set to 'lines' minus 1. + When resizing the Vim window, and the value is smaller than 1 or more + than or equal to 'lines' it will be set to 'lines' minus 1. Note: Do not confuse this with the height of the Vim window, use 'lines' for that. ]=], diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua index 7b3f7bd424..adbf15d2e3 100644 --- a/test/functional/legacy/matchparen_spec.lua +++ b/test/functional/legacy/matchparen_spec.lua @@ -19,7 +19,7 @@ describe('matchparen', function() call cursor(5, 1) ]]) - feed('V') + feed('V3j') screen:expect([[ {17:{} | {17:}} | diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim index 2d4314a276..ba084442d1 100644 --- a/test/old/testdir/test_edit.vim +++ b/test/old/testdir/test_edit.vim @@ -1312,15 +1312,15 @@ func Test_edit_PAGEUP_PAGEDOWN() call feedkeys("i\\", 'tnix') call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 30, 1, 0], getpos('.')) + call assert_equal([0, 29, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 23, 1, 0], getpos('.')) + call assert_equal([0, 21, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 15, 1, 0], getpos('.')) + call assert_equal([0, 13, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') call assert_equal([0, 10, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 10, 11, 0], getpos('.')) + call assert_equal([0, 2, 11, 0], getpos('.')) " is the same as " is the same as call cursor(1, 1) @@ -1335,28 +1335,28 @@ func Test_edit_PAGEUP_PAGEDOWN() call feedkeys("i\\", 'tnix') call assert_equal([0, 30, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 30, 1, 0], getpos('.')) + call assert_equal([0, 29, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 23, 1, 0], getpos('.')) + call assert_equal([0, 21, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 15, 1, 0], getpos('.')) + call assert_equal([0, 13, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') call assert_equal([0, 10, 1, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 10, 11, 0], getpos('.')) + call assert_equal([0, 2, 11, 0], getpos('.')) set nostartofline call cursor(30, 11) norm! zt call feedkeys("A\\", 'tnix') - call assert_equal([0, 30, 11, 0], getpos('.')) + call assert_equal([0, 29, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 23, 11, 0], getpos('.')) + call assert_equal([0, 21, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 15, 11, 0], getpos('.')) + call assert_equal([0, 13, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') call assert_equal([0, 10, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 10, 11, 0], getpos('.')) + call assert_equal([0, 2, 11, 0], getpos('.')) call cursor(1, 1) call feedkeys("A\\", 'tnix') call assert_equal([0, 9, 11, 0], getpos('.')) @@ -1373,15 +1373,15 @@ func Test_edit_PAGEUP_PAGEDOWN() call cursor(30, 11) norm! zt call feedkeys("A\\", 'tnix') - call assert_equal([0, 30, 11, 0], getpos('.')) + call assert_equal([0, 29, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 23, 11, 0], getpos('.')) + call assert_equal([0, 21, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 15, 11, 0], getpos('.')) + call assert_equal([0, 13, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') call assert_equal([0, 10, 11, 0], getpos('.')) call feedkeys("A\\", 'tnix') - call assert_equal([0, 10, 11, 0], getpos('.')) + call assert_equal([0, 2, 11, 0], getpos('.')) call cursor(1, 1) call feedkeys("A\\", 'tnix') call assert_equal([0, 9, 11, 0], getpos('.')) diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim index 644a632413..937f18aa69 100644 --- a/test/old/testdir/test_normal.vim +++ b/test/old/testdir/test_normal.vim @@ -1283,9 +1283,13 @@ func Test_vert_scroll_cmds() exe "normal \" call assert_equal(46, line('.')) exe "normal \" - call assert_equal(36, line('.')) + call assert_equal(36, line('w0')) + call assert_equal(46, line('.')) exe "normal \" - call assert_equal(10, line('.')) + call assert_equal(1, line('w0')) + call assert_equal(40, line('.')) + exe "normal \" + call assert_equal(30, line('.')) exe "normal \" call assert_equal(1, line('.')) set scroll& @@ -1306,9 +1310,8 @@ func Test_vert_scroll_cmds() call assert_equal(50, line('.')) call assert_equal(100, line('w$')) normal z. - let lnum = winline() exe "normal \" - call assert_equal(lnum, winline()) + call assert_equal(1, winline()) call assert_equal(50, line('.')) normal zt exe "normal \" @@ -3077,7 +3080,8 @@ func Test_normal42_halfpage() call assert_equal(2, &scroll) set scroll=5 exe "norm! \" - call assert_equal('3', getline('.')) + call assert_equal('3', getline('w0')) + call assert_equal('8', getline('.')) 1 set scrolloff=5 exe "norm! \" @@ -3823,11 +3827,11 @@ func Test_normal_vert_scroll_longline() call assert_equal(11, line('.')) call assert_equal(1, winline()) exe "normal \" - call assert_equal(11, line('.')) - call assert_equal(9, winline()) + call assert_equal(10, line('.')) + call assert_equal(10, winline()) exe "normal \\" call assert_equal(5, line('.')) - call assert_equal(1, winline()) + call assert_equal(5, winline()) bwipe! endfunc @@ -4196,12 +4200,16 @@ func Test_single_line_scroll() norm! { call assert_equal([0, 1, 1, 0], getpos('.')) - " Ctrl-B scrolls up with hidden "above" virtual text. + " Ctrl-B/Ctrl-U scroll up with hidden "above" virtual text. set smoothscroll exe "normal \" call assert_notequal(0, winsaveview().skipcol) exe "normal \" call assert_equal(0, winsaveview().skipcol) + exe "normal \" + call assert_notequal(0, winsaveview().skipcol) + exe "normal \" + call assert_equal(0, winsaveview().skipcol) set smoothscroll& bw! diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim index ebfed77214..fbc714d9cc 100644 --- a/test/old/testdir/test_scroll_opt.vim +++ b/test/old/testdir/test_scroll_opt.vim @@ -1008,18 +1008,39 @@ func Test_smoothscroll_page() call setline(1, 'abcde '->repeat(150)) exe "norm! \" - call assert_equal(320, winsaveview().skipcol) + call assert_equal(400, winsaveview().skipcol) exe "norm! \" - call assert_equal(640, winsaveview().skipcol) + call assert_equal(800, winsaveview().skipcol) exe "norm! \" call assert_equal(880, winsaveview().skipcol) exe "norm! \" - call assert_equal(560, winsaveview().skipcol) + call assert_equal(480, winsaveview().skipcol) exe "norm! \" - call assert_equal(240, winsaveview().skipcol) + call assert_equal(80, winsaveview().skipcol) exe "norm! \" call assert_equal(0, winsaveview().skipcol) + exe "norm! \" + call assert_equal(200, winsaveview().skipcol) + exe "norm! \" + call assert_equal(400, winsaveview().skipcol) + exe "norm! \" + call assert_equal(600, winsaveview().skipcol) + exe "norm! \" + call assert_equal(800, winsaveview().skipcol) + exe "norm! \" + call assert_equal(880, winsaveview().skipcol) + exe "norm! \" + call assert_equal(680, winsaveview().skipcol) + exe "norm! \" + call assert_equal(480, winsaveview().skipcol) + exe "norm! \" + call assert_equal(280, winsaveview().skipcol) + exe "norm! \" + call assert_equal(80, winsaveview().skipcol) + exe "norm! \" + call assert_equal(0, winsaveview().skipcol) + set smoothscroll& endfunc