Merge branch 'rs/grep-function-context'

* rs/grep-function-context:
  grep: long context options
  grep: add option to show whole function as context
This commit is contained in:
Junio C Hamano 2011-08-11 11:03:09 -07:00
commit 5fb249aec7
5 changed files with 67 additions and 23 deletions

View File

@ -155,15 +155,6 @@ OPTIONS
Show the filename above the matches in that file instead of Show the filename above the matches in that file instead of
at the start of each shown line. at the start of each shown line.
-[ABC] <context>::
Show `context` trailing (`A` -- after), or leading (`B`
-- before), or both (`C` -- context) lines, and place a
line containing `--` between contiguous groups of
matches.
-<num>::
A shortcut for specifying `-C<num>`.
-p:: -p::
--show-function:: --show-function::
Show the preceding line that contains the function name of Show the preceding line that contains the function name of
@ -172,6 +163,29 @@ OPTIONS
patch hunk headers (see 'Defining a custom hunk-header' in patch hunk headers (see 'Defining a custom hunk-header' in
linkgit:gitattributes[5]). linkgit:gitattributes[5]).
-<num>::
-C <num>::
--context <num>::
Show <num> leading and trailing lines, and place a line
containing `--` between contiguous groups of matches.
-A <num>::
--after-context <num>::
Show <num> trailing lines, and place a line containing
`--` between contiguous groups of matches.
-B <num>::
--before-context <num>::
Show <num> leading lines, and place a line containing
`--` between contiguous groups of matches.
-W::
--function-context::
Show the surrounding text from the previous line containing a
function name up to the one before the next function name,
effectively showing the whole function in which the match was
found.
-f <file>:: -f <file>::
Read patterns from <file>, one per line. Read patterns from <file>, one per line.

View File

@ -827,17 +827,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN(0, "heading", &opt.heading, OPT_BOOLEAN(0, "heading", &opt.heading,
"show filename only once above matches from same file"), "show filename only once above matches from same file"),
OPT_GROUP(""), OPT_GROUP(""),
OPT_CALLBACK('C', NULL, &opt, "n", OPT_CALLBACK('C', "context", &opt, "n",
"show <n> context lines before and after matches", "show <n> context lines before and after matches",
context_callback), context_callback),
OPT_INTEGER('B', NULL, &opt.pre_context, OPT_INTEGER('B', "before-context", &opt.pre_context,
"show <n> context lines before matches"), "show <n> context lines before matches"),
OPT_INTEGER('A', NULL, &opt.post_context, OPT_INTEGER('A', "after-context", &opt.post_context,
"show <n> context lines after matches"), "show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback), context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname, OPT_BOOLEAN('p', "show-function", &opt.funcname,
"show a line with the function name before matches"), "show a line with the function name before matches"),
OPT_BOOLEAN('W', "function-context", &opt.funcbody,
"show the surrounding function"),
OPT_GROUP(""), OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file", OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback), "read patterns from file", file_callback),
@ -980,7 +982,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
use_threads = 0; use_threads = 0;
if (use_threads) { if (use_threads) {
if (opt.pre_context || opt.post_context || opt.file_break) if (opt.pre_context || opt.post_context || opt.file_break ||
opt.funcbody)
skip_first_line = 1; skip_first_line = 1;
start_threads(&opt); start_threads(&opt);
} }

32
grep.c
View File

@ -724,7 +724,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
if (opt->file_break && opt->last_shown == 0) { if (opt->file_break && opt->last_shown == 0) {
if (opt->show_hunk_mark) if (opt->show_hunk_mark)
opt->output(opt, "\n", 1); opt->output(opt, "\n", 1);
} else if (opt->pre_context || opt->post_context) { } else if (opt->pre_context || opt->post_context || opt->funcbody) {
if (opt->last_shown == 0) { if (opt->last_shown == 0) {
if (opt->show_hunk_mark) { if (opt->show_hunk_mark) {
output_color(opt, "--", 2, opt->color_sep); output_color(opt, "--", 2, opt->color_sep);
@ -819,10 +819,13 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
} }
static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
char *bol, unsigned lno) char *bol, char *end, unsigned lno)
{ {
unsigned cur = lno, from = 1, funcname_lno = 0; unsigned cur = lno, from = 1, funcname_lno = 0;
int funcname_needed = opt->funcname; int funcname_needed = !!opt->funcname;
if (opt->funcbody && !match_funcname(opt, bol, end))
funcname_needed = 2;
if (opt->pre_context < lno) if (opt->pre_context < lno)
from = lno - opt->pre_context; from = lno - opt->pre_context;
@ -830,7 +833,8 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
from = opt->last_shown + 1; from = opt->last_shown + 1;
/* Rewind. */ /* Rewind. */
while (bol > buf && cur > from) { while (bol > buf &&
cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
char *eol = --bol; char *eol = --bol;
while (bol > buf && bol[-1] != '\n') while (bol > buf && bol[-1] != '\n')
@ -942,13 +946,15 @@ 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;
int try_lookahead = 0; int try_lookahead = 0;
int show_function = 0;
enum grep_context ctx = GREP_CONTEXT_HEAD; enum grep_context ctx = GREP_CONTEXT_HEAD;
xdemitconf_t xecfg; xdemitconf_t xecfg;
if (!opt->output) if (!opt->output)
opt->output = std_output; opt->output = std_output;
if (opt->pre_context || opt->post_context || opt->file_break) { if (opt->pre_context || opt->post_context || opt->file_break ||
opt->funcbody) {
/* Show hunk marks, except for the first file. */ /* Show hunk marks, except for the first file. */
if (opt->last_shown) if (opt->last_shown)
opt->show_hunk_mark = 1; opt->show_hunk_mark = 1;
@ -1004,7 +1010,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
*/ */
if (try_lookahead if (try_lookahead
&& !(last_hit && !(last_hit
&& lno <= last_hit + opt->post_context) && (show_function ||
lno <= last_hit + opt->post_context))
&& look_ahead(opt, &left, &lno, &bol)) && look_ahead(opt, &left, &lno, &bol))
break; break;
eol = end_of_line(bol, &left); eol = end_of_line(bol, &left);
@ -1051,15 +1058,20 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
/* Hit at this line. If we haven't shown the /* Hit at this line. If we haven't shown the
* pre-context lines, we would need to show them. * pre-context lines, we would need to show them.
*/ */
if (opt->pre_context) if (opt->pre_context || opt->funcbody)
show_pre_context(opt, name, buf, bol, lno); show_pre_context(opt, name, buf, bol, eol, lno);
else if (opt->funcname) else if (opt->funcname)
show_funcname_line(opt, name, buf, bol, lno); show_funcname_line(opt, name, buf, bol, lno);
show_line(opt, bol, eol, name, lno, ':'); show_line(opt, bol, eol, name, lno, ':');
last_hit = lno; last_hit = lno;
if (opt->funcbody)
show_function = 1;
goto next_line;
} }
else if (last_hit && if (show_function && match_funcname(opt, bol, eol))
lno <= last_hit + opt->post_context) { show_function = 0;
if (show_function ||
(last_hit && lno <= last_hit + opt->post_context)) {
/* If the last hit is within the post context, /* If the last hit is within the post context,
* we need to show this line. * we need to show this line.
*/ */

1
grep.h
View File

@ -98,6 +98,7 @@ struct grep_opt {
int color; int color;
int max_depth; int max_depth;
int funcname; int funcname;
int funcbody;
char color_context[COLOR_MAXLEN]; char color_context[COLOR_MAXLEN];
char color_filename[COLOR_MAXLEN]; char color_filename[COLOR_MAXLEN];
char color_function[COLOR_MAXLEN]; char color_function[COLOR_MAXLEN];

View File

@ -509,6 +509,20 @@ test_expect_success 'grep -p -B5' '
test_cmp expected actual test_cmp expected actual
' '
cat >expected <<EOF
hello.c=int main(int argc, const char **argv)
hello.c-{
hello.c- printf("Hello world.\n");
hello.c: return 0;
hello.c- /* char ?? */
hello.c-}
EOF
test_expect_success 'grep -W' '
git grep -W return >actual &&
test_cmp expected actual
'
test_expect_success 'grep from a subdirectory to search wider area (1)' ' test_expect_success 'grep from a subdirectory to search wider area (1)' '
mkdir -p s && mkdir -p s &&
( (