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
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).