Skip to content

Commit 55f638b

Browse files
MarkLodatogitster
authored andcommitted
grep: Colorize filename, line number, and separator
Colorize the filename, line number, and separator in git grep output, as GNU grep does. The colors are customizable through color.grep.<slot>. The default is to only color the separator (in cyan), since this gives the biggest legibility increase without overwhelming the user with colors. GNU grep also defaults cyan for the separator, but defaults to magenta for the filename and to green for the line number, as well. There is one difference from GNU grep: When a binary file matches without -a, GNU grep does not color the <file> in "Binary file <file> matches", but we do. Like GNU grep, if --null is given, the null separators are not colored. For config.txt, use a a sub-list to describe the slots, rather than a single paragraph with parentheses, since this is much more readable. Remove the cast to int for `rm_eo - rm_so` since it is not necessary. Signed-off-by: Mark Lodato <lodatom@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 758df17 commit 55f638b

File tree

4 files changed

+78
-34
lines changed

4 files changed

+78
-34
lines changed

Documentation/config.txt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -683,9 +683,23 @@ color.grep::
683683
`never`), never. When set to `true` or `auto`, use color only
684684
when the output is written to the terminal. Defaults to `false`.
685685

686-
color.grep.match::
687-
Use customized color for matches. The value of this variable
688-
may be specified as in color.branch.<slot>.
686+
color.grep.<slot>::
687+
Use customized color for grep colorization. `<slot>` specifies which
688+
part of the line to use the specified color, and is one of
689+
+
690+
--
691+
`filename`;;
692+
filename prefix (when not using `-h`)
693+
`linenumber`;;
694+
line number prefix (when using `-n`)
695+
`match`;;
696+
matching text
697+
`separator`;;
698+
separators between fields on a line (`:`, `-`, and `=`)
699+
and between hunks (`--`)
700+
--
701+
+
702+
The values of these variables may be specified as in color.branch.<slot>.
689703

690704
color.interactive::
691705
When set to `always`, always use colors for interactive prompts

builtin-grep.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -289,24 +289,32 @@ static int wait_all(void)
289289
static int grep_config(const char *var, const char *value, void *cb)
290290
{
291291
struct grep_opt *opt = cb;
292+
char *color = NULL;
292293

293294
switch (userdiff_config(var, value)) {
294295
case 0: break;
295296
case -1: return -1;
296297
default: return 0;
297298
}
298299

299-
if (!strcmp(var, "color.grep")) {
300+
if (!strcmp(var, "color.grep"))
300301
opt->color = git_config_colorbool(var, value, -1);
301-
return 0;
302-
}
303-
if (!strcmp(var, "color.grep.match")) {
302+
else if (!strcmp(var, "color.grep.filename"))
303+
color = opt->color_filename;
304+
else if (!strcmp(var, "color.grep.linenumber"))
305+
color = opt->color_lineno;
306+
else if (!strcmp(var, "color.grep.match"))
307+
color = opt->color_match;
308+
else if (!strcmp(var, "color.grep.separator"))
309+
color = opt->color_sep;
310+
else
311+
return git_color_default_config(var, value, cb);
312+
if (color) {
304313
if (!value)
305314
return config_error_nonbool(var);
306-
color_parse(value, var, opt->color_match);
307-
return 0;
315+
color_parse(value, var, color);
308316
}
309-
return git_color_default_config(var, value, cb);
317+
return 0;
310318
}
311319

312320
/*
@@ -871,7 +879,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
871879
opt.regflags = REG_NEWLINE;
872880
opt.max_depth = -1;
873881

882+
strcpy(opt.color_filename, "");
883+
strcpy(opt.color_lineno, "");
874884
strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
885+
strcpy(opt.color_sep, GIT_COLOR_CYAN);
875886
opt.color = -1;
876887
git_config(grep_config, &opt);
877888
if (opt.color == -1)

grep.c

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,28 @@ static int word_char(char ch)
270270
return isalnum(ch) || ch == '_';
271271
}
272272

273+
static void output_color(struct grep_opt *opt, const void *data, size_t size,
274+
const char *color)
275+
{
276+
if (opt->color && color && color[0]) {
277+
opt->output(opt, color, strlen(color));
278+
opt->output(opt, data, size);
279+
opt->output(opt, GIT_COLOR_RESET, strlen(GIT_COLOR_RESET));
280+
} else
281+
opt->output(opt, data, size);
282+
}
283+
284+
static void output_sep(struct grep_opt *opt, char sign)
285+
{
286+
if (opt->null_following_name)
287+
opt->output(opt, "\0", 1);
288+
else
289+
output_color(opt, &sign, 1, opt->color_sep);
290+
}
291+
273292
static void show_name(struct grep_opt *opt, const char *name)
274293
{
275-
opt->output(opt, name, strlen(name));
294+
output_color(opt, name, strlen(name), opt->color_filename);
276295
opt->output(opt, opt->null_following_name ? "\0" : "\n", 1);
277296
}
278297

@@ -510,31 +529,30 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
510529
const char *name, unsigned lno, char sign)
511530
{
512531
int rest = eol - bol;
513-
char sign_str[1];
514532

515-
sign_str[0] = sign;
516533
if (opt->pre_context || opt->post_context) {
517534
if (opt->last_shown == 0) {
518-
if (opt->show_hunk_mark)
519-
opt->output(opt, "--\n", 3);
520-
else
535+
if (opt->show_hunk_mark) {
536+
output_color(opt, "--", 2, opt->color_sep);
537+
opt->output(opt, "\n", 1);
538+
} else
521539
opt->show_hunk_mark = 1;
522-
} else if (lno > opt->last_shown + 1)
523-
opt->output(opt, "--\n", 3);
540+
} else if (lno > opt->last_shown + 1) {
541+
output_color(opt, "--", 2, opt->color_sep);
542+
opt->output(opt, "\n", 1);
543+
}
524544
}
525545
opt->last_shown = lno;
526546

527-
if (opt->null_following_name)
528-
sign_str[0] = '\0';
529547
if (opt->pathname) {
530-
opt->output(opt, name, strlen(name));
531-
opt->output(opt, sign_str, 1);
548+
output_color(opt, name, strlen(name), opt->color_filename);
549+
output_sep(opt, sign);
532550
}
533551
if (opt->linenum) {
534552
char buf[32];
535553
snprintf(buf, sizeof(buf), "%d", lno);
536-
opt->output(opt, buf, strlen(buf));
537-
opt->output(opt, sign_str, 1);
554+
output_color(opt, buf, strlen(buf), opt->color_lineno);
555+
output_sep(opt, sign);
538556
}
539557
if (opt->color) {
540558
regmatch_t match;
@@ -548,12 +566,9 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
548566
break;
549567

550568
opt->output(opt, bol, match.rm_so);
551-
opt->output(opt, opt->color_match,
552-
strlen(opt->color_match));
553-
opt->output(opt, bol + match.rm_so,
554-
(int)(match.rm_eo - match.rm_so));
555-
opt->output(opt, GIT_COLOR_RESET,
556-
strlen(GIT_COLOR_RESET));
569+
output_color(opt, bol + match.rm_so,
570+
match.rm_eo - match.rm_so,
571+
opt->color_match);
557572
bol += match.rm_eo;
558573
rest -= match.rm_eo;
559574
eflags = REG_NOTBOL;
@@ -823,7 +838,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
823838
return 1;
824839
if (binary_match_only) {
825840
opt->output(opt, "Binary file ", 12);
826-
opt->output(opt, name, strlen(name));
841+
output_color(opt, name, strlen(name),
842+
opt->color_filename);
827843
opt->output(opt, " matches\n", 9);
828844
return 1;
829845
}
@@ -882,9 +898,9 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
882898
*/
883899
if (opt->count && count) {
884900
char buf[32];
885-
opt->output(opt, name, strlen(name));
886-
snprintf(buf, sizeof(buf), "%c%u\n",
887-
opt->null_following_name ? '\0' : ':', count);
901+
output_color(opt, name, strlen(name), opt->color_filename);
902+
output_sep(opt, ':');
903+
snprintf(buf, sizeof(buf), "%u\n", count);
888904
opt->output(opt, buf, strlen(buf));
889905
}
890906
return !!last_hit;

grep.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ struct grep_opt {
8484
int color;
8585
int max_depth;
8686
int funcname;
87+
char color_filename[COLOR_MAXLEN];
88+
char color_lineno[COLOR_MAXLEN];
8789
char color_match[COLOR_MAXLEN];
90+
char color_sep[COLOR_MAXLEN];
8891
int regflags;
8992
unsigned pre_context;
9093
unsigned post_context;

0 commit comments

Comments
 (0)