From: "Bhushan G. Lodha & David A. Dalrymple" <dad-...@mit.edu>

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) <davi...@alum.mit.edu>
---
 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, &regmatch, 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 = &empty;
+       if (!two)
+               two = &empty;
+       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 = &regex;
+       compile_regex(&regex, o->funcname, REG_EXTENDED | REG_NEWLINE);
+       pickaxe(&diff_queued_diff, o, diff_funcname_filter, &fno);
+       regfree(&regex);
+}
+
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to