Browse Source

Merge branch 'rs/grep-color'

* rs/grep-color:
  grep: add --heading
  grep: add --break
  grep: fix coloring of hunk marks between files
maint
Junio C Hamano 14 years ago
parent
commit
1692d0c64a
  1. 7
      Documentation/git-grep.txt
  2. 29
      builtin/grep.c
  3. 24
      grep.c
  4. 2
      grep.h
  5. 95
      t/t7810-grep.sh

7
Documentation/git-grep.txt

@ -148,6 +148,13 @@ OPTIONS
gives the default to color output. gives the default to color output.
Same as `--color=never`. Same as `--color=never`.


--break::
Print an empty line between matches from different files.

--heading::
Show the filename above the matches in that file instead of
at the start of each shown line.

-[ABC] <context>:: -[ABC] <context>::
Show `context` trailing (`A` -- after), or leading (`B` Show `context` trailing (`A` -- after), or leading (`B`
-- before), or both (`C` -- context) lines, and place a -- before), or both (`C` -- context) lines, and place a

29
builtin/grep.c

@ -93,8 +93,7 @@ static pthread_cond_t cond_write;
/* Signalled when we are finished with everything. */ /* Signalled when we are finished with everything. */
static pthread_cond_t cond_result; static pthread_cond_t cond_result;


static int print_hunk_marks_between_files; static int skip_first_line;
static int printed_something;


static void add_work(enum work_type type, char *name, void *id) static void add_work(enum work_type type, char *name, void *id)
{ {
@ -160,10 +159,20 @@ static void work_done(struct work_item *w)
todo_done = (todo_done+1) % ARRAY_SIZE(todo)) { todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
w = &todo[todo_done]; w = &todo[todo_done];
if (w->out.len) { if (w->out.len) {
if (print_hunk_marks_between_files && printed_something) const char *p = w->out.buf;
write_or_die(1, "--\n", 3); size_t len = w->out.len;
write_or_die(1, w->out.buf, w->out.len);
printed_something = 1; /* Skip the leading hunk mark of the first file. */
if (skip_first_line) {
while (len) {
len--;
if (*p++ == '\n')
break;
}
skip_first_line = 0;
}

write_or_die(1, p, len);
} }
free(w->name); free(w->name);
free(w->identifier); free(w->identifier);
@ -813,6 +822,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN('c', "count", &opt.count, OPT_BOOLEAN('c', "count", &opt.count,
"show the number of matches instead of matching lines"), "show the number of matches instead of matching lines"),
OPT__COLOR(&opt.color, "highlight matches"), OPT__COLOR(&opt.color, "highlight matches"),
OPT_BOOLEAN(0, "break", &opt.file_break,
"print empty line between matches from different files"),
OPT_BOOLEAN(0, "heading", &opt.heading,
"show filename only once above matches from same file"),
OPT_GROUP(""), OPT_GROUP(""),
OPT_CALLBACK('C', NULL, &opt, "n", OPT_CALLBACK('C', NULL, &opt, "n",
"show <n> context lines before and after matches", "show <n> context lines before and after matches",
@ -967,8 +980,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
use_threads = 0; use_threads = 0;


if (use_threads) { if (use_threads) {
if (opt.pre_context || opt.post_context) if (opt.pre_context || opt.post_context || opt.file_break)
print_hunk_marks_between_files = 1; skip_first_line = 1;
start_threads(&opt); start_threads(&opt);
} }
#else #else

24
grep.c

@ -721,7 +721,10 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
int rest = eol - bol; int rest = eol - bol;
char *line_color = NULL; char *line_color = NULL;


if (opt->pre_context || opt->post_context) { if (opt->file_break && opt->last_shown == 0) {
if (opt->show_hunk_mark)
opt->output(opt, "\n", 1);
} else if (opt->pre_context || opt->post_context) {
if (opt->last_shown == 0) { if (opt->last_shown == 0) {
if (opt->show_hunk_mark) { if (opt->show_hunk_mark) {
output_color(opt, "--", 2, opt->color_sep); output_color(opt, "--", 2, opt->color_sep);
@ -732,9 +735,13 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
opt->output(opt, "\n", 1); opt->output(opt, "\n", 1);
} }
} }
if (opt->heading && opt->last_shown == 0) {
output_color(opt, name, strlen(name), opt->color_filename);
opt->output(opt, "\n", 1);
}
opt->last_shown = lno; opt->last_shown = lno;


if (opt->pathname) { if (!opt->heading && opt->pathname) {
output_color(opt, name, strlen(name), opt->color_filename); output_color(opt, name, strlen(name), opt->color_filename);
output_sep(opt, sign); output_sep(opt, sign);
} }
@ -941,9 +948,18 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
if (!opt->output) if (!opt->output)
opt->output = std_output; opt->output = std_output;


if (opt->last_shown && (opt->pre_context || opt->post_context) && if (opt->pre_context || opt->post_context || opt->file_break) {
opt->output == std_output) /* Show hunk marks, except for the first file. */
if (opt->last_shown)
opt->show_hunk_mark = 1; opt->show_hunk_mark = 1;
/*
* If we're using threads then we can't easily identify
* the first file. Always put hunk marks in that case
* and skip the very first one later in work_done().
*/
if (opt->output != std_output)
opt->show_hunk_mark = 1;
}
opt->last_shown = 0; opt->last_shown = 0;


switch (opt->binary) { switch (opt->binary) {

2
grep.h

@ -110,6 +110,8 @@ struct grep_opt {
unsigned post_context; unsigned post_context;
unsigned last_shown; unsigned last_shown;
int show_hunk_mark; int show_hunk_mark;
int file_break;
int heading;
void *priv; void *priv;


void (*output)(struct grep_opt *opt, const void *data, size_t size); void (*output)(struct grep_opt *opt, const void *data, size_t size);

95
t/t7810-grep.sh

@ -716,4 +716,99 @@ test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
test_cmp expected actual test_cmp expected actual
' '


test_config() {
git config "$1" "$2" &&
test_when_finished "git config --unset $1"
}

cat >expected <<EOF
hello.c<RED>:<RESET>int main(int argc, const char **argv)
hello.c<RED>-<RESET>{
<RED>--<RESET>
hello.c<RED>:<RESET> /* char ?? */
hello.c<RED>-<RESET>}
<RED>--<RESET>
hello_world<RED>:<RESET>Hello_world
hello_world<RED>-<RESET>HeLLo_world
EOF

test_expect_success 'grep --color, separator' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.match normal &&
test_config color.grep.selected normal &&
test_config color.grep.separator red &&

git grep --color=always -A1 -e char -e lo_w hello.c hello_world |
test_decode_color >actual &&
test_cmp expected actual
'

cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c: /* char ?? */

hello_world:Hello_world
EOF

test_expect_success 'grep --break' '
git grep --break -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'

cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c-{
--
hello.c: /* char ?? */
hello.c-}

hello_world:Hello_world
hello_world-HeLLo_world
EOF

test_expect_success 'grep --break with context' '
git grep --break -A1 -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'

cat >expected <<EOF
hello.c
int main(int argc, const char **argv)
/* char ?? */
hello_world
Hello_world
EOF

test_expect_success 'grep --heading' '
git grep --heading -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'

cat >expected <<EOF
<BOLD;GREEN>hello.c<RESET>
2:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv)
6: /* <BLACK;BYELLOW>char<RESET> ?? */

<BOLD;GREEN>hello_world<RESET>
3:Hel<BLACK;BYELLOW>lo_w<RESET>orld
EOF

test_expect_success 'mimic ack-grep --group' '
test_config color.grep.context normal &&
test_config color.grep.filename "bold green" &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.match "black yellow" &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&

git grep --break --heading -n --color \
-e char -e lo_w hello.c hello_world |
test_decode_color >actual &&
test_cmp expected actual
'

test_done test_done

Loading…
Cancel
Save