diff --git a/tests/test_utils.py b/tests/test_utils.py index 9f0c030..5b68606 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,5 +1,4 @@ -from toot import utils -from toot.wcstring import wc_wrap +from toot.wcstring import wc_wrap, trunc, pad, fit_text def test_pad(): @@ -8,72 +7,72 @@ def test_pad(): text = 'Frank Zappa 🎸' # Negative values are basically ignored - assert utils.pad(text, -100) is text + assert pad(text, -100) is text # Padding to length smaller than text length does nothing - assert utils.pad(text, 11) is text - assert utils.pad(text, 12) is text - assert utils.pad(text, 13) is text - assert utils.pad(text, 14) is text + assert pad(text, 11) is text + assert pad(text, 12) is text + assert pad(text, 13) is text + assert pad(text, 14) is text - assert utils.pad(text, 15) == 'Frank Zappa 🎸 ' - assert utils.pad(text, 16) == 'Frank Zappa 🎸 ' - assert utils.pad(text, 17) == 'Frank Zappa 🎸 ' - assert utils.pad(text, 18) == 'Frank Zappa 🎸 ' - assert utils.pad(text, 19) == 'Frank Zappa 🎸 ' - assert utils.pad(text, 20) == 'Frank Zappa 🎸 ' + assert pad(text, 15) == 'Frank Zappa 🎸 ' + assert pad(text, 16) == 'Frank Zappa 🎸 ' + assert pad(text, 17) == 'Frank Zappa 🎸 ' + assert pad(text, 18) == 'Frank Zappa 🎸 ' + assert pad(text, 19) == 'Frank Zappa 🎸 ' + assert pad(text, 20) == 'Frank Zappa 🎸 ' def test_trunc(): text = 'Frank Zappa 🎸' - assert utils.trunc(text, 1) == '…' - assert utils.trunc(text, 2) == 'F…' - assert utils.trunc(text, 3) == 'Fr…' - assert utils.trunc(text, 4) == 'Fra…' - assert utils.trunc(text, 5) == 'Fran…' - assert utils.trunc(text, 6) == 'Frank…' - assert utils.trunc(text, 7) == 'Frank…' - assert utils.trunc(text, 8) == 'Frank Z…' - assert utils.trunc(text, 9) == 'Frank Za…' - assert utils.trunc(text, 10) == 'Frank Zap…' - assert utils.trunc(text, 11) == 'Frank Zapp…' - assert utils.trunc(text, 12) == 'Frank Zappa…' - assert utils.trunc(text, 13) == 'Frank Zappa…' + assert trunc(text, 1) == '…' + assert trunc(text, 2) == 'F…' + assert trunc(text, 3) == 'Fr…' + assert trunc(text, 4) == 'Fra…' + assert trunc(text, 5) == 'Fran…' + assert trunc(text, 6) == 'Frank…' + assert trunc(text, 7) == 'Frank…' + assert trunc(text, 8) == 'Frank Z…' + assert trunc(text, 9) == 'Frank Za…' + assert trunc(text, 10) == 'Frank Zap…' + assert trunc(text, 11) == 'Frank Zapp…' + assert trunc(text, 12) == 'Frank Zappa…' + assert trunc(text, 13) == 'Frank Zappa…' # Truncating to length larger than text length does nothing - assert utils.trunc(text, 14) is text - assert utils.trunc(text, 15) is text - assert utils.trunc(text, 16) is text - assert utils.trunc(text, 17) is text - assert utils.trunc(text, 18) is text - assert utils.trunc(text, 19) is text - assert utils.trunc(text, 20) is text + assert trunc(text, 14) is text + assert trunc(text, 15) is text + assert trunc(text, 16) is text + assert trunc(text, 17) is text + assert trunc(text, 18) is text + assert trunc(text, 19) is text + assert trunc(text, 20) is text def test_fit_text(): text = 'Frank Zappa 🎸' - assert utils.fit_text(text, 1) == '…' - assert utils.fit_text(text, 2) == 'F…' - assert utils.fit_text(text, 3) == 'Fr…' - assert utils.fit_text(text, 4) == 'Fra…' - assert utils.fit_text(text, 5) == 'Fran…' - assert utils.fit_text(text, 6) == 'Frank…' - assert utils.fit_text(text, 7) == 'Frank…' - assert utils.fit_text(text, 8) == 'Frank Z…' - assert utils.fit_text(text, 9) == 'Frank Za…' - assert utils.fit_text(text, 10) == 'Frank Zap…' - assert utils.fit_text(text, 11) == 'Frank Zapp…' - assert utils.fit_text(text, 12) == 'Frank Zappa…' - assert utils.fit_text(text, 13) == 'Frank Zappa…' - assert utils.fit_text(text, 14) == 'Frank Zappa 🎸' - assert utils.fit_text(text, 15) == 'Frank Zappa 🎸 ' - assert utils.fit_text(text, 16) == 'Frank Zappa 🎸 ' - assert utils.fit_text(text, 17) == 'Frank Zappa 🎸 ' - assert utils.fit_text(text, 18) == 'Frank Zappa 🎸 ' - assert utils.fit_text(text, 19) == 'Frank Zappa 🎸 ' - assert utils.fit_text(text, 20) == 'Frank Zappa 🎸 ' + assert fit_text(text, 1) == '…' + assert fit_text(text, 2) == 'F…' + assert fit_text(text, 3) == 'Fr…' + assert fit_text(text, 4) == 'Fra…' + assert fit_text(text, 5) == 'Fran…' + assert fit_text(text, 6) == 'Frank…' + assert fit_text(text, 7) == 'Frank…' + assert fit_text(text, 8) == 'Frank Z…' + assert fit_text(text, 9) == 'Frank Za…' + assert fit_text(text, 10) == 'Frank Zap…' + assert fit_text(text, 11) == 'Frank Zapp…' + assert fit_text(text, 12) == 'Frank Zappa…' + assert fit_text(text, 13) == 'Frank Zappa…' + assert fit_text(text, 14) == 'Frank Zappa 🎸' + assert fit_text(text, 15) == 'Frank Zappa 🎸 ' + assert fit_text(text, 16) == 'Frank Zappa 🎸 ' + assert fit_text(text, 17) == 'Frank Zappa 🎸 ' + assert fit_text(text, 18) == 'Frank Zappa 🎸 ' + assert fit_text(text, 19) == 'Frank Zappa 🎸 ' + assert fit_text(text, 20) == 'Frank Zappa 🎸 ' def test_wc_wrap_plain_text(): diff --git a/toot/utils.py b/toot/utils.py index bf1ad30..aa3a176 100644 --- a/toot/utils.py +++ b/toot/utils.py @@ -7,7 +7,6 @@ import unicodedata import warnings from bs4 import BeautifulSoup -from wcwidth import wcwidth, wcswidth from toot.exceptions import ConsoleError @@ -76,61 +75,6 @@ def assert_domain_exists(domain): raise ConsoleError("Domain {} not found".format(domain)) -def trunc(text, length): - """ - Truncates text to given length, taking into account wide characters. - - If truncated, the last char is replaced by an elipsis. - """ - if length < 1: - raise ValueError("length should be 1 or larger") - - # Remove whitespace first so no unneccesary truncation is done. - text = text.strip() - text_length = wcswidth(text) - - if text_length <= length: - return text - - # We cannot just remove n characters from the end since we don't know how - # wide these characters are and how it will affect text length. - # Use wcwidth to determine how many characters need to be truncated. - chars_to_truncate = 0 - trunc_length = 0 - for char in reversed(text): - chars_to_truncate += 1 - trunc_length += wcwidth(char) - if text_length - trunc_length <= length: - break - - # Additional char to make room for elipsis - n = chars_to_truncate + 1 - return text[:-n].strip() + '…' - - -def pad(text, length): - """Pads text to given length, taking into account wide characters.""" - text_length = wcswidth(text) - - if text_length < length: - return text + ' ' * (length - text_length) - - return text - - -def fit_text(text, length): - """Makes text fit the given length by padding or truncating it.""" - text_length = wcswidth(text) - - if text_length > length: - return trunc(text, length) - - if text_length < length: - return pad(text, length) - - return text - - EOF_KEY = "Ctrl-Z" if os.name == 'nt' else "Ctrl-D" diff --git a/toot/wcstring.py b/toot/wcstring.py index bc930ee..6ef2c3c 100644 --- a/toot/wcstring.py +++ b/toot/wcstring.py @@ -64,3 +64,58 @@ def wc_wrap(text, length): yield line else: yield from _wc_hard_wrap(line, length) + + +def trunc(text, length): + """ + Truncates text to given length, taking into account wide characters. + + If truncated, the last char is replaced by an elipsis. + """ + if length < 1: + raise ValueError("length should be 1 or larger") + + # Remove whitespace first so no unneccesary truncation is done. + text = text.strip() + text_length = wcswidth(text) + + if text_length <= length: + return text + + # We cannot just remove n characters from the end since we don't know how + # wide these characters are and how it will affect text length. + # Use wcwidth to determine how many characters need to be truncated. + chars_to_truncate = 0 + trunc_length = 0 + for char in reversed(text): + chars_to_truncate += 1 + trunc_length += wcwidth(char) + if text_length - trunc_length <= length: + break + + # Additional char to make room for elipsis + n = chars_to_truncate + 1 + return text[:-n].strip() + '…' + + +def pad(text, length): + """Pads text to given length, taking into account wide characters.""" + text_length = wcswidth(text) + + if text_length < length: + return text + ' ' * (length - text_length) + + return text + + +def fit_text(text, length): + """Makes text fit the given length by padding or truncating it.""" + text_length = wcswidth(text) + + if text_length > length: + return trunc(text, length) + + if text_length < length: + return pad(text, length) + + return text