From 47ce93ad6d71625df7298b69b4c6ed74977889ab Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 30 Jan 2026 20:09:33 +0800 Subject: [PATCH] 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 --- src/nvim/diff.c | 4 +++ test/functional/ui/diff_spec.lua | 47 ++++++++++++++++++++++++++++++ test/old/testdir/test_diffmode.vim | 26 +++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/nvim/diff.c b/src/nvim/diff.c index a56f371662..8077e8fcdc 100644 --- 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 index 415085bb2b..e7b679a3c4 100644 --- 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 index 2fa88ff1ad..b5e2c886ba 100644 --- 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\") + call VerifyScreenDump(buf, 'Test_diffput_to_empty_buf_02', {}) + call term_sendkeys(buf, ":redraw!\") + 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