Merge pull request #2036 from volundmush/ansi_format
Fixing up ANSIString
This commit is contained in:
commit
94b988936f
2 changed files with 69 additions and 0 deletions
|
|
@ -673,6 +673,10 @@ class ANSIString(str, metaclass=ANSIMeta):
|
||||||
and taken literally the second time around.
|
and taken literally the second time around.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# A compiled Regex for the format mini-language: https://docs.python.org/3/library/string.html#formatspec
|
||||||
|
re_format = re.compile(r"(?i)(?P<just>(?P<fill>.)?(?P<align>\<|\>|\=|\^))?(?P<sign>\+|\-| )?(?P<alt>\#)?"
|
||||||
|
r"(?P<zero>0)?(?P<width>\d+)?(?P<grouping>\_|\,)?(?:\.(?P<precision>\d+))?"
|
||||||
|
r"(?P<type>b|c|d|e|E|f|F|g|G|n|o|s|x|X|%)?")
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -733,6 +737,47 @@ class ANSIString(str, metaclass=ANSIMeta):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self._raw_string
|
return self._raw_string
|
||||||
|
|
||||||
|
def __format__(self, format_spec):
|
||||||
|
"""
|
||||||
|
This magic method covers ANSIString's behavior within a str.format() or f-string.
|
||||||
|
|
||||||
|
Current features supported: fill, align, width.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format_spec (str): The format specification passed by f-string or str.format(). This is a string such as
|
||||||
|
"0<30" which would mean "left justify to 30, filling with zeros". The full specification can be found
|
||||||
|
at https://docs.python.org/3/library/string.html#formatspec
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ansi_str (str): The formatted ANSIString's .raw() form, for display.
|
||||||
|
"""
|
||||||
|
# This calls the compiled regex stored on ANSIString's class to analyze the format spec.
|
||||||
|
# It returns a dictionary.
|
||||||
|
format_data = self.re_format.match(format_spec).groupdict()
|
||||||
|
clean = self.clean()
|
||||||
|
base_output = ANSIString(self.raw())
|
||||||
|
align = format_data.get('align', '<')
|
||||||
|
fill = format_data.get('fill', ' ')
|
||||||
|
|
||||||
|
# Need to coerce width into an integer. We can be certain that it's numeric thanks to regex.
|
||||||
|
width = format_data.get('width', None)
|
||||||
|
if width is None:
|
||||||
|
width = len(clean)
|
||||||
|
else:
|
||||||
|
width = int(width)
|
||||||
|
|
||||||
|
if align == '<':
|
||||||
|
base_output = self.ljust(width, fill)
|
||||||
|
elif align == '>':
|
||||||
|
base_output = self.rjust(width, fill)
|
||||||
|
elif align == '^':
|
||||||
|
base_output = self.center(width, fill)
|
||||||
|
elif align == '=':
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Return the raw string with ANSI markup, ready to be displayed.
|
||||||
|
return base_output.raw()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""
|
"""
|
||||||
Let's make the repr the command that would actually be used to
|
Let's make the repr the command that would actually be used to
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,30 @@ class TestMLen(TestCase):
|
||||||
self.assertEqual(utils.m_len({"hello": True, "Goodbye": False}), 2)
|
self.assertEqual(utils.m_len({"hello": True, "Goodbye": False}), 2)
|
||||||
|
|
||||||
|
|
||||||
|
class TestANSIString(TestCase):
|
||||||
|
"""
|
||||||
|
Verifies that ANSIString's string-API works as intended.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.example_raw = "|relectric |cboogaloo|n"
|
||||||
|
self.example_ansi = ANSIString(self.example_raw)
|
||||||
|
self.example_str = "electric boogaloo"
|
||||||
|
self.example_output = "\x1b[1m\x1b[31melectric \x1b[1m\x1b[36mboogaloo\x1b[0m"
|
||||||
|
|
||||||
|
def test_length(self):
|
||||||
|
self.assertEqual(len(self.example_ansi), 17)
|
||||||
|
|
||||||
|
def test_clean(self):
|
||||||
|
self.assertEqual(self.example_ansi.clean(), self.example_str)
|
||||||
|
|
||||||
|
def test_raw(self):
|
||||||
|
self.assertEqual(self.example_ansi.raw(), self.example_output)
|
||||||
|
|
||||||
|
def test_format(self):
|
||||||
|
self.assertEqual(f"{self.example_ansi:0<20}", self.example_output + "000")
|
||||||
|
|
||||||
|
|
||||||
class TestTimeformat(TestCase):
|
class TestTimeformat(TestCase):
|
||||||
"""
|
"""
|
||||||
Default function header from utils.py:
|
Default function header from utils.py:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue