diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt index f39a51022a..53692948f8 100644 --- a/runtime/doc/diff.txt +++ b/runtime/doc/diff.txt @@ -292,18 +292,20 @@ that the buffers will be equal within the specified range. When no [range] is given, the diff at the cursor position or just above it is -affected. When [range] is used, Vim tries to only put or get the specified -lines. When there are deleted lines, this may not always be possible. +affected. There can be deleted lines below the last line of the buffer. When +the cursor is on the last line in the buffer and there is no diff above this +line, and no [range] is given, the diff below the cursor position will be used +instead. -There can be deleted lines below the last line of the buffer. When the cursor -is on the last line in the buffer and there is no diff above this line, the -":diffget" and "do" commands will obtain lines from the other buffer. +When [range] is used, Vim tries to only put or get the specified lines. When +there are deleted lines, they will be used if they are between the lines +specified by [range]. -To be able to get those lines from another buffer in a [range] it's allowed to -use the last line number plus one. This command gets all diffs from the other -buffer: > +To be able to put or get those lines to/from another buffer in a [range] it's +allowed to use 0 and the last line number plus one. This command gets all +diffs from the other buffer: > - :1,$+1diffget + :0,$+1diffget Note that deleted lines are displayed, but not counted as text lines. You can't move the cursor into them. To fill the deleted lines with the lines diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 71d2dc687a..01e1c26911 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -3492,10 +3492,13 @@ void ex_diffgetput(exarg_T *eap) if (eap->addr_count == 0) { // Make it possible that ":diffget" on the last line gets line below // the cursor line when there is no difference above the cursor. - if ((eap->cmdidx == CMD_diffget) - && (eap->line1 == curbuf->b_ml.ml_line_count) - && (diff_check(curwin, eap->line1) == 0) - && ((eap->line1 == 1) || (diff_check(curwin, eap->line1 - 1) == 0))) { + int linestatus = 0; + if (eap->line1 == curbuf->b_ml.ml_line_count + && (diff_check_with_linestatus(curwin, eap->line1, &linestatus) == 0 + && linestatus == 0) + && (eap->line1 == 1 + || (diff_check_with_linestatus(curwin, eap->line1 - 1, &linestatus) >= 0 + && linestatus == 0))) { eap->line2++; } else if (eap->line1 > 0) { eap->line1--; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 39812d0311..c6f8baade5 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -752,7 +752,7 @@ M.cmds = { }, { command = 'diffget', - flags = bit.bor(RANGE, EXTRA, TRLBAR, MODIFY), + flags = bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, MODIFY), addr_type = 'ADDR_LINES', func = 'ex_diffgetput', }, @@ -770,7 +770,7 @@ M.cmds = { }, { command = 'diffput', - flags = bit.bor(RANGE, EXTRA, TRLBAR), + flags = bit.bor(RANGE, ZEROR, EXTRA, TRLBAR), addr_type = 'ADDR_LINES', func = 'ex_diffgetput', }, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index b4726f1120..b5418c3bb8 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3728,8 +3728,9 @@ char *invalid_range(exarg_T *eap) if (eap->argt & EX_RANGE) { switch (eap->addr_type) { case ADDR_LINES: - if (eap->line2 > (curbuf->b_ml.ml_line_count - + (eap->cmdidx == CMD_diffget))) { + if (eap->line2 > + (curbuf->b_ml.ml_line_count + + (eap->cmdidx == CMD_diffget || eap->cmdidx == CMD_diffput))) { return _(e_invrange); } break; diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim index 7767aa67a7..decee13529 100644 --- a/test/old/testdir/test_diffmode.vim +++ b/test/old/testdir/test_diffmode.vim @@ -288,6 +288,63 @@ func Test_diffget_diffput_range() %bw! endfunc +" Test :diffget/:diffput handling of added/deleted lines +func Test_diffget_diffput_deleted_lines() + call setline(1, ['2','4','6']) + diffthis + new + call setline(1, range(1,7)) + diffthis + wincmd w + + 3,3diffget " get nothing + call assert_equal(['2', '4', '6'], getline(1, '$')) + 3,4diffget " get the last insertion past the end of file + call assert_equal(['2', '4', '6', '7'], getline(1, '$')) + 0,1diffget " get the first insertion above first line + call assert_equal(['1', '2', '4', '6', '7'], getline(1, '$')) + + " When using non-range diffget on the last line, it should get the + " change above or at the line as usual, but if the only change is below the + " last line, diffget should get that instead. + 1,$delete + call setline(1, ['2','4','6']) + diffupdate + norm Gdo + call assert_equal(['2', '4', '5', '6'], getline(1, '$')) + norm Gdo + call assert_equal(['2', '4', '5', '6', '7'], getline(1, '$')) + + " Test non-range diffput on last line with the same logic + 1,$delete + call setline(1, ['2','4','6']) + diffupdate + norm Gdp + wincmd w + call assert_equal(['1', '2', '3', '4', '6', '7'], getline(1, '$')) + wincmd w + norm Gdp + wincmd w + call assert_equal(['1', '2', '3', '4', '6'], getline(1, '$')) + call setline(1, range(1,7)) + diffupdate + wincmd w + + " Test that 0,$+1 will get/put all changes from/to the other buffer + 1,$delete + call setline(1, ['2','4','6']) + diffupdate + 0,$+1diffget + call assert_equal(['1', '2', '3', '4', '5', '6', '7'], getline(1, '$')) + 1,$delete + call setline(1, ['2','4','6']) + diffupdate + 0,$+1diffput + wincmd w + call assert_equal(['2', '4', '6'], getline(1, '$')) + %bw! +endfunc + " Test for :diffget/:diffput with an empty buffer and a non-empty buffer func Test_diffget_diffput_empty_buffer() %d _