Junio C Hamano schrieb: > René Scharfe <rene.scharfe@xxxxxxxxxxxxxx> writes: > >> Hmm, even shorter would be to leave out these "==" things entirely: >> >> # mock-up >> $ git grep -p -n markers grep.c >> grep.c=746=static void clr_hit_marker(struct grep_expr *x) >> grep.c:748: /* All-hit markers are meaningful only at... >> grep.c=760=static int chk_hit_marker(struct grep_expr *x) >> grep.c:762: /* Top level nodes have hit markers. See... >> grep.c=772=int grep_buffer(struct grep_opt *opt, const ch... >> grep.c:782: * We first clear hit markers from them. >> >> Is that still readable? > > Actually the above matches what I expected to see when I read your [0/6]. OK. :) > Is the use of '=' your invention, or does somebody's grep have this > function header feature already and use '=' the same way? I didn't find a prior implementation, only this announcement: http://thread.gmane.org/gmane.comp.gnu.grep.bugs/141 Initially, I used '@' (similar to diff), but that looked strange. The equal sign seemed to fit well ('-' means context, '=' means even more context! ;-), but I haven't put a lot of thought or research into it. Here's patch 5 again, with all traces of "==" markers removed. Patch 6 still applies, albeit with a slight offset. --- snip! --- 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@xxxxxxxxxxxxxx> --- Documentation/git-grep.txt | 5 ++++ builtin-grep.c | 4 ++- grep.c | 49 ++++++++++++++++++++++++++++++++++++++++--- grep.h | 1 + t/t7002-grep.sh | 36 ++++++++++++++++++++++++++++++- 5 files changed, 88 insertions(+), 7 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index fccb82d..b3bb283 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -122,6 +122,11 @@ OPTIONS -<num>:: A shortcut for specifying -C<num>. +-p:: +--show-function:: + Show the preceding line that contains the function name of + the match, unless the matching line is a function name itself. + -f <file>:: Read patterns from <file>, one per line. diff --git a/builtin-grep.c b/builtin-grep.c index 48998af..44fd485 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -721,6 +721,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) "show <n> context lines after matches"), OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", context_callback), + OPT_BOOLEAN('p', "show-function", &opt.funcname, + "show a line with the function name before matches"), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, "file", "read patterns from file", file_callback), @@ -789,7 +791,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } - if (opt.color && !opt.color_external) + if ((opt.color && !opt.color_external) || opt.funcname) external_grep_allowed = 0; if (!opt.pattern_list) die("no pattern given."); diff --git a/grep.c b/grep.c index 9b9d2e3..364c7c3 100644 --- a/grep.c +++ b/grep.c @@ -531,10 +531,40 @@ 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) +{ + if (bol == eol) + return 0; + if (isalpha(*bol) || *bol == '_' || *bol == '$') + return 1; + return 0; +} + +static void show_funcname_line(struct grep_opt *opt, const char *name, + char *buf, char *bol, unsigned lno) +{ + while (bol > buf) { + char *eol = --bol; + + while (bol > buf && bol[-1] != '\n') + bol--; + lno--; + + if (lno <= opt->last_shown) + break; + + if (match_funcname(bol, eol)) { + show_line(opt, bol, eol, name, lno, '='); + break; + } + } +} + static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, char *bol, unsigned lno) { - unsigned cur = lno, from = 1; + unsigned cur = lno, from = 1, funcname_lno = 0; + int funcname_needed = opt->funcname; if (opt->pre_context < lno) from = lno - opt->pre_context; @@ -543,19 +573,28 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, /* Rewind. */ while (bol > buf && cur > from) { - bol--; + char *eol = --bol; + while (bol > buf && bol[-1] != '\n') bol--; cur--; + if (funcname_needed && match_funcname(bol, eol)) { + funcname_lno = cur; + funcname_needed = 0; + } } + /* We need to look even further back to find a function signature. */ + if (opt->funcname && funcname_needed) + show_funcname_line(opt, name, buf, bol, cur); + /* Back forward. */ while (cur < lno) { - char *eol = bol; + char *eol = bol, sign = (cur == funcname_lno) ? '=' : '-'; while (*eol != '\n') eol++; - show_line(opt, bol, eol, name, cur, '-'); + show_line(opt, bol, eol, name, cur, sign); bol = eol + 1; cur++; } @@ -635,6 +674,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, */ if (opt->pre_context) show_pre_context(opt, name, buf, bol, lno); + else if (opt->funcname) + show_funcname_line(opt, name, buf, bol, lno); if (!opt->count) show_line(opt, bol, eol, name, lno, ':'); last_hit = lno; diff --git a/grep.h b/grep.h index 730ffd6..3f75e3a 100644 --- a/grep.h +++ b/grep.h @@ -79,6 +79,7 @@ struct grep_opt { int pathname; int null_following_name; int color; + int funcname; char color_match[COLOR_MAXLEN]; const char *color_external; int regflags; diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index 155bfdb..ef59ab9 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -8,6 +8,15 @@ test_description='git grep various. . ./test-lib.sh +cat >hello.c <<EOF +#include <stdio.h> +int main(int argc, const char **argv) +{ + printf("Hello world.\n"); + return 0; +} +EOF + test_expect_success setup ' { echo foo mmap bar @@ -22,7 +31,7 @@ test_expect_success setup ' echo zzz > z && mkdir t && echo test >t/t && - git add file w x y z t/t && + git add file w x y z t/t hello.c && test_tick && git commit -m initial ' @@ -229,9 +238,32 @@ test_expect_success 'log grep (6)' ' test_expect_success 'grep with CE_VALID file' ' git update-index --assume-unchanged t/t && rm t/t && - test "$(git grep --no-ext-grep t)" = "t/t:test" && + test "$(git grep --no-ext-grep test)" = "t/t:test" && git update-index --no-assume-unchanged t/t && git checkout t/t ' +cat >expected <<EOF +hello.c=int main(int argc, const char **argv) +hello.c: return 0; +EOF + +test_expect_success 'grep -p' ' + git grep -p return >actual && + test_cmp expected actual +' + +cat >expected <<EOF +hello.c-#include <stdio.h> +hello.c=int main(int argc, const char **argv) +hello.c-{ +hello.c- printf("Hello world.\n"); +hello.c: return 0; +EOF + +test_expect_success 'grep -p -B5' ' + git grep -p -B5 return >actual && + test_cmp expected actual +' + test_done -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html