@@ -560,16 +560,68 @@ static void diff_words_append(char *line, unsigned long len,
560
560
buffer -> text .ptr [buffer -> text .size ] = '\0' ;
561
561
}
562
562
563
+ struct diff_words_style_elem
564
+ {
565
+ const char * prefix ;
566
+ const char * suffix ;
567
+ const char * color ; /* NULL; filled in by the setup code if
568
+ * color is enabled */
569
+ };
570
+
571
+ struct diff_words_style
572
+ {
573
+ enum diff_words_type type ;
574
+ struct diff_words_style_elem new , old , ctx ;
575
+ const char * newline ;
576
+ };
577
+
578
+ struct diff_words_style diff_words_styles [] = {
579
+ { DIFF_WORDS_PORCELAIN , {"+" , "\n" }, {"-" , "\n" }, {" " , "\n" }, "~\n" },
580
+ { DIFF_WORDS_PLAIN , {"{+" , "+}" }, {"[-" , "-]" }, {"" , "" }, "\n" },
581
+ { DIFF_WORDS_COLOR , {"" , "" }, {"" , "" }, {"" , "" }, "\n" }
582
+ };
583
+
563
584
struct diff_words_data {
564
585
struct diff_words_buffer minus , plus ;
565
586
const char * current_plus ;
566
587
FILE * file ;
567
588
regex_t * word_regex ;
589
+ enum diff_words_type type ;
590
+ struct diff_words_style * style ;
568
591
};
569
592
593
+ static int fn_out_diff_words_write_helper (FILE * fp ,
594
+ struct diff_words_style_elem * st_el ,
595
+ const char * newline ,
596
+ size_t count , const char * buf )
597
+ {
598
+ while (count ) {
599
+ char * p = memchr (buf , '\n' , count );
600
+ if (p != buf ) {
601
+ if (st_el -> color && fputs (st_el -> color , fp ) < 0 )
602
+ return -1 ;
603
+ if (fputs (st_el -> prefix , fp ) < 0 ||
604
+ fwrite (buf , p ? p - buf : count , 1 , fp ) != 1 ||
605
+ fputs (st_el -> suffix , fp ) < 0 )
606
+ return -1 ;
607
+ if (st_el -> color && * st_el -> color
608
+ && fputs (GIT_COLOR_RESET , fp ) < 0 )
609
+ return -1 ;
610
+ }
611
+ if (!p )
612
+ return 0 ;
613
+ if (fputs (newline , fp ) < 0 )
614
+ return -1 ;
615
+ count -= p + 1 - buf ;
616
+ buf = p + 1 ;
617
+ }
618
+ return 0 ;
619
+ }
620
+
570
621
static void fn_out_diff_words_aux (void * priv , char * line , unsigned long len )
571
622
{
572
623
struct diff_words_data * diff_words = priv ;
624
+ struct diff_words_style * style = diff_words -> style ;
573
625
int minus_first , minus_len , plus_first , plus_len ;
574
626
const char * minus_begin , * minus_end , * plus_begin , * plus_end ;
575
627
@@ -593,16 +645,17 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
593
645
plus_begin = plus_end = diff_words -> plus .orig [plus_first ].end ;
594
646
595
647
if (diff_words -> current_plus != plus_begin )
596
- fwrite (diff_words -> current_plus ,
597
- plus_begin - diff_words -> current_plus , 1 ,
598
- diff_words -> file );
648
+ fn_out_diff_words_write_helper (diff_words -> file ,
649
+ & style -> ctx , style -> newline ,
650
+ plus_begin - diff_words -> current_plus ,
651
+ diff_words -> current_plus );
599
652
if (minus_begin != minus_end )
600
- color_fwrite_lines (diff_words -> file ,
601
- diff_get_color ( 1 , DIFF_FILE_OLD ) ,
653
+ fn_out_diff_words_write_helper (diff_words -> file ,
654
+ & style -> old , style -> newline ,
602
655
minus_end - minus_begin , minus_begin );
603
656
if (plus_begin != plus_end )
604
- color_fwrite_lines (diff_words -> file ,
605
- diff_get_color ( 1 , DIFF_FILE_NEW ) ,
657
+ fn_out_diff_words_write_helper (diff_words -> file ,
658
+ & style -> new , style -> newline ,
606
659
plus_end - plus_begin , plus_begin );
607
660
608
661
diff_words -> current_plus = plus_end ;
@@ -684,11 +737,12 @@ static void diff_words_show(struct diff_words_data *diff_words)
684
737
xpparam_t xpp ;
685
738
xdemitconf_t xecfg ;
686
739
mmfile_t minus , plus ;
740
+ struct diff_words_style * style = diff_words -> style ;
687
741
688
742
/* special case: only removal */
689
743
if (!diff_words -> plus .text .size ) {
690
- color_fwrite_lines (diff_words -> file ,
691
- diff_get_color ( 1 , DIFF_FILE_OLD ) ,
744
+ fn_out_diff_words_write_helper (diff_words -> file ,
745
+ & style -> old , style -> newline ,
692
746
diff_words -> minus .text .size , diff_words -> minus .text .ptr );
693
747
diff_words -> minus .text .size = 0 ;
694
748
return ;
@@ -709,10 +763,10 @@ static void diff_words_show(struct diff_words_data *diff_words)
709
763
free (plus .ptr );
710
764
if (diff_words -> current_plus != diff_words -> plus .text .ptr +
711
765
diff_words -> plus .text .size )
712
- fwrite (diff_words -> current_plus ,
766
+ fn_out_diff_words_write_helper (diff_words -> file ,
767
+ & style -> ctx , style -> newline ,
713
768
diff_words -> plus .text .ptr + diff_words -> plus .text .size
714
- - diff_words -> current_plus , 1 ,
715
- diff_words -> file );
769
+ - diff_words -> current_plus , diff_words -> current_plus );
716
770
diff_words -> minus .text .size = diff_words -> plus .text .size = 0 ;
717
771
}
718
772
@@ -824,6 +878,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
824
878
825
879
if (len < 1 ) {
826
880
emit_line (ecbdata -> file , reset , reset , line , len );
881
+ if (ecbdata -> diff_words
882
+ && ecbdata -> diff_words -> type == DIFF_WORDS_PORCELAIN )
883
+ fputs ("~\n" , ecbdata -> file );
827
884
return ;
828
885
}
829
886
@@ -838,9 +895,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
838
895
return ;
839
896
}
840
897
diff_words_flush (ecbdata );
841
- line ++ ;
842
- len -- ;
843
- emit_line (ecbdata -> file , plain , reset , line , len );
898
+ if (ecbdata -> diff_words -> type == DIFF_WORDS_PORCELAIN ) {
899
+ emit_line (ecbdata -> file , plain , reset , line , len );
900
+ fputs ("~\n" , ecbdata -> file );
901
+ } else {
902
+ /* don't print the prefix character */
903
+ emit_line (ecbdata -> file , plain , reset , line + 1 , len - 1 );
904
+ }
844
905
return ;
845
906
}
846
907
@@ -1740,10 +1801,13 @@ static void builtin_diff(const char *name_a,
1740
1801
xecfg .ctxlen = strtoul (diffopts + 10 , NULL , 10 );
1741
1802
else if (!prefixcmp (diffopts , "-u" ))
1742
1803
xecfg .ctxlen = strtoul (diffopts + 2 , NULL , 10 );
1743
- if (DIFF_OPT_TST (o , COLOR_DIFF_WORDS )) {
1804
+ if (o -> word_diff ) {
1805
+ int i ;
1806
+
1744
1807
ecbdata .diff_words =
1745
1808
xcalloc (1 , sizeof (struct diff_words_data ));
1746
1809
ecbdata .diff_words -> file = o -> file ;
1810
+ ecbdata .diff_words -> type = o -> word_diff ;
1747
1811
if (!o -> word_regex )
1748
1812
o -> word_regex = userdiff_word_regex (one );
1749
1813
if (!o -> word_regex )
@@ -1759,10 +1823,23 @@ static void builtin_diff(const char *name_a,
1759
1823
die ("Invalid regular expression: %s" ,
1760
1824
o -> word_regex );
1761
1825
}
1826
+ for (i = 0 ; i < ARRAY_SIZE (diff_words_styles ); i ++ ) {
1827
+ if (o -> word_diff == diff_words_styles [i ].type ) {
1828
+ ecbdata .diff_words -> style =
1829
+ & diff_words_styles [i ];
1830
+ break ;
1831
+ }
1832
+ }
1833
+ if (DIFF_OPT_TST (o , COLOR_DIFF )) {
1834
+ struct diff_words_style * st = ecbdata .diff_words -> style ;
1835
+ st -> old .color = diff_get_color_opt (o , DIFF_FILE_OLD );
1836
+ st -> new .color = diff_get_color_opt (o , DIFF_FILE_NEW );
1837
+ st -> ctx .color = diff_get_color_opt (o , DIFF_PLAIN );
1838
+ }
1762
1839
}
1763
1840
xdi_diff_outf (& mf1 , & mf2 , fn_out_consume , & ecbdata ,
1764
1841
& xpp , & xecfg );
1765
- if (DIFF_OPT_TST ( o , COLOR_DIFF_WORDS ) )
1842
+ if (o -> word_diff )
1766
1843
free_diff_words_data (& ecbdata );
1767
1844
if (textconv_one )
1768
1845
free (mf1 .ptr );
@@ -2829,13 +2906,37 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
2829
2906
DIFF_OPT_CLR (options , COLOR_DIFF );
2830
2907
else if (!strcmp (arg , "--color-words" )) {
2831
2908
DIFF_OPT_SET (options , COLOR_DIFF );
2832
- DIFF_OPT_SET ( options , COLOR_DIFF_WORDS ) ;
2909
+ options -> word_diff = DIFF_WORDS_COLOR ;
2833
2910
}
2834
2911
else if (!prefixcmp (arg , "--color-words=" )) {
2835
2912
DIFF_OPT_SET (options , COLOR_DIFF );
2836
- DIFF_OPT_SET ( options , COLOR_DIFF_WORDS ) ;
2913
+ options -> word_diff = DIFF_WORDS_COLOR ;
2837
2914
options -> word_regex = arg + 14 ;
2838
2915
}
2916
+ else if (!strcmp (arg , "--word-diff" )) {
2917
+ if (options -> word_diff == DIFF_WORDS_NONE )
2918
+ options -> word_diff = DIFF_WORDS_PLAIN ;
2919
+ }
2920
+ else if (!prefixcmp (arg , "--word-diff=" )) {
2921
+ const char * type = arg + 12 ;
2922
+ if (!strcmp (type , "plain" ))
2923
+ options -> word_diff = DIFF_WORDS_PLAIN ;
2924
+ else if (!strcmp (type , "color" )) {
2925
+ DIFF_OPT_SET (options , COLOR_DIFF );
2926
+ options -> word_diff = DIFF_WORDS_COLOR ;
2927
+ }
2928
+ else if (!strcmp (type , "porcelain" ))
2929
+ options -> word_diff = DIFF_WORDS_PORCELAIN ;
2930
+ else if (!strcmp (type , "none" ))
2931
+ options -> word_diff = DIFF_WORDS_NONE ;
2932
+ else
2933
+ die ("bad --word-diff argument: %s" , type );
2934
+ }
2935
+ else if (!prefixcmp (arg , "--word-diff-regex=" )) {
2936
+ if (options -> word_diff == DIFF_WORDS_NONE )
2937
+ options -> word_diff = DIFF_WORDS_PLAIN ;
2938
+ options -> word_regex = arg + 18 ;
2939
+ }
2839
2940
else if (!strcmp (arg , "--exit-code" ))
2840
2941
DIFF_OPT_SET (options , EXIT_WITH_STATUS );
2841
2942
else if (!strcmp (arg , "--quiet" ))
0 commit comments