fetch does printf("%-*s", width, "foo") where "foo" can be an utf-8
string, but width is bytes, not letters. This results in misaligned
ref summary table.

Introduce gettext_length() function that returns the string length in
letters. Make the code use TRANSPORT_SUMMARY(x) where the length is
compensated properly in utf-8 locales.
---
 gettext_length() can be made to support other charsets too. But I'm
 on utf-8, it's not my itch.

 Grepping through '%-*s' does not reveal any other places that obviously
 need adjustment like this (apply and remote might, but pathnames and
 remote names are usually in ascii)

 builtin/fetch.c | 22 ++++++++++------------
 gettext.c       | 14 ++++++++++++--
 gettext.h       |  5 +++++
 transport.c     |  2 +-
 transport.h     |  1 +
 5 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index bb9a074..d7406d2 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -255,9 +255,8 @@ static int update_local_ref(struct ref *ref,
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbosity > 0)
                        strbuf_addf(display, "= %-*s %-*s -> %s",
-                                   TRANSPORT_SUMMARY_WIDTH,
-                                   _("[up to date]"), REFCOL_WIDTH,
-                                   remote, pretty_ref);
+                                   TRANSPORT_SUMMARY(_("[up to date]")),
+                                   REFCOL_WIDTH, remote, pretty_ref);
                return 0;
        }
 
@@ -271,7 +270,7 @@ static int update_local_ref(struct ref *ref,
                 */
                strbuf_addf(display,
                            _("! %-*s %-*s -> %s  (can't fetch in current 
branch)"),
-                           TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+                           TRANSPORT_SUMMARY(_("[rejected]")),
                            REFCOL_WIDTH, remote, pretty_ref);
                return 1;
        }
@@ -282,7 +281,7 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref("updating tag", ref, 0);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : '-',
-                           TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
+                           TRANSPORT_SUMMARY(_("[tag update]")),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("  (unable to update local ref)") : "");
                return r;
@@ -317,7 +316,7 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref(msg, ref, 0);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : '*',
-                           TRANSPORT_SUMMARY_WIDTH, what,
+                           TRANSPORT_SUMMARY(what),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("  (unable to update local ref)") : "");
                return r;
@@ -335,7 +334,7 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref("fast-forward", ref, 1);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : ' ',
-                           TRANSPORT_SUMMARY_WIDTH, quickref,
+                           TRANSPORT_SUMMARY(quickref),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("  (unable to update local ref)") : "");
                return r;
@@ -351,13 +350,13 @@ static int update_local_ref(struct ref *ref,
                r = s_update_ref("forced-update", ref, 1);
                strbuf_addf(display, "%c %-*s %-*s -> %s  (%s)",
                            r ? '!' : '+',
-                           TRANSPORT_SUMMARY_WIDTH, quickref,
+                           TRANSPORT_SUMMARY(quickref),
                            REFCOL_WIDTH, remote, pretty_ref,
                            r ? _("unable to update local ref") : _("forced 
update"));
                return r;
        } else {
                strbuf_addf(display, "! %-*s %-*s -> %s  %s",
-                           TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
+                           TRANSPORT_SUMMARY(_("[rejected]")),
                            REFCOL_WIDTH, remote, pretty_ref,
                            _("(non-fast-forward)"));
                return 1;
@@ -479,8 +478,7 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
                                free(ref);
                        } else
                                strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
-                                           TRANSPORT_SUMMARY_WIDTH,
-                                           *kind ? kind : "branch",
+                                           TRANSPORT_SUMMARY(*kind ? kind : 
"branch"),
                                            REFCOL_WIDTH,
                                            *what ? what : "HEAD");
                        if (note.len) {
@@ -554,7 +552,7 @@ static int prune_refs(struct refspec *refs, int ref_count, 
struct ref *ref_map)
                        result |= delete_ref(ref->name, NULL, 0);
                if (verbosity >= 0) {
                        fprintf(stderr, " x %-*s %-*s -> %s\n",
-                               TRANSPORT_SUMMARY_WIDTH, _("[deleted]"),
+                               TRANSPORT_SUMMARY(_("[deleted]")),
                                REFCOL_WIDTH, _("(none)"), 
prettify_refname(ref->name));
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
diff --git a/gettext.c b/gettext.c
index f75bca7..e9f0f0d 100644
--- a/gettext.c
+++ b/gettext.c
@@ -4,6 +4,8 @@
 
 #include "git-compat-util.h"
 #include "gettext.h"
+#include "strbuf.h"
+#include "utf8.h"
 
 #ifndef NO_GETTEXT
 #      include <locale.h>
@@ -27,10 +29,9 @@ int use_gettext_poison(void)
 #endif
 
 #ifndef NO_GETTEXT
+static const char *charset;
 static void init_gettext_charset(const char *domain)
 {
-       const char *charset;
-
        /*
           This trick arranges for messages to be emitted in the user's
           requested encoding, but avoids setting LC_CTYPE from the
@@ -128,4 +129,13 @@ void git_setup_gettext(void)
        init_gettext_charset("git");
        textdomain("git");
 }
+
+int gettext_length(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
diff --git a/gettext.h b/gettext.h
index 57ba8bb..7ea6db4 100644
--- a/gettext.h
+++ b/gettext.h
@@ -30,10 +30,15 @@
 
 #ifndef NO_GETTEXT
 extern void git_setup_gettext(void);
+extern int gettext_length(const char *s);
 #else
 static inline void git_setup_gettext(void)
 {
 }
+static inline int gettext_length(const char *s)
+{
+       return strlen(s);
+}
 #endif
 
 #ifdef GETTEXT_POISON
diff --git a/transport.c b/transport.c
index 1811b50..863aaa6 100644
--- a/transport.c
+++ b/transport.c
@@ -629,7 +629,7 @@ static void print_ref_status(char flag, const char 
*summary, struct ref *to, str
                else
                        fprintf(stdout, "%s\n", summary);
        } else {
-               fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY_WIDTH, 
summary);
+               fprintf(stderr, " %c %-*s ", flag, TRANSPORT_SUMMARY(summary));
                if (from)
                        fprintf(stderr, "%s -> %s", 
prettify_refname(from->name), prettify_refname(to->name));
                else
diff --git a/transport.h b/transport.h
index b866c12..1c95a8c 100644
--- a/transport.h
+++ b/transport.h
@@ -106,6 +106,7 @@ struct transport {
 #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
 
 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+#define TRANSPORT_SUMMARY(x) (TRANSPORT_SUMMARY_WIDTH + strlen(x) - 
gettext_length(x)), (x)
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
-- 
1.7.12.rc2.18.g61b472e

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to