diff options
author | Junio C Hamano <gitster@pobox.com> | 2010-09-12 22:15:35 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-09-13 01:11:55 -0700 |
commit | 5aaeb733f5745b37878901c4687ba67c6a70e581 (patch) | |
tree | 073bd6553e10f0c654a3e15e18c9c5bd52e055c5 /grep.c | |
parent | 95ce9ce296e1636a2b78e73b96905d781ef2ddc7 (diff) | |
download | git-5aaeb733f5745b37878901c4687ba67c6a70e581.tar.gz |
log --author: take union of multiple "author" requests
In the olden days,
log --author=me --committer=him --grep=this --grep=that
used to be turned into:
(OR (HEADER-AUTHOR me)
(HEADER-COMMITTER him)
(PATTERN this)
(PATTERN that))
showing my patches that do not have any "this" nor "that", which was
totally useless.
80235ba ("log --author=me --grep=it" should find intersection, not union,
2010-01-17) improved it greatly to turn the same into:
(ALL-MATCH
(HEADER-AUTHOR me)
(HEADER-COMMITTER him)
(OR (PATTERN this) (PATTERN that)))
That is, "show only patches by me and committed by him, that have either
this or that", which is a lot more natural thing to ask.
We however need to be a bit more clever when the user asks more than one
"author" (or "committer"); because a commit has only one author (and one
committer), they ought to be interpreted as asking for union to be useful.
The current implementation simply added another author/committer pattern
at the same top-level for ALL-MATCH to insist on matching all, finding
nothing.
Turn
log --author=me --author=her \
--committer=him --committer=you \
--grep=this --grep=that
into
(ALL-MATCH
(OR (HEADER-AUTHOR me) (HEADER-AUTHOR her))
(OR (HEADER-COMMITTER him) (HEADER-COMMITTER you))
(OR (PATTERN this) (PATTERN that)))
instead.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'grep.c')
-rw-r--r-- | grep.c | 65 |
1 files changed, 53 insertions, 12 deletions
@@ -189,17 +189,32 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list) return compile_pattern_or(list); } +static struct grep_expr *grep_true_expr(void) +{ + struct grep_expr *z = xcalloc(1, sizeof(*z)); + z->node = GREP_NODE_TRUE; + return z; +} + +static struct grep_expr *grep_or_expr(struct grep_expr *left, struct grep_expr *right) +{ + struct grep_expr *z = xcalloc(1, sizeof(*z)); + z->node = GREP_NODE_OR; + z->u.binary.left = left; + z->u.binary.right = right; + return z; +} + static struct grep_expr *prep_header_patterns(struct grep_opt *opt) { struct grep_pat *p; struct grep_expr *header_expr; + struct grep_expr *(header_group[GREP_HEADER_FIELD_MAX]); + enum grep_header_field fld; if (!opt->header_list) return NULL; p = opt->header_list; - header_expr = compile_pattern_expr(&p); - if (p) - die("incomplete pattern expression: %s", p->pattern); for (p = opt->header_list; p; p = p->next) { if (p->token != GREP_PATTERN_HEAD) die("bug: a non-header pattern in grep header list."); @@ -207,6 +222,33 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt) die("bug: unknown header field %d", p->field); compile_regexp(p, opt); } + + for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) + header_group[fld] = NULL; + + for (p = opt->header_list; p; p = p->next) { + struct grep_expr *h; + struct grep_pat *pp = p; + + h = compile_pattern_atom(&pp); + if (!h || pp != p->next) + die("bug: malformed header expr"); + if (!header_group[p->field]) { + header_group[p->field] = h; + continue; + } + header_group[p->field] = grep_or_expr(h, header_group[p->field]); + } + + header_expr = NULL; + + for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) { + if (!header_group[fld]) + continue; + if (!header_expr) + header_expr = grep_true_expr(); + header_expr = grep_or_expr(header_group[fld], header_expr); + } return header_expr; } @@ -242,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt) if (!header_expr) return; - if (opt->pattern_expression) { - struct grep_expr *z; - z = xcalloc(1, sizeof(*z)); - z->node = GREP_NODE_OR; - z->u.binary.left = opt->pattern_expression; - z->u.binary.right = header_expr; - opt->pattern_expression = z; - } else { + if (!opt->pattern_expression) opt->pattern_expression = header_expr; - } + else + opt->pattern_expression = grep_or_expr(opt->pattern_expression, + header_expr); opt->all_match = 1; } static void free_pattern_expr(struct grep_expr *x) { switch (x->node) { + case GREP_NODE_TRUE: case GREP_NODE_ATOM: break; case GREP_NODE_NOT: @@ -486,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, if (!x) die("Not a valid grep expression"); switch (x->node) { + case GREP_NODE_TRUE: + h = 1; + break; case GREP_NODE_ATOM: h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); break; |