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.

b9f5b95b7b
This commit is contained in:
Luuk van Baal 2024-03-26 19:06:39 +01:00
parent 19b443251f
commit 4147302f4b
9 changed files with 123 additions and 325 deletions

View File

@ -5693,8 +5693,8 @@ A jump table for the options with a short description can be found at |Q_op|.
highlighted with |hl-NonText|. highlighted with |hl-NonText|.
You may also want to add "lastline" to the 'display' option to show as You may also want to add "lastline" to the 'display' option to show as
much of the last line as possible. much of the last line as possible.
NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
and scrolling with the mouse. CTRL-B, CTRL-F and scrolling with the mouse.
*'softtabstop'* *'sts'* *'softtabstop'* *'sts'*
'softtabstop' 'sts' number (default 0) 'softtabstop' 'sts' number (default 0)

View File

@ -6075,8 +6075,8 @@ vim.go.sta = vim.go.smarttab
--- highlighted with `hl-NonText`. --- highlighted with `hl-NonText`.
--- You may also want to add "lastline" to the 'display' option to show as --- You may also want to add "lastline" to the 'display' option to show as
--- much of the last line as possible. --- much of the last line as possible.
--- NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y --- NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
--- and scrolling with the mouse. --- CTRL-B, CTRL-F and scrolling with the mouse.
--- ---
--- @type boolean --- @type boolean
vim.o.smoothscroll = false vim.o.smoothscroll = false

View File

@ -36,6 +36,7 @@
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/mouse.h" #include "nvim/mouse.h"
#include "nvim/move.h" #include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h" #include "nvim/option.h"
#include "nvim/option_vars.h" #include "nvim/option_vars.h"
#include "nvim/plines.h" #include "nvim/plines.h"
@ -1552,21 +1553,6 @@ void check_topfill(win_T *wp, bool down)
win_check_anchored_floats(wp); 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 // Scroll the screen one line down, but don't do it if it would move the
// cursor off the screen. // cursor off the screen.
void scrolldown_clamp(void) 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. // Recompute topline to put the cursor at the top of the window.
// Scroll at least "min_scroll" lines. // Scroll at least "min_scroll" lines.
// If "always" is true, always set topline (for "zt"). // 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. /// @return FAIL for failure, OK otherwise.
int onepage(Direction dir, int count) int onepage(Direction dir, int count)
{ {
int retval = OK; int prev_topfill = curwin->w_topfill;
lineoff_T loff; linenr_T prev_topline = curwin->w_topline;
linenr_T old_topline = curwin->w_topline; colnr_T prev_skipcol = curwin->w_skipcol;
int so = get_scrolloff_value(curwin);
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(); beep_flush();
return FAIL; } else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol) {
}
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) {
beginline(BL_SOL | BL_FIX); beginline(BL_SOL | BL_FIX);
} }
curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
if (retval == OK && dir == FORWARD) { return nochange;
// 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
}
} }
// Scroll 'scroll' lines up or down. // Scroll 'scroll' lines up or down.

View File

@ -7663,8 +7663,8 @@ return {
highlighted with |hl-NonText|. highlighted with |hl-NonText|.
You may also want to add "lastline" to the 'display' option to show as You may also want to add "lastline" to the 'display' option to show as
much of the last line as possible. much of the last line as possible.
NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y,
and scrolling with the mouse. CTRL-B, CTRL-F and scrolling with the mouse.
]=], ]=],
full_name = 'smoothscroll', full_name = 'smoothscroll',
pv_name = 'p_sms', pv_name = 'p_sms',

View File

@ -740,7 +740,7 @@ describe('smoothscroll', function()
| |
]]) ]])
exec("call setline(92, 'a'->repeat(100))") exec("call setline(92, 'a'->repeat(100))")
feed('<C-B>G') feed('<C-L><C-B>G')
-- cursor is not placed below window -- cursor is not placed below window
screen:expect([[ screen:expect([[
{1:<<<}aaaaaaaaaaaaaaaaa | {1:<<<}aaaaaaaaaaaaaaaaa |

View File

@ -1632,34 +1632,38 @@ endfunc
func Test_diff_scroll_many_filler() func Test_diff_scroll_many_filler()
20new 20new
vnew vnew
call setline(1, ['^^^', '^^^', '$$$', '$$$']) call setline(1, range(1, 40))
diffthis diffthis
setlocal scrolloff=0 setlocal scrolloff=0
wincmd p wincmd p
call setline(1, ['^^^', '^^^'] + repeat(['###'], 41) + ['$$$', '$$$']) call setline(1, range(1, 20)->reverse() + ['###']->repeat(41) + range(21, 40)->reverse())
diffthis diffthis
setlocal scrolloff=0 setlocal scrolloff=0
wincmd p wincmd p
redraw redraw
" Note: need a redraw after each scroll, otherwise the test always passes. " Note: need a redraw after each scroll, otherwise the test always passes.
normal! G for _ in range(2)
redraw normal! G
call assert_equal(3, winsaveview().topline) redraw
call assert_equal(18, winsaveview().topfill) call assert_equal(40, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(19, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(3, winsaveview().topline) redraw
call assert_equal(19, winsaveview().topfill) call assert_equal(22, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(0, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(2, winsaveview().topline) redraw
call assert_equal(0, winsaveview().topfill) call assert_equal(4, winsaveview().topline)
exe "normal! \<C-B>" call assert_equal(0, winsaveview().topfill)
redraw exe "normal! \<C-B>"
call assert_equal(1, winsaveview().topline) redraw
call assert_equal(0, winsaveview().topfill) call assert_equal(1, winsaveview().topline)
call assert_equal(0, winsaveview().topfill)
set smoothscroll
endfor
set smoothscroll&
bwipe! bwipe!
bwipe! bwipe!
endfunc endfunc

View File

@ -1312,15 +1312,15 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("i\<PageDown>\<esc>", 'tnix') call feedkeys("i\<PageDown>\<esc>", 'tnix')
call assert_equal([0, 30, 1, 0], getpos('.')) call assert_equal([0, 30, 1, 0], getpos('.'))
call feedkeys("A\<PageUp>\<esc>", 'tnix') 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 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 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 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 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-Up> is the same as <PageUp>
" <S-Down> is the same as <PageDown> " <S-Down> is the same as <PageDown>
call cursor(1, 1) call cursor(1, 1)
@ -1335,28 +1335,28 @@ func Test_edit_PAGEUP_PAGEDOWN()
call feedkeys("i\<S-Down>\<esc>", 'tnix') call feedkeys("i\<S-Down>\<esc>", 'tnix')
call assert_equal([0, 30, 1, 0], getpos('.')) call assert_equal([0, 30, 1, 0], getpos('.'))
call feedkeys("A\<S-Up>\<esc>", 'tnix') 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 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 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 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 feedkeys("A\<S-Up>\<esc>", 'tnix')
call assert_equal([0, 5, 11, 0], getpos('.')) call assert_equal([0, 10, 11, 0], getpos('.'))
set nostartofline set nostartofline
call cursor(30, 11) call cursor(30, 11)
norm! zt norm! zt
call feedkeys("A\<PageUp>\<esc>", 'tnix') 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 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 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 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 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 cursor(1, 1)
call feedkeys("A\<PageDown>\<esc>", 'tnix') call feedkeys("A\<PageDown>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.')) call assert_equal([0, 9, 11, 0], getpos('.'))
@ -1373,15 +1373,15 @@ func Test_edit_PAGEUP_PAGEDOWN()
call cursor(30, 11) call cursor(30, 11)
norm! zt norm! zt
call feedkeys("A\<S-Up>\<esc>", 'tnix') 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 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 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 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 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 cursor(1, 1)
call feedkeys("A\<S-Down>\<esc>", 'tnix') call feedkeys("A\<S-Down>\<esc>", 'tnix')
call assert_equal([0, 9, 11, 0], getpos('.')) call assert_equal([0, 9, 11, 0], getpos('.'))

View File

@ -131,7 +131,7 @@ func Test_normal01_keymodel()
call assert_equal([0, 1, 1, 0], getpos("'<")) call assert_equal([0, 1, 1, 0], getpos("'<"))
call assert_equal([0, 3, 1, 0], getpos("'>")) call assert_equal([0, 3, 1, 0], getpos("'>"))
call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt') 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("'>")) call assert_equal([0, 3, 8, 0], getpos("'>"))
" Test for <S-C-Home> and <S-C-End> " Test for <S-C-Home> and <S-C-End>
call cursor(2, 12) call cursor(2, 12)
@ -915,12 +915,10 @@ func Test_normal14_page()
set scrolloff=0 set scrolloff=0
100 100
exe "norm! $\<c-b>" exe "norm! $\<c-b>"
call assert_equal('92', getline('.'))
call assert_equal([0, 92, 1, 0, 1], getcurpos()) call assert_equal([0, 92, 1, 0, 1], getcurpos())
100 100
set nostartofline set nostartofline
exe "norm! $\<c-b>" exe "norm! $\<c-b>"
call assert_equal('92', getline('.'))
call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos()) call assert_equal([0, 92, 2, 0, v:maxcol], getcurpos())
" cleanup " cleanup
set startofline set startofline
@ -3825,11 +3823,11 @@ func Test_normal_vert_scroll_longline()
call assert_equal(11, line('.')) call assert_equal(11, line('.'))
call assert_equal(1, winline()) call assert_equal(1, winline())
exe "normal \<C-B>" exe "normal \<C-B>"
call assert_equal(10, line('.')) call assert_equal(11, line('.'))
call assert_equal(3, winline()) call assert_equal(9, winline())
exe "normal \<C-B>\<C-B>" exe "normal \<C-B>\<C-B>"
call assert_equal(5, line('.')) call assert_equal(5, line('.'))
call assert_equal(5, winline()) call assert_equal(1, winline())
bwipe! bwipe!
endfunc endfunc
@ -4182,20 +4180,30 @@ func Test_normal34_zet_large()
norm! z9765405999999999999 norm! z9765405999999999999
endfunc endfunc
" Test for { and } paragraph movements in a single line " Test for { and } paragraph movements and Ctrl-B in buffer with a single line
func Test_brace_single_line() func Test_single_line_scroll()
let text =<< trim [DATA] CheckFeature textprop
foobar one two three
[DATA]
new 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 1
norm! 0} norm! 0}
call assert_equal([0, 1, 20, 0], getpos('.')) call assert_equal([0, 1, 20, 0], getpos('.'))
norm! { norm! {
call assert_equal([0, 1, 1, 0], getpos('.')) 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! bw!
endfunc endfunc

View File

@ -832,7 +832,7 @@ func Test_smoothscroll_eob()
call VerifyScreenDump(buf, 'Test_smooth_eob_1', {}) call VerifyScreenDump(buf, 'Test_smooth_eob_1', {})
" cursor is not placed below window " 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 VerifyScreenDump(buf, 'Test_smooth_eob_2', {})
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
@ -1001,4 +1001,26 @@ func Test_smoothscroll_textoff_small_winwidth()
set smoothscroll& number& set smoothscroll& number&
endfunc 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 " vim: shiftwidth=2 sts=2 expandtab