grep.[ch]: extend grep_opt to allow showing matched column
To support showing the matched column when calling 'git-grep(1)', teach 'grep_opt' the normal set of options to configure the default behavior and colorization of this feature. Now that we have opt->columnnum, use it to disable short-circuiting over ORs and ANDs so that col and icol are always filled with the earliest matches on each line. In addition, don't return the first match from match_line(), for the same reason. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Taylor Blau committed
Jun 22, 2018 at 10:49 UTC
017c0fcfdb21dd44e2c83f533e9a6d78513e7d8c
2 files changed
+39
-10
grep.c
+37
-10
@@ -46,6 +46,7 @@ void init_grep_defaults(void)
46
color_set(opt->color_filename, "");
47
color_set(opt->color_function, "");
48
color_set(opt->color_lineno, "");
49
+ color_set(opt->color_columnno, "");
50
color_set(opt->color_match_context, GIT_COLOR_BOLD_RED);
51
color_set(opt->color_match_selected, GIT_COLOR_BOLD_RED);
52
color_set(opt->color_selected, "");
@@ -155,6 +156,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
156
opt->extended_regexp_option = def->extended_regexp_option;
157
opt->pattern_type_option = def->pattern_type_option;
158
opt->linenum = def->linenum;
159
+ opt->columnnum = def->columnnum;
160
opt->max_depth = def->max_depth;
161
opt->pathname = def->pathname;
162
opt->relative = def->relative;
@@ -164,6 +166,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
166
color_set(opt->color_filename, def->color_filename);
167
color_set(opt->color_function, def->color_function);
168
color_set(opt->color_lineno, def->color_lineno);
169
+ color_set(opt->color_columnno, def->color_columnno);
170
color_set(opt->color_match_context, def->color_match_context);
171
color_set(opt->color_match_selected, def->color_match_selected);
172
color_set(opt->color_selected, def->color_selected);
@@ -1277,23 +1280,36 @@ static int match_expr_eval(struct grep_opt *opt, struct grep_expr *x, char *bol,
1280
0);
1281
break;
1282
case GREP_NODE_AND:
1280
- if (!match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col,
1281
- icol, 0))
1282
- return 0;
1283
- h = match_expr_eval(opt, x->u.binary.right, bol, eol, ctx, col,
1283
+ h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col,
1284
icol, 0);
1285
+ if (h || opt->columnnum) {
1286
+ /*
1287
+ * Don't short-circuit AND when given --column, since a
1288
+ * NOT earlier in the tree may turn this into an OR. In
1289
+ * this case, see the below comment.
1290
+ */
1291
+ h &= match_expr_eval(opt, x->u.binary.right, bol, eol,
1292
+ ctx, col, icol, 0);
1293
+ }
1294
break;
1295
case GREP_NODE_OR:
1287
- if (!collect_hits)
1296
+ if (!(collect_hits || opt->columnnum)) {
1297
+ /*
1298
+ * Don't short-circuit OR when given --column (or
1299
+ * collecting hits) to ensure we don't skip a later
1300
+ * child that would produce an earlier match.
1301
+ */
1302
return (match_expr_eval(opt, x->u.binary.left, bol, eol,
1303
ctx, col, icol, 0) ||
1304
match_expr_eval(opt, x->u.binary.right, bol,
1305
eol, ctx, col, icol, 0));
1306
+ }
1307
h = match_expr_eval(opt, x->u.binary.left, bol, eol, ctx, col,
1308
icol, 0);
1294
- x->u.binary.left->hit |= h;
1309
+ if (collect_hits)
1310
+ x->u.binary.left->hit |= h;
1311
h |= match_expr_eval(opt, x->u.binary.right, bol, eol, ctx, col,
1296
- icol, 1);
1312
+ icol, collect_hits);
1313
break;
1314
default:
1315
die("Unexpected node type (internal error) %d", x->node);
@@ -1316,6 +1332,7 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol,
1332
enum grep_context ctx, int collect_hits)
1333
{
1334
struct grep_pat *p;
1335
+ int hit = 0;
1336
1337
if (opt->extended)
1338
return match_expr(opt, bol, eol, ctx, col, icol,
@@ -1325,11 +1342,21 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol,
1342
for (p = opt->pattern_list; p; p = p->next) {
1343
regmatch_t tmp;
1344
if (match_one_pattern(p, bol, eol, ctx, &tmp, 0)) {
1328
- *col = tmp.rm_so;
1329
- return 1;
1345
+ hit |= 1;
1346
+ if (!opt->columnnum) {
1347
+ /*
1348
+ * Without --column, any single match on a line
1349
+ * is enough to know that it needs to be
1350
+ * printed. With --column, scan _all_ patterns
1351
+ * to find the earliest.
1352
+ */
1353
+ break;
1354
+ }
1355
+ if (*col < 0 || tmp.rm_so < *col)
1356
+ *col = tmp.rm_so;
1357
}
1358
}
1332
- return 0;
1359
+ return hit;
1360
}
1361
1362
static int match_next_pattern(struct grep_pat *p, char *bol, char *eol,
grep.h
+2
@@ -127,6 +127,7 @@ struct grep_opt {
127
int prefix_length;
128
regex_t regexp;
129
int linenum;
130
+ int columnnum;
131
int invert;
132
int ignore_case;
133
int status_only;
@@ -159,6 +160,7 @@ struct grep_opt {
160
char color_filename[COLOR_MAXLEN];
161
char color_function[COLOR_MAXLEN];
162
char color_lineno[COLOR_MAXLEN];
163
+ char color_columnno[COLOR_MAXLEN];
164
char color_match_context[COLOR_MAXLEN];
165
char color_match_selected[COLOR_MAXLEN];
166
char color_selected[COLOR_MAXLEN];