]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1121: cursor positioning and display problems with 'smoothscroll' v9.0.1121
authorBram Moolenaar <Bram@vim.org>
Sat, 31 Dec 2022 15:13:22 +0000 (15:13 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 31 Dec 2022 15:13:22 +0000 (15:13 +0000)
Problem:    Cursor positioning and display problems with 'smoothscroll' and
            using "zt", "zb" or "zz".
Solution:   Adjust computations and conditions. (Yee Cheng Chin,
            closes #11764)

12 files changed:
src/macros.h
src/move.c
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_13.dump [new file with mode: 0644]
src/testdir/dumps/Test_smooth_long_14.dump [new file with mode: 0644]
src/testdir/dumps/Test_smooth_long_15.dump [new file with mode: 0644]
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

index 86fd60bd039f9fab567e91aa0e18bc1d47e3ad09..cb97d438331509b5c5271334a4e767a010e18d68 100644 (file)
 
 #ifdef FEAT_DIFF
 # define PLINES_NOFILL(x) plines_nofill(x)
+# define PLINES_WIN_NOFILL(w, l, h) plines_win_nofill((w), (l), (h))
 #else
 # define PLINES_NOFILL(x) plines(x)
+# define PLINES_WIN_NOFILL(w, l, h) plines_win((w), (l), (h))
 #endif
 
 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER)
index 29ba56940ba1353aaa18c5e96aec9ed1c9ddb9d5..c7fbc9defb0aa2c907ac7b34d9093ecc726d1b29 100644 (file)
@@ -221,6 +221,23 @@ smoothscroll_marker_overlap(int extra2)
     return extra2 > 3 ? 0 : 3 - extra2;
 }
 
+/*
+ * Calculates the skipcol offset for window "wp" given how many
+ * physical lines we want to scroll down.
+ */
+    static int
+skipcol_from_plines(win_T *wp, int plines_off)
+{
+    int width1 = wp->w_width - win_col_off(wp);
+
+    int skipcol = 0;
+    if (plines_off > 0)
+       skipcol += width1;
+    if (plines_off > 1)
+       skipcol += (width1 + win_col_off2(wp)) * (plines_off - 1);
+    return skipcol;
+}
+
 /*
  * Set curwin->s_skipcol to zero and redraw later if needed.
  */
@@ -2149,7 +2166,9 @@ scrollup_clamp(void)
  * Lines above the first one are incredibly high: MAXCOL.
  */
     static void
-topline_back(lineoff_T *lp)
+topline_back_winheight(
+    lineoff_T  *lp,
+    int                winheight)      // when TRUE limit to window height
 {
 #ifdef FEAT_DIFF
     if (lp->fill < diff_check_fill(curwin, lp->lnum))
@@ -2174,10 +2193,17 @@ topline_back(lineoff_T *lp)
            lp->height = 1;
        else
 #endif
-           lp->height = PLINES_NOFILL(lp->lnum);
+           lp->height = PLINES_WIN_NOFILL(curwin, lp->lnum, winheight);
     }
 }
 
+    static void
+topline_back(lineoff_T *lp)
+{
+    topline_back_winheight(lp, TRUE);
+}
+
+
 /*
  * Add one line below "lp->lnum".  This can be a filler line, a closed fold or
  * a (wrapped) text line.  Uses and sets "lp->fill".
@@ -2317,6 +2343,14 @@ scroll_cursor_top(int min_scroll, int always)
        else
 #endif
            i = PLINES_NOFILL(top);
+       if (top < curwin->w_topline)
+           scrolled += i;
+
+       // If scrolling is needed, scroll at least 'sj' lines.
+       if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
+               && extra >= off)
+           break;
+
        used += i;
        if (extra + i <= off && bot < curbuf->b_ml.ml_line_count)
        {
@@ -2330,15 +2364,6 @@ scroll_cursor_top(int min_scroll, int always)
        }
        if (used > curwin->w_height)
            break;
-       if (top < curwin->w_topline)
-           scrolled += i;
-
-       /*
-        * If scrolling is needed, scroll at least 'sj' lines.
-        */
-       if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
-               && extra >= off)
-           break;
 
        extra += i;
        new_topline = top;
@@ -2436,6 +2461,7 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
     int                i;
     linenr_T   line_count;
     linenr_T   old_topline = curwin->w_topline;
+    int                old_skipcol = curwin->w_skipcol;
     lineoff_T  loff;
     lineoff_T  boff;
 #ifdef FEAT_DIFF
@@ -2451,6 +2477,8 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
     cln = curwin->w_cursor.lnum;
     if (set_topbot)
     {
+       int set_skipcol = FALSE;
+
        used = 0;
        curwin->w_botline = cln + 1;
 #ifdef FEAT_DIFF
@@ -2461,9 +2489,32 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
                curwin->w_topline = loff.lnum)
        {
            loff.lnum = curwin->w_topline;
-           topline_back(&loff);
-           if (loff.height == MAXCOL || used + loff.height > curwin->w_height)
+           topline_back_winheight(&loff, FALSE);
+           if (loff.height == MAXCOL)
                break;
+           if (used + loff.height > curwin->w_height)
+           {
+               if (curwin->w_p_sms && curwin->w_p_wrap)
+               {
+                   // 'smoothscroll' and 'wrap' are set.  The above line is
+                   // too long to show in its entirety, so we show just a part
+                   // of it.
+                   if (used < curwin->w_height)
+                   {
+                       int plines_offset = used + loff.height
+                                                           - curwin->w_height;
+                       used = curwin->w_height;
+#ifdef FEAT_DIFF
+                       curwin->w_topfill = loff.fill;
+#endif
+                       curwin->w_topline = loff.lnum;
+                       curwin->w_skipcol = skipcol_from_plines(
+                                                       curwin, plines_offset);
+                       set_skipcol = TRUE;
+                   }
+               }
+               break;
+           }
            used += loff.height;
 #ifdef FEAT_DIFF
            curwin->w_topfill = loff.fill;
@@ -2475,8 +2526,15 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
 #ifdef FEAT_DIFF
                || curwin->w_topfill != old_topfill
 #endif
-               )
+               || set_skipcol
+               || curwin->w_skipcol != 0)
+       {
            curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
+           if (set_skipcol)
+               redraw_later(UPD_NOT_VALID);
+           else
+               reset_skipcol();
+       }
     }
     else
        validate_botline();
@@ -2680,7 +2738,9 @@ scroll_cursor_bot(int min_scroll, int set_topbot)
      * (we changed them).
      * If topline did change, update_screen() will set botline.
      */
-    if (curwin->w_topline == old_topline && set_topbot)
+    if (curwin->w_topline == old_topline
+           && curwin->w_skipcol == old_skipcol
+           && set_topbot)
     {
        curwin->w_botline = old_botline;
        curwin->w_empty_rows = old_empty_rows;
@@ -2698,6 +2758,8 @@ scroll_cursor_halfway(int atend)
 {
     int                above = 0;
     linenr_T   topline;
+    colnr_T    skipcol = 0;
+    int                set_skipcol = FALSE;
 #ifdef FEAT_DIFF
     int                topfill = 0;
 #endif
@@ -2725,8 +2787,57 @@ scroll_cursor_halfway(int atend)
     used = plines(loff.lnum);
 #endif
     topline = loff.lnum;
+
+    int half_height = 0;
+    int smooth_scroll = FALSE;
+    if (curwin->w_p_sms && curwin->w_p_wrap)
+    {
+       // 'smoothscroll' and 'wrap' are set
+       smooth_scroll = TRUE;
+       half_height = (curwin->w_height - used) / 2;
+       used = 0;
+    }
+
     while (topline > 1)
     {
+       // If using smoothscroll, we can precisely scroll to the
+       // exact point where the cursor is halfway down the screen.
+       if (smooth_scroll)
+       {
+           topline_back_winheight(&loff, FALSE);
+           if (loff.height == MAXCOL)
+               break;
+           else
+               used += loff.height;
+           if (used > half_height)
+           {
+               if (used - loff.height < half_height)
+               {
+                   int plines_offset = used - half_height;
+                   loff.height -= plines_offset;
+                   used = half_height;
+
+                   topline = loff.lnum;
+#ifdef FEAT_DIFF
+                   topfill = loff.fill;
+#endif
+                   skipcol = skipcol_from_plines(curwin, plines_offset);
+                   set_skipcol = TRUE;
+               }
+               break;
+           }
+           topline = loff.lnum;
+#ifdef FEAT_DIFF
+           topfill = loff.fill;
+#endif
+           continue;
+       }
+
+       // 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).
+
        if (below <= above)         // add a line below the cursor first
        {
            if (boff.lnum < curbuf->b_ml.ml_line_count)
@@ -2764,7 +2875,21 @@ scroll_cursor_halfway(int atend)
 #ifdef FEAT_FOLDING
     if (!hasFolding(topline, &curwin->w_topline, NULL))
 #endif
-       curwin->w_topline = topline;
+    {
+       if (curwin->w_topline != topline
+               || set_skipcol
+               || curwin->w_skipcol != 0)
+       {
+           curwin->w_topline = topline;
+           if (set_skipcol)
+           {
+               curwin->w_skipcol = skipcol;
+               redraw_later(UPD_NOT_VALID);
+           }
+           else
+               reset_skipcol();
+       }
+    }
 #ifdef FEAT_DIFF
     curwin->w_topfill = topfill;
     if (old_topline > curwin->w_topline + curwin->w_height)
index a7aee24f3839a7c08839fc123a81ded4cf579755..10634be6c93ad71349b6c254d1acbbe33ba8a723 100644 (file)
@@ -1,6 +1,6 @@
->f+0&#ffffff0|o|u|r| @35
+|<+0#4040ff13#ffffff0@2|o+0#0000000&|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
 |~+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| 
index 7f5bff746cfc0c0c36689f58879a25c8015a2acc..0aa7a4bee2004950c5a020dda6e3bd048c833564 100644 (file)
@@ -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| |e|n|d| @11
 >f|o|u|r| @35
-@22|4|,|1| @10|B|o|t| 
+|:|s|e|t| |s|c|r|o|l@1|o| @9|4|,|1| @10|B|o|t| 
index b82fca5994d9b34603ed785a2750ba63fa4525c5..10634be6c93ad71349b6c254d1acbbe33ba8a723 100644 (file)
@@ -1,6 +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
+|<+0#4040ff13#ffffff0@2|o+0#0000000&|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| 
+>f|o|u|r| @35
+|~+0#4040ff13&| @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_13.dump b/src/testdir/dumps/Test_smooth_long_13.dump
new file mode 100644 (file)
index 0000000..62d7992
--- /dev/null
@@ -0,0 +1,6 @@
+>f+0&#ffffff0|o|u|r| @35
+|~+0#4040ff13&| @38
+|~| @38
+|~| @38
+|~| @38
+| +0#0000000&@21|4|,|1| @10|B|o|t| 
diff --git a/src/testdir/dumps/Test_smooth_long_14.dump b/src/testdir/dumps/Test_smooth_long_14.dump
new file mode 100644 (file)
index 0000000..7f5bff7
--- /dev/null
@@ -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_15.dump b/src/testdir/dumps/Test_smooth_long_15.dump
new file mode 100644 (file)
index 0000000..b82fca5
--- /dev/null
@@ -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| 
index f4687be513771bebbd9cca41da38d3cde953de44..6d2f13c2a534c978935987a75780a5e9baec3f5b 100644 (file)
@@ -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|6@1|%| 
+| @21|3|,|1|3|0| @8|6@1|%| 
index f4687be513771bebbd9cca41da38d3cde953de44..6d2f13c2a534c978935987a75780a5e9baec3f5b 100644 (file)
@@ -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|6@1|%| 
+| @21|3|,|1|3|0| @8|6@1|%| 
index 58a8bf4f9ec1b002719e95c72e696d1b9e6b05b6..2fa91682d8d1dfe4ad5070968a5c515c74301c1d 100644 (file)
@@ -296,6 +296,14 @@ func Test_smoothscroll_wrap_long_line()
   call term_sendkeys(buf, "0j")
   call VerifyScreenDump(buf, 'Test_smooth_long_10', {})
 
+  " Test zt/zz/zb that they work properly when a long line is above it
+  call term_sendkeys(buf, "zb")
+  call VerifyScreenDump(buf, 'Test_smooth_long_11', {})
+  call term_sendkeys(buf, "zz")
+  call VerifyScreenDump(buf, 'Test_smooth_long_12', {})
+  call term_sendkeys(buf, "zt")
+  call VerifyScreenDump(buf, 'Test_smooth_long_13', {})
+
   " 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
@@ -303,7 +311,7 @@ func Test_smoothscroll_wrap_long_line()
   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', {})
+  call VerifyScreenDump(buf, 'Test_smooth_long_14', {})
 
   " 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
@@ -311,7 +319,7 @@ func Test_smoothscroll_wrap_long_line()
   " screen.
   call term_sendkeys(buf, "3Gzt")
   call term_sendkeys(buf, "\<C-E>j")
-  call VerifyScreenDump(buf, 'Test_smooth_long_12', {})
+  call VerifyScreenDump(buf, 'Test_smooth_long_15', {})
   
   call StopVimInTerminal(buf)
 endfunc
index 230db82be2c9af5e13e6e74959bfd5d10ac39bbb..ae993ffbbac3ea6c43fb381e993aa2b76e5d74d0 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1121,
 /**/
     1120,
 /**/