grep: add color.grep.matchcontext and color.grep.matchselected

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>

René Scharfe committed Oct 27, 2014 at 19:23 UTC 79a77109d3d0d364910ff7fa8c605c554dc4c3e0
4 files changed +123 -9
Documentation/config.txt
+5 -1
@@ -860,7 +860,11 @@ color.grep.<slot>::
860 `linenumber`;;
861 line number prefix (when using `-n`)
862 `match`;;
863 - matching text
863 + matching text (same as setting `matchContext` and `matchSelected`)
864 +`matchContext`;;
865 + matching text in context lines
866 +`matchSelected`;;
867 + matching text in selected lines
868 `selected`;;
869 non-matching text in selected lines
870 `separator`;;
grep.c
+22 -7
@@ -35,7 +35,8 @@ void init_grep_defaults(void)
35 strcpy(opt->color_filename, "");
36 strcpy(opt->color_function, "");
37 strcpy(opt->color_lineno, "");
38 - strcpy(opt->color_match, GIT_COLOR_BOLD_RED);
38 + strcpy(opt->color_match_context, GIT_COLOR_BOLD_RED);
39 + strcpy(opt->color_match_selected, GIT_COLOR_BOLD_RED);
40 strcpy(opt->color_selected, "");
41 strcpy(opt->color_sep, GIT_COLOR_CYAN);
42 opt->color = -1;
@@ -96,12 +97,22 @@ int grep_config(const char *var, const char *value, void *cb)
97 color = opt->color_function;
98 else if (!strcmp(var, "color.grep.linenumber"))
99 color = opt->color_lineno;
99 - else if (!strcmp(var, "color.grep.match"))
100 - color = opt->color_match;
100 + else if (!strcmp(var, "color.grep.matchcontext"))
101 + color = opt->color_match_context;
102 + else if (!strcmp(var, "color.grep.matchselected"))
103 + color = opt->color_match_selected;
104 else if (!strcmp(var, "color.grep.selected"))
105 color = opt->color_selected;
106 else if (!strcmp(var, "color.grep.separator"))
107 color = opt->color_sep;
108 + else if (!strcmp(var, "color.grep.match")) {
109 + int rc = 0;
110 + if (!value)
111 + return config_error_nonbool(var);
112 + color_parse(value, var, opt->color_match_context);
113 + color_parse(value, var, opt->color_match_selected);
114 + return rc;
115 + }
116
117 if (color) {
118 if (!value)
@@ -139,7 +150,8 @@ void grep_init(struct grep_opt *opt, const char *prefix)
150 strcpy(opt->color_filename, def->color_filename);
151 strcpy(opt->color_function, def->color_function);
152 strcpy(opt->color_lineno, def->color_lineno);
142 - strcpy(opt->color_match, def->color_match);
153 + strcpy(opt->color_match_context, def->color_match_context);
154 + strcpy(opt->color_match_selected, def->color_match_selected);
155 strcpy(opt->color_selected, def->color_selected);
156 strcpy(opt->color_sep, def->color_sep);
157 }
@@ -1079,7 +1091,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
1091 const char *name, unsigned lno, char sign)
1092 {
1093 int rest = eol - bol;
1082 - char *line_color = NULL;
1094 + const char *match_color, *line_color = NULL;
1095
1096 if (opt->file_break && opt->last_shown == 0) {
1097 if (opt->show_hunk_mark)
@@ -1117,6 +1129,10 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
1129 int ch = *eol;
1130 int eflags = 0;
1131
1132 + if (sign == ':')
1133 + match_color = opt->color_match_selected;
1134 + else
1135 + match_color = opt->color_match_context;
1136 if (sign == ':')
1137 line_color = opt->color_selected;
1138 else if (sign == '-')
@@ -1130,8 +1146,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
1146
1147 output_color(opt, bol, match.rm_so, line_color);
1148 output_color(opt, bol + match.rm_so,
1133 - match.rm_eo - match.rm_so,
1134 - opt->color_match);
1149 + match.rm_eo - match.rm_so, match_color);
1150 bol += match.rm_eo;
1151 rest -= match.rm_eo;
1152 eflags = REG_NOTBOL;
grep.h
+2 -1
@@ -124,7 +124,8 @@ struct grep_opt {
124 char color_filename[COLOR_MAXLEN];
125 char color_function[COLOR_MAXLEN];
126 char color_lineno[COLOR_MAXLEN];
127 - char color_match[COLOR_MAXLEN];
127 + char color_match_context[COLOR_MAXLEN];
128 + char color_match_selected[COLOR_MAXLEN];
129 char color_selected[COLOR_MAXLEN];
130 char color_sep[COLOR_MAXLEN];
131 int regflags;
t/t7810-grep.sh
+94
@@ -1195,4 +1195,98 @@ test_expect_success LIBPCRE 'grep -P "^ "' '
1195 test_cmp expected actual
1196 '
1197
1198 +cat >expected <<EOF
1199 +space-line without leading space1
1200 +space: line <RED>with <RESET>leading space1
1201 +space: line <RED>with <RESET>leading <RED>space2<RESET>
1202 +space: line <RED>with <RESET>leading space3
1203 +space:line without leading <RED>space2<RESET>
1204 +EOF
1205 +
1206 +test_expect_success 'grep --color -e A -e B with context' '
1207 + test_config color.grep.context normal &&
1208 + test_config color.grep.filename normal &&
1209 + test_config color.grep.function normal &&
1210 + test_config color.grep.linenumber normal &&
1211 + test_config color.grep.matchContext normal &&
1212 + test_config color.grep.matchSelected red &&
1213 + test_config color.grep.selected normal &&
1214 + test_config color.grep.separator normal &&
1215 +
1216 + git grep --color=always -C2 -e "with " -e space2 space |
1217 + test_decode_color >actual &&
1218 + test_cmp expected actual
1219 +'
1220 +
1221 +cat >expected <<EOF
1222 +space-line without leading space1
1223 +space- line with leading space1
1224 +space: line <RED>with <RESET>leading <RED>space2<RESET>
1225 +space- line with leading space3
1226 +space-line without leading space2
1227 +EOF
1228 +
1229 +test_expect_success 'grep --color -e A --and -e B with context' '
1230 + test_config color.grep.context normal &&
1231 + test_config color.grep.filename normal &&
1232 + test_config color.grep.function normal &&
1233 + test_config color.grep.linenumber normal &&
1234 + test_config color.grep.matchContext normal &&
1235 + test_config color.grep.matchSelected red &&
1236 + test_config color.grep.selected normal &&
1237 + test_config color.grep.separator normal &&
1238 +
1239 + git grep --color=always -C2 -e "with " --and -e space2 space |
1240 + test_decode_color >actual &&
1241 + test_cmp expected actual
1242 +'
1243 +
1244 +cat >expected <<EOF
1245 +space-line without leading space1
1246 +space: line <RED>with <RESET>leading space1
1247 +space- line with leading space2
1248 +space: line <RED>with <RESET>leading space3
1249 +space-line without leading space2
1250 +EOF
1251 +
1252 +test_expect_success 'grep --color -e A --and --not -e B with context' '
1253 + test_config color.grep.context normal &&
1254 + test_config color.grep.filename normal &&
1255 + test_config color.grep.function normal &&
1256 + test_config color.grep.linenumber normal &&
1257 + test_config color.grep.matchContext normal &&
1258 + test_config color.grep.matchSelected red &&
1259 + test_config color.grep.selected normal &&
1260 + test_config color.grep.separator normal &&
1261 +
1262 + git grep --color=always -C2 -e "with " --and --not -e space2 space |
1263 + test_decode_color >actual &&
1264 + test_cmp expected actual
1265 +'
1266 +
1267 +cat >expected <<EOF
1268 +hello.c-#include <stdio.h>
1269 +hello.c=int main(int argc, const char **argv)
1270 +hello.c-{
1271 +hello.c: pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n");
1272 +hello.c- return 0;
1273 +hello.c- /* char ?? */
1274 +hello.c-}
1275 +EOF
1276 +
1277 +test_expect_success 'grep --color -e A --and -e B -p with context' '
1278 + test_config color.grep.context normal &&
1279 + test_config color.grep.filename normal &&
1280 + test_config color.grep.function normal &&
1281 + test_config color.grep.linenumber normal &&
1282 + test_config color.grep.matchContext normal &&
1283 + test_config color.grep.matchSelected red &&
1284 + test_config color.grep.selected normal &&
1285 + test_config color.grep.separator normal &&
1286 +
1287 + git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c |
1288 + test_decode_color >actual &&
1289 + test_cmp expected actual
1290 +'
1291 +
1292 test_done