grep.c: teach 'git grep --only-matching'
[gitweb.git] / grep.c
diff --git a/grep.c b/grep.c
index 4ff8a73043b194dbeb5fc7bd011e5931ad734846..49a744f96b373c6b90cde4d2d090eea2aa18cbc3 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -51,6 +51,7 @@ void init_grep_defaults(void)
        color_set(opt->color_match_selected, GIT_COLOR_BOLD_RED);
        color_set(opt->color_selected, "");
        color_set(opt->color_sep, GIT_COLOR_CYAN);
+       opt->only_matching = 0;
        opt->color = -1;
        opt->output = std_output;
 }
@@ -158,6 +159,7 @@ void grep_init(struct grep_opt *opt, const char *prefix)
        opt->pattern_tail = &opt->pattern_list;
        opt->header_tail = &opt->header_list;
 
+       opt->only_matching = def->only_matching;
        opt->color = def->color;
        opt->extended_regexp_option = def->extended_regexp_option;
        opt->pattern_type_option = def->pattern_type_option;
@@ -1446,7 +1448,8 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                      const char *name, unsigned lno, ssize_t cno, char sign)
 {
        int rest = eol - bol;
-       const char *match_color, *line_color = NULL;
+       const char *match_color = NULL;
+       const char *line_color = NULL;
 
        if (opt->file_break && opt->last_shown == 0) {
                if (opt->show_hunk_mark)
@@ -1462,39 +1465,55 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
                        opt->output(opt, "\n", 1);
                }
        }
-       show_line_header(opt, name, lno, cno, sign);
-       if (opt->color) {
+       if (!opt->only_matching) {
+               /*
+                * In case the line we're being called with contains more than
+                * one match, leave printing each header to the loop below.
+                */
+               show_line_header(opt, name, lno, cno, sign);
+       }
+       if (opt->color || opt->only_matching) {
                regmatch_t match;
                enum grep_context ctx = GREP_CONTEXT_BODY;
                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 == '-')
-                       line_color = opt->color_context;
-               else if (sign == '=')
-                       line_color = opt->color_function;
+               if (opt->color) {
+                       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 == '-')
+                               line_color = opt->color_context;
+                       else if (sign == '=')
+                               line_color = opt->color_function;
+               }
                *eol = '\0';
                while (next_match(opt, bol, eol, ctx, &match, eflags)) {
                        if (match.rm_so == match.rm_eo)
                                break;
 
-                       output_color(opt, bol, match.rm_so, line_color);
+                       if (opt->only_matching)
+                               show_line_header(opt, name, lno, cno, sign);
+                       else
+                               output_color(opt, bol, match.rm_so, line_color);
                        output_color(opt, bol + match.rm_so,
                                     match.rm_eo - match.rm_so, match_color);
+                       if (opt->only_matching)
+                               opt->output(opt, "\n", 1);
                        bol += match.rm_eo;
+                       cno += match.rm_eo;
                        rest -= match.rm_eo;
                        eflags = REG_NOTBOL;
                }
                *eol = ch;
        }
-       output_color(opt, bol, rest, line_color);
-       opt->output(opt, "\n", 1);
+       if (!opt->only_matching) {
+               output_color(opt, bol, rest, line_color);
+               opt->output(opt, "\n", 1);
+       }
 }
 
 #ifndef NO_PTHREADS