From 3bd5bd660f47d4d5673bcbcaa9364602512d35c2 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sat, 20 Apr 2024 22:40:33 -0600 Subject: [PATCH] - Refactored - Removed simplify_settings because it caused issues, and it's impossible to fully handle properly --- src/ansi_string/ansi_string.py | 56 ++++++---------------------------- tests/test_ansi_string.py | 13 ++++++-- 2 files changed, 21 insertions(+), 48 deletions(-) diff --git a/src/ansi_string/ansi_string.py b/src/ansi_string/ansi_string.py index 859c25e..fa1dff5 100644 --- a/src/ansi_string/ansi_string.py +++ b/src/ansi_string/ansi_string.py @@ -931,6 +931,13 @@ def __eq__(self, value) -> bool: return value.add == self.add and value.rem == self.rem return False + def insert_settings(self, apply:bool, settings:'AnsiString.Settings', topmost:bool=True): + lst = self.add if apply else self.rem + if topmost: + lst.append(settings) + else: + lst.insert(0, settings) + def __init__(self, s:str='', *setting_or_settings:Union[List[str], str, List[int], int, List[AnsiFormat], AnsiFormat]): self._s = s # Key is the string index to make a color change at @@ -974,16 +981,6 @@ def base_str(self) -> str: def copy(self) -> 'AnsiString': return self[:] - @staticmethod - def _insert_settings_to_dict(settings_dict:Dict[int,'AnsiString.SettingPoint'], idx:int, apply:bool, settings:Settings, topmost:bool=True): - if idx not in settings_dict: - settings_dict[idx] = __class__.SettingPoint() - lst = settings_dict[idx].add if apply else settings_dict[idx].rem - if topmost: - lst.append(settings) - else: - lst.insert(0, settings) - @staticmethod def _shift_settings_idx(settings_dict:Dict[int,'AnsiString.SettingPoint'], num:int, keep_origin:bool): ''' @@ -996,7 +993,9 @@ def _shift_settings_idx(settings_dict:Dict[int,'AnsiString.SettingPoint'], num:i settings_dict[new_key] = settings_dict.pop(key) def _insert_settings(self, idx:int, apply:bool, settings:Settings, topmost:bool=True): - __class__._insert_settings_to_dict(self._color_settings, idx, apply, settings, topmost) + if idx not in self._color_settings: + self._color_settings[idx] = __class__.SettingPoint() + self._color_settings[idx].insert_settings(apply, settings, topmost) def apply_formatting( self, @@ -1404,40 +1403,6 @@ def istitle(self) -> bool: def isupper(self) -> bool: return self._s.isupper() - def simplify_settings(self): - ''' - Attempts to simplify ANSI formatting settings by removing redundant parameters. This does nothing to interrogate - custom formatting strings that were applied using "[" string prefix. - ''' - previous_settings = [[],[]] - for idx, settings, current_settings in __class__.SettingsIterator(self._color_settings): - apply_list_original = list(settings.add) - - # Remove settings that are redundantly reapplied - self._color_settings[idx].add = [ - s for s in settings.add if s not in previous_settings - ] - - # Remove settings that are being applied and removed within the same index - remove_list = settings.rem - self._color_settings[idx].add = [ - v for v in settings.add if v not in remove_list - ] - self._color_settings[idx].rem = [ - v for v in settings.rem if v not in apply_list_original - ] - - # Save for next loop - previous_settings = list(current_settings) - - # Remove now empty indices - for idx in list(self._color_settings.keys()): - if ( - not self._color_settings[idx].add - and not self._color_settings[idx].rem - ): - del self._color_settings[idx] - def __add__(self, value:Union[str,'AnsiString']) -> 'AnsiString': cpy = self.copy() cpy += value @@ -1456,7 +1421,6 @@ def __iadd__(self, value:Union[str,'AnsiString']) -> 'AnsiString': self._color_settings[key].rem.extend(value.rem) else: self._color_settings[key] = value - self.simplify_settings() else: raise ValueError(f'value is invalid type: {type(value)}') return self diff --git a/tests/test_ansi_string.py b/tests/test_ansi_string.py index 1a95414..257da0c 100755 --- a/tests/test_ansi_string.py +++ b/tests/test_ansi_string.py @@ -314,8 +314,12 @@ def test_iterate(self): # Recreate the original string by iterating the characters for c in s: s2 += c - # Should have created a whole new copy of the original - self.assertEqual(str(s), str(s2)) + # This will look the same, even though each character now has formatting + self.assertEqual( + str(s2), + '\x1b[43mo\x1b[0;43mn\x1b[0;43me\x1b[0;43m \x1b[0;4mt\x1b[0;4mw\x1b[0;4mo\x1b[0;4m \x1b[0;1mt\x1b[0;1mh' + '\x1b[0;1mr\x1b[0;1me\x1b[0;1me\x1b[m' + ) self.assertIsNot(s, s2) def test_apply_string_equal_length(self): @@ -361,6 +365,11 @@ def test_remove_suffix_not_found(self): self.assertEqual(str(s), '\x1b[14mblah blah\x1b[m') self.assertIsNot(s, s2) + def test_cat_edge_case(self): + a = AnsiString('a', 'red') + b = AnsiString('b', 'red') + c = a + b + self.assertEqual(str(c), '\x1b[31ma\x1b[0;31mb\x1b[m') if __name__ == '__main__':