aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-05-12 07:24:13 +0800
committerGitHub <noreply@github.com>2023-05-12 07:24:13 +0800
commitd6e898b44fbd6b18b3ca23f780ffaedc343961f1 (patch)
treec72abf5286e3c89e6889c89cf3500e9008bda678
parent30a0299bc6d1ceedd04d897cf56b298dd3ded0cd (diff)
parent6f41eaa2b5abd5c252428ba278a9fcc356e48c1d (diff)
downloadrneovim-d6e898b44fbd6b18b3ca23f780ffaedc343961f1.tar.gz
rneovim-d6e898b44fbd6b18b3ca23f780ffaedc343961f1.tar.bz2
rneovim-d6e898b44fbd6b18b3ca23f780ffaedc343961f1.zip
Merge pull request #23558 from luukvbaal/smoothscroll
vim-patch:9.0.{1530,1533,1542,1543}
-rw-r--r--src/nvim/change.c15
-rw-r--r--src/nvim/move.c56
-rw-r--r--test/functional/legacy/display_spec.lua73
-rw-r--r--test/functional/legacy/normal_spec.lua41
-rw-r--r--test/functional/legacy/scroll_opt_spec.lua32
-rw-r--r--test/old/testdir/test_display.vim36
-rw-r--r--test/old/testdir/test_normal.vim18
-rw-r--r--test/old/testdir/test_scroll_opt.vim11
8 files changed, 207 insertions, 75 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 1d6869990e..a9e7126afc 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -247,11 +247,24 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
wp->w_redr_type = UPD_VALID;
}
+ linenr_T last = lnume + xtra - 1; // last line after the change
+
+ // Reset "w_skipcol" if the topline length has become smaller to
+ // such a degree that nothing will be visible anymore, accounting
+ // for 'smoothscroll' <<< or 'listchars' "precedes" marker.
+ if (wp->w_skipcol > 0
+ && (last < wp->w_topline
+ || (wp->w_topline >= lnum
+ && wp->w_topline < lnume
+ && win_linetabsize(wp, wp->w_topline, ml_get(wp->w_topline), (colnr_T)MAXCOL)
+ <= (unsigned)wp->w_skipcol + (wp->w_p_list && wp->w_p_lcs_chars.prec ? 1 : 3)))) {
+ wp->w_skipcol = 0;
+ }
+
// Check if a change in the buffer has invalidated the cached
// values for the cursor.
// Update the folds for this window. Can't postpone this, because
// a following operator might work on the whole fold: ">>dd".
- linenr_T last = lnume + xtra - 1; // last line after the change
foldUpdate(wp, lnum, last);
// The change may cause lines above or below the change to become
diff --git a/src/nvim/move.c b/src/nvim/move.c
index cff3e264f8..ada6d004e8 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1318,14 +1318,6 @@ bool scrolldown(long line_count, int byfold)
return moved;
}
-/// Return TRUE if scrollup() will scroll by screen line rather than text line.
-static int scrolling_screenlines(bool byfold)
-{
- return (curwin->w_p_wrap && curwin->w_p_sms)
- || (byfold && hasAnyFolding(curwin))
- || (curwin->w_p_diff && !curwin->w_p_wrap);
-}
-
/// Scroll the current window up by "line_count" logical lines. "CTRL-E"
///
/// @param line_count number of lines to scroll
@@ -1336,7 +1328,7 @@ bool scrollup(long line_count, int byfold)
linenr_T botline = curwin->w_botline;
int do_sms = curwin->w_p_wrap && curwin->w_p_sms;
- if (scrolling_screenlines(byfold) || win_may_fill(curwin)) {
+ if (do_sms || (byfold && hasAnyFolding(curwin)) || win_may_fill(curwin)) {
int width1 = curwin->w_width_inner - curwin_col_off();
int width2 = width1 + curwin_col_off2();
unsigned size = 0;
@@ -1873,6 +1865,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
int old_valid = curwin->w_valid;
int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
+ int do_sms = curwin->w_p_wrap && curwin->w_p_sms;
if (set_topbot) {
bool set_skipcol = false;
@@ -1889,7 +1882,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
break;
}
if (used + loff.height > curwin->w_height_inner) {
- if (curwin->w_p_sms && curwin->w_p_wrap) {
+ if (do_sms) {
// 'smoothscroll' and 'wrap' are set. The above line is
// too long to show in its entirety, so we show just a part
// of it.
@@ -1928,7 +1921,6 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
used = plines_win_nofill(curwin, cln, true);
int scrolled = 0;
- int min_scrolled = 1;
// 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.
@@ -1937,16 +1929,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
if (cln == curwin->w_botline) {
scrolled -= curwin->w_empty_rows;
}
- min_scrolled = scrolled;
- 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_win_nofill(curwin, lnum, true);
- }
- }
-
+ if (do_sms) {
+ // 'smoothscroll' and 'wrap' are set.
// 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
@@ -1965,7 +1949,6 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
top_plines -= skip_lines;
if (top_plines > curwin->w_height_inner) {
scrolled += (top_plines - curwin->w_height_inner);
- min_scrolled += (top_plines - curwin->w_height_inner);
}
}
}
@@ -2070,21 +2053,11 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
// Otherwise put it at 1/2 of the screen.
if (line_count >= curwin->w_height_inner && line_count > min_scroll) {
scroll_cursor_halfway(false, true);
- } else {
- // With 'smoothscroll' scroll at least the height of the cursor line,
- // unless it would move the cursor.
- if (curwin->w_p_wrap && curwin->w_p_sms && line_count < min_scrolled
- && (curwin->w_cursor.lnum < curwin->w_topline
- || (curwin->w_virtcol - curwin->w_skipcol >=
- curwin->w_width_inner - curwin_col_off()))) {
- line_count = min_scrolled;
- }
- if (line_count > 0) {
- if (scrolling_screenlines(true)) {
- scrollup(scrolled, true); // TODO(vim):
- } else {
- scrollup(line_count, true);
- }
+ } else if (line_count > 0) {
+ if (do_sms) {
+ scrollup(scrolled, true); // TODO(vim):
+ } else {
+ scrollup(line_count, true);
}
}
@@ -2117,10 +2090,9 @@ void scroll_cursor_halfway(bool atend, bool prefer_above)
colnr_T skipcol = 0;
int want_height;
- bool smooth_scroll = false;
- if (curwin->w_p_sms && curwin->w_p_wrap) {
+ bool do_sms = curwin->w_p_wrap && curwin->w_p_sms;
+ if (do_sms) {
// 'smoothscroll' and 'wrap' are set
- smooth_scroll = true;
if (atend) {
want_height = (curwin->w_height_inner - used) / 2;
used = 0;
@@ -2133,7 +2105,7 @@ void scroll_cursor_halfway(bool atend, bool prefer_above)
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) {
+ if (do_sms) {
topline_back_winheight(curwin, &loff, false);
if (loff.height == MAXCOL) {
break;
@@ -2217,7 +2189,7 @@ void scroll_cursor_halfway(bool atend, bool prefer_above)
if (skipcol != 0) {
curwin->w_skipcol = skipcol;
redraw_later(curwin, UPD_NOT_VALID);
- } else {
+ } else if (do_sms) {
reset_skipcol(curwin);
}
}
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index f1cd8d1aac..f59eac7674 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -196,17 +196,17 @@ describe('display', function()
end)
-- oldtest: Test_display_long_lastline()
- it('display "lastline" shows correct text when end of wrapped line is deleted', function()
+ it('"lastline" shows correct text when end of wrapped line is deleted', function()
local screen = Screen.new(35, 14)
screen:attach()
exec([[
- set display=lastline scrolloff=5
+ set display=lastline smoothscroll scrolloff=0
call setline(1, [
- \'aaaaa'->repeat(100),
+ \'aaaaa'->repeat(500),
\'bbbbb '->repeat(7) .. 'ccccc '->repeat(7) .. 'ddddd '->repeat(7)
\])
]])
- feed('482|')
+ feed('736|')
screen:expect([[
<<<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -219,10 +219,11 @@ describe('display', function()
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- aaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaa|
- aaaaaaaaaa |
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
|
]])
+ -- The correct part of the last line is moved into view.
feed('D')
screen:expect([[
<<<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -236,9 +237,67 @@ describe('display', function()
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- aaaaaaaaaaaaaaaaaaaaaaaaa^a |
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a|
bbbbb bbbbb bbbbb bbbbb bbbbb bb@@@|
|
]])
+ -- "w_skipcol" does not change because the topline is still long enough
+ -- to maintain the current skipcol.
+ feed('g04l11gkD')
+ screen:expect([[
+ <<<^a |
+ bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb|
+ bbbbb ccccc ccccc ccccc ccccc cccc|
+ c ccccc ccccc ddddd ddddd ddddd ddd|
+ dd ddddd ddddd ddddd |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ -- "w_skipcol" is reset to bring the entire topline into view because
+ -- the line length is now smaller than the current skipcol + marker.
+ feed('x')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aa^a |
+ bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb|
+ bbbbb ccccc ccccc ccccc ccccc cccc|
+ c ccccc ccccc ddddd ddddd ddddd @@@|
+ |
+ ]])
+ end)
+
+ -- oldtest: Test_display_cursor_long_line()
+ it("correctly shows line that doesn't fit in the window", function()
+ local screen = Screen.new(75, 8)
+ screen:attach()
+ exec([[
+ call setline(1, ['a', 'bbbbb '->repeat(100), 'c'])
+ norm $j
+ ]])
+ screen:expect([[
+ <<<bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb |
+ bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbb|
+ bb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb |
+ bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbb|
+ bb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb |
+ bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbb|
+ bb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb bbbbb^ |
+ |
+ ]])
end)
end)
diff --git a/test/functional/legacy/normal_spec.lua b/test/functional/legacy/normal_spec.lua
new file mode 100644
index 0000000000..ba875460f5
--- /dev/null
+++ b/test/functional/legacy/normal_spec.lua
@@ -0,0 +1,41 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+
+before_each(clear)
+
+describe('normal', function()
+ -- oldtest: Test_normal_j_below_botline()
+ it([["j" does not skip lines when scrolling below botline and 'foldmethod' is not "manual"]], function()
+ local screen = Screen.new(40, 19)
+ screen:attach()
+ screen:set_default_attr_ids({{foreground = Screen.colors.Brown}})
+ exec([[
+ set number foldmethod=diff scrolloff=0
+ call setline(1, map(range(1, 9), 'repeat(v:val, 200)'))
+ norm Lj
+ ]])
+ screen:expect([[
+ {1: 2 }222222222222222222222222222222222222|
+ {1: }222222222222222222222222222222222222|
+ {1: }222222222222222222222222222222222222|
+ {1: }222222222222222222222222222222222222|
+ {1: }222222222222222222222222222222222222|
+ {1: }22222222222222222222 |
+ {1: 3 }333333333333333333333333333333333333|
+ {1: }333333333333333333333333333333333333|
+ {1: }333333333333333333333333333333333333|
+ {1: }333333333333333333333333333333333333|
+ {1: }333333333333333333333333333333333333|
+ {1: }33333333333333333333 |
+ {1: 4 }^444444444444444444444444444444444444|
+ {1: }444444444444444444444444444444444444|
+ {1: }444444444444444444444444444444444444|
+ {1: }444444444444444444444444444444444444|
+ {1: }444444444444444444444444444444444444|
+ {1: }44444444444444444444 |
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 869763be3c..838ada4006 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -556,13 +556,13 @@ describe('smoothscroll', function()
|
]])
-- Test zt/zz/zb that they work properly when a long line is above it
- feed('zb')
+ feed('zt')
screen:expect([[
- <<<th lots of text with lots of text wit|
- h lots of text with lots of text with lo|
- ts of text with lots of text with lots o|
- f text with lots of text end |
^four |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
|
]])
feed('zz')
@@ -574,13 +574,13 @@ describe('smoothscroll', function()
~ |
|
]])
- feed('zt')
+ feed('zb')
screen:expect([[
+ <<<th lots of text with lots of text wit|
+ h lots of text with lots of text with lo|
+ ts of text with lots of text with lots o|
+ f text with lots of text end |
^four |
- ~ |
- ~ |
- ~ |
- ~ |
|
]])
-- Repeat the step and move the cursor down again.
@@ -588,15 +588,11 @@ describe('smoothscroll', function()
-- 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.
exec("call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])")
+ -- Currently visible lines were replaced, test that the lines and cursor
+ -- are correctly displayed.
+ screen:expect_unchanged()
feed('3Gztj')
- screen:expect([[
- <<<th lots of text with lots of text wit|
- h lots of text with lots of text with lo|
- ts of text with lots of text with lots o|
- f text with lots of text end |
- ^four |
- |
- ]])
+ screen:expect_unchanged()
-- 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
diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim
index f27a8362a9..a2b40521d9 100644
--- a/test/old/testdir/test_display.vim
+++ b/test/old/testdir/test_display.vim
@@ -482,9 +482,9 @@ func Test_display_long_lastline()
CheckScreendump
let lines =<< trim END
- set display=lastline
+ set display=lastline smoothscroll scrolloff=0
call setline(1, [
- \'aaaaa'->repeat(100),
+ \'aaaaa'->repeat(150),
\'bbbbb '->repeat(7) .. 'ccccc '->repeat(7) .. 'ddddd '->repeat(7)
\])
END
@@ -492,11 +492,41 @@ func Test_display_long_lastline()
call writefile(lines, 'XdispLongline', 'D')
let buf = RunVimInTerminal('-S XdispLongline', #{rows: 14, cols: 35})
- call term_sendkeys(buf, "482|")
+ call term_sendkeys(buf, "736|")
call VerifyScreenDump(buf, 'Test_display_long_line_1', {})
+
+ " The correct part of the last line is moved into view.
call term_sendkeys(buf, "D")
call VerifyScreenDump(buf, 'Test_display_long_line_2', {})
+ " "w_skipcol" does not change because the topline is still long enough
+ " to maintain the current skipcol.
+ call term_sendkeys(buf, "g04l11gkD")
+ call VerifyScreenDump(buf, 'Test_display_long_line_3', {})
+
+ " "w_skipcol" is reset to bring the entire topline into view because
+ " the line length is now smaller than the current skipcol + marker.
+ call term_sendkeys(buf, "x")
+ call VerifyScreenDump(buf, 'Test_display_long_line_4', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Moving the cursor to a line that doesn't fit in the window should show
+" correctly.
+func Test_display_cursor_long_line()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['a', 'bbbbb '->repeat(100), 'c'])
+ norm $j
+ END
+
+ call writefile(lines, 'XdispCursorLongline', 'D')
+ let buf = RunVimInTerminal('-S XdispCursorLongline', #{rows: 8})
+
+ call VerifyScreenDump(buf, 'Test_display_cursor_long_line', {})
+
call StopVimInTerminal(buf)
endfunc
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index a854c9538f..23baebb78c 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -3993,4 +3993,22 @@ func Test_mouse_shape_after_cancelling_gr()
call delete('Xmouseshapes')
endfunc
+" Test that "j" does not skip lines when scrolling below botline and
+" 'foldmethod' is not "manual".
+func Test_normal_j_below_botline()
+ CheckScreendump
+
+ let lines =<< trim END
+ set number foldmethod=diff scrolloff=0
+ call setline(1, map(range(1, 9), 'repeat(v:val, 200)'))
+ norm Lj
+ END
+ call writefile(lines, 'XNormalJBelowBotline', 'D')
+ let buf = RunVimInTerminal('-S XNormalJBelowBotline', #{rows: 19, cols: 40})
+
+ call VerifyScreenDump(buf, 'Test_normal_j_below_botline', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim
index 4edf9cc6f5..6f3d12679e 100644
--- a/test/old/testdir/test_scroll_opt.vim
+++ b/test/old/testdir/test_scroll_opt.vim
@@ -323,11 +323,11 @@ func Test_smoothscroll_wrap_long_line()
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 term_sendkeys(buf, "zt")
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 term_sendkeys(buf, "zb")
call VerifyScreenDump(buf, 'Test_smooth_long_13', {})
" Repeat the step and move the cursor down again.
@@ -335,9 +335,12 @@ func Test_smoothscroll_wrap_long_line()
" 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>")
+ " Currently visible lines were replaced, test that the lines and cursor
+ " are correctly displayed.
+ call VerifyScreenDump(buf, 'Test_smooth_long_14', {})
call term_sendkeys(buf, "3Gzt")
call term_sendkeys(buf, "j")
- call VerifyScreenDump(buf, 'Test_smooth_long_14', {})
+ call VerifyScreenDump(buf, 'Test_smooth_long_15', {})
" 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
@@ -345,7 +348,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_15', {})
+ call VerifyScreenDump(buf, 'Test_smooth_long_16', {})
call StopVimInTerminal(buf)
endfunc