summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-grep.txt6
-rw-r--r--builtin/grep.c5
-rw-r--r--grep.c32
-rw-r--r--grep.h1
-rwxr-xr-xt/t7810-grep.sh14
5 files changed, 47 insertions, 11 deletions
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 07b3c6a086..6cd0c503f6 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -172,6 +172,12 @@ OPTIONS
patch hunk headers (see 'Defining a custom hunk-header' in
linkgit:gitattributes[5]).
+-W::
+ 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>::
Read patterns from <file>, one per line.
diff --git a/builtin/grep.c b/builtin/grep.c
index cccf8da6d2..1fae66262f 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -838,6 +838,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname,
"show a line with the function name before matches"),
+ OPT_BOOLEAN('W', NULL, &opt.funcbody,
+ "show the surrounding function"),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback),
@@ -980,7 +982,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
use_threads = 0;
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;
start_threads(&opt);
}
diff --git a/grep.c b/grep.c
index 04e9ba4ec4..26e8d8ec4c 100644
--- a/grep.c
+++ b/grep.c
@@ -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->show_hunk_mark)
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->show_hunk_mark) {
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,
- char *bol, unsigned lno)
+ char *bol, char *end, unsigned lno)
{
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)
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;
/* Rewind. */
- while (bol > buf && cur > from) {
+ while (bol > buf &&
+ cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
char *eol = --bol;
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;
unsigned count = 0;
int try_lookahead = 0;
+ int show_function = 0;
enum grep_context ctx = GREP_CONTEXT_HEAD;
xdemitconf_t xecfg;
if (!opt->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. */
if (opt->last_shown)
opt->show_hunk_mark = 1;
@@ -1004,7 +1010,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
*/
if (try_lookahead
&& !(last_hit
- && lno <= last_hit + opt->post_context)
+ && (show_function ||
+ lno <= last_hit + opt->post_context))
&& look_ahead(opt, &left, &lno, &bol))
break;
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
* pre-context lines, we would need to show them.
*/
- if (opt->pre_context)
- show_pre_context(opt, name, buf, bol, lno);
+ if (opt->pre_context || opt->funcbody)
+ show_pre_context(opt, name, buf, bol, eol, lno);
else if (opt->funcname)
show_funcname_line(opt, name, buf, bol, lno);
show_line(opt, bol, eol, name, lno, ':');
last_hit = lno;
+ if (opt->funcbody)
+ show_function = 1;
+ goto next_line;
}
- else if (last_hit &&
- lno <= last_hit + opt->post_context) {
+ if (show_function && match_funcname(opt, bol, eol))
+ show_function = 0;
+ if (show_function ||
+ (last_hit && lno <= last_hit + opt->post_context)) {
/* If the last hit is within the post context,
* we need to show this line.
*/
diff --git a/grep.h b/grep.h
index c5682973ea..ae50c45a4d 100644
--- a/grep.h
+++ b/grep.h
@@ -98,6 +98,7 @@ struct grep_opt {
int color;
int max_depth;
int funcname;
+ int funcbody;
char color_context[COLOR_MAXLEN];
char color_filename[COLOR_MAXLEN];
char color_function[COLOR_MAXLEN];
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index a29ae45b39..0d600163c8 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -509,6 +509,20 @@ test_expect_success 'grep -p -B5' '
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)' '
mkdir -p s &&
(