Merge branch 'rs/grep-color'
* rs/grep-color: grep: add --heading grep: add --break grep: fix coloring of hunk marks between files
This commit is contained in:
commit
1692d0c64a
@ -148,6 +148,13 @@ OPTIONS
|
||||
gives the default to color output.
|
||||
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>::
|
||||
Show `context` trailing (`A` -- after), or leading (`B`
|
||||
-- before), or both (`C` -- context) lines, and place a
|
||||
|
@ -93,8 +93,7 @@ static pthread_cond_t cond_write;
|
||||
/* Signalled when we are finished with everything. */
|
||||
static pthread_cond_t cond_result;
|
||||
|
||||
static int print_hunk_marks_between_files;
|
||||
static int printed_something;
|
||||
static int skip_first_line;
|
||||
|
||||
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)) {
|
||||
w = &todo[todo_done];
|
||||
if (w->out.len) {
|
||||
if (print_hunk_marks_between_files && printed_something)
|
||||
write_or_die(1, "--\n", 3);
|
||||
write_or_die(1, w->out.buf, w->out.len);
|
||||
printed_something = 1;
|
||||
const char *p = w->out.buf;
|
||||
size_t len = w->out.len;
|
||||
|
||||
/* 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->identifier);
|
||||
@ -813,6 +822,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOLEAN('c', "count", &opt.count,
|
||||
"show the number of matches instead of matching lines"),
|
||||
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_CALLBACK('C', NULL, &opt, "n",
|
||||
"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;
|
||||
|
||||
if (use_threads) {
|
||||
if (opt.pre_context || opt.post_context)
|
||||
print_hunk_marks_between_files = 1;
|
||||
if (opt.pre_context || opt.post_context || opt.file_break)
|
||||
skip_first_line = 1;
|
||||
start_threads(&opt);
|
||||
}
|
||||
#else
|
||||
|
24
grep.c
24
grep.c
@ -721,7 +721,10 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
|
||||
int rest = eol - bol;
|
||||
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->show_hunk_mark) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (opt->pathname) {
|
||||
if (!opt->heading && opt->pathname) {
|
||||
output_color(opt, name, strlen(name), opt->color_filename);
|
||||
output_sep(opt, sign);
|
||||
}
|
||||
@ -941,9 +948,18 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
|
||||
if (!opt->output)
|
||||
opt->output = std_output;
|
||||
|
||||
if (opt->last_shown && (opt->pre_context || opt->post_context) &&
|
||||
opt->output == std_output)
|
||||
if (opt->pre_context || opt->post_context || opt->file_break) {
|
||||
/* Show hunk marks, except for the first file. */
|
||||
if (opt->last_shown)
|
||||
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;
|
||||
|
||||
switch (opt->binary) {
|
||||
|
2
grep.h
2
grep.h
@ -110,6 +110,8 @@ struct grep_opt {
|
||||
unsigned post_context;
|
||||
unsigned last_shown;
|
||||
int show_hunk_mark;
|
||||
int file_break;
|
||||
int heading;
|
||||
void *priv;
|
||||
|
||||
void (*output)(struct grep_opt *opt, const void *data, size_t size);
|
||||
|
@ -716,4 +716,99 @@ test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user