vim-patch:9.0.1309: scrolling two lines with even line count and 'scrolloff' set

Problem:    Scrolling two lines with even line count and 'scrolloff' set.
Solution:   Adjust how the topline is computed. (closes vim/vim#10545)

1d6539cf36

Cherry-pick test_scroll_opt.vim changes from patch 8.2.1432.

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-02-16 07:25:16 +08:00
parent f1c5887377
commit 968cd1ed93
6 changed files with 74 additions and 35 deletions

View File

@ -1676,7 +1676,7 @@ void enter_buffer(buf_T *buf)
maketitle();
// when autocmds didn't change it
if (curwin->w_topline == 1 && !curwin->w_topline_was_set) {
scroll_cursor_halfway(false); // redisplay at correct position
scroll_cursor_halfway(false, false); // redisplay at correct position
}
// Change directories when the 'acd' option is set.

View File

@ -235,7 +235,7 @@ void update_topline(win_T *wp)
// cursor in the middle of the window. Otherwise put the cursor
// near the top of the window.
if (n >= halfheight) {
scroll_cursor_halfway(false);
scroll_cursor_halfway(false, false);
} else {
scroll_cursor_top(scrolljump_value(), false);
check_botline = true;
@ -314,7 +314,7 @@ void update_topline(win_T *wp)
if (line_count <= wp->w_height_inner + 1) {
scroll_cursor_bot(scrolljump_value(), false);
} else {
scroll_cursor_halfway(false);
scroll_cursor_halfway(false, false);
}
}
}
@ -1464,7 +1464,7 @@ void scroll_cursor_top(int min_scroll, int always)
// This makes sure we get the same position when using "k" and "j"
// in a small window.
if (used > curwin->w_height_inner) {
scroll_cursor_halfway(false);
scroll_cursor_halfway(false, false);
} else {
// If "always" is false, only adjust topline to a lower value, higher
// value may happen with wrapping lines
@ -1669,7 +1669,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
// Scroll up if the cursor is off the bottom of the screen a bit.
// Otherwise put it at 1/2 of the screen.
if (line_count >= curwin->w_height_inner && line_count > min_scroll) {
scroll_cursor_halfway(false);
scroll_cursor_halfway(false, true);
} else {
scrollup(line_count, true);
}
@ -1690,7 +1690,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
///
/// @param atend if true, also put the cursor halfway to the end of the file.
///
void scroll_cursor_halfway(int atend)
void scroll_cursor_halfway(bool atend, bool prefer_above)
{
int above = 0;
int topfill = 0;
@ -1705,38 +1705,59 @@ void scroll_cursor_halfway(int atend)
loff.fill = 0;
boff.fill = 0;
linenr_T topline = loff.lnum;
while (topline > 1) {
if (below <= above) { // add a line below the cursor first
if (boff.lnum < curbuf->b_ml.ml_line_count) {
botline_forw(curwin, &boff);
used += boff.height;
// This may not be right in the middle if the lines'
// physical height > 1 (e.g. 'wrap' is on).
// Depending on "prefer_above" we add a line above or below first.
// Loop twice to avoid duplicating code.
bool done = false;
for (int round = 1; round <= 2; round++) {
if (prefer_above
? (round == 2 && below < above)
: (round == 1 && below <= above)) {
// add a line below the cursor
if (boff.lnum < curbuf->b_ml.ml_line_count) {
botline_forw(curwin, &boff);
used += boff.height;
if (used > curwin->w_height_inner) {
done = true;
break;
}
below += boff.height;
} else {
below++; // count a "~" line
if (atend) {
used++;
}
}
}
if (prefer_above
? (round == 1 && below >= above)
: (round == 1 && below > above)) {
// add a line above the cursor
topline_back(curwin, &loff);
if (loff.height == MAXCOL) {
used = MAXCOL;
} else {
used += loff.height;
}
if (used > curwin->w_height_inner) {
done = true;
break;
}
below += boff.height;
} else {
below++; // count a "~" line
if (atend) {
used++;
}
above += loff.height;
topline = loff.lnum;
topfill = loff.fill;
}
}
if (below > above) { // add a line above the cursor
topline_back(curwin, &loff);
if (loff.height == MAXCOL) {
used = MAXCOL;
} else {
used += loff.height;
}
if (used > curwin->w_height_inner) {
break;
}
above += loff.height;
topline = loff.lnum;
topfill = loff.fill;
if (done) {
break;
}
}
if (!hasFolding(topline, &curwin->w_topline, NULL)) {
curwin->w_topline = topline;
}

View File

@ -2856,7 +2856,7 @@ static void nv_zet(cmdarg_T *cap)
FALLTHROUGH;
case 'z':
scroll_cursor_halfway(true);
scroll_cursor_halfway(true, false);
redraw_later(curwin, UPD_VALID);
set_fraction(curwin);
break;

View File

@ -1,5 +1,4 @@
" Test for reset 'scroll'
"
func Test_reset_scroll()
let scr = &l:scroll
@ -34,3 +33,22 @@ func Test_reset_scroll()
quit!
endfunc
func Test_scolloff_even_line_count()
new
resize 6
setlocal scrolloff=3
call setline(1, range(20))
normal 2j
call assert_equal(1, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(1, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(2, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(3, getwininfo(win_getid())[0].topline)
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -217,8 +217,8 @@ end of window 2
\ '7 line 02 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02',
\ '56789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02',
\ 'UTSRQPONMLKJIHGREDCBA9876543210 02',
\ '. line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11',
\ '. line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11',
\ '. line 10 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 10',
\ '. line 10 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 10',
\ ''], getline(1, '$'))
enew!

View File

@ -290,8 +290,8 @@ describe('search cmdline', function()
-- First match
feed('/thei')
screen:expect([[
3 the |
4 {inc:thei}r |
5 there |
/thei^ |
]])
-- Match from initial cursor position when modifying search