grep: add color.grep.matchcontext and color.grep.matchselected
authorRené Scharfe <l.s.r@web.de>
Mon, 27 Oct 2014 18:23:05 +0000 (19:23 +0100)
committerJunio C Hamano <gitster@pobox.com>
Tue, 28 Oct 2014 17:33:50 +0000 (10:33 -0700)
The config option color.grep.match can be used to specify the highlighting
color for matching strings. Add the options matchContext and matchSelected
to allow different colors to be specified for matching strings in the
context vs. in selected lines. This is similar to the ms and mc specifiers
in GNU grep's environment variable GREP_COLORS.

Tests are from Zoltan Klinger's earlier attempt to solve the same
issue in a different way.

Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
grep.c
grep.h
t/t7810-grep.sh
index ab26963d61877a2f8e03a3532ace5b31bc68738e..aa881fca1aa64f167784ef471671d030a340431a 100644 (file)
@@ -860,7 +860,11 @@ color.grep.<slot>::
 `linenumber`;;
        line number prefix (when using `-n`)
 `match`;;
 `linenumber`;;
        line number prefix (when using `-n`)
 `match`;;
-       matching text
+       matching text (same as setting `matchContext` and `matchSelected`)
+`matchContext`;;
+       matching text in context lines
+`matchSelected`;;
+       matching text in selected lines
 `selected`;;
        non-matching text in selected lines
 `separator`;;
 `selected`;;
        non-matching text in selected lines
 `separator`;;
diff --git a/grep.c b/grep.c
index c668034739258d0cd1e7108357da80d44891221f..f950651ae61e80cd57c6d224a461313d14cb320d 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -35,7 +35,8 @@ void init_grep_defaults(void)
        strcpy(opt->color_filename, "");
        strcpy(opt->color_function, "");
        strcpy(opt->color_lineno, "");
        strcpy(opt->color_filename, "");
        strcpy(opt->color_function, "");
        strcpy(opt->color_lineno, "");
-       strcpy(opt->color_match, GIT_COLOR_BOLD_RED);
+       strcpy(opt->color_match_context, GIT_COLOR_BOLD_RED);
+       strcpy(opt->color_match_selected, GIT_COLOR_BOLD_RED);
        strcpy(opt->color_selected, "");
        strcpy(opt->color_sep, GIT_COLOR_CYAN);
        opt->color = -1;
        strcpy(opt->color_selected, "");
        strcpy(opt->color_sep, GIT_COLOR_CYAN);
        opt->color = -1;
@@ -96,12 +97,22 @@ int grep_config(const char *var, const char *value, void *cb)
                color = opt->color_function;
        else if (!strcmp(var, "color.grep.linenumber"))
                color = opt->color_lineno;
                color = opt->color_function;
        else if (!strcmp(var, "color.grep.linenumber"))
                color = opt->color_lineno;
-       else if (!strcmp(var, "color.grep.match"))
-               color = opt->color_match;
+       else if (!strcmp(var, "color.grep.matchcontext"))
+               color = opt->color_match_context;
+       else if (!strcmp(var, "color.grep.matchselected"))
+               color = opt->color_match_selected;
        else if (!strcmp(var, "color.grep.selected"))
                color = opt->color_selected;
        else if (!strcmp(var, "color.grep.separator"))
                color = opt->color_sep;
        else if (!strcmp(var, "color.grep.selected"))
                color = opt->color_selected;
        else if (!strcmp(var, "color.grep.separator"))
                color = opt->color_sep;
+       else if (!strcmp(var, "color.grep.match")) {
+               int rc = 0;
+               if (!value)
+                       return config_error_nonbool(var);
+               color_parse(value, var, opt->color_match_context);
+               color_parse(value, var, opt->color_match_selected);
+               return rc;
+       }
 
        if (color) {
                if (!value)
 
        if (color) {
                if (!value)
@@ -139,7 +150,8 @@ void grep_init(struct grep_opt *opt, const char *prefix)
        strcpy(opt->color_filename, def->color_filename);
        strcpy(opt->color_function, def->color_function);
        strcpy(opt->color_lineno, def->color_lineno);
        strcpy(opt->color_filename, def->color_filename);
        strcpy(opt->color_function, def->color_function);
        strcpy(opt->color_lineno, def->color_lineno);
-       strcpy(opt->color_match, def->color_match);
+       strcpy(opt->color_match_context, def->color_match_context);
+       strcpy(opt->color_match_selected, def->color_match_selected);
        strcpy(opt->color_selected, def->color_selected);
        strcpy(opt->color_sep, def->color_sep);
 }
        strcpy(opt->color_selected, def->color_selected);
        strcpy(opt->color_sep, def->color_sep);
 }
@@ -1079,7 +1091,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                      const char *name, unsigned lno, char sign)
 {
        int rest = eol - bol;
                      const char *name, unsigned lno, char sign)
 {
        int rest = eol - bol;
-       char *line_color = NULL;
+       const char *match_color, *line_color = NULL;
 
        if (opt->file_break && opt->last_shown == 0) {
                if (opt->show_hunk_mark)
 
        if (opt->file_break && opt->last_shown == 0) {
                if (opt->show_hunk_mark)
@@ -1117,6 +1129,10 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                int ch = *eol;
                int eflags = 0;
 
                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 == '-')
                if (sign == ':')
                        line_color = opt->color_selected;
                else if (sign == '-')
@@ -1130,8 +1146,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
 
                        output_color(opt, bol, match.rm_so, line_color);
                        output_color(opt, bol + match.rm_so,
 
                        output_color(opt, bol, match.rm_so, line_color);
                        output_color(opt, bol + match.rm_so,
-                                    match.rm_eo - match.rm_so,
-                                    opt->color_match);
+                                    match.rm_eo - match.rm_so, match_color);
                        bol += match.rm_eo;
                        rest -= match.rm_eo;
                        eflags = REG_NOTBOL;
                        bol += match.rm_eo;
                        rest -= match.rm_eo;
                        eflags = REG_NOTBOL;
diff --git a/grep.h b/grep.h
index eaaced19737dfd46e718779cecadc352ff8d5f69..95f197a8d9bfc2a264530d17fcfa90f68dfa840d 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -124,7 +124,8 @@ struct grep_opt {
        char color_filename[COLOR_MAXLEN];
        char color_function[COLOR_MAXLEN];
        char color_lineno[COLOR_MAXLEN];
        char color_filename[COLOR_MAXLEN];
        char color_function[COLOR_MAXLEN];
        char color_lineno[COLOR_MAXLEN];
-       char color_match[COLOR_MAXLEN];
+       char color_match_context[COLOR_MAXLEN];
+       char color_match_selected[COLOR_MAXLEN];
        char color_selected[COLOR_MAXLEN];
        char color_sep[COLOR_MAXLEN];
        int regflags;
        char color_selected[COLOR_MAXLEN];
        char color_sep[COLOR_MAXLEN];
        int regflags;
index f698001c996ea20847c574f04dad9a65684f324f..e3eeaf988a932367a10c5e030c5d1cee4af8dcb9 100755 (executable)
@@ -1195,4 +1195,98 @@ test_expect_success LIBPCRE 'grep -P "^ "' '
        test_cmp expected actual
 '
 
        test_cmp expected actual
 '
 
+cat >expected <<EOF
+space-line without leading space1
+space: line <RED>with <RESET>leading space1
+space: line <RED>with <RESET>leading <RED>space2<RESET>
+space: line <RED>with <RESET>leading space3
+space:line without leading <RED>space2<RESET>
+EOF
+
+test_expect_success 'grep --color -e A -e B with context' '
+       test_config color.grep.context          normal &&
+       test_config color.grep.filename         normal &&
+       test_config color.grep.function         normal &&
+       test_config color.grep.linenumber       normal &&
+       test_config color.grep.matchContext     normal &&
+       test_config color.grep.matchSelected    red &&
+       test_config color.grep.selected         normal &&
+       test_config color.grep.separator        normal &&
+
+       git grep --color=always -C2 -e "with " -e space2  space |
+       test_decode_color >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+space-line without leading space1
+space- line with leading space1
+space: line <RED>with <RESET>leading <RED>space2<RESET>
+space- line with leading space3
+space-line without leading space2
+EOF
+
+test_expect_success 'grep --color -e A --and -e B with context' '
+       test_config color.grep.context          normal &&
+       test_config color.grep.filename         normal &&
+       test_config color.grep.function         normal &&
+       test_config color.grep.linenumber       normal &&
+       test_config color.grep.matchContext     normal &&
+       test_config color.grep.matchSelected    red &&
+       test_config color.grep.selected         normal &&
+       test_config color.grep.separator        normal &&
+
+       git grep --color=always -C2 -e "with " --and -e space2  space |
+       test_decode_color >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+space-line without leading space1
+space: line <RED>with <RESET>leading space1
+space- line with leading space2
+space: line <RED>with <RESET>leading space3
+space-line without leading space2
+EOF
+
+test_expect_success 'grep --color -e A --and --not -e B with context' '
+       test_config color.grep.context          normal &&
+       test_config color.grep.filename         normal &&
+       test_config color.grep.function         normal &&
+       test_config color.grep.linenumber       normal &&
+       test_config color.grep.matchContext     normal &&
+       test_config color.grep.matchSelected    red &&
+       test_config color.grep.selected         normal &&
+       test_config color.grep.separator        normal &&
+
+       git grep --color=always -C2 -e "with " --and --not -e space2  space |
+       test_decode_color >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+hello.c-#include <stdio.h>
+hello.c=int main(int argc, const char **argv)
+hello.c-{
+hello.c:       pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n");
+hello.c-       return 0;
+hello.c-       /* char ?? */
+hello.c-}
+EOF
+
+test_expect_success 'grep --color -e A --and -e B -p with context' '
+       test_config color.grep.context          normal &&
+       test_config color.grep.filename         normal &&
+       test_config color.grep.function         normal &&
+       test_config color.grep.linenumber       normal &&
+       test_config color.grep.matchContext     normal &&
+       test_config color.grep.matchSelected    red &&
+       test_config color.grep.selected         normal &&
+       test_config color.grep.separator        normal &&
+
+       git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c |
+       test_decode_color >actual &&
+       test_cmp expected actual
+'
+
 test_done
 test_done