mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-29 05:54:10 -05:00
diff: extract a line-range diff helper for reuse
builtin_diff() open-codes the line-range filter setup and teardown around its xdi_diff_outf() call: zero the struct, point it at the output callback, inflate ctxlen to the largest range span so each range yields a single xdiff hunk, run the diff, flush the trailing range hunk, and release the buffer. The upcoming -L stat and check formats need the same sequence. Extract line_range_filter_init() for the setup and a line_range_filter_diff() helper that prepares the xdiff config the filter needs, runs an initialized filter through xdi_diff_outf(), flushes the final range hunk, and releases it, returning the latched error. The helper inflates ctxlen to the largest range span so each range yields a single xdiff hunk, and clears XDL_EMIT_NO_HUNK_HDR so the hunk headers the filter seeds its position from are always emitted. Folding both into the helper keeps these invariants, which the filter's position tracking relies on, in a single place for every consumer. builtin_diff() now does init + line_range_filter_diff(); the next two patches reuse them in builtin_diffstat() and builtin_checkdiff() instead of repeating the boilerplate. No behavior change: builtin_diff() leaves XDL_EMIT_NO_HUNK_HDR unset, so clearing it is a no-op until the suppressing consumers arrive. Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
3e0ea8b284
commit
84532f64fd
100
diff.c
100
diff.c
@@ -2580,6 +2580,18 @@ static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void line_range_filter_init(struct line_range_filter *filter,
|
||||
const struct range_set *ranges,
|
||||
xdiff_emit_line_fn line_fn,
|
||||
void *cb_data)
|
||||
{
|
||||
memset(filter, 0, sizeof(*filter));
|
||||
filter->orig_line_fn = line_fn;
|
||||
filter->orig_cb_data = cb_data;
|
||||
filter->ranges = ranges;
|
||||
strbuf_init(&filter->hunk.lines, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin a range hunk at the first in-range line. Its position fixes the
|
||||
* hunk's begins, taken from the two image cursors before they advance:
|
||||
@@ -2744,6 +2756,50 @@ static int line_range_line_fn(void *priv, char *line, unsigned long len)
|
||||
return filter->ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run an xdiff pass through an initialized line-range filter, flush the
|
||||
* final range hunk, and release the filter. Inflates ctxlen to the largest
|
||||
* range span first, so that every change within a single range lands in one
|
||||
* xdiff hunk and the inter-change context is emitted; the filter then clips
|
||||
* back to range boundaries. The optimal ctxlen depends on where changes fall
|
||||
* within the range, which is only known after xdiff runs, so the max span is
|
||||
* the upper bound that guarantees correctness in a single pass. Every
|
||||
* consumer (patch, diffstat, check) relies on one xdiff hunk per range, so
|
||||
* this lives here rather than at each call site. Also clears
|
||||
* XDL_EMIT_NO_HUNK_HDR: the filter seeds its per-image position from the hunk
|
||||
* headers, so a consumer that otherwise suppresses them (diffstat) still gets
|
||||
* them here. Returns non-zero if xdiff or any forwarded callback failed.
|
||||
*/
|
||||
static int line_range_filter_diff(struct line_range_filter *filter,
|
||||
mmfile_t *mf1, mmfile_t *mf2,
|
||||
xpparam_t *xpp, xdemitconf_t *xecfg)
|
||||
{
|
||||
const struct range_set *ranges = filter->ranges;
|
||||
long max_span = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ranges->nr; i++) {
|
||||
long span = ranges->ranges[i].end - ranges->ranges[i].start;
|
||||
if (span > max_span)
|
||||
max_span = span;
|
||||
}
|
||||
if (max_span > xecfg->ctxlen)
|
||||
xecfg->ctxlen = max_span;
|
||||
|
||||
/* the filter seeds its per-image position from hunk headers */
|
||||
xecfg->flags &= ~XDL_EMIT_NO_HUNK_HDR;
|
||||
|
||||
ret = xdi_diff_outf(mf1, mf2, line_range_hunk_fn,
|
||||
line_range_line_fn, filter, xpp, xecfg);
|
||||
if (!ret) {
|
||||
flush_range_hunk(filter);
|
||||
ret = filter->ret;
|
||||
}
|
||||
strbuf_release(&filter->hunk.lines);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
|
||||
{
|
||||
const char *old_name = a;
|
||||
@@ -4108,49 +4164,15 @@ static void builtin_diff(const char *name_a,
|
||||
xdi_diff_outf(&mf1, &mf2, NULL, quick_consume,
|
||||
&ecbdata, &xpp, &xecfg);
|
||||
} else if (line_ranges) {
|
||||
struct line_range_filter lr_state;
|
||||
unsigned int i;
|
||||
long max_span = 0;
|
||||
struct line_range_filter lr_filter;
|
||||
|
||||
memset(&lr_state, 0, sizeof(lr_state));
|
||||
lr_state.orig_line_fn = fn_out_consume;
|
||||
lr_state.orig_cb_data = &ecbdata;
|
||||
lr_state.ranges = line_ranges;
|
||||
strbuf_init(&lr_state.hunk.lines, 0);
|
||||
line_range_filter_init(&lr_filter, line_ranges,
|
||||
fn_out_consume, &ecbdata);
|
||||
|
||||
/*
|
||||
* Inflate ctxlen so that all changes within
|
||||
* any single range are merged into one xdiff
|
||||
* hunk and the inter-change context is emitted.
|
||||
* The callback clips back to range boundaries.
|
||||
*
|
||||
* The optimal ctxlen depends on where changes
|
||||
* fall within the range, which is only known
|
||||
* after xdiff runs; the max range span is the
|
||||
* upper bound that guarantees correctness in a
|
||||
* single pass.
|
||||
*/
|
||||
for (i = 0; i < line_ranges->nr; i++) {
|
||||
long span = line_ranges->ranges[i].end -
|
||||
line_ranges->ranges[i].start;
|
||||
if (span > max_span)
|
||||
max_span = span;
|
||||
}
|
||||
if (max_span > xecfg.ctxlen)
|
||||
xecfg.ctxlen = max_span;
|
||||
|
||||
if (xdi_diff_outf(&mf1, &mf2,
|
||||
line_range_hunk_fn,
|
||||
line_range_line_fn,
|
||||
&lr_state, &xpp, &xecfg))
|
||||
if (line_range_filter_diff(&lr_filter, &mf1, &mf2,
|
||||
&xpp, &xecfg))
|
||||
die("unable to generate diff for %s",
|
||||
one->path);
|
||||
|
||||
flush_range_hunk(&lr_state);
|
||||
if (lr_state.ret)
|
||||
die("unable to generate diff for %s",
|
||||
one->path);
|
||||
strbuf_release(&lr_state.hunk.lines);
|
||||
} else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
|
||||
&ecbdata, &xpp, &xecfg))
|
||||
die("unable to generate diff for %s", one->path);
|
||||
|
||||
Reference in New Issue
Block a user