1
0
forked from aniani/vim

patch 9.1.1473: inconsistent range arg for :diffget/diffput

Problem:  inconsistent range arg for :diffget/diffput
Solution: fix the range specification, place the cursor for :diffput and
          :diffget consistently on the last line (Yee Cheng Chin)

Previously, `:<range>diffget` only allowed using 1 or above in the range
value, making it impossible to use the command for a diff block at the
beginning of the file. Fix the range specification so the user can now
use 0 to specify the space before the first line. This allows
`:0,$+1diffget` to work to retrieve all the changes from the other file
instead of missing the first diff block. Also do this for `:diffput`.

Also, make `:diffput` work more similar to `:diffget`. Make it so that
if the cursor is on the last line and a new line is inserted in the
other file, doing `:diffput` will select that diff block below the line,
just like `:diffget` would.

Also clean up the logic a little bit for edge cases and for handling
line matched diff blocks better.

closes: #17579

Signed-off-by: Yee Cheng Chin <ychin.git@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yee Cheng Chin 2025-06-20 18:44:18 +02:00 committed by Christian Brabandt
parent 476b65ebac
commit d75ab0cbf5
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
6 changed files with 82 additions and 17 deletions

View File

@ -1,4 +1,4 @@
*diff.txt* For Vim version 9.1. Last change: 2025 Mar 28
*diff.txt* For Vim version 9.1. Last change: 2025 Jun 20
VIM REFERENCE MANUAL by Bram Moolenaar
@ -304,18 +304,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

View File

@ -3874,10 +3874,13 @@ ex_diffgetput(exarg_T *eap)
{
// 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;

View File

@ -486,7 +486,7 @@ EXCMD(CMD_diffupdate, "diffupdate", ex_diffupdate,
EX_BANG|EX_TRLBAR,
ADDR_NONE),
EXCMD(CMD_diffget, "diffget", ex_diffgetput,
EX_RANGE|EX_EXTRA|EX_TRLBAR|EX_MODIFY,
EX_RANGE|EX_ZEROR|EX_EXTRA|EX_TRLBAR|EX_MODIFY,
ADDR_LINES),
EXCMD(CMD_diffoff, "diffoff", ex_diffoff,
EX_BANG|EX_TRLBAR,
@ -495,7 +495,7 @@ EXCMD(CMD_diffpatch, "diffpatch", ex_diffpatch,
EX_EXTRA|EX_FILE1|EX_TRLBAR|EX_MODIFY,
ADDR_NONE),
EXCMD(CMD_diffput, "diffput", ex_diffgetput,
EX_RANGE|EX_EXTRA|EX_TRLBAR,
EX_RANGE|EX_ZEROR|EX_EXTRA|EX_TRLBAR,
ADDR_LINES),
EXCMD(CMD_diffsplit, "diffsplit", ex_diffsplit,
EX_EXTRA|EX_FILE1|EX_TRLBAR,

View File

@ -4850,7 +4850,8 @@ invalid_range(exarg_T *eap)
case ADDR_LINES:
if (eap->line2 > curbuf->b_ml.ml_line_count
#ifdef FEAT_DIFF
+ (eap->cmdidx == CMD_diffget)
+ (eap->cmdidx == CMD_diffget ||
eap->cmdidx == CMD_diffput)
#endif
)
return _(e_invalid_range);

View File

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

View File

@ -709,6 +709,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1473,
/**/
1472,
/**/