summaryrefslogtreecommitdiff
path: root/grep.c
diff options
context:
space:
mode:
authorTaylor Blau <me@ttaylorr.com>2018-07-09 20:33:47 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-07-09 21:15:28 (GMT)
commit9d8db06eb4a5d5577db559a0059a377914c1ce5a (patch)
treea0ef841c1f6cd361d25b5c9f0e25337eb4a1c38d /grep.c
parentc707ded332375a5b51c1acf9b7ce1c29cbd4536d (diff)
downloadgit-9d8db06eb4a5d5577db559a0059a377914c1ce5a.zip
git-9d8db06eb4a5d5577db559a0059a377914c1ce5a.tar.gz
git-9d8db06eb4a5d5577db559a0059a377914c1ce5a.tar.bz2
grep.c: teach 'git grep --only-matching'
Teach 'git grep --only-matching', a new option to only print the matching part(s) of a line. For instance, a line containing the following (taken from README.md:27): (`man gitcvs-migration` or `git help cvs-migration` if git is Is printed as follows: $ git grep --line-number --column --only-matching -e git -- \ README.md | grep ":27" README.md:27:7:git README.md:27:16:git README.md:27:38:git The patch works mostly as one would expect, with the exception of a few considerations that are worth mentioning here. Like GNU grep, this patch ignores --only-matching when --invert (-v) is given. There is a sensible answer here, but parity with the behavior of other tools is preferred. Because a line might contain more than one match, there are special considerations pertaining to when to print line headers, newlines, and how to increment the match column offset. The line header and newlines are handled as a special case within the main loop to avoid polluting the surrounding code with conditionals that have large blocks. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'grep.c')
-rw-r--r--grep.c51
1 files changed, 35 insertions, 16 deletions
diff --git a/grep.c b/grep.c
index 4ff8a73..49a744f 100644
--- a/grep.c
+++ b/grep.c
@@ -51,6 +51,7 @@ void init_grep_defaults(void)
color_set(opt->color_match_selected, GIT_COLOR_BOLD_RED);
color_set(opt->color_selected, "");
color_set(opt->color_sep, GIT_COLOR_CYAN);
+ opt->only_matching = 0;
opt->color = -1;
opt->output = std_output;
}
@@ -158,6 +159,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
opt->pattern_tail = &opt->pattern_list;
opt->header_tail = &opt->header_list;
+ opt->only_matching = def->only_matching;
opt->color = def->color;
opt->extended_regexp_option = def->extended_regexp_option;
opt->pattern_type_option = def->pattern_type_option;
@@ -1446,7 +1448,8 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
const char *name, unsigned lno, ssize_t cno, char sign)
{
int rest = eol - bol;
- const char *match_color, *line_color = NULL;
+ const char *match_color = NULL;
+ const char *line_color = NULL;
if (opt->file_break && opt->last_shown == 0) {
if (opt->show_hunk_mark)
@@ -1462,39 +1465,55 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
opt->output(opt, "\n", 1);
}
}
- show_line_header(opt, name, lno, cno, sign);
- if (opt->color) {
+ if (!opt->only_matching) {
+ /*
+ * In case the line we're being called with contains more than
+ * one match, leave printing each header to the loop below.
+ */
+ show_line_header(opt, name, lno, cno, sign);
+ }
+ if (opt->color || opt->only_matching) {
regmatch_t match;
enum grep_context ctx = GREP_CONTEXT_BODY;
int ch = *eol;
int eflags = 0;
- if (sign == ':')
- match_color = opt->color_match_selected;
- else
- match_color = opt->color_match_context;
- if (sign == ':')
- line_color = opt->color_selected;
- else if (sign == '-')
- line_color = opt->color_context;
- else if (sign == '=')
- line_color = opt->color_function;
+ if (opt->color) {
+ if (sign == ':')
+ match_color = opt->color_match_selected;
+ else
+ match_color = opt->color_match_context;
+ if (sign == ':')
+ line_color = opt->color_selected;
+ else if (sign == '-')
+ line_color = opt->color_context;
+ else if (sign == '=')
+ line_color = opt->color_function;
+ }
*eol = '\0';
while (next_match(opt, bol, eol, ctx, &match, eflags)) {
if (match.rm_so == match.rm_eo)
break;
- output_color(opt, bol, match.rm_so, line_color);
+ if (opt->only_matching)
+ show_line_header(opt, name, lno, cno, sign);
+ else
+ output_color(opt, bol, match.rm_so, line_color);
output_color(opt, bol + match.rm_so,
match.rm_eo - match.rm_so, match_color);
+ if (opt->only_matching)
+ opt->output(opt, "\n", 1);
bol += match.rm_eo;
+ cno += match.rm_eo;
rest -= match.rm_eo;
eflags = REG_NOTBOL;
}
*eol = ch;
}
- output_color(opt, bol, rest, line_color);
- opt->output(opt, "\n", 1);
+ if (!opt->only_matching) {
+ output_color(opt, bol, rest, line_color);
+ opt->output(opt, "\n", 1);
+ }
}
#ifndef NO_PTHREADS