Code

grep -p: support user defined regular expressions
authorRené Scharfe <rene.scharfe@lsrfire.ath.cx>
Wed, 1 Jul 2009 22:07:24 +0000 (00:07 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Jul 2009 02:16:50 +0000 (19:16 -0700)
Respect the userdiff attributes and config settings when looking for
lines with function definitions in git grep -p.

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-grep.txt
builtin-grep.c
grep.c
grep.h
t/t7002-grep.sh

index b3bb2836444fff2964deb47d1e8e2f6c36b1fe50..b753c9d76fde51198eb7ef34b9ff298095fb1f72 100644 (file)
@@ -126,6 +126,9 @@ OPTIONS
 --show-function::
        Show the preceding line that contains the function name of
        the match, unless the matching line is a function name itself.
+       The name is determined in the same way as 'git diff' works out
+       patch hunk headers (see 'Defining a custom hunk-header' in
+       linkgit:gitattributes[5]).
 
 -f <file>::
        Read patterns from <file>, one per line.
index 037452ec79475244f4cae7cfc936695e1de58a63..9343cc5e5dc66e6e47b15d49de71df39a24050bf 100644 (file)
@@ -11,6 +11,7 @@
 #include "tree-walk.h"
 #include "builtin.h"
 #include "parse-options.h"
+#include "userdiff.h"
 #include "grep.h"
 
 #ifndef NO_EXTERNAL_GREP
@@ -30,6 +31,12 @@ static int grep_config(const char *var, const char *value, void *cb)
 {
        struct grep_opt *opt = cb;
 
+       switch (userdiff_config(var, value)) {
+       case 0: break;
+       case -1: return -1;
+       default: return 0;
+       }
+
        if (!strcmp(var, "color.grep")) {
                opt->color = git_config_colorbool(var, value, -1);
                return 0;
diff --git a/grep.c b/grep.c
index 3a5c138476e5bc643656ec7a6e41da9fa3168969..c47785a2f0df79fd5ee8bc77a165fb0be3811091 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "grep.h"
+#include "userdiff.h"
 #include "xdiff-interface.h"
 
 void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
@@ -535,8 +536,15 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
        printf("%.*s\n", rest, bol);
 }
 
-static int match_funcname(char *bol, char *eol)
+static int match_funcname(struct grep_opt *opt, char *bol, char *eol)
 {
+       xdemitconf_t *xecfg = opt->priv;
+       if (xecfg && xecfg->find_func) {
+               char buf[1];
+               return xecfg->find_func(bol, eol - bol, buf, 1,
+                                       xecfg->find_func_priv) >= 0;
+       }
+
        if (bol == eol)
                return 0;
        if (isalpha(*bol) || *bol == '_' || *bol == '$')
@@ -557,7 +565,7 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
                if (lno <= opt->last_shown)
                        break;
 
-               if (match_funcname(bol, eol)) {
+               if (match_funcname(opt, bol, eol)) {
                        show_line(opt, bol, eol, name, lno, '=');
                        break;
                }
@@ -582,7 +590,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
                while (bol > buf && bol[-1] != '\n')
                        bol--;
                cur--;
-               if (funcname_needed && match_funcname(bol, eol)) {
+               if (funcname_needed && match_funcname(opt, bol, eol)) {
                        funcname_lno = cur;
                        funcname_needed = 0;
                }
@@ -614,6 +622,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
        int binary_match_only = 0;
        unsigned count = 0;
        enum grep_context ctx = GREP_CONTEXT_HEAD;
+       xdemitconf_t xecfg;
 
        opt->last_shown = 0;
 
@@ -630,6 +639,17 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
                }
        }
 
+       memset(&xecfg, 0, sizeof(xecfg));
+       if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
+           !opt->name_only && !binary_match_only && !collect_hits) {
+               struct userdiff_driver *drv = userdiff_find_by_path(name);
+               if (drv && drv->funcname.pattern) {
+                       const struct userdiff_funcname *pe = &drv->funcname;
+                       xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
+                       opt->priv = &xecfg;
+               }
+       }
+
        while (left) {
                char *eol, ch;
                int hit;
@@ -711,6 +731,9 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
                return 1;
        }
 
+       xdiff_clear_find_func(&xecfg);
+       opt->priv = NULL;
+
        /* NEEDSWORK:
         * The real "grep -c foo *.c" gives many "bar.c:0" lines,
         * which feels mostly useless but sometimes useful.  Maybe
diff --git a/grep.h b/grep.h
index 3f75e3a3d4d3136d850b8c0204206f5ac9459a1d..f00db0e40273c7cca1695ddc6be00921f9da8ef4 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -87,6 +87,7 @@ struct grep_opt {
        unsigned post_context;
        unsigned last_shown;
        int show_hunk_mark;
+       void *priv;
 };
 
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
index ef59ab9941ffb3bafc0bd45ebbee02e7a117c527..b13aa7e89ad51566979ab674baa2ac36c7e33da6 100755 (executable)
@@ -243,12 +243,25 @@ test_expect_success 'grep with CE_VALID file' '
        git checkout t/t
 '
 
+cat >expected <<EOF
+hello.c=#include <stdio.h>
+hello.c:       return 0;
+EOF
+
+test_expect_success 'grep -p with userdiff' '
+       git config diff.custom.funcname "^#" &&
+       echo "hello.c diff=custom" >.gitattributes &&
+       git grep -p return >actual &&
+       test_cmp expected actual
+'
+
 cat >expected <<EOF
 hello.c=int main(int argc, const char **argv)
 hello.c:       return 0;
 EOF
 
 test_expect_success 'grep -p' '
+       rm -f .gitattributes &&
        git grep -p return >actual &&
        test_cmp expected actual
 '