diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index cf70ad8bdf..2356f12d74 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1376,6 +1376,7 @@ static void win_update(win_T *wp) int bot_start = 999; // first row of the bot area that needs // updating. 999 when no bot area updating bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit + bool scrolled_for_mod = false; // true after scrolling for changed lines bool top_to_mod = false; // redraw above mod_top int bot_scroll_start = 999; // first line that needs to be redrawn due to @@ -2038,10 +2039,13 @@ static void win_update(win_T *wp) // When at start of changed lines: May scroll following lines // up or down to minimize redrawing. // Don't do this when the change continues until the end. - // Don't scroll when redrawing the top, scrolled already above. - if (lnum == mod_top - && mod_bot != MAXLNUM + // Don't scroll the top area which was already scrolled above, + // but do scroll for changed lines below the top area. + if (!scrolled_for_mod && mod_bot != MAXLNUM + && lnum >= mod_top && lnum < MAX(mod_bot, mod_top + 1) && row >= top_end) { + scrolled_for_mod = true; + int old_cline_height = 0; int old_rows = 0; linenr_T l; diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua index 034a04d242..32ead91a60 100644 --- a/test/functional/legacy/display_spec.lua +++ b/test/functional/legacy/display_spec.lua @@ -12,7 +12,6 @@ describe('display', function() -- oldtest: Test_display_scroll_at_topline() it('scroll when modified at topline vim-patch:8.2.1488', function() local screen = Screen.new(20, 4) - command([[call setline(1, repeat('a', 21))]]) feed('O') screen:expect([[ @@ -26,7 +25,6 @@ describe('display', function() -- oldtest: Test_display_scroll_update_visual() it('scrolling when modified at topline in Visual mode vim-patch:8.2.4626', function() local screen = Screen.new(60, 8) - exec([[ set scrolloff=0 call setline(1, repeat(['foo'], 10)) @@ -43,6 +41,111 @@ describe('display', function() ]]) end) + -- oldtest: Test_display_scroll_setline() + it('scrolling with sign_unplace() and setline() in CursorMoved', function() + local screen = Screen.new(20, 15) + exec([[ + setlocal scrolloff=5 signcolumn=yes + call setline(1, range(1, 100)) + call sign_define('foo', #{text: '>'}) + call sign_place(1, 'bar', 'foo', bufnr(), #{lnum: 73}) + call sign_place(2, 'bar', 'foo', bufnr(), #{lnum: 74}) + call sign_place(3, 'bar', 'foo', bufnr(), #{lnum: 75}) + normal! G + autocmd CursorMoved * if line('.') == 79 + \ | call sign_unplace('bar', #{id: 2}) + \ | call setline(80, repeat('foo', 15)) + \ | endif + ]]) + screen:expect([[ + {7: }87 | + {7: }88 | + {7: }89 | + {7: }90 | + {7: }91 | + {7: }92 | + {7: }93 | + {7: }94 | + {7: }95 | + {7: }96 | + {7: }97 | + {7: }98 | + {7: }99 | + {7: }^100 | + | + ]]) + feed('19k') + screen:expect([[ + {7:> }75 | + {7: }76 | + {7: }77 | + {7: }78 | + {7: }79 | + {7: }80 | + {7: }^81 | + {7: }82 | + {7: }83 | + {7: }84 | + {7: }85 | + {7: }86 | + {7: }87 | + {7: }88 | + | + ]]) + feed('k') + screen:expect([[ + {7:> }75 | + {7: }76 | + {7: }77 | + {7: }78 | + {7: }79 | + {7: }^80 | + {7: }81 | + {7: }82 | + {7: }83 | + {7: }84 | + {7: }85 | + {7: }86 | + {7: }87 | + {7: }88 | + | + ]]) + feed('k') + screen:expect([[ + {7: }74 | + {7:> }75 | + {7: }76 | + {7: }77 | + {7: }78 | + {7: }^79 | + {7: }foofoofoofoofoofoo|*2 + {7: }foofoofoo | + {7: }81 | + {7: }82 | + {7: }83 | + {7: }84 | + {7: }85 | + | + ]]) + feed('k') + screen:expect([[ + {7:> }73 | + {7: }74 | + {7:> }75 | + {7: }76 | + {7: }77 | + {7: }^78 | + {7: }79 | + {7: }foofoofoofoofoofoo|*2 + {7: }foofoofoo | + {7: }81 | + {7: }82 | + {7: }83 | + {7: }84 | + | + ]]) + end) + local function run_test_display_lastline(euro) local screen = Screen.new(75, 10) exec([[ diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim index 90f0077ae9..49330978e0 100644 --- a/test/old/testdir/test_display.vim +++ b/test/old/testdir/test_display.vim @@ -268,6 +268,38 @@ func Test_display_scroll_update_visual() call StopVimInTerminal(buf) endfunc +func Test_display_scroll_setline() + CheckScreendump + + let lines =<< trim END + setlocal scrolloff=5 signcolumn=yes + call setline(1, range(1, 100)) + call sign_define('foo', #{text: '>'}) + call sign_place(1, 'bar', 'foo', bufnr(), #{lnum: 73}) + call sign_place(2, 'bar', 'foo', bufnr(), #{lnum: 74}) + call sign_place(3, 'bar', 'foo', bufnr(), #{lnum: 75}) + normal! G + autocmd CursorMoved * if line('.') == 79 + \ | call sign_unplace('bar', #{id: 2}) + \ | call setline(80, repeat('foo', 15)) + \ | endif + END + call writefile(lines, 'XscrollSetline.vim', 'D') + + let buf = RunVimInTerminal('-S XscrollSetline.vim', #{rows: 15, cols: 20}) + call VerifyScreenDump(buf, 'Test_display_scroll_setline_1', {}) + call term_sendkeys(buf, '19k') + call VerifyScreenDump(buf, 'Test_display_scroll_setline_2', {}) + call term_sendkeys(buf, 'k') + call VerifyScreenDump(buf, 'Test_display_scroll_setline_3', {}) + call term_sendkeys(buf, 'k') + call VerifyScreenDump(buf, 'Test_display_scroll_setline_4', {}) + call term_sendkeys(buf, 'k') + call VerifyScreenDump(buf, 'Test_display_scroll_setline_5', {}) + + call StopVimInTerminal(buf) +endfunc + " Test for 'eob' (EndOfBuffer) item in 'fillchars' func Test_eob_fillchars() " default value