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(); maketitle();
// when autocmds didn't change it // when autocmds didn't change it
if (curwin->w_topline == 1 && !curwin->w_topline_was_set) { 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. // 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 // cursor in the middle of the window. Otherwise put the cursor
// near the top of the window. // near the top of the window.
if (n >= halfheight) { if (n >= halfheight) {
scroll_cursor_halfway(false); scroll_cursor_halfway(false, false);
} else { } else {
scroll_cursor_top(scrolljump_value(), false); scroll_cursor_top(scrolljump_value(), false);
check_botline = true; check_botline = true;
@@ -314,7 +314,7 @@ void update_topline(win_T *wp)
if (line_count <= wp->w_height_inner + 1) { if (line_count <= wp->w_height_inner + 1) {
scroll_cursor_bot(scrolljump_value(), false); scroll_cursor_bot(scrolljump_value(), false);
} else { } 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" // This makes sure we get the same position when using "k" and "j"
// in a small window. // in a small window.
if (used > curwin->w_height_inner) { if (used > curwin->w_height_inner) {
scroll_cursor_halfway(false); scroll_cursor_halfway(false, false);
} else { } else {
// If "always" is false, only adjust topline to a lower value, higher // If "always" is false, only adjust topline to a lower value, higher
// value may happen with wrapping lines // 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. // Scroll up if the cursor is off the bottom of the screen a bit.
// Otherwise put it at 1/2 of the screen. // Otherwise put it at 1/2 of the screen.
if (line_count >= curwin->w_height_inner && line_count > min_scroll) { if (line_count >= curwin->w_height_inner && line_count > min_scroll) {
scroll_cursor_halfway(false); scroll_cursor_halfway(false, true);
} else { } else {
scrollup(line_count, true); 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. /// @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 above = 0;
int topfill = 0; int topfill = 0;
@@ -1705,12 +1705,24 @@ void scroll_cursor_halfway(int atend)
loff.fill = 0; loff.fill = 0;
boff.fill = 0; boff.fill = 0;
linenr_T topline = loff.lnum; linenr_T topline = loff.lnum;
while (topline > 1) { while (topline > 1) {
if (below <= above) { // add a line below the cursor first // 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) { if (boff.lnum < curbuf->b_ml.ml_line_count) {
botline_forw(curwin, &boff); botline_forw(curwin, &boff);
used += boff.height; used += boff.height;
if (used > curwin->w_height_inner) { if (used > curwin->w_height_inner) {
done = true;
break; break;
} }
below += boff.height; below += boff.height;
@@ -1722,7 +1734,10 @@ void scroll_cursor_halfway(int atend)
} }
} }
if (below > above) { // add a line above the cursor if (prefer_above
? (round == 1 && below >= above)
: (round == 1 && below > above)) {
// add a line above the cursor
topline_back(curwin, &loff); topline_back(curwin, &loff);
if (loff.height == MAXCOL) { if (loff.height == MAXCOL) {
used = MAXCOL; used = MAXCOL;
@@ -1730,6 +1745,7 @@ void scroll_cursor_halfway(int atend)
used += loff.height; used += loff.height;
} }
if (used > curwin->w_height_inner) { if (used > curwin->w_height_inner) {
done = true;
break; break;
} }
above += loff.height; above += loff.height;
@@ -1737,6 +1753,11 @@ void scroll_cursor_halfway(int atend)
topfill = loff.fill; topfill = loff.fill;
} }
} }
if (done) {
break;
}
}
if (!hasFolding(topline, &curwin->w_topline, NULL)) { if (!hasFolding(topline, &curwin->w_topline, NULL)) {
curwin->w_topline = topline; curwin->w_topline = topline;
} }

View File

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

View File

@@ -1,5 +1,4 @@
" Test for reset 'scroll' " Test for reset 'scroll'
"
func Test_reset_scroll() func Test_reset_scroll()
let scr = &l:scroll let scr = &l:scroll
@@ -34,3 +33,22 @@ func Test_reset_scroll()
quit! quit!
endfunc 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', \ '7 line 02 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02',
\ '56789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02', \ '56789ABCDEFGHIJKLMNOPQRSTUVWXYZ 02',
\ 'UTSRQPONMLKJIHGREDCBA9876543210 02', \ 'UTSRQPONMLKJIHGREDCBA9876543210 02',
\ '. line 11 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 11', \ '. line 10 ZYXWVUTSRQPONMLKJIHGREDCBA9876543210 10',
\ '. line 11 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 11', \ '. line 10 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 10',
\ ''], getline(1, '$')) \ ''], getline(1, '$'))
enew! enew!

View File

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