]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1473: inconsistent range arg for :diffget/diffput v9.1.1473
authorYee Cheng Chin <ychin.git@gmail.com>
Fri, 20 Jun 2025 16:44:18 +0000 (18:44 +0200)
committerChristian Brabandt <cb@256bit.org>
Fri, 20 Jun 2025 16:44:18 +0000 (18:44 +0200)
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>
runtime/doc/diff.txt
src/diff.c
src/ex_cmds.h
src/ex_docmd.c
src/testdir/test_diffmode.vim
src/version.c

index 81564664eb51190734c9896a022c09e8cc82e0a4..493c740ad4a1f170588c72161855b5a9855d5aa2 100644 (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
index c4f550d63cfb433fbaf01205128900bf8e74e02e..b212e71fe5ea9cf3dfa59c5b66e583898cb6dfb4 100644 (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;
index fb8d62f608a9e86d8739ca10029732496391a21b..2bbf5ef0015d175d9553c3ac8b2ea7c6e6eb52d5 100644 (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,
index 08d2c1e664f931d33fd0d43f453919ad59b941d9..4ccc5f7592992c9adffb261f147267ab7c7983bf 100644 (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);
index 1ab194568b2ff4be75ea3e2850ebcc50cb581815..a348d3a40f93455f0aa485dbeedc9f6ccc319c0b 100644 (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 _
index e8673ed06c9aa2e1bf429545c08d886b9c94edb2..bafcef18b06f8eadf44507706e766f75352457f4 100644 (file)
@@ -709,6 +709,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1473,
 /**/
     1472,
 /**/