All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mark Lodato <lodatom@gmail.com>
To: git@vger.kernel.org
Cc: Mark Lodato <lodatom@gmail.com>
Subject: [PATCH 4/4] grep: add --hunk-heading option
Date: Sun, 25 Mar 2012 22:41:45 -0400	[thread overview]
Message-ID: <1332729705-9283-5-git-send-email-lodatom@gmail.com> (raw)
In-Reply-To: <1332729705-9283-1-git-send-email-lodatom@gmail.com>

The purpose of this option is to make the output of grep when showing
context (i.e., -A, -B, -C, or -W) easier to read.  By default, grep
prints a simple separator ("--") between each hunk and then prefixes
each line within the hunk with the same filename and optionally an
incrementing line number.  This repeated information is redundant, so
the new --hunk-heading option moves it all to the hunk separator line.
The idea is similar to the hunk context line of diff.

The new option can be combined with --heading to provide both the
filename and line number of each hunk with minimal visual clutter.

The new configuration, grep.hunkHeading, can be used to set this option
by default.

Signed-off-by: Mark Lodato <lodatom@gmail.com>
---
 Documentation/config.txt     |    3 +
 Documentation/git-grep.txt   |   10 ++-
 builtin/grep.c               |   10 ++-
 grep.c                       |   28 ++++++-
 grep.h                       |    1 +
 t/t7812-grep-hunk-heading.sh |  181 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 227 insertions(+), 6 deletions(-)
 create mode 100755 t/t7812-grep-hunk-heading.sh

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c081657..ade9503 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1140,6 +1140,9 @@ grep.lineNumber::
 grep.extendedRegexp::
 	If set to true, enable '--extended-regexp' option by default.
 
+grep.hunkHeading::
+	If set to true, enable '--hunk-heading' option by default.
+
 gpg.program::
 	Use this custom program instead of "gpg" found on $PATH when
 	making or verifying a PGP signature. The program must support the
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 343eadd..26c085b 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -20,7 +20,7 @@ SYNOPSIS
 	   [-c | --count] [--all-match] [-q | --quiet]
 	   [--max-depth <depth>]
 	   [--color[=<when>] | --no-color]
-	   [--break] [--heading] [-p | --show-function]
+	   [--break] [--heading] [--hunk-heading] [-p | --show-function]
 	   [-A <post-context>] [-B <pre-context>] [-C <context>]
 	   [-W | --function-context]
 	   [-f <file>] [-e] <pattern>
@@ -43,6 +43,9 @@ grep.lineNumber::
 grep.extendedRegexp::
 	If set to true, enable '--extended-regexp' option by default.
 
+grep.hunkHeading::
+	If set to true, enable '--hunk-heading' option by default.
+
 
 OPTIONS
 -------
@@ -173,6 +176,11 @@ OPTIONS
 	Show the filename above the matches in that file instead of
 	at the start of each shown line.
 
+--hunk-heading::
+	Append the filename (if not `--heading` and not `-h`) and line number
+	(if not `-n`) to each hunk separator, and suppress printing of the
+	filename at the start of each shown line.
+
 -p::
 --show-function::
 	Show the preceding line that contains the function name of
diff --git a/builtin/grep.c b/builtin/grep.c
index 643938d..cdafc5a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -276,6 +276,11 @@ static int grep_config(const char *var, const char *value, void *cb)
 		return 0;
 	}
 
+	if (!strcmp(var, "grep.hunkheading")) {
+		opt->hunk_heading = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "grep.linenumber")) {
 		opt->linenum = git_config_bool(var, value);
 		return 0;
@@ -740,6 +745,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			"print empty line between matches from different files"),
 		OPT_BOOLEAN(0, "heading", &opt.heading,
 			"show filename only once above matches from same file"),
+		OPT_BOOLEAN(0, "hunk-heading", &opt.hunk_heading,
+			"show filename and line number after hunk separator"),
 		OPT_GROUP(""),
 		OPT_CALLBACK('C', "context", &opt, "n",
 			"show <n> context lines before and after matches",
@@ -920,8 +927,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 #ifndef NO_PTHREADS
 	if (use_threads) {
 		if (!(opt.name_only || opt.unmatch_name_only || opt.count)
+		    && !(opt.hunk_heading && !opt.heading && !opt.file_break)
 		    && (opt.pre_context || opt.post_context ||
-			opt.file_break || opt.funcbody))
+			opt.file_break || opt.funcbody || opt.hunk_heading))
 			skip_first_line = 1;
 		start_threads(&opt);
 	}
diff --git a/grep.c b/grep.c
index 14e0480..f0e00f7 100644
--- a/grep.c
+++ b/grep.c
@@ -747,21 +747,41 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
 		if (opt->heading && !opt->file_break)
 			output_color(opt, "--", 2, opt->color_sep);
 		opt->output(opt, "\n", 1);
-		show_hunk = 0;
+		if (!opt->hunk_heading)
+			show_hunk = 0;
 	}
 	if (opt->heading && opt->last_shown == 0) {
 		output_color(opt, name, strlen(name), opt->color_filename);
 		opt->output(opt, "\n", 1);
 	}
 	if (show_hunk &&
-	    ((opt->last_shown == 0 && opt->show_hunk_mark) ||
+	    ((opt->last_shown == 0 && (opt->show_hunk_mark || opt->hunk_heading)) ||
 	     (opt->last_shown != 0 && lno > opt->last_shown + 1))) {
 		output_color(opt, "--", 2, opt->color_sep);
+		if (opt->hunk_heading &&
+		    ((!opt->heading && opt->pathname) || !opt->linenum)) {
+			opt->output(opt, " ", 1);
+			if (!opt->heading && opt->pathname) {
+				output_color(opt, name, strlen(name),
+					     opt->color_filename);
+				if (!opt->linenum)
+					output_sep(opt, ':');
+			}
+			if (!opt->linenum) {
+				char buf[32];
+				snprintf(buf, sizeof(buf), "%d", lno);
+				output_color(opt, buf, strlen(buf),
+					     opt->color_lineno);
+			}
+			opt->output(opt, " ", 1);
+			output_color(opt, "--", 2, opt->color_sep);
+		}
 		opt->output(opt, "\n", 1);
 	}
 	opt->last_shown = lno;
 
-	if (!opt->heading && opt->pathname) {
+	if (opt->pathname && !opt->heading &&
+	    !(opt->hunk_heading && show_hunk)) {
 		output_color(opt, name, strlen(name), opt->color_filename);
 		output_sep(opt, sign);
 	}
@@ -1001,7 +1021,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
 		opt->output = std_output;
 
 	if (opt->pre_context || opt->post_context || opt->file_break ||
-	    opt->funcbody) {
+	    opt->funcbody || opt->hunk_heading) {
 		/* Show hunk marks, except for the first file. */
 		if (opt->last_shown)
 			opt->show_hunk_mark = 1;
diff --git a/grep.h b/grep.h
index 36e49d8..761db2a 100644
--- a/grep.h
+++ b/grep.h
@@ -117,6 +117,7 @@ struct grep_opt {
 	int show_hunk_mark;
 	int file_break;
 	int heading;
+	int hunk_heading;
 	void *priv;
 
 	void (*output)(struct grep_opt *opt, const void *data, size_t size);
diff --git a/t/t7812-grep-hunk-heading.sh b/t/t7812-grep-hunk-heading.sh
new file mode 100755
index 0000000..6db9ba6
--- /dev/null
+++ b/t/t7812-grep-hunk-heading.sh
@@ -0,0 +1,181 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Mark Lodato
+#
+
+test_description='git grep --hunk-heading'
+
+. ./test-lib.sh
+
+cat >one.c <<EOF
+#include <stdio.h>
+int main(int argc, const char **argv)
+{
+	printf("Hello world.\n");
+	return 0;
+}
+EOF
+
+cat >two.c <<EOF
+int hello_int(int x)
+{
+	printf("Hello, %d.\n", x);
+	return 0;
+}
+
+int hello_str(const char *s)
+{
+	printf("Hello, %s.\n", s);
+	return 0;
+}
+EOF
+
+test_expect_success 'setup' '
+	git add . &&
+	git commit -m initial
+'
+
+cat >expected <<EOF
+one.c:	printf("Hello world.\n");
+two.c:	printf("Hello, %d.\n", x);
+two.c:	printf("Hello, %s.\n", s);
+EOF
+
+test_expect_success 'grep --hunk-heading without context' '
+	git grep -e Hello --hunk-heading >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+-- one.c:4 --
+	printf("Hello world.\n");
+	return 0;
+-- two.c:3 --
+	printf("Hello, %d.\n", x);
+	return 0;
+-- two.c:9 --
+	printf("Hello, %s.\n", s);
+	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading -A1' '
+	git grep -e Hello -A1 --hunk-heading >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'grep --hunk-heading -B1' '
+	git grep -e return -B1 --hunk-heading >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+<RED>--<RESET> <BLUE>one.c<RESET><RED>:<RESET><GREEN>4<RESET> <RED>--<RESET>
+	printf("Hello world.\n");
+	return 0;
+<RED>--<RESET> <BLUE>two.c<RESET><RED>:<RESET><GREEN>3<RESET> <RED>--<RESET>
+	printf("Hello, %d.\n", x);
+	return 0;
+<RED>--<RESET> <BLUE>two.c<RESET><RED>:<RESET><GREEN>9<RESET> <RED>--<RESET>
+	printf("Hello, %s.\n", s);
+	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading --color' '
+	test_config color.grep.context		normal &&
+	test_config color.grep.filename		"blue" &&
+	test_config color.grep.function		normal &&
+	test_config color.grep.linenumber	"green" &&
+	test_config color.grep.match		normal &&
+	test_config color.grep.selected		normal &&
+	test_config color.grep.separator	"red" &&
+
+	git grep -e Hello -A1 --hunk-heading --color |
+	test_decode_color >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+-- one.c:4 --
+	printf("Hello world.\n");
+	return 0;
+
+-- two.c:3 --
+	printf("Hello, %d.\n", x);
+	return 0;
+-- two.c:9 --
+	printf("Hello, %s.\n", s);
+	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading --break' '
+	git grep -e Hello -A1 --hunk-heading --break >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+one.c
+-- 4 --
+	printf("Hello world.\n");
+	return 0;
+--
+two.c
+-- 3 --
+	printf("Hello, %d.\n", x);
+	return 0;
+-- 9 --
+	printf("Hello, %s.\n", s);
+	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading --heading' '
+	git grep -e Hello -A1 --hunk-heading --heading >actual &&
+	test_cmp expected actual
+'
+
+mv expected expected.old
+sed -e 's/^--$//' expected.old > expected
+rm expected.old
+
+test_expect_success 'grep --hunk-heading --heading --break' '
+	git grep -e Hello -A1 --hunk-heading --heading --break >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+-- one.c --
+4:	printf("Hello world.\n");
+5-	return 0;
+-- two.c --
+3:	printf("Hello, %d.\n", x);
+4-	return 0;
+-- two.c --
+9:	printf("Hello, %s.\n", s);
+10-	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading -n' '
+	git grep -e Hello -A1 --hunk-heading -n >actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<EOF
+one.c
+--
+4:	printf("Hello world.\n");
+5-	return 0;
+--
+two.c
+--
+3:	printf("Hello, %d.\n", x);
+4-	return 0;
+--
+9:	printf("Hello, %s.\n", s);
+10-	return 0;
+EOF
+
+test_expect_success 'grep --hunk-heading --heading -n' '
+	git grep -e Hello -A1 --hunk-heading --heading -n >actual &&
+	test_cmp expected actual
+'
+
+test_done
-- 
1.7.9.2

  parent reply	other threads:[~2012-03-26  2:42 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-26  2:41 [PATCH 0/4] grep: add more information to hunk separators Mark Lodato
2012-03-26  2:41 ` [PATCH 1/4] grep doc: add --break / --heading / -W to synopsis Mark Lodato
2012-03-26  2:41 ` [PATCH 2/4] add tests for grep --heading with context Mark Lodato
2012-03-26  2:41 ` [PATCH 3/4] grep: move code to print hunk markers after heading Mark Lodato
2012-03-26  2:41 ` Mark Lodato [this message]
2012-03-26  5:14 ` [PATCH 0/4] grep: add more information to hunk separators Junio C Hamano
2012-03-26 16:16   ` René Scharfe
2012-03-26 18:05     ` Junio C Hamano
2012-03-26 18:48   ` Bert Wesarg
2012-03-26 16:16 ` René Scharfe
2012-03-26 18:01   ` Junio C Hamano
2012-03-26 21:12     ` René Scharfe
2012-03-26 21:19       ` Junio C Hamano
2012-03-27  5:31 ` [PATCH 5/4] move sane_truncate_line to utf8_truncate_line Mark Lodato
2012-03-27  5:31 ` [PATCH 6/4] add grep.hunkHeadingFunction option Mark Lodato

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1332729705-9283-5-git-send-email-lodatom@gmail.com \
    --to=lodatom@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.