@@ -29,12 +29,11 @@ static int diffgrep_consume(void *priv, char *line, unsigned long len)
if (line[0] != '+' && line[0] != '-')
return 0;
if (data->hit)
- /*
- * NEEDSWORK: we should have a way to terminate the
- * caller early.
- */
- return 0;
- data->hit = patmatch(grep_pat, line + 1, line + len + 1, ®match, 0);
+ BUG("Already matched in diffgrep_consume! Broken xdiff_emit_line_fn?");
+ if (patmatch(grep_pat, line + 1, line + len + 1, ®match, 0)) {
+ data->hit = 1;
+ return -1;
+ }
return 0;
}
@@ -47,6 +46,7 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
xdemitconf_t xecfg;
regmatch_t regmatch;
struct grep_pat *grep_pat = grep_filter->pattern_list;
+ int ret;
if (!one)
return patmatch(grep_pat, two->ptr, two->ptr + two->size,
@@ -65,10 +65,19 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
ecbdata.hit = 0;
xecfg.ctxlen = 0;
xecfg.interhunkctxlen = o->interhunkcontext;
- if (xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume,
- &ecbdata, &xpp, &xecfg))
- return 0;
- return ecbdata.hit;
+
+ /*
+ * An xdiff error might be our "data->hit" from above. See the
+ * comment for xdiff_emit_{line,hunk}_fn in xdiff-interface.h
+ * for why.
+ */
+ ret = xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume,
+ &ecbdata, &xpp, &xecfg);
+ if (ecbdata.hit)
+ return 1;
+ if (ret)
+ return ret;
+ return 0;
}
static unsigned int contains(mmfile_t *mf, struct grep_opt *grep_filter)
@@ -25,6 +25,11 @@
* granular return values, but for now use it carefully, or consider
* e.g. using discard_hunk_line() if you say just don't care about
* hunk headers.
+ *
+ * Note that just returning -1 will make your early return
+ * indistinguishable from an error internal to xdiff. See "diff_grep"
+ * in diffcore-pickaxe.c for a trick to work around this, i.e. using
+ * the "consume_callback_data" to note the desired early return.
*/
typedef int (*xdiff_emit_line_fn)(void *, char *, unsigned long);
typedef int (*xdiff_emit_hunk_fn)(void *data,
Solve a long-standing item for "git log -Grx" of us e.g. finding "+ str" in the diff context and noting that we had a "hit", but xdiff diligently continuing to generate and spew the rest of the diff at us. The TODO item has been there since "git log -G" was implemented. See f506b8e8b5f (git log/diff: add -G<regexp> that greps in the patch text, 2010-08-23). Our xdiff interface also had the limitation of not being able to abort early since the beginning, see d9ea73e0564 (combine-diff: refactor built-in xdiff interface., 2006-04-05). Although at that time "xdiff_emit_line_fn" was called "xdiff_emit_consume_fn", and "xdiff_emit_hunk_fn" didn't exist yet. But now with the support added in the preceding ""xdiff-interface: allow early return from xdiff_emit_{line,hunk}_fn" commit we can return early, and furthermore test the functionality of the new early-exit xdiff-interface by having a BUG() call here to die if it ever starts handing us needless work again. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> --- diffcore-pickaxe.c | 29 +++++++++++++++++++---------- xdiff-interface.h | 5 +++++ 2 files changed, 24 insertions(+), 10 deletions(-)