summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-12-31 15:13:22 +0000
committerBram Moolenaar <Bram@vim.org>2022-12-31 15:13:22 +0000
commitdb4d88c2adfe8f8122341ac9d6cae27ef78451c8 (patch)
treee98c92ce9ab5afa6e7d2a1892009a40f4484339e
parentc55e8f2c6f5cafe11494df3e2d28ff3d03b92c71 (diff)
patch 9.0.1121: cursor positioning and display problems with 'smoothscroll'v9.0.1121
Problem: Cursor positioning and display problems with 'smoothscroll' and using "zt", "zb" or "zz". Solution: Adjust computations and conditions. (Yee Cheng Chin, closes #11764)
-rw-r--r--src/macros.h2
-rw-r--r--src/move.c157
-rw-r--r--src/testdir/dumps/Test_smooth_long_10.dump6
-rw-r--r--src/testdir/dumps/Test_smooth_long_11.dump2
-rw-r--r--src/testdir/dumps/Test_smooth_long_12.dump10
-rw-r--r--src/testdir/dumps/Test_smooth_long_13.dump6
-rw-r--r--src/testdir/dumps/Test_smooth_long_14.dump6
-rw-r--r--src/testdir/dumps/Test_smooth_long_15.dump6
-rw-r--r--src/testdir/dumps/Test_smooth_long_8.dump2
-rw-r--r--src/testdir/dumps/Test_smooth_long_9.dump2
-rw-r--r--src/testdir/test_scroll_opt.vim12
-rw-r--r--src/version.c2
12 files changed, 184 insertions, 29 deletions
diff --git a/src/macros.h b/src/macros.h
index 86fd60bd03..cb97d43833 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -253,8 +253,10 @@
#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)
diff --git a/src/move.c b/src/move.c
index 29ba56940b..c7fbc9defb 100644
--- a/src/move.c
+++ b/src/move.c
@@ -222,6 +222,23 @@ smoothscroll_marker_overlap(int 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.
*/
static void
@@ -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)
diff --git a/src/testdir/dumps/Test_smooth_long_10.dump b/src/testdir/dumps/Test_smooth_long_10.dump
index a7aee24f38..10634be6c9 100644
--- a/src/testdir/dumps/Test_smooth_long_10.dump
+++ b/src/testdir/dumps/Test_smooth_long_10.dump
@@ -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|
diff --git a/src/testdir/dumps/Test_smooth_long_11.dump b/src/testdir/dumps/Test_smooth_long_11.dump
index 7f5bff746c..0aa7a4bee2 100644
--- a/src/testdir/dumps/Test_smooth_long_11.dump
+++ b/src/testdir/dumps/Test_smooth_long_11.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| |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|
diff --git a/src/testdir/dumps/Test_smooth_long_12.dump b/src/testdir/dumps/Test_smooth_long_12.dump
index b82fca5994..10634be6c9 100644
--- a/src/testdir/dumps/Test_smooth_long_12.dump
+++ b/src/testdir/dumps/Test_smooth_long_12.dump
@@ -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
index 0000000000..62d7992820
--- /dev/null
+++ b/src/testdir/dumps/Test_smooth_long_13.dump
@@ -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
index 0000000000..7f5bff746c
--- /dev/null
+++ b/src/testdir/dumps/Test_smooth_long_14.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_15.dump b/src/testdir/dumps/Test_smooth_long_15.dump
new file mode 100644
index 0000000000..b82fca5994
--- /dev/null
+++ b/src/testdir/dumps/Test_smooth_long_15.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_8.dump b/src/testdir/dumps/Test_smooth_long_8.dump
index f4687be513..6d2f13c2a5 100644
--- 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|6@1|%|
+| @21|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
index f4687be513..6d2f13c2a5 100644
--- a/src/testdir/dumps/Test_smooth_long_9.dump
+++ b/src/testdir/dumps/Test_smooth_long_9.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|6@1|%|
+| @21|3|,|1|3|0| @8|6@1|%|
diff --git a/src/testdir/test_scroll_opt.vim b/src/testdir/test_scroll_opt.vim
index 58a8bf4f9e..2fa91682d8 100644
--- a/src/testdir/test_scroll_opt.vim
+++ b/src/testdir/test_scroll_opt.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 230db82be2..ae993ffbba 100644
--- 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 */
/**/
+ 1121,
+/**/
1120,
/**/
1119,