@@ -2624,7 +2624,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
26242624 continue ;
26252625 }
26262626 fill_print_name (file );
2627- len = strlen (file -> print_name );
2627+ len = utf8_strwidth (file -> print_name );
26282628 if (max_len < len )
26292629 max_len = len ;
26302630
@@ -2677,6 +2677,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
26772677 * making the line longer than the maximum width.
26782678 */
26792679
2680+ /*
2681+ * NEEDSWORK: line_prefix is often used for "log --graph" output
2682+ * and contains ANSI-colored string. utf8_strnwidth() should be
2683+ * used to correctly count the display width instead of strlen().
2684+ */
26802685 if (options -> stat_width == -1 )
26812686 width = term_columns () - strlen (line_prefix );
26822687 else
@@ -2738,7 +2743,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
27382743 char * name = file -> print_name ;
27392744 uintmax_t added = file -> added ;
27402745 uintmax_t deleted = file -> deleted ;
2741- int name_len ;
2746+ int name_len , padding ;
27422747
27432748 if (!file -> is_interesting && (added + deleted == 0 ))
27442749 continue ;
@@ -2747,20 +2752,34 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
27472752 * "scale" the filename
27482753 */
27492754 len = name_width ;
2750- name_len = strlen (name );
2755+ name_len = utf8_strwidth (name );
27512756 if (name_width < name_len ) {
27522757 char * slash ;
27532758 prefix = "..." ;
27542759 len -= 3 ;
2760+ /*
2761+ * NEEDSWORK: (name_len - len) counts the display
2762+ * width, which would be shorter than the byte
2763+ * length of the corresponding substring.
2764+ * Advancing "name" by that number of bytes does
2765+ * *NOT* skip over that many columns, so it is
2766+ * very likely that chomping the pathname at the
2767+ * slash we will find starting from "name" will
2768+ * leave the resulting string still too long.
2769+ */
27552770 name += name_len - len ;
27562771 slash = strchr (name , '/' );
27572772 if (slash )
27582773 name = slash ;
27592774 }
2775+ padding = len - utf8_strwidth (name );
2776+ if (padding < 0 )
2777+ padding = 0 ;
27602778
27612779 if (file -> is_binary ) {
2762- strbuf_addf (& out , " %s%-*s |" , prefix , len , name );
2763- strbuf_addf (& out , " %*s" , number_width , "Bin" );
2780+ strbuf_addf (& out , " %s%s%*s | %*s" ,
2781+ prefix , name , padding , "" ,
2782+ number_width , "Bin" );
27642783 if (!added && !deleted ) {
27652784 strbuf_addch (& out , '\n' );
27662785 emit_diff_symbol (options , DIFF_SYMBOL_STATS_LINE ,
@@ -2780,8 +2799,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
27802799 continue ;
27812800 }
27822801 else if (file -> is_unmerged ) {
2783- strbuf_addf (& out , " %s%-*s |" , prefix , len , name );
2784- strbuf_addstr (& out , " Unmerged\n" );
2802+ strbuf_addf (& out , " %s%s%*s | %*s" ,
2803+ prefix , name , padding , "" ,
2804+ number_width , "Unmerged" );
27852805 emit_diff_symbol (options , DIFF_SYMBOL_STATS_LINE ,
27862806 out .buf , out .len , 0 );
27872807 strbuf_reset (& out );
@@ -2807,10 +2827,10 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
28072827 add = total - del ;
28082828 }
28092829 }
2810- strbuf_addf (& out , " %s%- *s |" , prefix , len , name );
2811- strbuf_addf ( & out , " %*" PRIuMAX "%s " ,
2812- number_width , added + deleted ,
2813- added + deleted ? " " : "" );
2830+ strbuf_addf (& out , " %s%s% *s | %*" PRIuMAX "%s" ,
2831+ prefix , name , padding , " " ,
2832+ number_width , added + deleted ,
2833+ added + deleted ? " " : "" );
28142834 show_graph (& out , '+' , add , add_c , reset );
28152835 show_graph (& out , '-' , del , del_c , reset );
28162836 strbuf_addch (& out , '\n' );
0 commit comments