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>
diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt
index 8156466..493c740 100644
--- a/runtime/doc/diff.txt
+++ b/runtime/doc/diff.txt
@@ -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 @@
 
 
 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/diff.c b/src/diff.c
index c4f550d..b212e71 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -3874,10 +3874,13 @@
     {
 	// 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/ex_cmds.h b/src/ex_cmds.h
index fb8d62f..2bbf5ef 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -486,7 +486,7 @@
 	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 @@
 	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,
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 08d2c1e..4ccc5f7 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -4850,7 +4850,8 @@
 	    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);
diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim
index 1ab1945..a348d3a 100644
--- a/src/testdir/test_diffmode.vim
+++ b/src/testdir/test_diffmode.vim
Binary files differ
diff --git a/src/version.c b/src/version.c
index e8673ed..bafcef1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -710,6 +710,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1473,
+/**/
     1472,
 /**/
     1471,