# HG changeset patch # User Bram Moolenaar # Date 1676396705 -3600 # Node ID d8fdafc4b3907c55ee950ebc5e42c8f0cc7a00ae # Parent 80d41e6f9f2a458c7b254e1e2c35a47d7ab666cf patch 9.0.1309: scrolling two lines with even line count and 'scrolloff' set Commit: https://github.com/vim/vim/commit/1d6539cf36a7b6d1afe76fb6316fe662f543bf60 Author: Bram Moolenaar Date: Tue Feb 14 17:41:20 2023 +0000 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 https://github.com/vim/vim/issues/10545) diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -1953,7 +1953,7 @@ 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 #ifdef FEAT_NETBEANS_INTG // Send fileOpened event because we've changed buffers. diff --git a/src/move.c b/src/move.c --- a/src/move.c +++ b/src/move.c @@ -396,7 +396,7 @@ update_topline(void) // 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); @@ -499,7 +499,7 @@ update_topline(void) if (line_count <= curwin->w_height + 1) scroll_cursor_bot(scrolljump_value(), FALSE); else - scroll_cursor_halfway(FALSE); + scroll_cursor_halfway(FALSE, FALSE); } } } @@ -2383,7 +2383,7 @@ scroll_cursor_top(int min_scroll, int al * in a small window. */ if (used > curwin->w_height) - scroll_cursor_halfway(FALSE); + scroll_cursor_halfway(FALSE, FALSE); else { /* @@ -2720,7 +2720,7 @@ scroll_cursor_bot(int min_scroll, int se * Otherwise put it at 1/2 of the screen. */ if (line_count >= curwin->w_height && line_count > min_scroll) - scroll_cursor_halfway(FALSE); + scroll_cursor_halfway(FALSE, TRUE); else { // With 'smoothscroll' scroll at least the height of the cursor line, @@ -2760,7 +2760,7 @@ scroll_cursor_bot(int min_scroll, int se * If "atend" is TRUE, also put it halfway at the end of the file. */ void -scroll_cursor_halfway(int atend) +scroll_cursor_halfway(int atend, int prefer_above) { int above = 0; linenr_T topline; @@ -2841,43 +2841,62 @@ scroll_cursor_halfway(int atend) // If not using smoothscroll, we have to iteratively find how many // lines to scroll down to roughly fit the cursor. - // This may not be right in the middle if the lines' physical height > - // 1 (e.g. 'wrap' is on). + // This may not be right in the middle if the lines' + // physical height > 1 (e.g. 'wrap' is on). - if (below <= above) // add a line below the cursor first + // Depending on "prefer_above" we add a line above or below first. + // Loop twice to avoid duplicating code. + int done = FALSE; + for (int round = 1; round <= 2; ++round) { - if (boff.lnum < curbuf->b_ml.ml_line_count) + if (prefer_above ? (round == 2 && below < above) + : (round == 1 && below <= above)) { - botline_forw(&boff); - used += boff.height; - if (used > curwin->w_height) - break; - below += boff.height; + // add a line below the cursor + if (boff.lnum < curbuf->b_ml.ml_line_count) + { + botline_forw(&boff); + used += boff.height; + if (used > curwin->w_height) + { + done = TRUE; + break; + } + below += boff.height; + } + else + { + ++below; // count a "~" line + if (atend) + ++used; + } } - else + + if (prefer_above ? (round == 1 && below >= above) + : (round == 1 && below > above)) { - ++below; // count a "~" line - if (atend) - ++used; + // add a line above the cursor + topline_back(&loff); + if (loff.height == MAXCOL) + used = MAXCOL; + else + used += loff.height; + if (used > curwin->w_height) + { + done = TRUE; + break; + } + above += loff.height; + topline = loff.lnum; +#ifdef FEAT_DIFF + topfill = loff.fill; +#endif } } + if (done) + break; + } - if (below > above) // add a line above the cursor - { - topline_back(&loff); - if (loff.height == MAXCOL) - used = MAXCOL; - else - used += loff.height; - if (used > curwin->w_height) - break; - above += loff.height; - topline = loff.lnum; -#ifdef FEAT_DIFF - topfill = loff.fill; -#endif - } - } #ifdef FEAT_FOLDING if (!hasFolding(topline, &curwin->w_topline, NULL)) #endif diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -2712,7 +2712,7 @@ nv_zet(cmdarg_T *cap) case '.': beginline(BL_WHITE | BL_FIX); // FALLTHROUGH - case 'z': scroll_cursor_halfway(TRUE); + case 'z': scroll_cursor_halfway(TRUE, FALSE); redraw_later(UPD_VALID); set_fraction(curwin); break; diff --git a/src/proto/move.pro b/src/proto/move.pro --- a/src/proto/move.pro +++ b/src/proto/move.pro @@ -43,7 +43,7 @@ void scrollup_clamp(void); void scroll_cursor_top(int min_scroll, int always); void set_empty_rows(win_T *wp, int used); void scroll_cursor_bot(int min_scroll, int set_topbot); -void scroll_cursor_halfway(int atend); +void scroll_cursor_halfway(int atend, int prefer_above); void cursor_correct(void); int onepage(int dir, long count); void halfpage(int flag, linenr_T Prenum); diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_2.dump b/src/testdir/dumps/Test_popupwin_previewpopup_2.dump --- a/src/testdir/dumps/Test_popupwin_previewpopup_2.dump +++ b/src/testdir/dumps/Test_popupwin_previewpopup_2.dump @@ -2,10 +2,10 @@ |#|i|n|c|l|u|d|e| |"|X|h|e|a|d|e|r|.|h|"| @54 |t|h|r|e@1| @69 |f|o|u|r| @3|╔+0&#afffff255| |X|t|a|g|f|i|l|e| |═@30|X| +0&#ffffff0@23 -|f|i|v|e| @3|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 -|s|i|x| @4|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 -|s|e|v|e|n| @2|║+0&#afffff255|2|9| @37| +0|║+0&#afffff255| +0&#ffffff0@23 -|f|i|n|d| |t|h|e|║+0&#afffff255|3|0| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 +|f|i|v|e| @3|║+0&#afffff255|2|6| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 +|s|i|x| @4|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 +|s|e|v|e|n| @2|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0|║+0&#afffff255| +0&#ffffff0@23 +|f|i|n|d| |t|h|e|║+0&#afffff255|2|9| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@23 |n|i|n|e| @3|╚+0&#afffff255|═@40|⇲| +0&#ffffff0@23 |t|h|i|s| |i|s| >a|n|o|t|h|e|r| |w|o|r|d| @54 |v|e|r|y| |l|o|n|g| |l|i|n|e| |w|h|e|r|e| |t|h|e| |w|o|r|d| |i|s| |a|l|s|o| |a|n|o|t|h|e|r| @29 diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_3.dump b/src/testdir/dumps/Test_popupwin_previewpopup_3.dump --- a/src/testdir/dumps/Test_popupwin_previewpopup_3.dump +++ b/src/testdir/dumps/Test_popupwin_previewpopup_3.dump @@ -2,10 +2,10 @@ |#|i|n|c|l|u|d|e| |"|X|h|e|a|d|e|r|.|h|"| @54 |t|h|r|e@1| @69 |f|o|u|r| @9|╔+0&#afffff255| |X|t|a|g|f|i|l|e| |═@30|X| +0&#ffffff0@17 -|f|i|v|e| @9|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 -|s|i|x| @10|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 -|s|e|v|e|n| @8|║+0&#afffff255|2|9| @37| +0|║+0&#afffff255| +0&#ffffff0@17 -|f|i|n|d| |t|h|e|w|o|r|d| |s|║+0&#afffff255|3|0| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 +|f|i|v|e| @9|║+0&#afffff255|2|6| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 +|s|i|x| @10|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 +|s|e|v|e|n| @8|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0|║+0&#afffff255| +0&#ffffff0@17 +|f|i|n|d| |t|h|e|w|o|r|d| |s|║+0&#afffff255|2|9| @37| +0&#a8a8a8255|║+0&#afffff255| +0&#ffffff0@17 |n|i|n|e| @9|╚+0&#afffff255|═@40|⇲| +0&#ffffff0@17 |t|h|i|s| |i|s| >a|n|o|t|h|e|r| |w|o|r|d| @54 |v|e|r|y| |l|o|n|g| |l|i|n|e| |w|h|e|r|e| |t|h|e| |w|o|r|d| |i|s| |a|l|s|o| |a|n|o|t|h|e|r| @29 diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_4.dump b/src/testdir/dumps/Test_popupwin_previewpopup_4.dump --- a/src/testdir/dumps/Test_popupwin_previewpopup_4.dump +++ b/src/testdir/dumps/Test_popupwin_previewpopup_4.dump @@ -3,10 +3,10 @@ |t|h|r|e@1| @69 |f|o|u|r| @70 |f|i|v|e| @27|╔+0&#afffff255| |X|t|a|g|f|i|l|e| |═@30|X -|s+0&#ffffff0|i|x| @28|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255 -|s+0&#ffffff0|e|v|e|n| @26|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0&#a8a8a8255|║+0&#afffff255 -|f+0&#ffffff0|i|n|d| |t|h|e|w|o|r|d| |s|o|m|e|w|h|e|r|e| @9|║+0&#afffff255|2|9| @37| +0|║+0&#afffff255 -|n+0&#ffffff0|i|n|e| @27|║+0&#afffff255|3|0| @37| +0&#a8a8a8255|║+0&#afffff255 +|s+0&#ffffff0|i|x| @28|║+0&#afffff255|2|6| @37| +0&#a8a8a8255|║+0&#afffff255 +|s+0&#ffffff0|e|v|e|n| @26|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255 +|f+0&#ffffff0|i|n|d| |t|h|e|w|o|r|d| |s|o|m|e|w|h|e|r|e| @9|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0|║+0&#afffff255 +|n+0&#ffffff0|i|n|e| @27|║+0&#afffff255|2|9| @37| +0&#a8a8a8255|║+0&#afffff255 |t+0&#ffffff0|h|i|s| |i|s| |a|n|o|t|h|e|r| |w|o|r|d| @11|╚+0&#afffff255|═@40|⇲ |v+0&#ffffff0|e|r|y| |l|o|n|g| |l|i|n|e| |w|h|e|r|e| |t|h|e| |w|o|r|d| |i|s| |a|l|s|o| >a|n|o|t|h|e|r| @29 |~+0#4040ff13&| @73 diff --git a/src/testdir/dumps/Test_popupwin_previewpopup_5.dump b/src/testdir/dumps/Test_popupwin_previewpopup_5.dump --- a/src/testdir/dumps/Test_popupwin_previewpopup_5.dump +++ b/src/testdir/dumps/Test_popupwin_previewpopup_5.dump @@ -3,10 +3,10 @@ |t|h|r|e@1| @69 |f|o|u|r| @70 |f|i|v|e| @27|╔+0&#afffff255| |t|e|s|t|d|i|r|/|X|t|a|g|f|i|l|e| |═@22|X -|s+0&#ffffff0|i|x| @28|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255 -|s+0&#ffffff0|e|v|e|n| @26|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0&#a8a8a8255|║+0&#afffff255 -|f+0&#ffffff0|i|n|d| |t|h|e|w|o|r|d| |s|o|m|e|w|h|e|r|e| @9|║+0&#afffff255|2|9| @37| +0|║+0&#afffff255 -|n+0&#ffffff0|i|n|e| @27|║+0&#afffff255|3|0| @37| +0&#a8a8a8255|║+0&#afffff255 +|s+0&#ffffff0|i|x| @28|║+0&#afffff255|2|6| @37| +0&#a8a8a8255|║+0&#afffff255 +|s+0&#ffffff0|e|v|e|n| @26|║+0&#afffff255|2|7| @37| +0&#a8a8a8255|║+0&#afffff255 +|f+0&#ffffff0|i|n|d| |t|h|e|w|o|r|d| |s|o|m|e|w|h|e|r|e| @9|║+0&#afffff255|t|h|i|s| |i|s| |a|n|o|t|h|e|r| |p|l|a|c|e| @18| +0|║+0&#afffff255 +|n+0&#ffffff0|i|n|e| @27|║+0&#afffff255|2|9| @37| +0&#a8a8a8255|║+0&#afffff255 |t+0&#ffffff0|h|i|s| |i|s| |a|n|o|t|h|e|r| |w|o|r|d| @11|╚+0&#afffff255|═@40|⇲ |v+0&#ffffff0|e|r|y| |l|o|n|g| |l|i|n|e| |w|h|e|r|e| |t|h|e| |w|o|r|d| |i|s| |a|l|s|o| >a|n|o|t|h|e|r| @29 |~+0#4040ff13&| @73 diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim --- a/src/testdir/test_scroll_opt.vim +++ b/src/testdir/test_scroll_opt.vim @@ -38,6 +38,23 @@ 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 + func Test_CtrlE_CtrlY_stop_at_end() enew call setline(1, ['one', 'two']) diff --git a/src/testdir/test_scrollbind.vim b/src/testdir/test_scrollbind.vim --- a/src/testdir/test_scrollbind.vim +++ b/src/testdir/test_scrollbind.vim @@ -218,8 +218,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! diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1309, +/**/ 1308, /**/ 1307,