mirror of
https://github.com/vim/vim.git
synced 2025-09-27 04:14:06 -04:00
patch 9.0.1121: cursor positioning and display problems with 'smoothscroll'
Problem: Cursor positioning and display problems with 'smoothscroll' and using "zt", "zb" or "zz". Solution: Adjust computations and conditions. (Yee Cheng Chin, closes #11764)
This commit is contained in:
@@ -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)
|
||||
|
155
src/move.c
155
src/move.c
@@ -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
|
||||
{
|
||||
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)
|
||||
|
@@ -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|
|
||||
|
@@ -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|
|
||||
|
@@ -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|
|
||||
|
6
src/testdir/dumps/Test_smooth_long_13.dump
Normal file
6
src/testdir/dumps/Test_smooth_long_13.dump
Normal file
@@ -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|
|
6
src/testdir/dumps/Test_smooth_long_14.dump
Normal file
6
src/testdir/dumps/Test_smooth_long_14.dump
Normal file
@@ -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|
|
6
src/testdir/dumps/Test_smooth_long_15.dump
Normal file
6
src/testdir/dumps/Test_smooth_long_15.dump
Normal file
@@ -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|
|
@@ -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|%|
|
||||
|
@@ -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|%|
|
||||
|
@@ -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
|
||||
|
@@ -695,6 +695,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1121,
|
||||
/**/
|
||||
1120,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user