@@ -478,26 +478,59 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
478478 return ws_blank_line (line , len , ecbdata -> ws_rule );
479479}
480480
481- static void emit_add_line (const char * reset ,
482- struct emit_callback * ecbdata ,
483- const char * line , int len )
481+ static void emit_line_checked (const char * reset ,
482+ struct emit_callback * ecbdata ,
483+ const char * line , int len ,
484+ enum color_diff color ,
485+ unsigned ws_error_highlight ,
486+ char sign )
484487{
485- const char * ws = diff_get_color (ecbdata -> color_diff , DIFF_WHITESPACE );
486- const char * set = diff_get_color ( ecbdata -> color_diff , DIFF_FILE_NEW ) ;
488+ const char * set = diff_get_color (ecbdata -> color_diff , color );
489+ const char * ws = NULL ;
487490
488- if (!* ws )
489- emit_line_0 (ecbdata -> opt , set , reset , '+' , line , len );
490- else if (new_blank_line_at_eof (ecbdata , line , len ))
491+ if (ecbdata -> opt -> ws_error_highlight & ws_error_highlight ) {
492+ ws = diff_get_color (ecbdata -> color_diff , DIFF_WHITESPACE );
493+ if (!* ws )
494+ ws = NULL ;
495+ }
496+
497+ if (!ws )
498+ emit_line_0 (ecbdata -> opt , set , reset , sign , line , len );
499+ else if (sign == '+' && new_blank_line_at_eof (ecbdata , line , len ))
491500 /* Blank line at EOF - paint '+' as well */
492- emit_line_0 (ecbdata -> opt , ws , reset , '+' , line , len );
501+ emit_line_0 (ecbdata -> opt , ws , reset , sign , line , len );
493502 else {
494503 /* Emit just the prefix, then the rest. */
495- emit_line_0 (ecbdata -> opt , set , reset , '+' , "" , 0 );
504+ emit_line_0 (ecbdata -> opt , set , reset , sign , "" , 0 );
496505 ws_check_emit (line , len , ecbdata -> ws_rule ,
497506 ecbdata -> opt -> file , set , reset , ws );
498507 }
499508}
500509
510+ static void emit_add_line (const char * reset ,
511+ struct emit_callback * ecbdata ,
512+ const char * line , int len )
513+ {
514+ emit_line_checked (reset , ecbdata , line , len ,
515+ DIFF_FILE_NEW , WSEH_NEW , '+' );
516+ }
517+
518+ static void emit_del_line (const char * reset ,
519+ struct emit_callback * ecbdata ,
520+ const char * line , int len )
521+ {
522+ emit_line_checked (reset , ecbdata , line , len ,
523+ DIFF_FILE_OLD , WSEH_OLD , '-' );
524+ }
525+
526+ static void emit_context_line (const char * reset ,
527+ struct emit_callback * ecbdata ,
528+ const char * line , int len )
529+ {
530+ emit_line_checked (reset , ecbdata , line , len ,
531+ DIFF_PLAIN , WSEH_CONTEXT , ' ' );
532+ }
533+
501534static void emit_hunk_header (struct emit_callback * ecbdata ,
502535 const char * line , int len )
503536{
@@ -603,7 +636,6 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
603636{
604637 const char * endp = NULL ;
605638 static const char * nneof = " No newline at end of file\n" ;
606- const char * old = diff_get_color (ecb -> color_diff , DIFF_FILE_OLD );
607639 const char * reset = diff_get_color (ecb -> color_diff , DIFF_RESET );
608640
609641 while (0 < size ) {
@@ -613,8 +645,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
613645 len = endp ? (endp - data + 1 ) : size ;
614646 if (prefix != '+' ) {
615647 ecb -> lno_in_preimage ++ ;
616- emit_line_0 (ecb -> opt , old , reset , '-' ,
617- data , len );
648+ emit_del_line (reset , ecb , data , len );
618649 } else {
619650 ecb -> lno_in_postimage ++ ;
620651 emit_add_line (reset , ecb , data , len );
@@ -1250,17 +1281,27 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
12501281 return ;
12511282 }
12521283
1253- if (line [0 ] != '+' ) {
1254- const char * color =
1255- diff_get_color (ecbdata -> color_diff ,
1256- line [0 ] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN );
1257- ecbdata -> lno_in_preimage ++ ;
1258- if (line [0 ] == ' ' )
1259- ecbdata -> lno_in_postimage ++ ;
1260- emit_line (ecbdata -> opt , color , reset , line , len );
1261- } else {
1284+ switch (line [0 ]) {
1285+ case '+' :
12621286 ecbdata -> lno_in_postimage ++ ;
12631287 emit_add_line (reset , ecbdata , line + 1 , len - 1 );
1288+ break ;
1289+ case '-' :
1290+ ecbdata -> lno_in_preimage ++ ;
1291+ emit_del_line (reset , ecbdata , line + 1 , len - 1 );
1292+ break ;
1293+ case ' ' :
1294+ ecbdata -> lno_in_postimage ++ ;
1295+ ecbdata -> lno_in_preimage ++ ;
1296+ emit_context_line (reset , ecbdata , line + 1 , len - 1 );
1297+ break ;
1298+ default :
1299+ /* incomplete line at the end */
1300+ ecbdata -> lno_in_preimage ++ ;
1301+ emit_line (ecbdata -> opt ,
1302+ diff_get_color (ecbdata -> color_diff , DIFF_PLAIN ),
1303+ reset , line , len );
1304+ break ;
12641305 }
12651306}
12661307
@@ -3223,6 +3264,7 @@ void diff_setup(struct diff_options *options)
32233264 options -> rename_limit = -1 ;
32243265 options -> dirstat_permille = diff_dirstat_permille_default ;
32253266 options -> context = diff_context_default ;
3267+ options -> ws_error_highlight = WSEH_NEW ;
32263268 DIFF_OPT_SET (options , RENAME_EMPTY );
32273269
32283270 /* pathchange left =NULL by default */
@@ -3609,6 +3651,40 @@ static void enable_patch_output(int *fmt) {
36093651 * fmt |= DIFF_FORMAT_PATCH ;
36103652}
36113653
3654+ static int parse_one_token (const char * * arg , const char * token )
3655+ {
3656+ return skip_prefix (* arg , token , arg ) && (!* * arg || * * arg == ',' );
3657+ }
3658+
3659+ static int parse_ws_error_highlight (struct diff_options * opt , const char * arg )
3660+ {
3661+ const char * orig_arg = arg ;
3662+ unsigned val = 0 ;
3663+ while (* arg ) {
3664+ if (parse_one_token (& arg , "none" ))
3665+ val = 0 ;
3666+ else if (parse_one_token (& arg , "default" ))
3667+ val = WSEH_NEW ;
3668+ else if (parse_one_token (& arg , "all" ))
3669+ val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT ;
3670+ else if (parse_one_token (& arg , "new" ))
3671+ val |= WSEH_NEW ;
3672+ else if (parse_one_token (& arg , "old" ))
3673+ val |= WSEH_OLD ;
3674+ else if (parse_one_token (& arg , "context" ))
3675+ val |= WSEH_CONTEXT ;
3676+ else {
3677+ error ("unknown value after ws-error-highlight=%.*s" ,
3678+ (int )(arg - orig_arg ), orig_arg );
3679+ return 0 ;
3680+ }
3681+ if (* arg )
3682+ arg ++ ;
3683+ }
3684+ opt -> ws_error_highlight = val ;
3685+ return 1 ;
3686+ }
3687+
36123688int diff_opt_parse (struct diff_options * options , const char * * av , int ac )
36133689{
36143690 const char * arg = av [0 ];
@@ -3806,6 +3882,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
38063882 DIFF_OPT_SET (options , SUBMODULE_LOG );
38073883 else if (skip_prefix (arg , "--submodule=" , & arg ))
38083884 return parse_submodule_opt (options , arg );
3885+ else if (skip_prefix (arg , "--ws-error-highlight=" , & arg ))
3886+ return parse_ws_error_highlight (options , arg );
38093887
38103888 /* misc options */
38113889 else if (!strcmp (arg , "-z" ))
0 commit comments