fetch: align per-ref summary report in UTF-8 locales

fetch does printf("%-*s", width, "foo") where "foo" can be a utf-8 string, but width is in bytes, not columns. For ASCII it's fine as one byte takes one column. For utf-8, this may result in misaligned ref summary table. Introduce gettext_width() function that returns the string length in columns (currently only supports utf-8 locales). Make the code use TRANSPORT_SUMMARY(x) where the length is compensated properly in non-English locales. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Sep 4, 2012 at 17:39 UTC 754395d3052fc0d46948b2ff7006b3c6701785c8
4 files changed +26 -10
builtin/fetch.c
+7 -8
@@ -255,9 +255,8 @@ static int update_local_ref(struct ref *ref,
255 if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
256 if (verbosity > 0)
257 strbuf_addf(display, "= %-*s %-*s -> %s",
258 - TRANSPORT_SUMMARY_WIDTH,
259 - _("[up to date]"), REFCOL_WIDTH,
260 - remote, pretty_ref);
258 + TRANSPORT_SUMMARY(_("[up to date]")),
259 + REFCOL_WIDTH, remote, pretty_ref);
260 return 0;
261 }
262
@@ -271,7 +270,7 @@ static int update_local_ref(struct ref *ref,
270 */
271 strbuf_addf(display,
272 _("! %-*s %-*s -> %s (can't fetch in current branch)"),
274 - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
273 + TRANSPORT_SUMMARY(_("[rejected]")),
274 REFCOL_WIDTH, remote, pretty_ref);
275 return 1;
276 }
@@ -282,7 +281,7 @@ static int update_local_ref(struct ref *ref,
281 r = s_update_ref("updating tag", ref, 0);
282 strbuf_addf(display, "%c %-*s %-*s -> %s%s",
283 r ? '!' : '-',
285 - TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
284 + TRANSPORT_SUMMARY(_("[tag update]")),
285 REFCOL_WIDTH, remote, pretty_ref,
286 r ? _(" (unable to update local ref)") : "");
287 return r;
@@ -317,7 +316,7 @@ static int update_local_ref(struct ref *ref,
316 r = s_update_ref(msg, ref, 0);
317 strbuf_addf(display, "%c %-*s %-*s -> %s%s",
318 r ? '!' : '*',
320 - TRANSPORT_SUMMARY_WIDTH, what,
319 + TRANSPORT_SUMMARY(what),
320 REFCOL_WIDTH, remote, pretty_ref,
321 r ? _(" (unable to update local ref)") : "");
322 return r;
@@ -357,7 +356,7 @@ static int update_local_ref(struct ref *ref,
356 return r;
357 } else {
358 strbuf_addf(display, "! %-*s %-*s -> %s %s",
360 - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
359 + TRANSPORT_SUMMARY(_("[rejected]")),
360 REFCOL_WIDTH, remote, pretty_ref,
361 _("(non-fast-forward)"));
362 return 1;
@@ -554,7 +553,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
553 result |= delete_ref(ref->name, NULL, 0);
554 if (verbosity >= 0) {
555 fprintf(stderr, " x %-*s %-*s -> %s\n",
557 - TRANSPORT_SUMMARY_WIDTH, _("[deleted]"),
556 + TRANSPORT_SUMMARY(_("[deleted]")),
557 REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
558 warn_dangling_symref(stderr, dangling_msg, ref->name);
559 }
gettext.c
+13 -2
@@ -4,6 +4,8 @@
4
5 #include "git-compat-util.h"
6 #include "gettext.h"
7 +#include "strbuf.h"
8 +#include "utf8.h"
9
10 #ifndef NO_GETTEXT
11 # include <locale.h>
@@ -27,10 +29,9 @@ int use_gettext_poison(void)
29 #endif
30
31 #ifndef NO_GETTEXT
32 +static const char *charset;
33 static void init_gettext_charset(const char *domain)
34 {
32 - const char *charset;
33 -
35 /*
36 This trick arranges for messages to be emitted in the user's
37 requested encoding, but avoids setting LC_CTYPE from the
@@ -128,4 +129,14 @@ void git_setup_gettext(void)
129 init_gettext_charset("git");
130 textdomain("git");
131 }
132 +
133 +/* return the number of columns of string 's' in current locale */
134 +int gettext_width(const char *s)
135 +{
136 + static int is_utf8 = -1;
137 + if (is_utf8 == -1)
138 + is_utf8 = !strcmp(charset, "UTF-8");
139 +
140 + return is_utf8 ? utf8_strwidth(s) : strlen(s);
141 +}
142 #endif
gettext.h
+5
@@ -30,10 +30,15 @@
30
31 #ifndef NO_GETTEXT
32 extern void git_setup_gettext(void);
33 +extern int gettext_width(const char *s);
34 #else
35 static inline void git_setup_gettext(void)
36 {
37 }
38 +static inline int gettext_width(const char *s)
39 +{
40 + return strlen(s);
41 +}
42 #endif
43
44 #ifdef GETTEXT_POISON
transport.h
+1
@@ -106,6 +106,7 @@ struct transport {
106 #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
107
108 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
109 +#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
110
111 /* Returns a transport suitable for the url */
112 struct transport *transport_get(struct remote *, const char *);