From 568a5e5e8b31b9be4a88cca888e3d1cbc84669e9 Mon Sep 17 00:00:00 2001 From: Adam Waldenberg <adam.waldenberg@ejwa.se> Date: Fri, 19 Dec 2014 03:02:08 +0100 Subject: [PATCH] Fixed the terminal column alignment for languages with multi-column chars. This is for example needed for the Chinese and Korean translations to work correctly when using terminal output. --- gitinspector/blame.py | 6 +++--- gitinspector/changes.py | 7 ++++--- gitinspector/terminal.py | 17 +++++++++++++++++ gitinspector/timeline.py | 17 +++++++++++------ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/gitinspector/blame.py b/gitinspector/blame.py index eb1bb58..a9c0629 100644 --- a/gitinspector/blame.py +++ b/gitinspector/blame.py @@ -276,11 +276,11 @@ class BlameOutput(Outputable): terminal.clear_row() print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n") - terminal.printb(_("Author").ljust(21) + _("Rows").rjust(10) + _("Stability").rjust(15) + _("Age").rjust(13) + - _("% in comments").rjust(20)) + terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Rows"), 10) + terminal.rjust(_("Stability"), 15) + + terminal.rjust(_("Age"), 13) + terminal.rjust(_("% in comments"), 20)) for i in sorted(__blame__.get_summed_blames().items()): - print(i[0].ljust(20)[0:20], end=" ") + print(terminal.ljust(i[0], 20)[0:20 - terminal.get_excess_column_count(i[0])], end=" ") print(str(i[1].rows).rjust(10), end=" ") print("{0:.1f}".format(Blame.get_stability(i[0], i[1].rows, self.changes)).rjust(14), end=" ") print("{0:.1f}".format(float(i[1].skew) / i[1].rows).rjust(12), end=" ") diff --git a/gitinspector/changes.py b/gitinspector/changes.py index 2fc03cd..472e788 100644 --- a/gitinspector/changes.py +++ b/gitinspector/changes.py @@ -278,14 +278,15 @@ class ChangesOutput(Outputable): if authorinfo_list: print(textwrap.fill(_(HISTORICAL_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n") - terminal.printb(_("Author").ljust(21) + _("Commits").rjust(13) + _("Insertions").rjust(14) + - _("Deletions").rjust(15) + _("% of changes").rjust(16)) + terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Commits"), 13) + + terminal.rjust(_("Insertions"), 14) + terminal.rjust(_("Deletions"), 15) + + terminal.rjust(_("% of changes"), 16)) for i in sorted(authorinfo_list): authorinfo = authorinfo_list.get(i) percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100 - print(i.ljust(20)[0:20], end=" ") + print(terminal.ljust(i, 20)[0:20 - terminal.get_excess_column_count(i)], end=" ") print(str(authorinfo.commits).rjust(13), end=" ") print(str(authorinfo.insertions).rjust(13), end=" ") print(str(authorinfo.deletions).rjust(14), end=" ") diff --git a/gitinspector/terminal.py b/gitinspector/terminal.py index f912d19..55b8b99 100644 --- a/gitinspector/terminal.py +++ b/gitinspector/terminal.py @@ -22,6 +22,7 @@ import codecs import os import platform import sys +import unicodedata __bold__ = "\033[1m" __normal__ = "\033[0;0m" @@ -128,3 +129,19 @@ def check_terminal_encoding(): if sys.stdout.isatty() and (sys.stdout.encoding == None or sys.stdin.encoding == None): print(_("WARNING: The terminal encoding is not correctly configured. gitinspector might malfunction. " "The encoding can be configured with the environment variable 'PYTHONIOENCODING'."), file=sys.stderr) + +def get_excess_column_count(string): + width_mapping = {'F': 2, 'H': 1, 'W': 2, 'Na': 1, 'N': 1, 'A': 1} + result = 0 + + for c in string: + w = unicodedata.east_asian_width(c) + result += width_mapping[w] + + return result - len(string) + +def ljust(string, pad): + return string.ljust(pad - get_excess_column_count(string)) + +def rjust(string, pad): + return string.rjust(pad - get_excess_column_count(string)) diff --git a/gitinspector/timeline.py b/gitinspector/timeline.py index 0b49bc4..30b74bd 100644 --- a/gitinspector/timeline.py +++ b/gitinspector/timeline.py @@ -111,16 +111,17 @@ TIMELINE_INFO_TEXT = N_("The following history timeline has been gathered from t MODIFIED_ROWS_TEXT = N_("Modified Rows:") def __output_row__text__(timeline_data, periods, names): - print("\n" + terminal.__bold__ + _("Author").ljust(20), end=" ") + print("\n" + terminal.__bold__ + terminal.ljust(_("Author"), 20), end=" ") for period in periods: - print(period.rjust(10), end=" ") + print(terminal.rjust(period, 10), end=" ") print(terminal.__normal__) for name in names: if timeline_data.is_author_in_periods(periods, name[0]): - print(name[0].ljust(20)[0:20], end=" ") + print(terminal.ljust(name[0], 20)[0:20 - terminal.get_excess_column_count(name[0])], end=" ") + for period in periods: multiplier = timeline_data.get_multiplier(period, 9) signs = timeline_data.get_author_signs_in_period(name[0], period, multiplier) @@ -129,11 +130,15 @@ def __output_row__text__(timeline_data, periods, names): len(signs_str) == 0 else signs_str).rjust(10), end=" ") print("") - print(terminal.__bold__ + _(MODIFIED_ROWS_TEXT).ljust(20) + terminal.__normal__, end=" ") + print(terminal.__bold__ + terminal.ljust(_(MODIFIED_ROWS_TEXT), 20) + terminal.__normal__, end=" ") for period in periods: - total_changes = timeline_data.get_total_changes_in_period(period) - print("" + str(total_changes[2]).rjust(10), end=" ") + total_changes = str(timeline_data.get_total_changes_in_period(period)[2]) + + if hasattr(total_changes, 'decode'): + total_changes = total_changes.decode("utf-8", "replace") + + print(terminal.rjust(total_changes, 10), end=" ") print("")