diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index d7b5e02f6..a33518cd7 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -983,6 +983,8 @@ def ellipsis_truncate(msg, space): """ shorten a long string by adding ellipsis between it and return it, example: this_is_a_very_long_string -------> this_is..._string + + The result is padded with spaces to a width of *space* terminal cells (if *space* >= 3). """ from ..platform import swidth ellipsis_width = swidth('...') @@ -991,8 +993,10 @@ def ellipsis_truncate(msg, space): # if there is very little space, just show ... return '...' + ' ' * (space - ellipsis_width) if space < ellipsis_width + msg_width: - return '{}...{}'.format(swidth_slice(msg, space // 2 - ellipsis_width), - swidth_slice(msg, -space // 2)) + # swidth_slice does not split a wide character, so a slice can be one cell short: pad below. + msg = '{}...{}'.format(swidth_slice(msg, space // 2 - ellipsis_width), + swidth_slice(msg, -space // 2)) + msg_width = swidth(msg) return msg + ' ' * (space - msg_width) diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py index 52fc97423..0ab91805d 100644 --- a/src/borg/testsuite/helpers.py +++ b/src/borg/testsuite/helpers.py @@ -26,6 +26,7 @@ from ..helpers import StableDict, int_to_bigint, bigint_to_int, bin_to_hex from ..helpers import parse_timestamp, ChunkIteratorFileWrapper, ChunkerParams from ..helpers import ProgressIndicatorPercent, ProgressIndicatorEndless from ..helpers import swidth_slice +from ..helpers import ellipsis_truncate from ..helpers import chunkit from ..helpers import safe_ns, safe_s, SUPPORT_32BIT_PLATFORMS from ..helpers import popen_with_error_handling @@ -1128,6 +1129,19 @@ def test_swidth_slice_mixed_characters(): assert swidth_slice(string, 6) == '나윤a' +@pytest.mark.skipif(not working_swidth(), reason='swidth() is not supported / active') +@pytest.mark.parametrize('msg', ['나윤선나윤선나윤선나윤선나윤선', '나윤a선나윤선나윤선나윤선나윤선', 'a' * 40, 'short']) +@pytest.mark.parametrize('space', [8, 9, 20, 21]) +def test_ellipsis_truncate_width(msg, space): + # the result always fills the space, so it overwrites a longer line printed before it. + result = ellipsis_truncate(msg, space) + assert platform.swidth(result) == space + if platform.swidth(msg) > space: + assert '...' in result + else: + assert result == msg + ' ' * (space - platform.swidth(msg)) + + def utcfromtimestamp(timestamp): """Returns a naive datetime instance representing the timestamp in the UTC timezone""" return datetime.fromtimestamp(timestamp, timezone.utc).replace(tzinfo=None)