From 8a9391e9440028c03345afa9f21459237a529592 Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Fri, 30 Jan 2009 04:41:28 -0500 Subject: [PATCH 1/2] utf8: add utf8_strwidth() I'm about to use this pattern more than once, so make it a common function. Signed-off-by: Geoffrey Thomas Signed-off-by: Junio C Hamano --- utf8.c | 19 +++++++++++++++++++ utf8.h | 1 + 2 files changed, 20 insertions(+) diff --git a/utf8.c b/utf8.c index dc3735364f..ddfdc5e2b8 100644 --- a/utf8.c +++ b/utf8.c @@ -246,6 +246,25 @@ int utf8_width(const char **start, size_t *remainder_p) return git_wcwidth(ch); } +/* + * Returns the total number of columns required by a null-terminated + * string, assuming that the string is utf8. Returns strlen() instead + * if the string does not look like a valid utf8 string. + */ +int utf8_strwidth(const char *string) +{ + int width = 0; + const char *orig = string; + + while (1) { + if (!string) + return strlen(orig); + if (!*string) + return width; + width += utf8_width(&string, NULL); + } +} + int is_utf8(const char *text) { while (*text) { diff --git a/utf8.h b/utf8.h index 98cce1b038..2f1b14ff49 100644 --- a/utf8.h +++ b/utf8.h @@ -5,6 +5,7 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */ ucs_char_t pick_one_utf8_char(const char **start, size_t *remainder_p); int utf8_width(const char **start, size_t *remainder_p); +int utf8_strwidth(const char *string); int is_utf8(const char *text); int is_encoding_utf8(const char *name); From ffaf9cc0ff0692a0b60cdf1b62e8375706b7865d Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Fri, 30 Jan 2009 04:41:29 -0500 Subject: [PATCH 2/2] builtin-blame.c: Use utf8_strwidth for author's names git blame misaligns output if a author's name has a differing display width and strlen; for instance, an accented Latin letter that takes two bytes to encode will cause the rest of the line to be shifted to the left by one. To fix this, use utf8_strwidth instead of strlen (and compute the padding ourselves, since printf doesn't know about UTF-8). Signed-off-by: Geoffrey Thomas Signed-off-by: Junio C Hamano --- builtin-blame.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index aae14ef8bb..9b9f5442a2 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -19,6 +19,7 @@ #include "string-list.h" #include "mailmap.h" #include "parse-options.h" +#include "utf8.h" static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; @@ -1618,13 +1619,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) printf(" %*d", max_orig_digits, ent->s_lno + 1 + cnt); - if (!(opt & OUTPUT_NO_AUTHOR)) - printf(" (%-*.*s %10s", - longest_author, longest_author, - ci.author, + if (!(opt & OUTPUT_NO_AUTHOR)) { + int pad = longest_author - utf8_strwidth(ci.author); + printf(" (%s%*s %10s", + ci.author, pad, "", format_time(ci.author_time, ci.author_tz, show_raw_time)); + } printf(" %*d) ", max_digits, ent->lno + 1 + cnt); } @@ -1755,7 +1757,7 @@ static void find_alignment(struct scoreboard *sb, int *option) if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { suspect->commit->object.flags |= METAINFO_SHOWN; get_commit_info(suspect->commit, &ci, 1); - num = strlen(ci.author); + num = utf8_strwidth(ci.author); if (longest_author < num) longest_author = num; }