Skip to content

Commit 87ece7c

Browse files
committed
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()
2 parents 562413e + 9d8db06 commit 87ece7c

File tree

5 files changed

+86
-34
lines changed

5 files changed

+86
-34
lines changed

Documentation/git-grep.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ SYNOPSIS
1717
[-l | --files-with-matches] [-L | --files-without-match]
1818
[(-O | --open-files-in-pager) [<pager>]]
1919
[-z | --null]
20-
[-c | --count] [--all-match] [-q | --quiet]
20+
[ -o | --only-matching ] [-c | --count] [--all-match] [-q | --quiet]
2121
[--max-depth <depth>]
2222
[--color[=<when>] | --no-color]
2323
[--break] [--heading] [-p | --show-function]
@@ -201,6 +201,11 @@ providing this option will cause it to die.
201201
Output \0 instead of the character that normally follows a
202202
file name.
203203

204+
-o::
205+
--only-matching::
206+
Print only the matched (non-empty) parts of a matching line, with each such
207+
part on a separate output line.
208+
204209
-c::
205210
--count::
206211
Instead of showing every matched line, show the number of

builtin/grep.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
844844
OPT_BOOL_F('z', "null", &opt.null_following_name,
845845
N_("print NUL after filenames"),
846846
PARSE_OPT_NOCOMPLETE),
847+
OPT_BOOL('o', "only-matching", &opt.only_matching,
848+
N_("show only matching parts of a line")),
847849
OPT_BOOL('c', "count", &opt.count,
848850
N_("show the number of matches instead of matching lines")),
849851
OPT__COLOR(&opt.color, N_("highlight matches")),
@@ -963,6 +965,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
963965
if (!opt.pattern_list)
964966
die(_("no pattern given."));
965967

968+
/* --only-matching has no effect with --invert. */
969+
if (opt.invert)
970+
opt.only_matching = 0;
971+
966972
/*
967973
* We have to find "--" in a separate pass, because its presence
968974
* influences how we will parse arguments that come before it.

grep.c

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ void init_grep_defaults(void)
6565
color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED);
6666
color_set(opt->colors[GREP_COLOR_SELECTED], "");
6767
color_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN);
68+
opt->only_matching = 0;
6869
opt->color = -1;
6970
opt->output = std_output;
7071
}
@@ -159,6 +160,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
159160
opt->pattern_tail = &opt->pattern_list;
160161
opt->header_tail = &opt->header_list;
161162

163+
opt->only_matching = def->only_matching;
162164
opt->color = def->color;
163165
opt->extended_regexp_option = def->extended_regexp_option;
164166
opt->pattern_type_option = def->pattern_type_option;
@@ -1404,26 +1406,9 @@ static int next_match(struct grep_opt *opt, char *bol, char *eol,
14041406
return hit;
14051407
}
14061408

1407-
static void show_line(struct grep_opt *opt, char *bol, char *eol,
1408-
const char *name, unsigned lno, ssize_t cno, char sign)
1409+
static void show_line_header(struct grep_opt *opt, const char *name,
1410+
unsigned lno, ssize_t cno, char sign)
14091411
{
1410-
int rest = eol - bol;
1411-
const char *match_color, *line_color = NULL;
1412-
1413-
if (opt->file_break && opt->last_shown == 0) {
1414-
if (opt->show_hunk_mark)
1415-
opt->output(opt, "\n", 1);
1416-
} else if (opt->pre_context || opt->post_context || opt->funcbody) {
1417-
if (opt->last_shown == 0) {
1418-
if (opt->show_hunk_mark) {
1419-
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
1420-
opt->output(opt, "\n", 1);
1421-
}
1422-
} else if (lno > opt->last_shown + 1) {
1423-
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
1424-
opt->output(opt, "\n", 1);
1425-
}
1426-
}
14271412
if (opt->heading && opt->last_shown == 0) {
14281413
output_color(opt, name, strlen(name), opt->colors[GREP_COLOR_FILENAME]);
14291414
opt->output(opt, "\n", 1);
@@ -1451,38 +1436,78 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
14511436
output_color(opt, buf, strlen(buf), opt->colors[GREP_COLOR_COLUMNNO]);
14521437
output_sep(opt, sign);
14531438
}
1454-
if (opt->color) {
1439+
}
1440+
1441+
static void show_line(struct grep_opt *opt, char *bol, char *eol,
1442+
const char *name, unsigned lno, ssize_t cno, char sign)
1443+
{
1444+
int rest = eol - bol;
1445+
const char *match_color = NULL;
1446+
const char *line_color = NULL;
1447+
1448+
if (opt->file_break && opt->last_shown == 0) {
1449+
if (opt->show_hunk_mark)
1450+
opt->output(opt, "\n", 1);
1451+
} else if (opt->pre_context || opt->post_context || opt->funcbody) {
1452+
if (opt->last_shown == 0) {
1453+
if (opt->show_hunk_mark) {
1454+
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
1455+
opt->output(opt, "\n", 1);
1456+
}
1457+
} else if (lno > opt->last_shown + 1) {
1458+
output_color(opt, "--", 2, opt->colors[GREP_COLOR_SEP]);
1459+
opt->output(opt, "\n", 1);
1460+
}
1461+
}
1462+
if (!opt->only_matching) {
1463+
/*
1464+
* In case the line we're being called with contains more than
1465+
* one match, leave printing each header to the loop below.
1466+
*/
1467+
show_line_header(opt, name, lno, cno, sign);
1468+
}
1469+
if (opt->color || opt->only_matching) {
14551470
regmatch_t match;
14561471
enum grep_context ctx = GREP_CONTEXT_BODY;
14571472
int ch = *eol;
14581473
int eflags = 0;
14591474

1460-
if (sign == ':')
1461-
match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
1462-
else
1463-
match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];
1464-
if (sign == ':')
1465-
line_color = opt->colors[GREP_COLOR_SELECTED];
1466-
else if (sign == '-')
1467-
line_color = opt->colors[GREP_COLOR_CONTEXT];
1468-
else if (sign == '=')
1469-
line_color = opt->colors[GREP_COLOR_FUNCTION];
1475+
if (opt->color) {
1476+
if (sign == ':')
1477+
match_color = opt->colors[GREP_COLOR_MATCH_SELECTED];
1478+
else
1479+
match_color = opt->colors[GREP_COLOR_MATCH_CONTEXT];
1480+
if (sign == ':')
1481+
line_color = opt->colors[GREP_COLOR_SELECTED];
1482+
else if (sign == '-')
1483+
line_color = opt->colors[GREP_COLOR_CONTEXT];
1484+
else if (sign == '=')
1485+
line_color = opt->colors[GREP_COLOR_FUNCTION];
1486+
}
14701487
*eol = '\0';
14711488
while (next_match(opt, bol, eol, ctx, &match, eflags)) {
14721489
if (match.rm_so == match.rm_eo)
14731490
break;
14741491

1475-
output_color(opt, bol, match.rm_so, line_color);
1492+
if (opt->only_matching)
1493+
show_line_header(opt, name, lno, cno, sign);
1494+
else
1495+
output_color(opt, bol, match.rm_so, line_color);
14761496
output_color(opt, bol + match.rm_so,
14771497
match.rm_eo - match.rm_so, match_color);
1498+
if (opt->only_matching)
1499+
opt->output(opt, "\n", 1);
14781500
bol += match.rm_eo;
1501+
cno += match.rm_eo;
14791502
rest -= match.rm_eo;
14801503
eflags = REG_NOTBOL;
14811504
}
14821505
*eol = ch;
14831506
}
1484-
output_color(opt, bol, rest, line_color);
1485-
opt->output(opt, "\n", 1);
1507+
if (!opt->only_matching) {
1508+
output_color(opt, bol, rest, line_color);
1509+
opt->output(opt, "\n", 1);
1510+
}
14861511
}
14871512

14881513
#ifndef NO_PTHREADS

grep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ struct grep_opt {
163163
int relative;
164164
int pathname;
165165
int null_following_name;
166+
int only_matching;
166167
int color;
167168
int max_depth;
168169
int funcname;

t/t7810-grep.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,21 @@ do
262262
fi
263263
'
264264

265+
test_expect_success "grep $L (with --column, --only-matching)" '
266+
{
267+
echo ${HC}file:1:5:mmap
268+
echo ${HC}file:2:5:mmap
269+
echo ${HC}file:3:5:mmap
270+
echo ${HC}file:3:13:mmap
271+
echo ${HC}file:4:5:mmap
272+
echo ${HC}file:4:13:mmap
273+
echo ${HC}file:5:5:mmap
274+
echo ${HC}file:5:13:mmap
275+
} >expected &&
276+
git grep --column -n -o -e mmap $H >actual &&
277+
test_cmp expected actual
278+
'
279+
265280
test_expect_success "grep $L (t-1)" '
266281
echo "${HC}t/t:1:test" >expected &&
267282
git grep -n -e test $H >actual &&

0 commit comments

Comments
 (0)