commit 5235f3663fb4b398b2b18d2e3c4ef0f9bfd9eebc
parent 3bc9a5b5d2730eaf8181772b27dbc276296f479e
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue, 9 Dec 2025 22:25:34 +0800
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
Diffstat:
3 files changed, 101 insertions(+), 11 deletions(-)
diff --git 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
@@ -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"<CR>]])
+ screen:expect([[
+ 1 |
+ 2 |
+ 3 |
+ {3: }|
+ abc |
+ def |
+ ghi |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed([[:call setline(2, repeat('foo', 35))<CR>]])
+ 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
@@ -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, "\<CR>")
+ call VerifyScreenDump(buf, 'Test_display_hit_enter_setline_2', {})
+ call term_sendkeys(buf, ":call setline(2, repeat('foo', 35))\<CR>")
+ call VerifyScreenDump(buf, 'Test_display_hit_enter_setline_3', {})
call StopVimInTerminal(buf)
endfunc