Просмотр исходного кода

Merge pull request #1635 from enkore/issue/1624

Fix broken --progress for double-cell paths
enkore 8 лет назад
Родитель
Сommit
ea9e859026
3 измененных файлов с 53 добавлено и 3 удалено
  1. 5 3
      src/borg/archive.py
  2. 26 0
      src/borg/helpers.py
  3. 22 0
      src/borg/testsuite/helpers.py

+ 5 - 3
src/borg/archive.py

@@ -28,7 +28,7 @@ from .helpers import Error, IntegrityError
 from .helpers import uid2user, user2uid, gid2group, group2gid
 from .helpers import parse_timestamp, to_localtime
 from .helpers import format_time, format_timedelta, format_file_size, file_status
-from .helpers import safe_encode, safe_decode, make_path_safe, remove_surrogates
+from .helpers import safe_encode, safe_decode, make_path_safe, remove_surrogates, swidth_slice
 from .helpers import decode_dict, StableDict
 from .helpers import int_to_bigint, bigint_to_int, bin_to_hex
 from .helpers import ProgressIndicatorPercent, log_multi
@@ -94,8 +94,10 @@ class Statistics:
                     space = columns - swidth(msg)
                 if space >= 8:
                     if space < swidth('...') + swidth(path):
-                        path = '%s...%s' % (path[:(space // 2) - swidth('...')], path[-space // 2:])
-                    msg += "{0:<{space}}".format(path, space=space)
+                        path = '%s...%s' % (swidth_slice(path, space // 2 - swidth('...')),
+                                            swidth_slice(path, -space // 2))
+                    space -= swidth(path)
+                    msg += path + ' ' * space
             else:
                 msg = ' ' * columns
             print(msg, file=stream or sys.stderr, end="\r", flush=True)

+ 26 - 0
src/borg/helpers.py

@@ -1696,3 +1696,29 @@ class ErrorIgnoringTextIOWrapper(io.TextIOWrapper):
                 except OSError:
                     pass
         return len(s)
+
+
+def swidth_slice(string, max_width):
+    """
+    Return a slice of *max_width* cells from *string*.
+
+    Negative *max_width* means from the end of string.
+
+    *max_width* is in units of character cells (or "columns").
+    Latin characters are usually one cell wide, many CJK characters are two cells wide.
+    """
+    from .platform import swidth
+    reverse = max_width < 0
+    max_width = abs(max_width)
+    if reverse:
+        string = reversed(string)
+    current_swidth = 0
+    result = []
+    for character in string:
+        current_swidth += swidth(character)
+        if current_swidth > max_width:
+            break
+        result.append(character)
+    if reverse:
+        result.reverse()
+    return ''.join(result)

+ 22 - 0
src/borg/testsuite/helpers.py

@@ -9,6 +9,7 @@ import pytest
 import msgpack
 import msgpack.fallback
 
+from .. import platform
 from ..helpers import Location
 from ..helpers import Buffer
 from ..helpers import partial_format, format_file_size, parse_file_size, format_timedelta, format_line, PlaceholderError, replace_placeholders
@@ -23,6 +24,7 @@ from ..helpers import ProgressIndicatorPercent, ProgressIndicatorEndless
 from ..helpers import load_excludes
 from ..helpers import CompressionSpec, CompressionDecider1, CompressionDecider2
 from ..helpers import parse_pattern, PatternMatcher, RegexPattern, PathPrefixPattern, FnmatchPattern, ShellPattern
+from ..helpers import swidth_slice
 
 from . import BaseTestCase, environment_variable, FakeInputs
 
@@ -1041,3 +1043,23 @@ def test_replace_placeholders():
     now = datetime.now()
     assert " " not in replace_placeholders('{now}')
     assert int(replace_placeholders('{now:%Y}')) == now.year
+
+
+def working_swidth():
+    return platform.swidth('선') == 2
+
+
+@pytest.mark.skipif(not working_swidth(), reason='swidth() is not supported / active')
+def test_swidth_slice():
+    string = '나윤선나윤선나윤선나윤선나윤선'
+    assert swidth_slice(string, 1) == ''
+    assert swidth_slice(string, -1) == ''
+    assert swidth_slice(string, 4) == '나윤'
+    assert swidth_slice(string, -4) == '윤선'
+
+
+@pytest.mark.skipif(not working_swidth(), reason='swidth() is not supported / active')
+def test_swidth_slice_mixed_characters():
+    string = '나윤a선나윤선나윤선나윤선나윤선'
+    assert swidth_slice(string, 5) == '나윤a'
+    assert swidth_slice(string, 6) == '나윤a'