[PATCH v3 3/7] diff: emit -L hunk headers via xdiff's formatter
- From
Michael Montalbo via GitGitGadget <gitgitgadget@gmail.com>
- Date
- Sep 3, 2026, 05:05 UTC
- Message-ID
- <2081d5d257d65b7b823fc46777e952a2f650e6dd.1788411919.git.gitgitgadget@gmail.com>
- 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