changeset 31148:69cea3380d9a v9.0.0908

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 <ychin.git@gmail.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 19 Nov 2022 13:30:05 +0100
parents 92da50753ca6
children b2cd9ed7d829
files src/move.c src/testdir/dumps/Test_smooth_long_1.dump src/testdir/dumps/Test_smooth_long_10.dump src/testdir/dumps/Test_smooth_long_11.dump src/testdir/dumps/Test_smooth_long_12.dump src/testdir/dumps/Test_smooth_long_2.dump src/testdir/dumps/Test_smooth_long_3.dump src/testdir/dumps/Test_smooth_long_4.dump src/testdir/dumps/Test_smooth_long_5.dump src/testdir/dumps/Test_smooth_long_6.dump src/testdir/dumps/Test_smooth_long_7.dump src/testdir/dumps/Test_smooth_long_8.dump src/testdir/dumps/Test_smooth_long_9.dump src/testdir/test_scroll_opt.vim src/version.c
diffstat 15 files changed, 92 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- 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);
+	    }
+	}
     }
 
     /*
--- 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|%| 
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| 
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| 
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| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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|%| 
--- 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, "\<C-Y>")
   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\<CR>")
+  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'])\<CR>")
+  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, "\<C-E>j")
+  call VerifyScreenDump(buf, 'Test_smooth_long_12', {})
   
   call StopVimInTerminal(buf)
 endfunc
--- 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,