All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael Montalbo via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Michael Montalbo <mmontalbo@gmail.com>,
	Michael Montalbo <mmontalbo@gmail.com>
Subject: [PATCH v3 3/7] diff: emit -L hunk headers via xdiff's formatter
Date: Thu, 03 Sep 2026 05:05:15 +0000	[thread overview]
Message-ID: <2081d5d257d65b7b823fc46777e952a2f650e6dd.1788411919.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2152.v3.git.1788411919.gitgitgadget@gmail.com>

From: Michael Montalbo <mmontalbo@gmail.com>

Currently, diff's line-range filter implements its own method for
emitting diff hunk headers. This mostly matches what xdiff itself
outputs, but there is a discrepancy for postimage or preimage sides
with 0 line changes. For a side with no lines (count 0), the begin is
the line before the change. The header omits the line count of 1.

Rather than fix this case in the line-range implementation, expose the
function xdiff uses to emit its headers. Reusing it keeps the header
format consistent with and without -L.

Update test scenarios and fixtures to reflect the now consistent header
format.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
---
 diff.c                                   | 21 ++++++++-------------
 t/t4211/sha1/expect.no-assertion-error   |  2 +-
 t/t4211/sha1/expect.vanishes-early       |  6 +++---
 t/t4211/sha256/expect.no-assertion-error |  2 +-
 t/t4211/sha256/expect.vanishes-early     |  6 +++---
 xdiff-interface.c                        | 19 +++++++++++++++++++
 xdiff-interface.h                        | 13 +++++++++++++
 7 files changed, 48 insertions(+), 21 deletions(-)

diff --git a/diff.c b/diff.c
index c94ddbebe5..cb1a85c624 100644
--- a/diff.c
+++ b/diff.c
@@ -2560,15 +2560,10 @@ static void flush_range_hunk(struct line_range_filter *filter)
 		return;
 	}
 
-	strbuf_addf(&hdr, "@@ -%ld,%ld +%ld,%ld @@",
-		    filter->accumulating_hunk.old_begin, old_count,
-		    filter->accumulating_hunk.new_begin, new_count);
-	if (filter->accumulating_hunk.func_name_len > 0) {
-		strbuf_addch(&hdr, ' ');
-		strbuf_add(&hdr, filter->accumulating_hunk.func_name,
-			   filter->accumulating_hunk.func_name_len);
-	}
-	strbuf_addch(&hdr, '\n');
+	xdiff_emit_hunk_header(&hdr, filter->accumulating_hunk.old_begin, old_count,
+			       filter->accumulating_hunk.new_begin, new_count,
+			       filter->accumulating_hunk.func_name,
+			filter->accumulating_hunk.func_name_len);
 
 	filter->ret = filter->orig_line_fn(filter->orig_cb_data, hdr.buf, hdr.len);
 	strbuf_release(&hdr);
@@ -2589,14 +2584,14 @@ static void flush_range_hunk(struct line_range_filter *filter)
 }
 
 static void line_range_hunk_fn(void *data,
-			       long old_begin, long old_nr UNUSED,
-			       long new_begin, long new_nr UNUSED,
+			       long old_begin, long old_nr,
+			       long new_begin, long new_nr,
 			       const char *func, long funclen)
 {
 	struct line_range_filter *filter = data;
 
-	filter->accumulating_hunk.lno_in_postimage = new_begin;
-	filter->accumulating_hunk.lno_in_preimage = old_begin;
+	filter->accumulating_hunk.lno_in_postimage = new_nr ? new_begin : new_begin + 1;
+	filter->accumulating_hunk.lno_in_preimage = old_nr ? old_begin : old_begin + 1;
 
 	if (funclen > 0) {
 		if (funclen > (long)sizeof(filter->accumulating_hunk.func_name))
diff --git a/t/t4211/sha1/expect.no-assertion-error b/t/t4211/sha1/expect.no-assertion-error
index 54c568f273..95faf51a7b 100644
--- a/t/t4211/sha1/expect.no-assertion-error
+++ b/t/t4211/sha1/expect.no-assertion-error
@@ -8,7 +8,7 @@ diff --git a/b.c b/b.c
 index bf79c2f..27c829c 100644
 --- a/b.c
 +++ b/b.c
-@@ -25,0 +18,9 @@
+@@ -24,0 +18,9 @@
 +long f(long x)
 +{
 +	int s = 0;
diff --git a/t/t4211/sha1/expect.vanishes-early b/t/t4211/sha1/expect.vanishes-early
index a413ad3659..e4b1a201d5 100644
--- a/t/t4211/sha1/expect.vanishes-early
+++ b/t/t4211/sha1/expect.vanishes-early
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index 0b9cae5..5de3ea4 100644
 --- a/a.c
 +++ b/a.c
-@@ -23,0 +24,1 @@ int main ()
+@@ -22,0 +24 @@ int main ()
 +/* incomplete lines are bad! */
 
 commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
@@ -21,7 +21,7 @@ diff --git a/a.c b/a.c
 index 5e709a1..0b9cae5 100644
 --- a/a.c
 +++ b/a.c
-@@ -22,1 +22,1 @@ int main ()
+@@ -22 +22 @@ int main ()
 -}
 +}
 \ No newline at end of file
@@ -37,5 +37,5 @@ new file mode 100644
 index 0000000..444e415
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +20,1 @@
+@@ -0,0 +20 @@
 +}
diff --git a/t/t4211/sha256/expect.no-assertion-error b/t/t4211/sha256/expect.no-assertion-error
index c25f2ce19c..815d27f7f1 100644
--- a/t/t4211/sha256/expect.no-assertion-error
+++ b/t/t4211/sha256/expect.no-assertion-error
@@ -8,7 +8,7 @@ diff --git a/b.c b/b.c
 index 69cb69c..a0d566e 100644
 --- a/b.c
 +++ b/b.c
-@@ -25,0 +18,9 @@
+@@ -24,0 +18,9 @@
 +long f(long x)
 +{
 +	int s = 0;
diff --git a/t/t4211/sha256/expect.vanishes-early b/t/t4211/sha256/expect.vanishes-early
index bc33b963dc..263fc9eaac 100644
--- a/t/t4211/sha256/expect.vanishes-early
+++ b/t/t4211/sha256/expect.vanishes-early
@@ -8,7 +8,7 @@ diff --git a/a.c b/a.c
 index e4fa1d8..62c1fc2 100644
 --- a/a.c
 +++ b/a.c
-@@ -23,0 +24,1 @@ int main ()
+@@ -22,0 +24 @@ int main ()
 +/* incomplete lines are bad! */
 
 commit 29f32ac3141c48b22803e5c4127b719917b67d0f8ca8c5248bebfa2a19f7da10
@@ -21,7 +21,7 @@ diff --git a/a.c b/a.c
 index d325124..e4fa1d8 100644
 --- a/a.c
 +++ b/a.c
-@@ -22,1 +22,1 @@ int main ()
+@@ -22 +22 @@ int main ()
 -}
 +}
 \ No newline at end of file
@@ -37,5 +37,5 @@ new file mode 100644
 index 0000000..9f550c3
 --- /dev/null
 +++ b/a.c
-@@ -0,0 +20,1 @@
+@@ -0,0 +20 @@
 +}
diff --git a/xdiff-interface.c b/xdiff-interface.c
index db6938689f..686db8bb8b 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -91,6 +91,25 @@ static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
 	return 0;
 }
 
+static int strbuf_out_line(void *priv, mmbuffer_t *mb, int nbuf)
+{
+	struct strbuf *out = priv;
+	int i;
+	for (i = 0; i < nbuf; i++)
+		strbuf_add(out, mb[i].ptr, mb[i].size);
+	return 0;
+}
+
+void xdiff_emit_hunk_header(struct strbuf *out,
+			    long old_begin, long old_count,
+			    long new_begin, long new_count,
+			    const char *func, long funclen)
+{
+	xdemitcb_t ecb = { .priv = out, .out_line = strbuf_out_line };
+	xdl_emit_hunk_hdr(old_begin, old_count, new_begin, new_count,
+			  func, funclen, &ecb);
+}
+
 /*
  * Trim down common substring at the end of the buffers,
  * but end on a complete line.
diff --git a/xdiff-interface.h b/xdiff-interface.h
index ce54e1c0e0..2428456629 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -76,4 +76,17 @@ int xdiff_compare_lines(const char *l1, long s1,
  */
 unsigned long xdiff_hash_string(const char *s, size_t len, long flags);
 
+struct strbuf;
+
+/*
+ * Append a unified-diff hunk header to `out`, e.g.
+ * "@@ -<old> +<new> @@ func\n". The header comes from wrapping xdiff's
+ * own hunk-header emitter, so it matches what a normal diff would
+ * produce for the given line number begins and line counts.
+ */
+void xdiff_emit_hunk_header(struct strbuf *out,
+			    long old_begin, long old_nr,
+			    long new_begin, long new_nr,
+			    const char *func, long funclen);
+
 #endif
-- 
gitgitgadget


  parent reply	other threads:[~2026-09-03  5:05 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-18 18:16 [PATCH 0/7] line-log: range-scope stat, check, and -G under -L Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 1/7] diff: rename and group the line-range filter for clarity Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 2/7] diff: simplify the line-range filter by classifying removals immediately Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 3/7] diff: emit -L hunk headers via xdiff's formatter Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 4/7] diff: extract a line-range diff helper for reuse Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 5/7] line-log: support diff stat formats with -L Michael Montalbo via GitGitGadget
2026-06-18 22:00   ` Junio C Hamano
2026-06-23  2:25     ` Michael Montalbo
2026-06-18 18:16 ` [PATCH 6/7] diff: support --check with -L line ranges Michael Montalbo via GitGitGadget
2026-06-18 18:16 ` [PATCH 7/7] diffcore-pickaxe: scope -G to the -L tracked range Michael Montalbo via GitGitGadget
2026-06-27 17:28 ` [PATCH v2 0/7] line-log: scope stat, check, and -G to -L line ranges Michael Montalbo via GitGitGadget
2026-06-27 17:28   ` [PATCH v2 1/7] diff: rename and group the line-range filter for clarity Michael Montalbo via GitGitGadget
2026-06-27 17:28   ` [PATCH v2 2/7] diff: simplify the line-range filter by classifying removals immediately Michael Montalbo via GitGitGadget
2026-06-27 17:28   ` [PATCH v2 3/7] diff: emit -L hunk headers via xdiff's formatter Michael Montalbo via GitGitGadget
2026-06-27 17:28   ` [PATCH v2 4/7] diff: extract a line-range diff helper for reuse Michael Montalbo via GitGitGadget
2026-06-27 17:28   ` [PATCH v2 5/7] line-log: support diff stat formats with -L Michael Montalbo via GitGitGadget
2026-06-27 17:29   ` [PATCH v2 6/7] diff: support --check with -L line ranges Michael Montalbo via GitGitGadget
2026-06-27 17:29   ` [PATCH v2 7/7] diffcore-pickaxe: scope -G to the -L tracked range Michael Montalbo via GitGitGadget
2026-07-15 21:05 ` [PATCH 0/7] line-log: range-scope stat, check, and -G under -L Michael Montalbo
2026-09-03  5:05 ` [PATCH v3 0/7] line-log: scope stat, check, and -G to -L line ranges Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` [PATCH v3 1/7] diff: rename line-range filter struct and clarify fields Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` [PATCH v3 2/7] diff: simplify the line-range filter by classifying removals immediately Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` Michael Montalbo via GitGitGadget [this message]
2026-09-03  5:05   ` [PATCH v3 4/7] diff: extract a line-range diff helper for reuse Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` [PATCH v3 5/7] diff: support stat formats with -L Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` [PATCH v3 6/7] diff: support --check with -L line ranges Michael Montalbo via GitGitGadget
2026-09-03  5:05   ` [PATCH v3 7/7] diffcore-pickaxe: limit -G to the -L tracked range Michael Montalbo via GitGitGadget

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2081d5d257d65b7b823fc46777e952a2f650e6dd.1788411919.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=mmontalbo@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.