From 5235f3663fb4b398b2b18d2e3c4ef0f9bfd9eebc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 9 Dec 2025 22:25:34 +0800 Subject: [PATCH] vim-patch:9.1.1964: Wrong display when using setline() at hit-enter prompt (#36878) Problem: Wrong display when using setline() at hit-enter prompt (after 8.2.3204). Solution: Only skip scrolling for changed lines in top area if it's scrolled down due to w_topline change. Also add more testing for what 8.2.3204 fixed (zeertzjq). closes: vim/vim#18887 https://github.com/vim/vim/commit/e72eacceab2647e37e7d7a8a70e89dcd6ad01288 --- src/nvim/drawscreen.c | 6 +-- test/functional/legacy/display_spec.lua | 71 +++++++++++++++++++++++-- test/old/testdir/test_display.vim | 35 ++++++++++-- 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 2356f12d74..800572ae06 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -2039,11 +2039,11 @@ 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 the top area which was already scrolled above, - // but do scroll for changed lines below the top area. + // Don't scroll for changed lines in the top area if that's already + // done 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_down || row >= top_end)) { scrolled_for_mod = true; int old_cline_height = 0; diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua index 32ead91a60..875c739975 100644 --- a/test/functional/legacy/display_spec.lua +++ b/test/functional/legacy/display_spec.lua @@ -48,13 +48,19 @@ describe('display', function() 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}) + call sign_place(1, 'bar', 'foo', bufnr(), #{lnum: 71}) + call sign_place(2, 'bar', 'foo', bufnr(), #{lnum: 72}) + call sign_place(3, 'bar', 'foo', bufnr(), #{lnum: 73}) + call sign_place(4, 'bar', 'foo', bufnr(), #{lnum: 74}) + call sign_place(5, 'bar', 'foo', bufnr(), #{lnum: 75}) normal! G autocmd CursorMoved * if line('.') == 79 - \ | call sign_unplace('bar', #{id: 2}) + \ | call sign_unplace('bar', #{id: 4}) \ | call setline(80, repeat('foo', 15)) + \ | elseif line('.') == 78 + \ | call setline(72, repeat('bar', 10)) + \ | elseif line('.') == 77 + \ | call sign_unplace('bar', #{id: 2}) \ | endif ]]) screen:expect([[ @@ -144,6 +150,63 @@ describe('display', function() {7: }84 | | ]]) + feed('k') + screen:expect([[ + {7: }barbarbarbarbarbar| + {7: }barbarbarbar | + {7:> }73 | + {7: }74 | + {7:> }75 | + {7: }76 | + {7: }^77 | + {7: }78 | + {7: }79 | + {7: }foofoofoofoofoofoo|*2 + {7: }foofoofoo | + {7: }81 | + {7: }82 | + | + ]]) + end) + + -- oldtest: Test_display_hit_enter_setline() + it('using setline() at hit-enter prompt', function() + local screen = Screen.new(40, 8) + exec([[ + call setline(1, range(1, 100)) + ]]) + screen:expect([[ + ^1 | + 2 | + 3 | + 4 | + 5 | + 6 | + 7 | + | + ]]) + feed([[:echo "abc\ndef\nghi"]]) + screen:expect([[ + 1 | + 2 | + 3 | + {3: }| + abc | + def | + ghi | + {6:Press ENTER or type command to continue}^ | + ]]) + feed([[:call setline(2, repeat('foo', 35))]]) + screen:expect([[ + ^1 | + foofoofoofoofoofoofoofoofoofoofoofoofoof| + oofoofoofoofoofoofoofoofoofoofoofoofoofo| + ofoofoofoofoofoofoofoofoo | + 3 | + 4 | + 5 | + | + ]]) end) local function run_test_display_lastline(euro) diff --git a/test/old/testdir/test_display.vim b/test/old/testdir/test_display.vim index 49330978e0..c57093cee9 100644 --- a/test/old/testdir/test_display.vim +++ b/test/old/testdir/test_display.vim @@ -275,13 +275,19 @@ func Test_display_scroll_setline() 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}) + call sign_place(1, 'bar', 'foo', bufnr(), #{lnum: 71}) + call sign_place(2, 'bar', 'foo', bufnr(), #{lnum: 72}) + call sign_place(3, 'bar', 'foo', bufnr(), #{lnum: 73}) + call sign_place(4, 'bar', 'foo', bufnr(), #{lnum: 74}) + call sign_place(5, 'bar', 'foo', bufnr(), #{lnum: 75}) normal! G autocmd CursorMoved * if line('.') == 79 - \ | call sign_unplace('bar', #{id: 2}) + \ | call sign_unplace('bar', #{id: 4}) \ | call setline(80, repeat('foo', 15)) + \ | elseif line('.') == 78 + \ | call setline(72, repeat('bar', 10)) + \ | elseif line('.') == 77 + \ | call sign_unplace('bar', #{id: 2}) \ | endif END call writefile(lines, 'XscrollSetline.vim', 'D') @@ -296,6 +302,27 @@ func Test_display_scroll_setline() call VerifyScreenDump(buf, 'Test_display_scroll_setline_4', {}) call term_sendkeys(buf, 'k') call VerifyScreenDump(buf, 'Test_display_scroll_setline_5', {}) + call term_sendkeys(buf, 'k') + call VerifyScreenDump(buf, 'Test_display_scroll_setline_6', {}) + + call StopVimInTerminal(buf) +endfunc + +func Test_display_hit_enter_setline() + CheckScreendump + + let lines =<< trim END + call setline(1, range(1, 100)) + END + call writefile(lines, 'XhitEnterSetline.vim', 'D') + + let buf = RunVimInTerminal('-S XhitEnterSetline.vim', #{rows: 8, cols: 40}) + call VerifyScreenDump(buf, 'Test_display_hit_enter_setline_1', {}) + call term_sendkeys(buf, ':echo "abc\ndef\nghi"') + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_display_hit_enter_setline_2', {}) + call term_sendkeys(buf, ":call setline(2, repeat('foo', 35))\") + call VerifyScreenDump(buf, 'Test_display_hit_enter_setline_3', {}) call StopVimInTerminal(buf) endfunc