Implement ANSIString.strip() .lstrip() and .rstrip() as tag-aware methods. This handles the last prblem with #1117.

This commit is contained in:
Griatch 2016-11-17 00:21:05 +01:00
parent 596bfff35a
commit f00fbb9d88
3 changed files with 118 additions and 24 deletions

View file

@ -977,6 +977,29 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
break
return s
def __mul__(self, other):
"""
Multiplication method. Implemented for performance reasons.
"""
if not isinstance(other, int):
return NotImplemented
raw_string = self._raw_string * other
clean_string = self._clean_string * other
code_indexes = self._code_indexes[:]
char_indexes = self._char_indexes[:]
for i in range(1, other + 1):
code_indexes.extend(
self._shifter(self._code_indexes, i * len(self._raw_string)))
char_indexes.extend(
self._shifter(self._char_indexes, i * len(self._raw_string)))
return ANSIString(
raw_string, code_indexes=code_indexes, char_indexes=char_indexes,
clean_string=clean_string)
def __rmul__(self, other):
return self.__mul__(other)
def split(self, by=None, maxsplit=-1):
"""
Stolen from PyPy's pure Python string implementation, tweaked for
@ -1010,29 +1033,6 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
return [part for part in res if part != ""]
return res
def __mul__(self, other):
"""
Multiplication method. Implemented for performance reasons.
"""
if not isinstance(other, int):
return NotImplemented
raw_string = self._raw_string * other
clean_string = self._clean_string * other
code_indexes = self._code_indexes[:]
char_indexes = self._char_indexes[:]
for i in range(1, other + 1):
code_indexes.extend(
self._shifter(self._code_indexes, i * len(self._raw_string)))
char_indexes.extend(
self._shifter(self._char_indexes, i * len(self._raw_string)))
return ANSIString(
raw_string, code_indexes=code_indexes, char_indexes=char_indexes,
clean_string=clean_string)
def __rmul__(self, other):
return self.__mul__(other)
def rsplit(self, by=None, maxsplit=-1):
"""
Stolen from PyPy's pure Python string implementation, tweaked for
@ -1066,6 +1066,88 @@ class ANSIString(with_metaclass(ANSIMeta, unicode)):
return [part for part in res if part != ""]
return res
def strip(self, chars=None):
"""
Strip from both ends, taking ANSI markers into account.
"""
clean = self._clean_string
raw = self._raw_string
# count continuous sequence of chars from left and right
nlen = len(clean)
nlstripped = nlen - len(clean.lstrip(chars))
nrstripped = nlen - len(clean.rstrip(chars))
# within the stripped regions, only retain parts of the raw
# string *not* matching the clean string (these are ansi/mxp tags)
lstripped = ""
ic, ir1 = 0, 0
while nlstripped:
if ic >= nlstripped:
break
elif raw[ir1] != clean[ic]:
lstripped += raw[ir1]
else:
ic += 1
ir1 += 1
rstripped = ""
ic, ir2 = nlen-1, len(raw)-1
while nrstripped:
if nlen - ic > nrstripped:
break
elif raw[ir2] != clean[ic]:
rstripped += raw[ir2]
else:
ic -= 1
ir2 -= 1
rstripped = rstripped[::-1]
return ANSIString(lstripped + raw[ir1:ir2+1] + rstripped)
def lstrip(self, chars=None):
"""
Strip from the left, taking ANSI markers into account.
"""
clean = self._clean_string
raw = self._raw_string
# count continuous sequence of chars from left and right
nlen = len(clean)
nlstripped = nlen - len(clean.lstrip(chars))
# within the stripped regions, only retain parts of the raw
# string *not* matching the clean string (these are ansi/mxp tags)
lstripped = ""
ic, ir1 = 0, 0
while nlstripped:
if ic >= nlstripped:
break
elif raw[ir1] != clean[ic]:
lstripped += raw[ir1]
else:
ic += 1
ir1 += 1
return ANSIString(lstripped + raw[ir1:])
def rstrip(self, chars=None):
"""
Strip from the right, taking ANSI markers into account.
"""
clean = self._clean_string
raw = self._raw_string
nlen = len(clean)
nrstripped = nlen - len(clean.rstrip(chars))
rstripped = ""
ic, ir2 = nlen-1, len(raw)-1
while nrstripped:
if nlen - ic > nrstripped:
break
elif raw[ir2] != clean[ic]:
rstripped += raw[ir2]
else:
ic -= 1
ir2 -= 1
return ANSIString(raw[:ir2+1] + rstripped)
def join(self, iterable):
"""
Joins together strings in an iterable.

View file

@ -576,7 +576,8 @@ class EvCell(object):
hfill_char = self.hfill_char
width = self.width
if align == "l":
return [(line.lstrip(" ") + " " if line.startswith(" ") and not line.startswith(" ") else line) + hfill_char * (width - m_len(line)) for line in data]
lines= [(line.lstrip(" ") + " " if line.startswith(" ") and not line.startswith(" ") else line) + hfill_char * (width - m_len(line)) for line in data]
return lines
elif align == "r":
return [hfill_char * (width - m_len(line)) + (" " + line.rstrip(" ") if line.endswith(" ") and not line.endswith(" ") else line) for line in data]
else: # center, 'c'

View file

@ -152,6 +152,17 @@ class ANSIStringTestCase(TestCase):
]
self.table_check(c, char_table, code_table)
def test_strip(self):
"""
Test the ansi-aware .strip() methods
"""
a = ANSIString(" |r Test of stuff |b with spaces |n ")
b = ANSIString("|r|b")
self.assertEqual(a.strip(), ANSIString("|rTest of stuff |b with spaces|n"))
self.assertEqual(a.lstrip(), ANSIString("|rTest of stuff |b with spaces |n "))
self.assertEqual(a.rstrip(), ANSIString(" |r Test of stuff |b with spaces|n"))
self.assertEqual(b.strip(), b)
class TestIsIter(TestCase):
def test_is_iter(self):