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>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2012-09-04 17:39:35 +07:00 committed by Junio C Hamano
parent b52183179b
commit 754395d305
4 changed files with 26 additions and 10 deletions

View File

@ -255,9 +255,8 @@ static int update_local_ref(struct ref *ref,
if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbosity > 0) if (verbosity > 0)
strbuf_addf(display, "= %-*s %-*s -> %s", strbuf_addf(display, "= %-*s %-*s -> %s",
TRANSPORT_SUMMARY_WIDTH, TRANSPORT_SUMMARY(_("[up to date]")),
_("[up to date]"), REFCOL_WIDTH, REFCOL_WIDTH, remote, pretty_ref);
remote, pretty_ref);
return 0; return 0;
} }
@ -271,7 +270,7 @@ static int update_local_ref(struct ref *ref,
*/ */
strbuf_addf(display, strbuf_addf(display,
_("! %-*s %-*s -> %s (can't fetch in current branch)"), _("! %-*s %-*s -> %s (can't fetch in current branch)"),
TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref); REFCOL_WIDTH, remote, pretty_ref);
return 1; return 1;
} }
@ -282,7 +281,7 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref("updating tag", ref, 0); r = s_update_ref("updating tag", ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s", strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '-', r ? '!' : '-',
TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), TRANSPORT_SUMMARY(_("[tag update]")),
REFCOL_WIDTH, remote, pretty_ref, REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : ""); r ? _(" (unable to update local ref)") : "");
return r; return r;
@ -317,7 +316,7 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref(msg, ref, 0); r = s_update_ref(msg, ref, 0);
strbuf_addf(display, "%c %-*s %-*s -> %s%s", strbuf_addf(display, "%c %-*s %-*s -> %s%s",
r ? '!' : '*', r ? '!' : '*',
TRANSPORT_SUMMARY_WIDTH, what, TRANSPORT_SUMMARY(what),
REFCOL_WIDTH, remote, pretty_ref, REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : ""); r ? _(" (unable to update local ref)") : "");
return r; return r;
@ -357,7 +356,7 @@ static int update_local_ref(struct ref *ref,
return r; return r;
} else { } else {
strbuf_addf(display, "! %-*s %-*s -> %s %s", strbuf_addf(display, "! %-*s %-*s -> %s %s",
TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref, REFCOL_WIDTH, remote, pretty_ref,
_("(non-fast-forward)")); _("(non-fast-forward)"));
return 1; return 1;
@ -554,7 +553,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
result |= delete_ref(ref->name, NULL, 0); result |= delete_ref(ref->name, NULL, 0);
if (verbosity >= 0) { if (verbosity >= 0) {
fprintf(stderr, " x %-*s %-*s -> %s\n", fprintf(stderr, " x %-*s %-*s -> %s\n",
TRANSPORT_SUMMARY_WIDTH, _("[deleted]"), TRANSPORT_SUMMARY(_("[deleted]")),
REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name)); REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
warn_dangling_symref(stderr, dangling_msg, ref->name); warn_dangling_symref(stderr, dangling_msg, ref->name);
} }

View File

@ -4,6 +4,8 @@
#include "git-compat-util.h" #include "git-compat-util.h"
#include "gettext.h" #include "gettext.h"
#include "strbuf.h"
#include "utf8.h"
#ifndef NO_GETTEXT #ifndef NO_GETTEXT
# include <locale.h> # include <locale.h>
@ -27,10 +29,9 @@ int use_gettext_poison(void)
#endif #endif
#ifndef NO_GETTEXT #ifndef NO_GETTEXT
static const char *charset;
static void init_gettext_charset(const char *domain) static void init_gettext_charset(const char *domain)
{ {
const char *charset;
/* /*
This trick arranges for messages to be emitted in the user's This trick arranges for messages to be emitted in the user's
requested encoding, but avoids setting LC_CTYPE from the requested encoding, but avoids setting LC_CTYPE from the
@ -128,4 +129,14 @@ void git_setup_gettext(void)
init_gettext_charset("git"); init_gettext_charset("git");
textdomain("git"); textdomain("git");
} }
/* return the number of columns of string 's' in current locale */
int gettext_width(const char *s)
{
static int is_utf8 = -1;
if (is_utf8 == -1)
is_utf8 = !strcmp(charset, "UTF-8");
return is_utf8 ? utf8_strwidth(s) : strlen(s);
}
#endif #endif

View File

@ -30,10 +30,15 @@
#ifndef NO_GETTEXT #ifndef NO_GETTEXT
extern void git_setup_gettext(void); extern void git_setup_gettext(void);
extern int gettext_width(const char *s);
#else #else
static inline void git_setup_gettext(void) static inline void git_setup_gettext(void)
{ {
} }
static inline int gettext_width(const char *s)
{
return strlen(s);
}
#endif #endif
#ifdef GETTEXT_POISON #ifdef GETTEXT_POISON

View File

@ -106,6 +106,7 @@ struct transport {
#define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256 #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
#define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
/* Returns a transport suitable for the url */ /* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *); struct transport *transport_get(struct remote *, const char *);