0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -04:00

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>
This commit is contained in:
Luuk van Baal 2024-03-26 18:46:45 +01:00 committed by Christian Brabandt
parent 9ccc297237
commit b9f5b95b7b
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
8 changed files with 125 additions and 406 deletions

View File

@ -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 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|. 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

@ -41554,6 +41554,8 @@ Other improvements *new-other-9.2*
Changed *changed-9.2* Changed *changed-9.2*
------- -------
- use 'smoothscroll' logic for CTRL-F and CTRL-B for pagewise scrolling
Added *added-9.2* Added *added-9.2*
----- -----

View File

@ -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 #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. * Recompute topline to put the cursor at the top of the window.
* Scroll at least "min_scroll" lines. * Scroll at least "min_scroll" lines.
@ -3077,8 +3025,6 @@ cursor_correct(void)
curwin->w_valid |= VALID_TOPLINE; 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) * Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD)
* and update the screen. * and update the screen.
@ -3088,313 +3034,48 @@ static void get_scroll_overlap(lineoff_T *lp, int dir);
int int
onepage(int dir, long count) onepage(int dir, long count)
{ {
long n; #ifdef FEAT_DIFF
int retval = OK; int prev_topfill = curwin->w_topfill;
lineoff_T loff; #endif
linenr_T old_topline = curwin->w_topline; linenr_T prev_topline = curwin->w_topline;
long so = get_scrolloff_value(); 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) ?
beep_flush(); p_window : curwin->w_height) - 2;
return FAIL;
}
for ( ; count > 0; --count) if (curwin->w_p_sms)
{ scroll_redraw(dir == FORWARD, 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);
#endif
}
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.
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
// 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;
#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();
#endif
cursor_correct();
check_cursor_col();
if (retval == OK)
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(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
}
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;
#ifdef FEAT_DIFF
if (lp->fill > 0)
lp->height = 1;
else else
lp->height = plines_nofill(lp->lnum); {
// Scroll at least one full line without 'smoothscroll'.
#ifdef FEAT_DIFF
count -= plines_nofill(curwin->w_topline);
#else #else
lp->height = plines(lp->lnum); count -= plines(curwin->w_topline);
#endif #endif
h1 = lp->height; scroll_redraw(dir == FORWARD, 1);
if (h1 > min_height)
return; // no overlap
loff0 = *lp; // Temporarily set 'smoothscroll' so that scrolling count lines
if (dir > 0) // does not skip over parts of the buffer with wrapped lines.
botline_forw(lp); curwin->w_p_sms = TRUE;
else if (count > 0)
topline_back(lp); scroll_redraw(dir == FORWARD, count);
h2 = lp->height; curwin->w_p_sms = FALSE;
if (h2 == MAXCOL || h2 + h1 > min_height)
{
*lp = loff0; // no overlap
return;
} }
loff1 = *lp; int nochange = curwin->w_topline == prev_topline
if (dir > 0) #ifdef FEAT_DIFF
botline_forw(lp); && curwin->w_topfill == prev_topfill
else #endif
topline_back(lp); && curwin->w_skipcol == prev_skipcol;
h3 = lp->height;
if (h3 == MAXCOL || h3 + h2 > min_height)
{
*lp = loff0; // no overlap
return;
}
loff2 = *lp; if (nochange)
if (dir > 0) beep_flush();
botline_forw(lp); else if (!curwin->w_p_sms || curwin->w_skipcol == prev_skipcol)
else beginline(BL_SOL | BL_FIX);
topline_back(lp);
h4 = lp->height; return nochange;
if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
*lp = loff1; // 1 line overlap
else
*lp = loff2; // 2 lines overlap
} }
/* /*

View File

@ -1647,34 +1647,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

@ -1294,15 +1294,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)
@ -1317,28 +1317,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('.'))
@ -1355,15 +1355,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

@ -130,7 +130,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)
@ -912,12 +912,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
@ -3815,11 +3813,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
@ -4172,20 +4170,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

@ -829,7 +829,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)
@ -998,4 +998,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

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
211,
/**/ /**/
210, 210,
/**/ /**/