@@ -561,17 +561,54 @@ static void emit_line(struct diff_options *o, const char *set, const char *reset
561561}
562562
563563enum diff_symbol {
564+ DIFF_SYMBOL_CONTEXT ,
565+ DIFF_SYMBOL_PLUS ,
566+ DIFF_SYMBOL_MINUS ,
564567 DIFF_SYMBOL_NO_LF_EOF ,
565568 DIFF_SYMBOL_CONTEXT_FRAGINFO ,
566569 DIFF_SYMBOL_CONTEXT_MARKER ,
567570 DIFF_SYMBOL_SEPARATOR
568571};
572+ /*
573+ * Flags for content lines:
574+ * 0..12 are whitespace rules
575+ * 13-15 are WSEH_NEW | WSEH_OLD | WSEH_CONTEXT
576+ * 16 is marking if the line is blank at EOF
577+ */
578+ #define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<16)
579+ #define DIFF_SYMBOL_CONTENT_WS_MASK (WSEH_NEW | WSEH_OLD | WSEH_CONTEXT | WS_RULE_MASK)
580+
581+ static void emit_line_ws_markup (struct diff_options * o ,
582+ const char * set , const char * reset ,
583+ const char * line , int len , char sign ,
584+ unsigned ws_rule , int blank_at_eof )
585+ {
586+ const char * ws = NULL ;
587+
588+ if (o -> ws_error_highlight & ws_rule ) {
589+ ws = diff_get_color_opt (o , DIFF_WHITESPACE );
590+ if (!* ws )
591+ ws = NULL ;
592+ }
593+
594+ if (!ws )
595+ emit_line_0 (o , set , reset , sign , line , len );
596+ else if (blank_at_eof )
597+ /* Blank line at EOF - paint '+' as well */
598+ emit_line_0 (o , ws , reset , sign , line , len );
599+ else {
600+ /* Emit just the prefix, then the rest. */
601+ emit_line_0 (o , set , reset , sign , "" , 0 );
602+ ws_check_emit (line , len , ws_rule ,
603+ o -> file , set , reset , ws );
604+ }
605+ }
569606
570607static void emit_diff_symbol (struct diff_options * o , enum diff_symbol s ,
571- const char * line , int len )
608+ const char * line , int len , unsigned flags )
572609{
573610 static const char * nneof = " No newline at end of file\n" ;
574- const char * context , * reset ;
611+ const char * context , * reset , * set ;
575612 switch (s ) {
576613 case DIFF_SYMBOL_NO_LF_EOF :
577614 context = diff_get_color_opt (o , DIFF_CONTEXT );
@@ -593,6 +630,25 @@ static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
593630 diff_line_prefix (o ),
594631 o -> line_termination );
595632 break ;
633+ case DIFF_SYMBOL_CONTEXT :
634+ set = diff_get_color_opt (o , DIFF_CONTEXT );
635+ reset = diff_get_color_opt (o , DIFF_RESET );
636+ emit_line_ws_markup (o , set , reset , line , len , ' ' ,
637+ flags & (DIFF_SYMBOL_CONTENT_WS_MASK ), 0 );
638+ break ;
639+ case DIFF_SYMBOL_PLUS :
640+ set = diff_get_color_opt (o , DIFF_FILE_NEW );
641+ reset = diff_get_color_opt (o , DIFF_RESET );
642+ emit_line_ws_markup (o , set , reset , line , len , '+' ,
643+ flags & DIFF_SYMBOL_CONTENT_WS_MASK ,
644+ flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF );
645+ break ;
646+ case DIFF_SYMBOL_MINUS :
647+ set = diff_get_color_opt (o , DIFF_FILE_OLD );
648+ reset = diff_get_color_opt (o , DIFF_RESET );
649+ emit_line_ws_markup (o , set , reset , line , len , '-' ,
650+ flags & DIFF_SYMBOL_CONTENT_WS_MASK , 0 );
651+ break ;
596652 default :
597653 die ("BUG: unknown diff symbol" );
598654 }
@@ -609,57 +665,31 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
609665 return ws_blank_line (line , len , ecbdata -> ws_rule );
610666}
611667
612- static void emit_line_checked (const char * reset ,
613- struct emit_callback * ecbdata ,
614- const char * line , int len ,
615- enum color_diff color ,
616- unsigned ws_error_highlight ,
617- char sign )
618- {
619- const char * set = diff_get_color (ecbdata -> color_diff , color );
620- const char * ws = NULL ;
621-
622- if (ecbdata -> opt -> ws_error_highlight & ws_error_highlight ) {
623- ws = diff_get_color (ecbdata -> color_diff , DIFF_WHITESPACE );
624- if (!* ws )
625- ws = NULL ;
626- }
627-
628- if (!ws )
629- emit_line_0 (ecbdata -> opt , set , reset , sign , line , len );
630- else if (sign == '+' && new_blank_line_at_eof (ecbdata , line , len ))
631- /* Blank line at EOF - paint '+' as well */
632- emit_line_0 (ecbdata -> opt , ws , reset , sign , line , len );
633- else {
634- /* Emit just the prefix, then the rest. */
635- emit_line_0 (ecbdata -> opt , set , reset , sign , "" , 0 );
636- ws_check_emit (line , len , ecbdata -> ws_rule ,
637- ecbdata -> opt -> file , set , reset , ws );
638- }
639- }
640-
641668static void emit_add_line (const char * reset ,
642669 struct emit_callback * ecbdata ,
643670 const char * line , int len )
644671{
645- emit_line_checked (reset , ecbdata , line , len ,
646- DIFF_FILE_NEW , WSEH_NEW , '+' );
672+ unsigned flags = WSEH_NEW | ecbdata -> ws_rule ;
673+ if (new_blank_line_at_eof (ecbdata , line , len ))
674+ flags |= DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF ;
675+
676+ emit_diff_symbol (ecbdata -> opt , DIFF_SYMBOL_PLUS , line , len , flags );
647677}
648678
649679static void emit_del_line (const char * reset ,
650680 struct emit_callback * ecbdata ,
651681 const char * line , int len )
652682{
653- emit_line_checked ( reset , ecbdata , line , len ,
654- DIFF_FILE_OLD , WSEH_OLD , '-' );
683+ unsigned flags = WSEH_OLD | ecbdata -> ws_rule ;
684+ emit_diff_symbol ( ecbdata -> opt , DIFF_SYMBOL_MINUS , line , len , flags );
655685}
656686
657687static void emit_context_line (const char * reset ,
658688 struct emit_callback * ecbdata ,
659689 const char * line , int len )
660690{
661- emit_line_checked ( reset , ecbdata , line , len ,
662- DIFF_CONTEXT , WSEH_CONTEXT , ' ' );
691+ unsigned flags = WSEH_CONTEXT | ecbdata -> ws_rule ;
692+ emit_diff_symbol ( ecbdata -> opt , DIFF_SYMBOL_CONTEXT , line , len , flags );
663693}
664694
665695static void emit_hunk_header (struct emit_callback * ecbdata ,
@@ -683,7 +713,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
683713 memcmp (line , atat , 2 ) ||
684714 !(ep = memmem (line + 2 , len - 2 , atat , 2 ))) {
685715 emit_diff_symbol (ecbdata -> opt ,
686- DIFF_SYMBOL_CONTEXT_MARKER , line , len );
716+ DIFF_SYMBOL_CONTEXT_MARKER , line , len , 0 );
687717 return ;
688718 }
689719 ep += 2 ; /* skip over @@ */
@@ -719,7 +749,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
719749 strbuf_add (& msgbuf , line + len , org_len - len );
720750 strbuf_complete_line (& msgbuf );
721751 emit_diff_symbol (ecbdata -> opt ,
722- DIFF_SYMBOL_CONTEXT_FRAGINFO , msgbuf .buf , msgbuf .len );
752+ DIFF_SYMBOL_CONTEXT_FRAGINFO , msgbuf .buf , msgbuf .len , 0 );
723753 strbuf_release (& msgbuf );
724754}
725755
@@ -778,7 +808,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
778808 data += len ;
779809 }
780810 if (!endp )
781- emit_diff_symbol (ecb -> opt , DIFF_SYMBOL_NO_LF_EOF , NULL , 0 );
811+ emit_diff_symbol (ecb -> opt , DIFF_SYMBOL_NO_LF_EOF , NULL , 0 , 0 );
782812}
783813
784814static void emit_rewrite_diff (const char * name_a ,
@@ -4771,6 +4801,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
47714801{
47724802 int i ;
47734803 struct diff_queue_struct * q = & diff_queued_diff ;
4804+
4805+ if (WSEH_NEW & WS_RULE_MASK )
4806+ die ("BUG: WS rules bit mask overlaps with diff symbol flags" );
4807+
47744808 for (i = 0 ; i < q -> nr ; i ++ ) {
47754809 struct diff_filepair * p = q -> queue [i ];
47764810 if (check_pair_status (p ))
@@ -4861,7 +4895,7 @@ void diff_flush(struct diff_options *options)
48614895
48624896 if (output_format & DIFF_FORMAT_PATCH ) {
48634897 if (separator ) {
4864- emit_diff_symbol (options , DIFF_SYMBOL_SEPARATOR , NULL , 0 );
4898+ emit_diff_symbol (options , DIFF_SYMBOL_SEPARATOR , NULL , 0 , 0 );
48654899 if (options -> stat_sep ) {
48664900 /* attach patch instead of inline */
48674901 fputs (options -> stat_sep , options -> file );
0 commit comments