# HG changeset patch # User Bram Moolenaar # Date 1668861005 -3600 # Node ID 69cea3380d9a0ba7f800793c9b91aac991cda000 # Parent 92da50753ca64ad25dce6469c5fccc1db9c0ce79 patch 9.0.0908: with 'smoothscroll' cursor may end up in wrong position Commit: https://github.com/vim/vim/commit/361895d2a15b4b0bbbb4c009261eab5b3d69ebf1 Author: Yee Cheng Chin Date: Sat Nov 19 12:25:16 2022 +0000 patch 9.0.0908: with 'smoothscroll' cursor may end up in wrong position Problem: With 'smoothscroll' cursor may end up in wrong position. Solution: Correct the computation of screen lines. (Yee Cheng Chin, closes #11502) diff --git a/src/move.c b/src/move.c --- a/src/move.c +++ b/src/move.c @@ -2460,18 +2460,50 @@ scroll_cursor_bot(int min_scroll, int se used = curwin->w_cline_height; #endif - // If the cursor is below botline, we will at least scroll by the height - // of the cursor line. Correct for empty lines, which are really part of - // botline. + // If the cursor is on or below botline, we will at least scroll by the + // height of the cursor line, which is "used". Correct for empty lines, + // which are really part of botline. if (cln >= curwin->w_botline) { scrolled = used; if (cln == curwin->w_botline) scrolled -= curwin->w_empty_rows; min_scrolled = scrolled; - if (cln > curwin->w_botline && curwin->w_p_sms && curwin->w_p_wrap) - for (linenr_T lnum = curwin->w_botline + 1; lnum <= cln; ++lnum) - min_scrolled += PLINES_NOFILL(lnum); + if (curwin->w_p_sms && curwin->w_p_wrap) + { + // 'smoothscroll' and 'wrap' are set + if (cln > curwin->w_botline) + // add screen lines below w_botline + for (linenr_T lnum = curwin->w_botline + 1; lnum <= cln; ++lnum) + min_scrolled += PLINES_NOFILL(lnum); + + // Calculate how many screen lines the current top line of window + // occupies. If it is occupying more than the entire window, we + // need to scroll the additional clipped lines to scroll past the + // top line before we can move on to the other lines. + int top_plines = +#ifdef FEAT_DIFF + plines_win_nofill +#else + plines_win +#endif + (curwin, curwin->w_topline, FALSE); + int skip_lines = 0; + int width1 = curwin->w_width - curwin_col_off(); + int width2 = width1 + curwin_col_off2(); + // similar formula is used in curs_columns() + if (curwin->w_skipcol > width1) + skip_lines += (curwin->w_skipcol - width1) / width2 + 1; + else if (curwin->w_skipcol > 0) + skip_lines = 1; + + top_plines -= skip_lines; + if (top_plines > curwin->w_height) + { + scrolled += (top_plines - curwin->w_height); + min_scrolled += (top_plines - curwin->w_height); + } + } } /* diff --git a/src/testdir/dumps/Test_smooth_long_1.dump b/src/testdir/dumps/Test_smooth_long_1.dump --- a/src/testdir/dumps/Test_smooth_long_1.dump +++ b/src/testdir/dumps/Test_smooth_long_1.dump @@ -3,4 +3,4 @@ |h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e -| @21|3|,|1|0| @9|B|o|t| +| @21|3|,|1|0| @9|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_10.dump b/src/testdir/dumps/Test_smooth_long_10.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_smooth_long_10.dump @@ -0,0 +1,6 @@ +>f+0&#ffffff0|o|u|r| @35 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +|~| @38 +|:+0#0000000&|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| diff --git a/src/testdir/dumps/Test_smooth_long_11.dump b/src/testdir/dumps/Test_smooth_long_11.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_smooth_long_11.dump @@ -0,0 +1,6 @@ +|<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t +|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o +|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o +|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 +>f|o|u|r| @35 +@22|4|,|1| @10|B|o|t| diff --git a/src/testdir/dumps/Test_smooth_long_12.dump b/src/testdir/dumps/Test_smooth_long_12.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_smooth_long_12.dump @@ -0,0 +1,6 @@ +|<+0#4040ff13#ffffff0@2|t+0#0000000&|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t +|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o +|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o +|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |e|n|d| @11 +|f|o|u>r| @35 +@22|4|,|4| @10|B|o|t| diff --git a/src/testdir/dumps/Test_smooth_long_2.dump b/src/testdir/dumps/Test_smooth_long_2.dump --- a/src/testdir/dumps/Test_smooth_long_2.dump +++ b/src/testdir/dumps/Test_smooth_long_2.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -| @21|3|,|5|0| @9|B|o|t| +| @21|3|,|5|0| @9|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_3.dump b/src/testdir/dumps/Test_smooth_long_3.dump --- a/src/testdir/dumps/Test_smooth_long_3.dump +++ b/src/testdir/dumps/Test_smooth_long_3.dump @@ -3,4 +3,4 @@ | |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t | |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t -| @21|3|,|2|5|0| @8|B|o|t| +| @21|3|,|2|5|0| @8|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_4.dump b/src/testdir/dumps/Test_smooth_long_4.dump --- a/src/testdir/dumps/Test_smooth_long_4.dump +++ b/src/testdir/dumps/Test_smooth_long_4.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l>o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -| @21|3|,|2|1|0| @8|B|o|t| +| @21|3|,|2|1|0| @8|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_5.dump b/src/testdir/dumps/Test_smooth_long_5.dump --- a/src/testdir/dumps/Test_smooth_long_5.dump +++ b/src/testdir/dumps/Test_smooth_long_5.dump @@ -3,4 +3,4 @@ |h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i>t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e -| @21|3|,|1|7|0| @8|B|o|t| +| @21|3|,|1|7|0| @8|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_6.dump b/src/testdir/dumps/Test_smooth_long_6.dump --- a/src/testdir/dumps/Test_smooth_long_6.dump +++ b/src/testdir/dumps/Test_smooth_long_6.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -| @21|3|,|9|0| @9|B|o|t| +| @21|3|,|9|0| @9|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_7.dump b/src/testdir/dumps/Test_smooth_long_7.dump --- a/src/testdir/dumps/Test_smooth_long_7.dump +++ b/src/testdir/dumps/Test_smooth_long_7.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i>t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -| @21|3|,|1|7|0| @8|B|o|t| +| @21|3|,|1|7|0| @8|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_8.dump b/src/testdir/dumps/Test_smooth_long_8.dump --- a/src/testdir/dumps/Test_smooth_long_8.dump +++ b/src/testdir/dumps/Test_smooth_long_8.dump @@ -3,4 +3,4 @@ |t|s| |o|f| |t|e|x>t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o |f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w -|:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|B|o|t| +|:|s|e|t| |s|c|r|o|l@1|o| @9|3|,|1|3|0| @8|6@1|%| diff --git a/src/testdir/dumps/Test_smooth_long_9.dump b/src/testdir/dumps/Test_smooth_long_9.dump --- a/src/testdir/dumps/Test_smooth_long_9.dump +++ b/src/testdir/dumps/Test_smooth_long_9.dump @@ -3,4 +3,4 @@ |f| |t|e|x|t| |w|i>t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e |x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w |i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| |l|o|t|s| |o|f| |t|e|x|t| |w|i|t|h| -@22|3|,|1|7|0| @8|B|o|t| +@22|3|,|1|7|0| @8|6@1|%| 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 @@ -246,7 +246,7 @@ func Test_smoothscroll_wrap_long_line() let lines =<< trim END vim9script - setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30))]) + setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30)) .. ' end', 'four']) set smoothscroll scrolloff=0 normal 3G10|zt END @@ -287,6 +287,30 @@ func Test_smoothscroll_wrap_long_line() call term_sendkeys(buf, "gj") call term_sendkeys(buf, "\") call VerifyScreenDump(buf, 'Test_smooth_long_9', {}) + + " 'scrolloff' set to 0, move cursor down one line. + " Cursor should move properly, and since this is a really long line, it will + " be put on top of the screen. + call term_sendkeys(buf, ":set scrolloff=0\") + call term_sendkeys(buf, "0j") + call VerifyScreenDump(buf, 'Test_smooth_long_10', {}) + + " Repeat the step and move the cursor down again. + " This time, use a shorter long line that is barely long enough to span more + " than one window. Note that the cursor is at the bottom this time because + " Vim prefers to do so if we are scrolling a few lines only. + call term_sendkeys(buf, ":call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])\") + call term_sendkeys(buf, "3Gzt") + call term_sendkeys(buf, "j") + call VerifyScreenDump(buf, 'Test_smooth_long_11', {}) + + " Repeat the step but this time start it when the line is smooth-scrolled by + " one line. This tests that the offset calculation is still correct and + " still end up scrolling down to the next line with cursor at bottom of + " screen. + call term_sendkeys(buf, "3Gzt") + call term_sendkeys(buf, "\j") + call VerifyScreenDump(buf, 'Test_smooth_long_12', {}) call StopVimInTerminal(buf) endfunc 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 */ /**/ + 908, +/**/ 907, /**/ 906,