From: "Bhushan G. Lodha & David A. Dalrymple" <[email protected]>
This is similar to the pickaxe grep option (-G), but applies the
provided regex only to diff hunk headers, thereby showing only those
commits which affect a "function" with a definition line matching the
pattern. These are "functions" in the same sense as with
--function-context, i.e., they may be classes, structs, etc. depending
on the programming-language-specific pattern specified by the "diff"
attribute in .gitattributes.
builtin/log.c:
as with pickaxe, set always_show_header when using --function-name
diff.c:
parse option; as with pickaxe, always set the RECURSIVE option
for --function-name
diff.h:
include "funcname" field in struct diff_options
diffcore-pickaxe.c:
implementation of --function-name filtering (diffcore_funcname), like
the existing diffcore_pickaxe_grep and diffcore_pickaxe_count
revision.c:
as with pickaxe, set revs->diff to always generate diffs when
using --function-name
Signed-off-by: David Dalrymple (on zayin) <[email protected]>
---
builtin/log.c | 2 +-
diff.c | 8 +++++--
diff.h | 1 +
diffcore-pickaxe.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
revision.c | 3 ++-
5 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/builtin/log.c b/builtin/log.c
index b97373d..78694de 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -158,7 +158,7 @@ static void cmd_log_init_finish(int argc, const char
**argv, const char *prefix,
if (rev->show_notes)
init_display_notes(&rev->notes_opt);
- if (rev->diffopt.pickaxe || rev->diffopt.filter)
+ if (rev->diffopt.pickaxe || rev->diffopt.filter ||
rev->diffopt.funcname)
rev->always_show_header = 0;
if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
rev->always_show_header = 0;
diff --git a/diff.c b/diff.c
index f978ee7..2f6dbc1 100644
--- a/diff.c
+++ b/diff.c
@@ -3298,7 +3298,7 @@ void diff_setup_done(struct diff_options *options)
/*
* Also pickaxe would not work very well if you do not say recursive
*/
- if (options->pickaxe)
+ if (options->pickaxe || options->funcname)
DIFF_OPT_SET(options, RECURSIVE);
/*
* When patches are generated, submodules diffed against the work tree
@@ -3821,6 +3821,10 @@ int diff_opt_parse(struct diff_options *options, const
char **av, int ac)
options->orderfile = optarg;
return argcount;
}
+ else if ((argcount = parse_long_opt("function-name", av, &optarg))) {
+ options->funcname = optarg;
+ return argcount;
+ }
else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
int offending = parse_diff_filter_opt(optarg, options);
if (offending)
@@ -4768,7 +4772,7 @@ void diffcore_std(struct diff_options *options)
if (options->break_opt != -1)
diffcore_merge_broken();
}
- if (options->pickaxe)
+ if (options->pickaxe || options->funcname)
diffcore_pickaxe(options);
if (options->orderfile)
diffcore_order(options->orderfile);
diff --git a/diff.h b/diff.h
index 9e96fc9..0fd5f1d 100644
--- a/diff.h
+++ b/diff.h
@@ -107,6 +107,7 @@ enum diff_words_type {
struct diff_options {
const char *orderfile;
const char *pickaxe;
+ const char *funcname;
const char *single_follow;
const char *a_prefix, *b_prefix;
unsigned flags;
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 103fe6c..259a8fa 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -67,6 +67,12 @@ struct diffgrep_cb {
int hit;
};
+struct funcname_cb {
+ struct userdiff_funcname *pattern;
+ regex_t *regex;
+ int hit;
+};
+
static void diffgrep_consume(void *priv, char *line, unsigned long len)
{
struct diffgrep_cb *data = priv;
@@ -88,6 +94,20 @@ static void diffgrep_consume(void *priv, char *line,
unsigned long len)
line[len] = hold;
}
+static void match_funcname(void *priv, char *line, unsigned long len)
+{
+ regmatch_t regmatch;
+ int hold;
+ struct funcname_cb *data = priv;
+ hold = line[len];
+ line[len] = '\0';
+
+ if (line[0] == '@' && line[1] == '@')
+ if (!regexec(data->regex, line, 1, ®match, 0))
+ data->hit = 1;
+ line[len] = hold;
+}
+
static int diff_grep(mmfile_t *one, mmfile_t *two,
struct diff_options *o,
struct fn_options *fno)
@@ -117,6 +137,38 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
return ecbdata.hit;
}
+static int diff_funcname_filter(mmfile_t *one, mmfile_t *two,
+ struct diff_options *o,
+ struct fn_options *fno)
+{
+ struct funcname_cb ecbdata;
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
+
+ mmfile_t empty;
+ empty.ptr = "";
+ empty.size = 0;
+ if (!one)
+ one = ∅
+ if (!two)
+ two = ∅
+ memset(&xpp, 0, sizeof(xpp));
+ memset(&xecfg, 0, sizeof(xecfg));
+ ecbdata.regex = fno->regex;
+ ecbdata.hit = 0;
+ xecfg.ctxlen = o->context;
+
+ if (fno->funcname_pattern)
+ xdiff_set_find_func(&xecfg, fno->funcname_pattern->pattern,
+ fno->funcname_pattern->cflags);
+ xecfg.interhunkctxlen = o->interhunkcontext;
+ if (!(one && two))
+ xecfg.flags = XDL_EMIT_FUNCCONTEXT;
+ xecfg.flags |= XDL_EMIT_FUNCNAMES;
+ xdi_diff_outf(one, two, match_funcname, &ecbdata, &xpp, &xecfg);
+ return ecbdata.hit;
+}
+
static void diffcore_pickaxe_grep(struct diff_options *o)
{
regex_t regex;
@@ -204,7 +256,7 @@ static int pickaxe_match(struct diff_filepair *p, struct
diff_options *o,
mmfile_t mf1, mf2;
int ret;
- if (!o->pickaxe[0])
+ if (o->pickaxe && !o->pickaxe[0])
return 0;
/* ignore unmerged */
@@ -280,11 +332,24 @@ static void diffcore_pickaxe_count(struct diff_options *o)
return;
}
+static void diffcore_funcname(struct diff_options *o)
+{
+ struct fn_options fno;
+ regex_t regex;
+
+ fno.regex = ®ex;
+ compile_regex(®ex, o->funcname, REG_EXTENDED | REG_NEWLINE);
+ pickaxe(&diff_queued_diff, o, diff_funcname_filter, &fno);
+ regfree(®ex);
+}
+
void diffcore_pickaxe(struct diff_options *o)
{
+ if (o->funcname)
+ diffcore_funcname(o);
/* Might want to warn when both S and G are on; I don't care... */
if (o->pickaxe_opts & DIFF_PICKAXE_KIND_G)
diffcore_pickaxe_grep(o);
- else
+ else if (o-> pickaxe_opts & DIFF_PICKAXE_KIND_S)
diffcore_pickaxe_count(o);
}
diff --git a/revision.c b/revision.c
index 8508550..d81d9b9 100644
--- a/revision.c
+++ b/revision.c
@@ -2211,8 +2211,9 @@ int setup_revisions(int argc, const char **argv, struct
rev_info *revs, struct s
if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)
revs->diff = 1;
- /* Pickaxe, diff-filter and rename following need diffs */
+ /* Pickaxe, funcname, diff-filter and rename following need diffs */
if (revs->diffopt.pickaxe ||
+ revs->diffopt.funcname ||
revs->diffopt.filter ||
DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
revs->diff = 1;
--
1.7.12.4 (Apple Git-37)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html