66#include "pathspec.h"
77#include "color.h"
88#include "diff.h"
9+ #include "compat/terminal.h"
910
1011enum prompt_mode_type {
1112 PROMPT_MODE_CHANGE = 0 , PROMPT_DELETION , PROMPT_HUNK ,
@@ -360,6 +361,7 @@ static int is_octal(const char *p, size_t len)
360361static int parse_diff (struct add_p_state * s , const struct pathspec * ps )
361362{
362363 struct argv_array args = ARGV_ARRAY_INIT ;
364+ const char * diff_algorithm = s -> s .interactive_diff_algorithm ;
363365 struct strbuf * plain = & s -> plain , * colored = NULL ;
364366 struct child_process cp = CHILD_PROCESS_INIT ;
365367 char * p , * pend , * colored_p = NULL , * colored_pend = NULL , marker = '\0' ;
@@ -369,6 +371,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
369371 int res ;
370372
371373 argv_array_pushv (& args , s -> mode -> diff_cmd );
374+ if (diff_algorithm )
375+ argv_array_pushf (& args , "--diff-algorithm=%s" , diff_algorithm );
372376 if (s -> revision ) {
373377 struct object_id oid ;
374378 argv_array_push (& args ,
@@ -398,6 +402,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
398402
399403 if (want_color_fd (1 , -1 )) {
400404 struct child_process colored_cp = CHILD_PROCESS_INIT ;
405+ const char * diff_filter = s -> s .interactive_diff_filter ;
401406
402407 setup_child_process (s , & colored_cp , NULL );
403408 xsnprintf ((char * )args .argv [color_arg_index ], 8 , "--color" );
@@ -407,6 +412,24 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
407412 argv_array_clear (& args );
408413 if (res )
409414 return error (_ ("could not parse colored diff" ));
415+
416+ if (diff_filter ) {
417+ struct child_process filter_cp = CHILD_PROCESS_INIT ;
418+
419+ setup_child_process (s , & filter_cp ,
420+ diff_filter , NULL );
421+ filter_cp .git_cmd = 0 ;
422+ filter_cp .use_shell = 1 ;
423+ strbuf_reset (& s -> buf );
424+ if (pipe_command (& filter_cp ,
425+ colored -> buf , colored -> len ,
426+ & s -> buf , colored -> len ,
427+ NULL , 0 ) < 0 )
428+ return error (_ ("failed to run '%s'" ),
429+ diff_filter );
430+ strbuf_swap (colored , & s -> buf );
431+ }
432+
410433 strbuf_complete_line (colored );
411434 colored_p = colored -> buf ;
412435 colored_pend = colored_p + colored -> len ;
@@ -531,6 +554,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
531554 colored_pend - colored_p );
532555 if (colored_eol )
533556 colored_p = colored_eol + 1 ;
557+ else if (p != pend )
558+ /* colored shorter than non-colored? */
559+ goto mismatched_output ;
534560 else
535561 colored_p = colored_pend ;
536562
@@ -555,6 +581,15 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
555581 */
556582 hunk -> splittable_into ++ ;
557583
584+ /* non-colored shorter than colored? */
585+ if (colored_p != colored_pend ) {
586+ mismatched_output :
587+ error (_ ("mismatched output from interactive.diffFilter" ));
588+ advise (_ ("Your filter must maintain a one-to-one correspondence\n"
589+ "between its input and output lines." ));
590+ return -1 ;
591+ }
592+
558593 return 0 ;
559594}
560595
@@ -1115,14 +1150,27 @@ static int run_apply_check(struct add_p_state *s,
11151150 return 0 ;
11161151}
11171152
1153+ static int read_single_character (struct add_p_state * s )
1154+ {
1155+ if (s -> s .use_single_key ) {
1156+ int res = read_key_without_echo (& s -> answer );
1157+ printf ("%s\n" , res == EOF ? "" : s -> answer .buf );
1158+ return res ;
1159+ }
1160+
1161+ if (strbuf_getline (& s -> answer , stdin ) == EOF )
1162+ return EOF ;
1163+ strbuf_trim_trailing_newline (& s -> answer );
1164+ return 0 ;
1165+ }
1166+
11181167static int prompt_yesno (struct add_p_state * s , const char * prompt )
11191168{
11201169 for (;;) {
11211170 color_fprintf (stdout , s -> s .prompt_color , "%s" , _ (prompt ));
11221171 fflush (stdout );
1123- if (strbuf_getline ( & s -> answer , stdin ) == EOF )
1172+ if (read_single_character ( s ) == EOF )
11241173 return -1 ;
1125- strbuf_trim_trailing_newline (& s -> answer );
11261174 switch (tolower (s -> answer .buf [0 ])) {
11271175 case 'n' : return 0 ;
11281176 case 'y' : return 1 ;
@@ -1362,9 +1410,8 @@ static int patch_update_file(struct add_p_state *s,
13621410 _ (s -> mode -> prompt_mode [prompt_mode_type ]),
13631411 s -> buf .buf );
13641412 fflush (stdout );
1365- if (strbuf_getline ( & s -> answer , stdin ) == EOF )
1413+ if (read_single_character ( s ) == EOF )
13661414 break ;
1367- strbuf_trim_trailing_newline (& s -> answer );
13681415
13691416 if (!s -> answer .len )
13701417 continue ;
@@ -1612,6 +1659,7 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
16121659 parse_diff (& s , ps ) < 0 ) {
16131660 strbuf_release (& s .plain );
16141661 strbuf_release (& s .colored );
1662+ clear_add_i_state (& s .s );
16151663 return -1 ;
16161664 }
16171665
@@ -1630,5 +1678,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
16301678 strbuf_release (& s .buf );
16311679 strbuf_release (& s .plain );
16321680 strbuf_release (& s .colored );
1681+ clear_add_i_state (& s .s );
16331682 return 0 ;
16341683}
0 commit comments