aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/move.c37
-rw-r--r--test/functional/legacy/scroll_opt_spec.lua41
-rw-r--r--test/old/testdir/test_scroll_opt.vim26
3 files changed, 96 insertions, 8 deletions
diff --git a/src/nvim/move.c b/src/nvim/move.c
index b0a4a3848a..abe908cfa0 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1877,18 +1877,43 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
// The lines of the cursor line itself are always used.
used = plines_win_nofill(curwin, cln, true);
- // 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_win_nofill(curwin, lnum, true);
+ 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);
+ }
+ }
+
+ // 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 = plines_win_nofill(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);
}
}
}
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index a05470418f..6c8ca2cf97 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -410,7 +410,7 @@ describe('smoothscroll', function()
it("adjusts the cursor position in a long line", function()
screen:try_resize(40, 6)
exec([[
- call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30))])
+ call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30)) .. ' end', 'four'])
set smoothscroll scrolloff=0
normal 3G10|zt
]])
@@ -502,6 +502,45 @@ describe('smoothscroll', function()
ith lots of text with lots of text with |
|
]])
+ -- '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.
+ exec('set scrolloff=0')
+ feed('0j')
+ screen:expect([[
+ ^four |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ -- 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.
+ exec("call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])")
+ 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 |
+ |
+ ]])
+ -- 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.
+ feed('3Gzt<C-E>j')
+ 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 |
+ fou^r |
+ |
+ ]])
end)
-- oldtest: Test_smoothscroll_one_long_line()
diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim
index b9645898e8..8d1942e037 100644
--- a/test/old/testdir/test_scroll_opt.vim
+++ b/test/old/testdir/test_scroll_opt.vim
@@ -263,7 +263,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
@@ -304,6 +304,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