git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] git-grep: add --color to highlight matches

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
May 24, 2008, 04:31 UTC
Message-ID
<20080524043118.GA23118@laptop>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 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
Next: Jakub Narebski
Message 1 of 10 in “git-grep: add --color to highlight matches”
  1. git-grep: add --color to highlight matchesNguyễn Thái Ngọc Duy, May 24, 2008
  2. Jakub NarebskiMay 24, 2008
  3. Nguyen Thai Ngoc DuyMay 24, 2008
  4. Jakub NarebskiMay 24, 2008
  5. Andreas EricssonMay 26, 2008
  6. Johannes SchindelinMay 26, 2008
  7. Nguyen Thai Ngoc DuyMay 26, 2008
  8. Johannes SchindelinMay 26, 2008
  9. Nguyen Thai Ngoc DuyMay 26, 2008
  10. Johannes SchindelinMay 26, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.