Skip to content

Commit 7d5a4d8

Browse files
committed
Merge branch 'tb/diffstat-with-utf8-strwidth'
"git diff --stat" etc. were invented back when everything was ASCII and strlen() was a way to measure the display width of a string; adjust them to compute the display width assuming UTF-8 pathnames. * tb/diffstat-with-utf8-strwidth: diff: leave NEEDWORK notes in show_stats() function diff.c: use utf8_strwidth() to count display width
2 parents 330135a + ce8529b commit 7d5a4d8

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

diff.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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');

t/t4012-diff-binary.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,20 @@ test_expect_success 'diff --no-index with binary creation' '
113113
'
114114

115115
cat >expect <<EOF
116-
binfile | Bin 0 -> 1026 bytes
117-
textfile | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
116+
binfilë | Bin 0 -> 1026 bytes
117+
tëxtfilë | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
118118
EOF
119119

120120
test_expect_success 'diff --stat with binary files and big change count' '
121-
printf "\01\00%1024d" 1 >binfile &&
122-
git add binfile &&
121+
printf "\01\00%1024d" 1 >binfilë &&
122+
git add binfilë &&
123123
i=0 &&
124124
while test $i -lt 10000; do
125125
echo $i &&
126126
i=$(($i + 1)) || return 1
127-
done >textfile &&
128-
git add textfile &&
129-
git diff --cached --stat binfile textfile >output &&
127+
done >tëxtfilë &&
128+
git add tëxtfilë &&
129+
git -c core.quotepath=false diff --cached --stat binfilë tëxtfilë >output &&
130130
grep " | " output >actual &&
131131
test_cmp expect actual
132132
'

0 commit comments

Comments
 (0)