@matheusbsbs / matheus-bagliano / commits / e3bd11b4eb
Fork 0

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 <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Dec 13, 2019 at 08:07 UTC e3bd11b4ebed7dd6fd0cccc6765be64f76cc5766
1 file changed +62 -17
add-patch.c
+62 -17
@@ -4,9 +4,10 @@
4 #include "run-command.h"
5 #include "argv-array.h"
6 #include "pathspec.h"
7 +#include "color.h"
8
9 struct hunk {
9 - size_t start, end;
10 + size_t start, end, colored_start, colored_end;
11 enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
12 };
13
@@ -15,7 +16,7 @@ struct add_p_state {
16 struct strbuf answer, buf;
17
18 /* parsed diff */
18 - struct strbuf plain;
19 + struct strbuf plain, colored;
20 struct hunk head;
21 struct hunk *hunk;
22 size_t hunk_nr, hunk_alloc;
@@ -39,26 +40,50 @@ static void setup_child_process(struct add_p_state *s,
40
41 static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
42 {
42 - struct strbuf *plain = &s->plain;
43 + struct argv_array args = ARGV_ARRAY_INIT;
44 + struct strbuf *plain = &s->plain, *colored = NULL;
45 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;
48 struct hunk *hunk = NULL;
49 int res;
50
51 /* Use `--no-color` explicitly, just in case `diff.color = always`. */
50 - setup_child_process(s, &cp,
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;
54 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);
56
57 + setup_child_process(s, &cp, NULL);
58 + cp.argv = args.argv;
59 res = capture_command(&cp, plain, 0);
56 - if (res)
60 + if (res) {
61 + argv_array_clear(&args);
62 return error(_("could not parse diff"));
58 - if (!plain->len)
63 + }
64 + if (!plain->len) {
65 + argv_array_clear(&args);
66 return 0;
67 + }
68 strbuf_complete_line(plain);
69
70 + if (want_color_fd(1, -1)) {
71 + struct child_process colored_cp = CHILD_PROCESS_INIT;
72 +
73 + setup_child_process(s, &colored_cp, 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 +
87 /* parse hunks */
88 p = plain->buf;
89 pend = p + plain->len;
@@ -82,20 +107,37 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
107 memset(hunk, 0, sizeof(*hunk));
108
109 hunk->start = p - plain->buf;
110 + if (colored)
111 + hunk->colored_start = colored_p - colored->buf;
112 }
113
114 p = eol == pend ? pend : eol + 1;
115 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 + }
127 }
128
129 return 0;
130 }
131
132 static void render_hunk(struct add_p_state *s, struct hunk *hunk,
95 - struct strbuf *out)
133 + int colored, struct strbuf *out)
134 {
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);
141 }
142
143 static void reassemble_patch(struct add_p_state *s, struct strbuf *out)
@@ -103,12 +145,12 @@ static void reassemble_patch(struct add_p_state *s, struct strbuf *out)
145 struct hunk *hunk;
146 size_t i;
147
106 - render_hunk(s, &s->head, out);
148 + render_hunk(s, &s->head, 0, out);
149
150 for (i = 0; i < s->hunk_nr; i++) {
151 hunk = s->hunk + i;
152 if (hunk->use == USE_HUNK)
111 - render_hunk(s, hunk, out);
153 + render_hunk(s, hunk, 0, out);
154 }
155 }
156
@@ -130,12 +172,13 @@ static int patch_update_file(struct add_p_state *s)
172 struct hunk *hunk;
173 char ch;
174 struct child_process cp = CHILD_PROCESS_INIT;
175 + int colored = !!s->colored.len;
176
177 if (!s->hunk_nr)
178 return 0;
179
180 strbuf_reset(&s->buf);
138 - render_hunk(s, &s->head, &s->buf);
181 + render_hunk(s, &s->head, colored, &s->buf);
182 fputs(s->buf.buf, stdout);
183 for (;;) {
184 if (hunk_index >= s->hunk_nr)
@@ -162,7 +205,7 @@ static int patch_update_file(struct add_p_state *s)
205 break;
206
207 strbuf_reset(&s->buf);
165 - render_hunk(s, hunk, &s->buf);
208 + render_hunk(s, hunk, colored, &s->buf);
209 fputs(s->buf.buf, stdout);
210
211 strbuf_reset(&s->buf);
@@ -252,6 +295,7 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
295 NULL, NULL, NULL) < 0 ||
296 parse_diff(&s, ps) < 0) {
297 strbuf_release(&s.plain);
298 + strbuf_release(&s.colored);
299 return -1;
300 }
301
@@ -261,5 +305,6 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
305 strbuf_release(&s.answer);
306 strbuf_release(&s.buf);
307 strbuf_release(&s.plain);
308 + strbuf_release(&s.colored);
309 return 0;
310 }