44#include "run-command.h"
55#include "argv-array.h"
66#include "pathspec.h"
7+ #include "color.h"
78
89struct 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
4041static 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
94132static 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
101143static 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