@@ -572,16 +572,68 @@ static void diff_words_append(char *line, unsigned long len,
572572 buffer -> text .ptr [buffer -> text .size ] = '\0' ;
573573}
574574
575+ struct diff_words_style_elem
576+ {
577+ const char * prefix ;
578+ const char * suffix ;
579+ const char * color ; /* NULL; filled in by the setup code if
580+ * color is enabled */
581+ };
582+
583+ struct diff_words_style
584+ {
585+ enum diff_words_type type ;
586+ struct diff_words_style_elem new , old , ctx ;
587+ const char * newline ;
588+ };
589+
590+ struct diff_words_style diff_words_styles [] = {
591+ { DIFF_WORDS_PORCELAIN , {"+" , "\n" }, {"-" , "\n" }, {" " , "\n" }, "~\n" },
592+ { DIFF_WORDS_PLAIN , {"{+" , "+}" }, {"[-" , "-]" }, {"" , "" }, "\n" },
593+ { DIFF_WORDS_COLOR , {"" , "" }, {"" , "" }, {"" , "" }, "\n" }
594+ };
595+
575596struct diff_words_data {
576597 struct diff_words_buffer minus , plus ;
577598 const char * current_plus ;
578599 FILE * file ;
579600 regex_t * word_regex ;
601+ enum diff_words_type type ;
602+ struct diff_words_style * style ;
580603};
581604
605+ static int fn_out_diff_words_write_helper (FILE * fp ,
606+ struct diff_words_style_elem * st_el ,
607+ const char * newline ,
608+ size_t count , const char * buf )
609+ {
610+ while (count ) {
611+ char * p = memchr (buf , '\n' , count );
612+ if (p != buf ) {
613+ if (st_el -> color && fputs (st_el -> color , fp ) < 0 )
614+ return -1 ;
615+ if (fputs (st_el -> prefix , fp ) < 0 ||
616+ fwrite (buf , p ? p - buf : count , 1 , fp ) != 1 ||
617+ fputs (st_el -> suffix , fp ) < 0 )
618+ return -1 ;
619+ if (st_el -> color && * st_el -> color
620+ && fputs (GIT_COLOR_RESET , fp ) < 0 )
621+ return -1 ;
622+ }
623+ if (!p )
624+ return 0 ;
625+ if (fputs (newline , fp ) < 0 )
626+ return -1 ;
627+ count -= p + 1 - buf ;
628+ buf = p + 1 ;
629+ }
630+ return 0 ;
631+ }
632+
582633static void fn_out_diff_words_aux (void * priv , char * line , unsigned long len )
583634{
584635 struct diff_words_data * diff_words = priv ;
636+ struct diff_words_style * style = diff_words -> style ;
585637 int minus_first , minus_len , plus_first , plus_len ;
586638 const char * minus_begin , * minus_end , * plus_begin , * plus_end ;
587639
@@ -605,16 +657,17 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
605657 plus_begin = plus_end = diff_words -> plus .orig [plus_first ].end ;
606658
607659 if (diff_words -> current_plus != plus_begin )
608- fwrite (diff_words -> current_plus ,
609- plus_begin - diff_words -> current_plus , 1 ,
610- diff_words -> file );
660+ fn_out_diff_words_write_helper (diff_words -> file ,
661+ & style -> ctx , style -> newline ,
662+ plus_begin - diff_words -> current_plus ,
663+ diff_words -> current_plus );
611664 if (minus_begin != minus_end )
612- color_fwrite_lines (diff_words -> file ,
613- diff_get_color ( 1 , DIFF_FILE_OLD ) ,
665+ fn_out_diff_words_write_helper (diff_words -> file ,
666+ & style -> old , style -> newline ,
614667 minus_end - minus_begin , minus_begin );
615668 if (plus_begin != plus_end )
616- color_fwrite_lines (diff_words -> file ,
617- diff_get_color ( 1 , DIFF_FILE_NEW ) ,
669+ fn_out_diff_words_write_helper (diff_words -> file ,
670+ & style -> new , style -> newline ,
618671 plus_end - plus_begin , plus_begin );
619672
620673 diff_words -> current_plus = plus_end ;
@@ -697,11 +750,12 @@ static void diff_words_show(struct diff_words_data *diff_words)
697750 xdemitconf_t xecfg ;
698751 xdemitcb_t ecb ;
699752 mmfile_t minus , plus ;
753+ struct diff_words_style * style = diff_words -> style ;
700754
701755 /* special case: only removal */
702756 if (!diff_words -> plus .text .size ) {
703- color_fwrite_lines (diff_words -> file ,
704- diff_get_color ( 1 , DIFF_FILE_OLD ) ,
757+ fn_out_diff_words_write_helper (diff_words -> file ,
758+ & style -> old , style -> newline ,
705759 diff_words -> minus .text .size , diff_words -> minus .text .ptr );
706760 diff_words -> minus .text .size = 0 ;
707761 return ;
@@ -722,10 +776,10 @@ static void diff_words_show(struct diff_words_data *diff_words)
722776 free (plus .ptr );
723777 if (diff_words -> current_plus != diff_words -> plus .text .ptr +
724778 diff_words -> plus .text .size )
725- fwrite (diff_words -> current_plus ,
779+ fn_out_diff_words_write_helper (diff_words -> file ,
780+ & style -> ctx , style -> newline ,
726781 diff_words -> plus .text .ptr + diff_words -> plus .text .size
727- - diff_words -> current_plus , 1 ,
728- diff_words -> file );
782+ - diff_words -> current_plus , diff_words -> current_plus );
729783 diff_words -> minus .text .size = diff_words -> plus .text .size = 0 ;
730784}
731785
@@ -837,6 +891,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
837891
838892 if (len < 1 ) {
839893 emit_line (ecbdata -> file , reset , reset , line , len );
894+ if (ecbdata -> diff_words
895+ && ecbdata -> diff_words -> type == DIFF_WORDS_PORCELAIN )
896+ fputs ("~\n" , ecbdata -> file );
840897 return ;
841898 }
842899
@@ -851,9 +908,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
851908 return ;
852909 }
853910 diff_words_flush (ecbdata );
854- line ++ ;
855- len -- ;
856- emit_line (ecbdata -> file , plain , reset , line , len );
911+ if (ecbdata -> diff_words -> type == DIFF_WORDS_PORCELAIN ) {
912+ emit_line (ecbdata -> file , plain , reset , line , len );
913+ fputs ("~\n" , ecbdata -> file );
914+ } else {
915+ /* don't print the prefix character */
916+ emit_line (ecbdata -> file , plain , reset , line + 1 , len - 1 );
917+ }
857918 return ;
858919 }
859920
@@ -1755,10 +1816,13 @@ static void builtin_diff(const char *name_a,
17551816 xecfg .ctxlen = strtoul (diffopts + 10 , NULL , 10 );
17561817 else if (!prefixcmp (diffopts , "-u" ))
17571818 xecfg .ctxlen = strtoul (diffopts + 2 , NULL , 10 );
1758- if (DIFF_OPT_TST (o , COLOR_DIFF_WORDS )) {
1819+ if (o -> word_diff ) {
1820+ int i ;
1821+
17591822 ecbdata .diff_words =
17601823 xcalloc (1 , sizeof (struct diff_words_data ));
17611824 ecbdata .diff_words -> file = o -> file ;
1825+ ecbdata .diff_words -> type = o -> word_diff ;
17621826 if (!o -> word_regex )
17631827 o -> word_regex = userdiff_word_regex (one );
17641828 if (!o -> word_regex )
@@ -1774,10 +1838,23 @@ static void builtin_diff(const char *name_a,
17741838 die ("Invalid regular expression: %s" ,
17751839 o -> word_regex );
17761840 }
1841+ for (i = 0 ; i < ARRAY_SIZE (diff_words_styles ); i ++ ) {
1842+ if (o -> word_diff == diff_words_styles [i ].type ) {
1843+ ecbdata .diff_words -> style =
1844+ & diff_words_styles [i ];
1845+ break ;
1846+ }
1847+ }
1848+ if (DIFF_OPT_TST (o , COLOR_DIFF )) {
1849+ struct diff_words_style * st = ecbdata .diff_words -> style ;
1850+ st -> old .color = diff_get_color_opt (o , DIFF_FILE_OLD );
1851+ st -> new .color = diff_get_color_opt (o , DIFF_FILE_NEW );
1852+ st -> ctx .color = diff_get_color_opt (o , DIFF_PLAIN );
1853+ }
17771854 }
17781855 xdi_diff_outf (& mf1 , & mf2 , fn_out_consume , & ecbdata ,
17791856 & xpp , & xecfg , & ecb );
1780- if (DIFF_OPT_TST ( o , COLOR_DIFF_WORDS ) )
1857+ if (o -> word_diff )
17811858 free_diff_words_data (& ecbdata );
17821859 if (textconv_one )
17831860 free (mf1 .ptr );
@@ -2845,13 +2922,37 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
28452922 DIFF_OPT_CLR (options , COLOR_DIFF );
28462923 else if (!strcmp (arg , "--color-words" )) {
28472924 DIFF_OPT_SET (options , COLOR_DIFF );
2848- DIFF_OPT_SET ( options , COLOR_DIFF_WORDS ) ;
2925+ options -> word_diff = DIFF_WORDS_COLOR ;
28492926 }
28502927 else if (!prefixcmp (arg , "--color-words=" )) {
28512928 DIFF_OPT_SET (options , COLOR_DIFF );
2852- DIFF_OPT_SET ( options , COLOR_DIFF_WORDS ) ;
2929+ options -> word_diff = DIFF_WORDS_COLOR ;
28532930 options -> word_regex = arg + 14 ;
28542931 }
2932+ else if (!strcmp (arg , "--word-diff" )) {
2933+ if (options -> word_diff == DIFF_WORDS_NONE )
2934+ options -> word_diff = DIFF_WORDS_PLAIN ;
2935+ }
2936+ else if (!prefixcmp (arg , "--word-diff=" )) {
2937+ const char * type = arg + 12 ;
2938+ if (!strcmp (type , "plain" ))
2939+ options -> word_diff = DIFF_WORDS_PLAIN ;
2940+ else if (!strcmp (type , "color" )) {
2941+ DIFF_OPT_SET (options , COLOR_DIFF );
2942+ options -> word_diff = DIFF_WORDS_COLOR ;
2943+ }
2944+ else if (!strcmp (type , "porcelain" ))
2945+ options -> word_diff = DIFF_WORDS_PORCELAIN ;
2946+ else if (!strcmp (type , "none" ))
2947+ options -> word_diff = DIFF_WORDS_NONE ;
2948+ else
2949+ die ("bad --word-diff argument: %s" , type );
2950+ }
2951+ else if (!prefixcmp (arg , "--word-diff-regex=" )) {
2952+ if (options -> word_diff == DIFF_WORDS_NONE )
2953+ options -> word_diff = DIFF_WORDS_PLAIN ;
2954+ options -> word_regex = arg + 18 ;
2955+ }
28552956 else if (!strcmp (arg , "--exit-code" ))
28562957 DIFF_OPT_SET (options , EXIT_WITH_STATUS );
28572958 else if (!strcmp (arg , "--quiet" ))
0 commit comments