diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-05-12 07:24:13 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-12 07:24:13 +0800 |
commit | d6e898b44fbd6b18b3ca23f780ffaedc343961f1 (patch) | |
tree | c72abf5286e3c89e6889c89cf3500e9008bda678 | |
parent | 30a0299bc6d1ceedd04d897cf56b298dd3ded0cd (diff) | |
parent | 6f41eaa2b5abd5c252428ba278a9fcc356e48c1d (diff) | |
download | rneovim-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.c | 15 | ||||
-rw-r--r-- | src/nvim/move.c | 56 | ||||
-rw-r--r-- | test/functional/legacy/display_spec.lua | 73 | ||||
-rw-r--r-- | test/functional/legacy/normal_spec.lua | 41 | ||||
-rw-r--r-- | test/functional/legacy/scroll_opt_spec.lua | 32 | ||||
-rw-r--r-- | test/old/testdir/test_display.vim | 36 | ||||
-rw-r--r-- | test/old/testdir/test_normal.vim | 18 | ||||
-rw-r--r-- | test/old/testdir/test_scroll_opt.vim | 11 |
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 |