git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 5/6] grep: add option -p/--show-function

From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Date
Jul 2, 2009, 06:16 UTC
Message-ID
<4A4C50C7.1050303@lsrfire.ath.cx>
In-Reply-To
<7vy6r7d583.fsf@alter.siamese.dyndns.org>
Junio C Hamano schrieb:
Show 16 quoted lines
> René Scharfe <rene.scharfe@lsrfire.ath.cx> 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@lsrfire.ath.cx>
---
 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
Previous: Junio C HamanoNext: René Scharfe
Message 13 of 15 in “grep: add option -p/--show-function, similar to diff's”
  1. 0/6 grep: add option -p/--show-function, similar to diff'sRené Scharfe, Jul 1, 2009
  2. 1/6 userdiff: add xdiff_clear_find_func()René Scharfe, Jul 1, 2009
  3. 2/6 grep: move context hunk mark handling into show_line()René Scharfe, Jul 1, 2009
  4. Junio C HamanoJul 1, 2009
  5. René ScharfeJul 2, 2009
  6. Junio C HamanoJul 2, 2009
  7. 3/6 grep: print context hunk marks between filesRené Scharfe, Jul 1, 2009
  8. 4/6 grep: handle pre context lines on demandRené Scharfe, Jul 1, 2009
  9. 5/6 grep: add option -p/--show-functionRené Scharfe, Jul 1, 2009
  10. Junio C HamanoJul 2, 2009
  11. René ScharfeJul 2, 2009
  12. Junio C HamanoJul 2, 2009
  13. René ScharfeJul 2, 2009
  14. René ScharfeJul 2, 2009
  15. 6/6 grep -p: support user defined regular expressionsRené Scharfe, Jul 1, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.