commit 47ce93ad6d71625df7298b69b4c6ed74977889ab
parent ebfbe4db498cbc1dead5a8ea7fc99b574f383696
Author: zeertzjq <zeertzjq@outlook.com>
Date: Fri, 30 Jan 2026 20:09:33 +0800
vim-patch:9.1.2118: 'cursorline' missing after :diffput to empty buf (#37628)
Problem: 'cursorline' and part of 'statusline' are missing after
:diffput to an empty buffer.
Solution: Make sure the cursor doesn't go beyond the last line after
:diffput (zeertzjq)
related: neovim/neovim#37621
closes: vim/vim#19281
https://github.com/vim/vim/commit/ce1e562fdafa998e577d65a8b0a1b8bc1cbfcf4c
Diffstat:
3 files changed, 77 insertions(+), 0 deletions(-)
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
@@ -3890,6 +3890,10 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr
// lines.
if (curwin->w_cursor.lnum >= lnum + count) {
curwin->w_cursor.lnum += added;
+ // When the buffer was previously empty, the cursor may
+ // now be beyond the last line, so clamp cursor lnum.
+ curwin->w_cursor.lnum = MIN(curwin->w_cursor.lnum,
+ curbuf->b_ml.ml_line_count);
} else if (added < 0) {
curwin->w_cursor.lnum = lnum;
}
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
@@ -3379,3 +3379,50 @@ it(':%bwipe does not crash when using diffexpr', function()
4 buffers wiped out |
]])
end)
+
+-- oldtest: Test_diffput_to_empty_buf()
+it(':diffput to empty buffer redraws properly', function()
+ local screen = Screen.new(75, 20)
+ exec([[
+ set ruler
+ call setline(1, ['foo', 'bar', 'baz'])
+ rightbelow vnew
+ windo diffthis
+ windo set cursorline nofoldenable
+ wincmd t
+ ]])
+ screen:add_extra_attr_ids({
+ [100] = { underline = true, background = Screen.colors.LightBlue },
+ })
+ screen:expect([[
+ {7: }{100:^foo }│{7: }{23:-----------------------------------}|
+ {7: }{22:bar }│{7: }{23:-----------------------------------}|
+ {7: }{22:baz }│{7: }{23:-----------------------------------}|
+ {1:~ }│{7: }{21: }|
+ {1:~ }│{1:~ }|*14
+ {3:[No Name] [+] 1,1 All }{2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ feed('0') -- Trigger an initial 'cursorbind' check.
+ screen:expect_unchanged()
+ command('diffput')
+ screen:expect([[
+ {7: }{21:^foo }│{7: }foo |
+ {7: }bar │{7: }bar |
+ {7: }baz │{7: }{21:baz }|
+ {1:~ }│{1:~ }|*15
+ {3:[No Name] [+] 1,1 All }{2:[No Name] [+] 3,1 All}|
+ |
+ ]])
+ command(':redraw!')
+ screen:expect_unchanged()
+ feed('j')
+ screen:expect([[
+ {7: }foo │{7: }foo |
+ {7: }{21:^bar }│{7: }{21:bar }|
+ {7: }baz │{7: }baz |
+ {1:~ }│{1:~ }|*15
+ {3:[No Name] [+] 2,1 All }{2:[No Name] [+] 2,1 All}|
+ |
+ ]])
+end)
diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim
@@ -3347,4 +3347,30 @@ func Test_diffexpr_wipe_buffers()
call StopVimInTerminal(buf)
endfunc
+func Test_diffput_to_empty_buf()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['foo', 'bar', 'baz'])
+ rightbelow vnew
+ windo diffthis
+ windo set cursorline nofoldenable
+ wincmd t
+ END
+ call writefile(lines, 'Xtest_diffput_to_empty_buf', 'D')
+
+ let buf = RunVimInTerminal('-S Xtest_diffput_to_empty_buf', {})
+ call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_01', {})
+ call term_sendkeys(buf, '0') " Trigger an initial 'cursorbind' check.
+ call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_01', {})
+ call term_sendkeys(buf, ":diffput | echo\<CR>")
+ call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_02', {})
+ call term_sendkeys(buf, ":redraw!\<CR>")
+ call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_02', {})
+ call term_sendkeys(buf, 'j')
+ call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_03', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab