grep: add option to show whole function as context
Add a new option, -W, to show the whole surrounding function of a match. It uses the same regular expressions as -p and diff to find the beginning of sections. Currently it will not display comments in front of a function, but those that are following one. Despite this shortcoming it is already useful, e.g. to simply see a more complete applicable context or to extract whole functions. Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
René Scharfe committed
Aug 1, 2011 at 19:20 UTC
ba8ea7496f2b95c49fccb72ed6b332afbd865e7b
5 files changed
+47
-11
Documentation/git-grep.txt
+6
@@ -172,6 +172,12 @@ OPTIONS
172
patch hunk headers (see 'Defining a custom hunk-header' in
173
linkgit:gitattributes[5]).
174
175
+-W::
176
+ Show the surrounding text from the previous line containing a
177
+ function name up to the one before the next function name,
178
+ effectively showing the whole function in which the match was
179
+ found.
180
+
181
-f <file>::
182
Read patterns from <file>, one per line.
183
builtin/grep.c
+4
-1
@@ -838,6 +838,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
838
context_callback),
839
OPT_BOOLEAN('p', "show-function", &opt.funcname,
840
"show a line with the function name before matches"),
841
+ OPT_BOOLEAN('W', NULL, &opt.funcbody,
842
+ "show the surrounding function"),
843
OPT_GROUP(""),
844
OPT_CALLBACK('f', NULL, &opt, "file",
845
"read patterns from file", file_callback),
@@ -980,7 +982,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
982
use_threads = 0;
983
984
if (use_threads) {
983
- if (opt.pre_context || opt.post_context || opt.file_break)
985
+ if (opt.pre_context || opt.post_context || opt.file_break ||
986
+ opt.funcbody)
987
skip_first_line = 1;
988
start_threads(&opt);
989
}
grep.c
+22
-10
@@ -724,7 +724,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
724
if (opt->file_break && opt->last_shown == 0) {
725
if (opt->show_hunk_mark)
726
opt->output(opt, "\n", 1);
727
- } else if (opt->pre_context || opt->post_context) {
727
+ } else if (opt->pre_context || opt->post_context || opt->funcbody) {
728
if (opt->last_shown == 0) {
729
if (opt->show_hunk_mark) {
730
output_color(opt, "--", 2, opt->color_sep);
@@ -819,10 +819,13 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
819
}
820
821
static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
822
- char *bol, unsigned lno)
822
+ char *bol, char *end, unsigned lno)
823
{
824
unsigned cur = lno, from = 1, funcname_lno = 0;
825
- int funcname_needed = opt->funcname;
825
+ int funcname_needed = !!opt->funcname;
826
+
827
+ if (opt->funcbody && !match_funcname(opt, bol, end))
828
+ funcname_needed = 2;
829
830
if (opt->pre_context < lno)
831
from = lno - opt->pre_context;
@@ -830,7 +833,8 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
833
from = opt->last_shown + 1;
834
835
/* Rewind. */
833
- while (bol > buf && cur > from) {
836
+ while (bol > buf &&
837
+ cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
838
char *eol = --bol;
839
840
while (bol > buf && bol[-1] != '\n')
@@ -942,13 +946,15 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
946
int binary_match_only = 0;
947
unsigned count = 0;
948
int try_lookahead = 0;
949
+ int show_function = 0;
950
enum grep_context ctx = GREP_CONTEXT_HEAD;
951
xdemitconf_t xecfg;
952
953
if (!opt->output)
954
opt->output = std_output;
955
951
- if (opt->pre_context || opt->post_context || opt->file_break) {
956
+ if (opt->pre_context || opt->post_context || opt->file_break ||
957
+ opt->funcbody) {
958
/* Show hunk marks, except for the first file. */
959
if (opt->last_shown)
960
opt->show_hunk_mark = 1;
@@ -1004,7 +1010,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
1010
*/
1011
if (try_lookahead
1012
&& !(last_hit
1007
- && lno <= last_hit + opt->post_context)
1013
+ && (show_function ||
1014
+ lno <= last_hit + opt->post_context))
1015
&& look_ahead(opt, &left, &lno, &bol))
1016
break;
1017
eol = end_of_line(bol, &left);
@@ -1051,15 +1058,20 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
1058
/* Hit at this line. If we haven't shown the
1059
* pre-context lines, we would need to show them.
1060
*/
1054
- if (opt->pre_context)
1055
- show_pre_context(opt, name, buf, bol, lno);
1061
+ if (opt->pre_context || opt->funcbody)
1062
+ show_pre_context(opt, name, buf, bol, eol, lno);
1063
else if (opt->funcname)
1064
show_funcname_line(opt, name, buf, bol, lno);
1065
show_line(opt, bol, eol, name, lno, ':');
1066
last_hit = lno;
1067
+ if (opt->funcbody)
1068
+ show_function = 1;
1069
+ goto next_line;
1070
}
1061
- else if (last_hit &&
1062
- lno <= last_hit + opt->post_context) {
1071
+ if (show_function && match_funcname(opt, bol, eol))
1072
+ show_function = 0;
1073
+ if (show_function ||
1074
+ (last_hit && lno <= last_hit + opt->post_context)) {
1075
/* If the last hit is within the post context,
1076
* we need to show this line.
1077
*/
grep.h
+1
@@ -98,6 +98,7 @@ struct grep_opt {
98
int color;
99
int max_depth;
100
int funcname;
101
+ int funcbody;
102
char color_context[COLOR_MAXLEN];
103
char color_filename[COLOR_MAXLEN];
104
char color_function[COLOR_MAXLEN];
t/t7810-grep.sh
+14
@@ -509,6 +509,20 @@ test_expect_success 'grep -p -B5' '
509
test_cmp expected actual
510
'
511
512
+cat >expected <<EOF
513
+hello.c=int main(int argc, const char **argv)
514
+hello.c-{
515
+hello.c- printf("Hello world.\n");
516
+hello.c: return 0;
517
+hello.c- /* char ?? */
518
+hello.c-}
519
+EOF
520
+
521
+test_expect_success 'grep -W' '
522
+ git grep -W return >actual &&
523
+ test_cmp expected actual
524
+'
525
+
526
test_expect_success 'grep from a subdirectory to search wider area (1)' '
527
mkdir -p s &&
528
(