Merge branch 'tb/grep-only-matching'

"git grep" learned the "--only-matching" option.

* tb/grep-only-matching:
  grep.c: teach 'git grep --only-matching'
  grep.c: extract show_line_header()
This commit is contained in:
Junio C Hamano 2018-08-02 15:30:44 -07:00
commit 87ece7ce11
5 changed files with 86 additions and 34 deletions

View File

@ -17,7 +17,7 @@ SYNOPSIS
[-l | --files-with-matches] [-L | --files-without-match] [-l | --files-with-matches] [-L | --files-without-match]
[(-O | --open-files-in-pager) [<pager>]] [(-O | --open-files-in-pager) [<pager>]]
[-z | --null] [-z | --null]
[-c | --count] [--all-match] [-q | --quiet] [ -o | --only-matching ] [-c | --count] [--all-match] [-q | --quiet]
[--max-depth <depth>] [--max-depth <depth>]
[--color[=<when>] | --no-color] [--color[=<when>] | --no-color]
[--break] [--heading] [-p | --show-function] [--break] [--heading] [-p | --show-function]
@ -201,6 +201,11 @@ providing this option will cause it to die.
Output \0 instead of the character that normally follows a Output \0 instead of the character that normally follows a
file name. file name.
-o::
--only-matching::
Print only the matched (non-empty) parts of a matching line, with each such
part on a separate output line.
-c:: -c::
--count:: --count::
Instead of showing every matched line, show the number of Instead of showing every matched line, show the number of

View File

@ -844,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOL_F('z', "null", &opt.null_following_name, OPT_BOOL_F('z', "null", &opt.null_following_name,
N_("print NUL after filenames"), N_("print NUL after filenames"),
PARSE_OPT_NOCOMPLETE), PARSE_OPT_NOCOMPLETE),
OPT_BOOL('o', "only-matching", &opt.only_matching,
N_("show only matching parts of a line")),
OPT_BOOL('c', "count", &opt.count, OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")), N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")), OPT__COLOR(&opt.color, N_("highlight matches")),
@ -963,6 +965,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!opt.pattern_list) if (!opt.pattern_list)
die(_("no pattern given.")); die(_("no pattern given."));
/* --only-matching has no effect with --invert. */
if (opt.invert)
opt.only_matching = 0;
/* /*
* We have to find "--" in a separate pass, because its presence * We have to find "--" in a separate pass, because its presence
* influences how we will parse arguments that come before it. * influences how we will parse arguments that come before it.

91
grep.c
View File

@ -65,6 +65,7 @@ void init_grep_defaults(void)
color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED); color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED);
color_set(opt->colors[GREP_COLOR_SELECTED], ""); color_set(opt->colors[GREP_COLOR_SELECTED], "");
color_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN); color_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN);
opt->only_matching = 0;
opt->color = -1; opt->color = -1;
opt->output = std_output; opt->output = std_output;
} }
@ -159,6 +160,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
opt->pattern_tail = &opt->pattern_list; opt->pattern_tail = &opt->pattern_list;
opt->header_tail = &opt->header_list; opt->header_tail = &opt->header_list;
opt->only_matching = def->only_matching;
opt->color = def->color; opt->color = def->color;
opt->extended_regexp_option = def->extended_regexp_option; opt->extended_regexp_option = def->extended_regexp_option;
opt->pattern_type_option = def->pattern_type_option; opt->pattern_type_option = def->pattern_type_option;
@ -1404,26 +1406,9 @@ static int next_match(struct grep_opt *opt, char *bol, char *eol,
return hit; return hit;
} }
static void show_line(struct grep_opt *opt, char *bol, char *eol, static void show_line_header(struct grep_opt *opt, const char *name,
const char *name, unsigned lno, ssize_t cno, char sign) unsigned lno, ssize_t cno, char sign)
{ {
int rest = eol - bol;
const char *match_color, *line_color = NULL;
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 || opt->funcbody) {
if (opt->last_shown == 0) {
if (opt->show_hunk_mark) {
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
opt->output(opt, "\n", 1);
}
} else if (lno > opt->last_shown + 1) {
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
opt->output(opt, "\n", 1);
}
}
if (opt->heading && opt->last_shown == 0) { if (opt->heading && opt->last_shown == 0) {
output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]); output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
opt->output(opt, "\n", 1); opt->output(opt, "\n", 1);
@ -1451,38 +1436,78 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_COLUMNNO]); output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_COLUMNNO]);
output_sep(opt, sign); output_sep(opt, sign);
} }
if (opt->color) { }
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 = NULL;
const char *line_color = NULL;
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 || opt->funcbody) {
if (opt->last_shown == 0) {
if (opt->show_hunk_mark) {
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
opt->output(opt, "\n", 1);
}
} else if (lno > opt->last_shown + 1) {
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
opt->output(opt, "\n", 1);
}
}
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; regmatch_t match;
enum grep_context ctx = GREP_CONTEXT_BODY; enum grep_context ctx = GREP_CONTEXT_BODY;
int ch = *eol; int ch = *eol;
int eflags = 0; int eflags = 0;
if (sign == ':') if (opt->color) {
match_color = opt->colors[GREP_COLOR_MATCH_SELECTED]; if (sign == ':')
else match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT]; else
if (sign == ':') match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];
line_color = opt->colors[GREP_COLOR_SELECTED]; if (sign == ':')
else if (sign == '-') line_color = opt->colors[GREP_COLOR_SELECTED];
line_color = opt->colors[GREP_COLOR_CONTEXT]; else if (sign == '-')
else if (sign == '=') line_color = opt->colors[GREP_COLOR_CONTEXT];
line_color = opt->colors[GREP_COLOR_FUNCTION]; else if (sign == '=')
line_color = opt->colors[GREP_COLOR_FUNCTION];
}
*eol = '\0'; *eol = '\0';
while (next_match(opt, bol, eol, ctx, &match, eflags)) { while (next_match(opt, bol, eol, ctx, &match, eflags)) {
if (match.rm_so == match.rm_eo) if (match.rm_so == match.rm_eo)
break; 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, output_color(opt, bol + match.rm_so,
match.rm_eo - match.rm_so, match_color); match.rm_eo - match.rm_so, match_color);
if (opt->only_matching)
opt->output(opt, "\n", 1);
bol += match.rm_eo; bol += match.rm_eo;
cno += match.rm_eo;
rest -= match.rm_eo; rest -= match.rm_eo;
eflags = REG_NOTBOL; eflags = REG_NOTBOL;
} }
*eol = ch; *eol = ch;
} }
output_color(opt, bol, rest, line_color); if (!opt->only_matching) {
opt->output(opt, "\n", 1); output_color(opt, bol, rest, line_color);
opt->output(opt, "\n", 1);
}
} }
#ifndef NO_PTHREADS #ifndef NO_PTHREADS

1
grep.h
View File

@ -163,6 +163,7 @@ struct grep_opt {
int relative; int relative;
int pathname; int pathname;
int null_following_name; int null_following_name;
int only_matching;
int color; int color;
int max_depth; int max_depth;
int funcname; int funcname;

View File

@ -262,6 +262,21 @@ do
fi fi
' '
test_expect_success "grep $L (with --column, --only-matching)" '
{
echo ${HC}file:1:5:mmap
echo ${HC}file:2:5:mmap
echo ${HC}file:3:5:mmap
echo ${HC}file:3:13:mmap
echo ${HC}file:4:5:mmap
echo ${HC}file:4:13:mmap
echo ${HC}file:5:5:mmap
echo ${HC}file:5:13:mmap
} >expected &&
git grep --column -n -o -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep $L (t-1)" ' test_expect_success "grep $L (t-1)" '
echo "${HC}t/t:1:test" >expected && echo "${HC}t/t:1:test" >expected &&
git grep -n -e test $H >actual && git grep -n -e test $H >actual &&