Browse Source

grep -p: support user defined regular expressions

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>
maint
René Scharfe 16 years ago committed by Junio C Hamano
parent
commit
60ecac98ed
  1. 3
      Documentation/git-grep.txt
  2. 7
      builtin-grep.c
  3. 29
      grep.c
  4. 1
      grep.h
  5. 13
      t/t7002-grep.sh

3
Documentation/git-grep.txt

@ -126,6 +126,9 @@ OPTIONS
--show-function:: --show-function::
Show the preceding line that contains the function name of Show the preceding line that contains the function name of
the match, unless the matching line is a function name itself. 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>:: -f <file>::
Read patterns from <file>, one per line. Read patterns from <file>, one per line.

7
builtin-grep.c

@ -11,6 +11,7 @@
#include "tree-walk.h" #include "tree-walk.h"
#include "builtin.h" #include "builtin.h"
#include "parse-options.h" #include "parse-options.h"
#include "userdiff.h"
#include "grep.h" #include "grep.h"


#ifndef NO_EXTERNAL_GREP #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; 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")) { if (!strcmp(var, "color.grep")) {
opt->color = git_config_colorbool(var, value, -1); opt->color = git_config_colorbool(var, value, -1);
return 0; return 0;

29
grep.c

@ -1,5 +1,6 @@
#include "cache.h" #include "cache.h"
#include "grep.h" #include "grep.h"
#include "userdiff.h"
#include "xdiff-interface.h" #include "xdiff-interface.h"


void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat) 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); 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) if (bol == eol)
return 0; return 0;
if (isalpha(*bol) || *bol == '_' || *bol == '$') 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) if (lno <= opt->last_shown)
break; break;


if (match_funcname(bol, eol)) { if (match_funcname(opt, bol, eol)) {
show_line(opt, bol, eol, name, lno, '='); show_line(opt, bol, eol, name, lno, '=');
break; 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') while (bol > buf && bol[-1] != '\n')
bol--; bol--;
cur--; cur--;
if (funcname_needed && match_funcname(bol, eol)) { if (funcname_needed && match_funcname(opt, bol, eol)) {
funcname_lno = cur; funcname_lno = cur;
funcname_needed = 0; funcname_needed = 0;
} }
@ -614,6 +622,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
int binary_match_only = 0; int binary_match_only = 0;
unsigned count = 0; unsigned count = 0;
enum grep_context ctx = GREP_CONTEXT_HEAD; enum grep_context ctx = GREP_CONTEXT_HEAD;
xdemitconf_t xecfg;


opt->last_shown = 0; 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) { while (left) {
char *eol, ch; char *eol, ch;
int hit; int hit;
@ -711,6 +731,9 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
return 1; return 1;
} }


xdiff_clear_find_func(&xecfg);
opt->priv = NULL;

/* NEEDSWORK: /* NEEDSWORK:
* The real "grep -c foo *.c" gives many "bar.c:0" lines, * The real "grep -c foo *.c" gives many "bar.c:0" lines,
* which feels mostly useless but sometimes useful. Maybe * which feels mostly useless but sometimes useful. Maybe

1
grep.h

@ -87,6 +87,7 @@ struct grep_opt {
unsigned post_context; unsigned post_context;
unsigned last_shown; unsigned last_shown;
int show_hunk_mark; 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); extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);

13
t/t7002-grep.sh

@ -243,12 +243,25 @@ test_expect_success 'grep with CE_VALID file' '
git checkout t/t 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 cat >expected <<EOF
hello.c=int main(int argc, const char **argv) hello.c=int main(int argc, const char **argv)
hello.c: return 0; hello.c: return 0;
EOF EOF


test_expect_success 'grep -p' ' test_expect_success 'grep -p' '
rm -f .gitattributes &&
git grep -p return >actual && git grep -p return >actual &&
test_cmp expected actual test_cmp expected actual
' '

Loading…
Cancel
Save