vim-patch:9.1.1958: Wrong display with sign_unplace() and setline() in CursorMoved (#36851)

Problem:  Wrong display when scrolling with 'scrolloff' and calling
          sign_unplace() and setline() in CursorMoved (after 8.2.3204).
Solution: Still scroll for changed lines below the top area when the top
          is scrolled down (zeertzjq)

closes: vim/vim#18878

2da433cff7
This commit is contained in:
zeertzjq
2025-12-08 09:24:26 +08:00
committed by GitHub
parent 8aafe4f26c
commit 647f11e6ae
3 changed files with 144 additions and 5 deletions

View File

@@ -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;

View File

@@ -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([[

View File

@@ -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