@matheusbsbs / matheus-bagliano / commits / 2944e4e614
Fork 0

grep: add option -p/--show-function

The new option -p instructs git grep to print the previous function definition as a context line, similar to diff -p. Such context lines are marked with an equal sign instead of a dash. This option complements the existing context options -A, -B, -C. Function definitions are detected using the same heuristic that diff uses. User defined regular expressions are not supported, yet. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Jul 2, 2009 at 00:06 UTC 2944e4e6145bdfcb1a8730d7da671786d72c86ed
5 files changed +98 -13
Documentation/git-grep.txt
+5
@@ -122,6 +122,11 @@ OPTIONS
122 -<num>::
123 A shortcut for specifying -C<num>.
124
125 +-p::
126 +--show-function::
127 + Show the preceding line that contains the function name of
128 + the match, unless the matching line is a function name itself.
129 +
130 -f <file>::
131 Read patterns from <file>, one per line.
132
builtin-grep.c
+5 -3
@@ -278,13 +278,13 @@ static int flush_grep(struct grep_opt *opt,
278 argc -= 2;
279 }
280
281 - if (opt->pre_context || opt->post_context) {
281 + if (opt->pre_context || opt->post_context || opt->funcname) {
282 /*
283 * grep handles hunk marks between files, but we need to
284 * do that ourselves between multiple calls.
285 */
286 if (opt->show_hunk_mark)
287 - write_or_die(1, "--\n", 3);
287 + write_or_die(1, opt->funcname ? "==\n" : "--\n", 3);
288 else
289 opt->show_hunk_mark = 1;
290 }
@@ -721,6 +721,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
721 "show <n> context lines after matches"),
722 OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
723 context_callback),
724 + OPT_BOOLEAN('p', "show-function", &opt.funcname,
725 + "show a line with the function name before matches"),
726 OPT_GROUP(""),
727 OPT_CALLBACK('f', NULL, &opt, "file",
728 "read patterns from file", file_callback),
@@ -789,7 +791,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
791 argc--;
792 }
793
792 - if (opt.color && !opt.color_external)
794 + if ((opt.color && !opt.color_external) || opt.funcname)
795 external_grep_allowed = 0;
796 if (!opt.pattern_list)
797 die("no pattern given.");
grep.c
+53 -8
@@ -490,14 +490,18 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
490 {
491 int rest = eol - bol;
492
493 - if (opt->pre_context || opt->post_context) {
493 + if (opt->pre_context || opt->post_context || opt->funcname) {
494 if (opt->last_shown == 0) {
495 if (opt->show_hunk_mark)
496 - fputs("--\n", stdout);
496 + fputs(opt->funcname ? "==\n" : "--\n", stdout);
497 else
498 opt->show_hunk_mark = 1;
499 - } else if (lno > opt->last_shown + 1)
500 - fputs("--\n", stdout);
499 + } else if (lno > opt->last_shown + 1) {
500 + if (opt->pre_context || opt->post_context)
501 + fputs((sign == '=') ? "==\n" : "--\n", stdout);
502 + else if (sign == '=')
503 + fputs("==\n", stdout);
504 + }
505 }
506 opt->last_shown = lno;
507
@@ -531,10 +535,40 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
535 printf("%.*s\n", rest, bol);
536 }
537
538 +static int match_funcname(char *bol, char *eol)
539 +{
540 + if (bol == eol)
541 + return 0;
542 + if (isalpha(*bol) || *bol == '_' || *bol == '$')
543 + return 1;
544 + return 0;
545 +}
546 +
547 +static void show_funcname_line(struct grep_opt *opt, const char *name,
548 + char *buf, char *bol, unsigned lno)
549 +{
550 + while (bol > buf) {
551 + char *eol = --bol;
552 +
553 + while (bol > buf && bol[-1] != '\n')
554 + bol--;
555 + lno--;
556 +
557 + if (lno <= opt->last_shown)
558 + break;
559 +
560 + if (match_funcname(bol, eol)) {
561 + show_line(opt, bol, eol, name, lno, '=');
562 + break;
563 + }
564 + }
565 +}
566 +
567 static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
568 char *bol, unsigned lno)
569 {
537 - unsigned cur = lno, from = 1;
570 + unsigned cur = lno, from = 1, funcname_lno = 0;
571 + int funcname_needed = opt->funcname;
572
573 if (opt->pre_context < lno)
574 from = lno - opt->pre_context;
@@ -543,19 +577,28 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
577
578 /* Rewind. */
579 while (bol > buf && cur > from) {
546 - bol--;
580 + char *eol = --bol;
581 +
582 while (bol > buf && bol[-1] != '\n')
583 bol--;
584 cur--;
585 + if (funcname_needed && match_funcname(bol, eol)) {
586 + funcname_lno = cur;
587 + funcname_needed = 0;
588 + }
589 }
590
591 + /* We need to look even further back to find a function signature. */
592 + if (opt->funcname && funcname_needed)
593 + show_funcname_line(opt, name, buf, bol, cur);
594 +
595 /* Back forward. */
596 while (cur < lno) {
554 - char *eol = bol;
597 + char *eol = bol, sign = (cur == funcname_lno) ? '=' : '-';
598
599 while (*eol != '\n')
600 eol++;
558 - show_line(opt, bol, eol, name, cur, '-');
601 + show_line(opt, bol, eol, name, cur, sign);
602 bol = eol + 1;
603 cur++;
604 }
@@ -635,6 +678,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
678 */
679 if (opt->pre_context)
680 show_pre_context(opt, name, buf, bol, lno);
681 + else if (opt->funcname)
682 + show_funcname_line(opt, name, buf, bol, lno);
683 if (!opt->count)
684 show_line(opt, bol, eol, name, lno, ':');
685 last_hit = lno;
grep.h
+1
@@ -79,6 +79,7 @@ struct grep_opt {
79 int pathname;
80 int null_following_name;
81 int color;
82 + int funcname;
83 char color_match[COLOR_MAXLEN];
84 const char *color_external;
85 int regflags;
t/t7002-grep.sh
+34 -2
@@ -8,6 +8,15 @@ test_description='git grep various.
8
9 . ./test-lib.sh
10
11 +cat >hello.c <<EOF
12 +#include <stdio.h>
13 +int main(int argc, const char **argv)
14 +{
15 + printf("Hello world.\n");
16 + return 0;
17 +}
18 +EOF
19 +
20 test_expect_success setup '
21 {
22 echo foo mmap bar
@@ -22,7 +31,7 @@ test_expect_success setup '
31 echo zzz > z &&
32 mkdir t &&
33 echo test >t/t &&
25 - git add file w x y z t/t &&
34 + git add file w x y z t/t hello.c &&
35 test_tick &&
36 git commit -m initial
37 '
@@ -229,9 +238,32 @@ test_expect_success 'log grep (6)' '
238 test_expect_success 'grep with CE_VALID file' '
239 git update-index --assume-unchanged t/t &&
240 rm t/t &&
232 - test "$(git grep --no-ext-grep t)" = "t/t:test" &&
241 + test "$(git grep --no-ext-grep test)" = "t/t:test" &&
242 git update-index --no-assume-unchanged t/t &&
243 git checkout t/t
244 '
245
246 +cat >expected <<EOF
247 +hello.c=int main(int argc, const char **argv)
248 +hello.c: return 0;
249 +EOF
250 +
251 +test_expect_success 'grep -p' '
252 + git grep -p return >actual &&
253 + test_cmp expected actual
254 +'
255 +
256 +cat >expected <<EOF
257 +hello.c-#include <stdio.h>
258 +hello.c=int main(int argc, const char **argv)
259 +hello.c-{
260 +hello.c- printf("Hello world.\n");
261 +hello.c: return 0;
262 +EOF
263 +
264 +test_expect_success 'grep -p -B5' '
265 + git grep -p -B5 return >actual &&
266 + test_cmp expected actual
267 +'
268 +
269 test_done