Skip to content

Commit e79b65b

Browse files
committed
built-in add -p: show colored hunks by default
Just like the Perl version, we now generate two diffs if `color.diff` is set: one with and one without color. Then we parse them in parallel and record which hunks start at which offsets in both. Note that this is a (slight) deviation from the way the Perl version did it: we are no longer reading the output of `diff-files` line by line (which is more natural for Perl than for C), but in one go, and parse everything later, so we might just as well do it in synchrony. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent cf4bbd3 commit e79b65b

File tree

1 file changed

+62
-17
lines changed

1 file changed

+62
-17
lines changed

add-patch.c

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
#include "run-command.h"
55
#include "argv-array.h"
66
#include "pathspec.h"
7+
#include "color.h"
78

89
struct hunk {
9-
size_t start, end;
10+
size_t start, end, colored_start, colored_end;
1011
enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
1112
};
1213

@@ -15,7 +16,7 @@ struct add_p_state {
1516
struct strbuf answer, buf;
1617

1718
/* parsed diff */
18-
struct strbuf plain;
19+
struct strbuf plain, colored;
1920
struct hunk head;
2021
struct hunk *hunk;
2122
size_t hunk_nr, hunk_alloc;
@@ -39,26 +40,50 @@ static void setup_child_process(struct child_process *cp,
3940

4041
static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
4142
{
42-
struct strbuf *plain = &s->plain;
43+
struct argv_array args = ARGV_ARRAY_INIT;
44+
struct strbuf *plain = &s->plain, *colored = NULL;
4345
struct child_process cp = CHILD_PROCESS_INIT;
44-
char *p, *pend;
45-
size_t i;
46+
char *p, *pend, *colored_p = NULL, *colored_pend = NULL;
47+
size_t i, color_arg_index;
4648
struct hunk *hunk = NULL;
4749
int res;
4850

4951
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
50-
setup_child_process(&cp, s,
51-
"diff-files", "-p", "--no-color", "--", NULL);
52+
argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
53+
color_arg_index = args.argc - 2;
5254
for (i = 0; i < ps->nr; i++)
53-
argv_array_push(&cp.args, ps->items[i].original);
55+
argv_array_push(&args, ps->items[i].original);
5456

57+
setup_child_process(&cp, s, NULL);
58+
cp.argv = args.argv;
5559
res = capture_command(&cp, plain, 0);
56-
if (res)
60+
if (res) {
61+
argv_array_clear(&args);
5762
return error(_("could not parse diff"));
58-
if (!plain->len)
63+
}
64+
if (!plain->len) {
65+
argv_array_clear(&args);
5966
return 0;
67+
}
6068
strbuf_complete_line(plain);
6169

70+
if (want_color_fd(1, -1)) {
71+
struct child_process colored_cp = CHILD_PROCESS_INIT;
72+
73+
setup_child_process(&colored_cp, s, NULL);
74+
xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
75+
colored_cp.argv = args.argv;
76+
colored = &s->colored;
77+
res = capture_command(&colored_cp, colored, 0);
78+
argv_array_clear(&args);
79+
if (res)
80+
return error(_("could not parse colored diff"));
81+
strbuf_complete_line(colored);
82+
colored_p = colored->buf;
83+
colored_pend = colored_p + colored->len;
84+
}
85+
argv_array_clear(&args);
86+
6287
/* parse hunks */
6388
p = plain->buf;
6489
pend = p + plain->len;
@@ -82,33 +107,50 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
82107
memset(hunk, 0, sizeof(*hunk));
83108

84109
hunk->start = p - plain->buf;
110+
if (colored)
111+
hunk->colored_start = colored_p - colored->buf;
85112
}
86113

87114
p = eol == pend ? pend : eol + 1;
88115
hunk->end = p - plain->buf;
116+
117+
if (colored) {
118+
char *colored_eol = memchr(colored_p, '\n',
119+
colored_pend - colored_p);
120+
if (colored_eol)
121+
colored_p = colored_eol + 1;
122+
else
123+
colored_p = colored_pend;
124+
125+
hunk->colored_end = colored_p - colored->buf;
126+
}
89127
}
90128

91129
return 0;
92130
}
93131

94132
static void render_hunk(struct add_p_state *s, struct hunk *hunk,
95-
struct strbuf *out)
133+
int colored, struct strbuf *out)
96134
{
97-
strbuf_add(out, s->plain.buf + hunk->start,
98-
hunk->end - hunk->start);
135+
if (colored)
136+
strbuf_add(out, s->colored.buf + hunk->colored_start,
137+
hunk->colored_end - hunk->colored_start);
138+
else
139+
strbuf_add(out, s->plain.buf + hunk->start,
140+
hunk->end - hunk->start);
99141
}
100142

101143
static void reassemble_patch(struct add_p_state *s, struct strbuf *out)
102144
{
103145
struct hunk *hunk;
104146
size_t i;
105147

106-
render_hunk(s, &s->head, out);
148+
render_hunk(s, &s->head, 0, out);
107149

108150
for (i = 0; i < s->hunk_nr; i++) {
109151
hunk = s->hunk + i;
110152
if (hunk->use == USE_HUNK)
111-
render_hunk(s, hunk, out);
153+
render_hunk(s, hunk, 0, out);
112154
}
113155
}
114156

@@ -130,12 +172,13 @@ static int patch_update_file(struct add_p_state *s)
130172
struct hunk *hunk;
131173
char ch;
132174
struct child_process cp = CHILD_PROCESS_INIT;
175+
int colored = !!s->colored.len;
133176

134177
if (!s->hunk_nr)
135178
return 0;
136179

137180
strbuf_reset(&s->buf);
138-
render_hunk(s, &s->head, &s->buf);
181+
render_hunk(s, &s->head, colored, &s->buf);
139182
fputs(s->buf.buf, stdout);
140183
for (;;) {
141184
if (hunk_index >= s->hunk_nr)
@@ -162,7 +205,7 @@ static int patch_update_file(struct add_p_state *s)
162205
break;
163206

164207
strbuf_reset(&s->buf);
165-
render_hunk(s, hunk, &s->buf);
208+
render_hunk(s, hunk, colored, &s->buf);
166209
fputs(s->buf.buf, stdout);
167210

168211
strbuf_reset(&s->buf);
@@ -247,6 +290,7 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
247290
if (repo_refresh_and_write_index(r, REFRESH_QUIET, 0) < 0 ||
248291
parse_diff(&s, ps) < 0) {
249292
strbuf_release(&s.plain);
293+
strbuf_release(&s.colored);
250294
return -1;
251295
}
252296

@@ -256,5 +300,6 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
256300
strbuf_release(&s.answer);
257301
strbuf_release(&s.buf);
258302
strbuf_release(&s.plain);
303+
strbuf_release(&s.colored);
259304
return 0;
260305
}

0 commit comments

Comments
 (0)