Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/git-grep.txt | 4 +++ builtin-grep.c | 6 +++- grep.c | 62 +++++++++++++++++++++++++++++++++++++++++--- grep.h | 1 + 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index a97f055..20ef098 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -16,6 +16,7 @@ SYNOPSIS [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] [-c | --count] [--all-match] + [--color] [-A <post-context>] [-B <pre-context>] [-C <context>] [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [<tree>...] @@ -85,6 +86,9 @@ OPTIONS Instead of showing every matched line, show the number of lines that match. +--color:: + Show colored matches. + -[ABC] <context>:: Show `context` trailing (`A` -- after), or leading (`B` -- before), or both (`C` -- context) lines, and place a diff --git a/builtin-grep.c b/builtin-grep.c index ef29910..118ec32 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -386,7 +386,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) * we grep through the checked-out files. It tends to * be a lot more optimized */ - if (!cached) { + if (!cached && !opt->color) { hit = external_grep(opt, paths, cached); if (hit >= 0) return hit; @@ -708,6 +708,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.relative = 0; continue; } + if (!strcmp("--color", arg)) { + opt.color = 1; + continue; + } if (!strcmp("--", arg)) { /* later processing wants to have this at argv[1] */ argv--; diff --git a/grep.c b/grep.c index f67d671..7cc05b0 100644 --- a/grep.c +++ b/grep.c @@ -247,7 +247,10 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) } } -static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) +static int match_one_pattern_1(struct grep_opt *opt, struct grep_pat *p, + char *bol, char *eol, + enum grep_context ctx, int eflags, + int *rm_so, int *rm_eo) { int hit = 0; int at_true_bol = 1; @@ -261,7 +264,7 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol if (!opt->fixed) { regex_t *exp = &p->regexp; hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), - pmatch, 0); + pmatch, eflags); } else { hit = !fixmatch(p->pattern, bol, pmatch); @@ -298,9 +301,20 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol goto again; } } + if (hit) { + if (rm_so) + *rm_so = pmatch[0].rm_so; + if (rm_eo) + *rm_eo = pmatch[0].rm_eo; + } return hit; } +static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) +{ + return match_one_pattern_1(opt, p, bol, eol, ctx, 0, NULL, NULL); +} + static int match_expr_eval(struct grep_opt *o, struct grep_expr *x, char *bol, char *eol, @@ -365,6 +379,42 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol, return 0; } +static void show_line_colored(struct grep_opt *opt, char *bol, char *eol, + const char *name, unsigned lno, char sign) +{ + struct grep_pat *p; + int rm_so, rm_eo, eflags = 0; + int ch; + + if (opt->pathname) + printf("%s%c", name, sign); + if (opt->linenum) + printf("%d%c", lno, sign); + + ch = *eol; + *eol = 0; + while (bol < eol) { + for (p = opt->pattern_list; p; p = p->next) { + if (match_one_pattern_1(opt, p, bol, eol, GREP_CONTEXT_BODY, eflags, &rm_so, &rm_eo)) + break; + } + + /* No match, break the loop */ + if (!p || + (rm_so < 0) || (eol - bol) <= rm_so || + (rm_eo < 0) || (eol - bol) < rm_eo) + break; + + printf("%.*s\033[31m\033[1m%.*s\033[m", + rm_so, bol, + rm_eo-rm_so, bol+rm_so); + bol += rm_eo; + eflags = REG_NOTBOL; + } + printf("%s\n", bol); + *eol = ch; +} + static int grep_buffer_1(struct grep_opt *opt, const char *name, char *buf, unsigned long size, int collect_hits) { @@ -466,8 +516,12 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, } if (last_shown && lno != last_shown + 1) printf(hunk_mark); - if (!opt->count) - show_line(opt, bol, eol, name, lno, ':'); + if (!opt->count) { + if (opt->color) + show_line_colored(opt, bol, eol, name, lno, ':'); + else + show_line(opt, bol, eol, name, lno, ':'); + } last_shown = last_hit = lno; } else if (last_hit && diff --git a/grep.h b/grep.h index d252dd2..979f7d0 100644 --- a/grep.h +++ b/grep.h @@ -68,6 +68,7 @@ struct grep_opt { unsigned extended:1; unsigned relative:1; unsigned pathname:1; + unsigned color:1; int regflags; unsigned pre_context; unsigned post_context; -- 1.5.5.GIT -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html