From 6f41eaa2b5abd5c252428ba278a9fcc356e48c1d Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 11 May 2023 20:37:49 +0200 Subject: [PATCH] vim-patch:9.0.1543: display errors when making topline shorter Problem: Display errors when making topline shorter and 'smoothscroll' is set. Solution: Reset w_skipcol when the topline becomes shorter than its current value. (Luuk van Baal, closes vim/vim#12367) https://github.com/vim/vim/commit/5d01f86d99bc3a3fd92d4f4e9338a9e78e9ebe16 --- src/nvim/change.c | 15 ++++++- test/functional/legacy/display_spec.lua | 51 +++++++++++++++++++--- test/functional/legacy/scroll_opt_spec.lua | 3 ++ test/old/testdir/test_display.vim | 18 ++++++-- test/old/testdir/test_scroll_opt.vim | 7 ++- 5 files changed, 82 insertions(+), 12 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/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua index a698bed9f7..f59eac7674 100644 --- a/test/functional/legacy/display_spec.lua +++ b/test/functional/legacy/display_spec.lua @@ -200,13 +200,13 @@ describe('display', 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([[ <<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_unchanged() -- Repeat the step but this time start it when the line is smooth-scrolled by diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim index b30f3bbeef..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,23 @@ 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 diff --git a/test/old/testdir/test_scroll_opt.vim b/test/old/testdir/test_scroll_opt.vim index c0c3134ff4..6f3d12679e 100644 --- a/test/old/testdir/test_scroll_opt.vim +++ b/test/old/testdir/test_scroll_opt.vim @@ -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'])\") + " 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, "\j") - call VerifyScreenDump(buf, 'Test_smooth_long_15', {}) + call VerifyScreenDump(buf, 'Test_smooth_long_16', {}) call StopVimInTerminal(buf) endfunc