@@ -478,26 +478,59 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
478
478
return ws_blank_line (line , len , ecbdata -> ws_rule );
479
479
}
480
480
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 )
484
487
{
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 ;
487
490
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 ))
491
500
/* 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 );
493
502
else {
494
503
/* 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 );
496
505
ws_check_emit (line , len , ecbdata -> ws_rule ,
497
506
ecbdata -> opt -> file , set , reset , ws );
498
507
}
499
508
}
500
509
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
+
501
534
static void emit_hunk_header (struct emit_callback * ecbdata ,
502
535
const char * line , int len )
503
536
{
@@ -603,7 +636,6 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
603
636
{
604
637
const char * endp = NULL ;
605
638
static const char * nneof = " No newline at end of file\n" ;
606
- const char * old = diff_get_color (ecb -> color_diff , DIFF_FILE_OLD );
607
639
const char * reset = diff_get_color (ecb -> color_diff , DIFF_RESET );
608
640
609
641
while (0 < size ) {
@@ -613,8 +645,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
613
645
len = endp ? (endp - data + 1 ) : size ;
614
646
if (prefix != '+' ) {
615
647
ecb -> lno_in_preimage ++ ;
616
- emit_line_0 (ecb -> opt , old , reset , '-' ,
617
- data , len );
648
+ emit_del_line (reset , ecb , data , len );
618
649
} else {
619
650
ecb -> lno_in_postimage ++ ;
620
651
emit_add_line (reset , ecb , data , len );
@@ -1250,17 +1281,27 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
1250
1281
return ;
1251
1282
}
1252
1283
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 '+' :
1262
1286
ecbdata -> lno_in_postimage ++ ;
1263
1287
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 ;
1264
1305
}
1265
1306
}
1266
1307
@@ -3223,6 +3264,7 @@ void diff_setup(struct diff_options *options)
3223
3264
options -> rename_limit = -1 ;
3224
3265
options -> dirstat_permille = diff_dirstat_permille_default ;
3225
3266
options -> context = diff_context_default ;
3267
+ options -> ws_error_highlight = WSEH_NEW ;
3226
3268
DIFF_OPT_SET (options , RENAME_EMPTY );
3227
3269
3228
3270
/* pathchange left =NULL by default */
@@ -3609,6 +3651,40 @@ static void enable_patch_output(int *fmt) {
3609
3651
* fmt |= DIFF_FORMAT_PATCH ;
3610
3652
}
3611
3653
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
+
3612
3688
int diff_opt_parse (struct diff_options * options , const char * * av , int ac )
3613
3689
{
3614
3690
const char * arg = av [0 ];
@@ -3806,6 +3882,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3806
3882
DIFF_OPT_SET (options , SUBMODULE_LOG );
3807
3883
else if (skip_prefix (arg , "--submodule=" , & arg ))
3808
3884
return parse_submodule_opt (options , arg );
3885
+ else if (skip_prefix (arg , "--ws-error-highlight=" , & arg ))
3886
+ return parse_ws_error_highlight (options , arg );
3809
3887
3810
3888
/* misc options */
3811
3889
else if (!strcmp (arg , "-z" ))
0 commit comments