Skip to content

Commit

Permalink
Tweaked the meaning of topmost in apply_formatting to also extend to …
Browse files Browse the repository at this point in the history
…all settings leading up to the start index
  • Loading branch information
James Smith authored and James Smith committed Nov 24, 2024
1 parent bb71683 commit 911d445
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
16 changes: 13 additions & 3 deletions src/ansi_string/ansi_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from .ansi_parsing import ParsedAnsiControlSequenceString, parse_graphic_sequence, settings_to_dict

__version__ = '1.1.7'
__version__ = '1.1.8'
PACKAGE_NAME = 'ansi_string'

# Constant: all characters considered to be whitespaces - this is used in strip functionality
Expand Down Expand Up @@ -315,8 +315,7 @@ def apply_formatting(
settings - setting or list of settings to apply
start - The string start index where setting(s) are to be applied
end - The string index where the setting(s) should be removed
topmost - When true, the settings placed at the end of the set for the given
start_index, meaning it takes precedent over others; the opposite when False
topmost - When False, all other existing settings in this range will take precedent
'''
start = self._slice_val_to_idx(start, 0)
end = self._slice_val_to_idx(end, len(self._s))
Expand All @@ -336,6 +335,17 @@ def apply_formatting(
self._fmts[start] = _AnsiSettingPoint()
self._fmts[start].insert_settings(True, ansi_settings, topmost)

# When not topmost, do a remove and re-add of any settings that lead up to the start index
if not topmost:
remove_and_add_settings = []
settings_at_start = self.ansi_settings_at(start)
for setting in settings_at_start:
if setting not in self._fmts[start].add:
remove_and_add_settings.append(setting)
if remove_and_add_settings:
self._fmts[start].insert_settings(False, remove_and_add_settings)
self._fmts[start].insert_settings(True, remove_and_add_settings)

# Remove settings
if end not in self._fmts:
self._fmts[end] = _AnsiSettingPoint()
Expand Down
23 changes: 23 additions & 0 deletions tests/test_ansi_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,29 @@ def test_rpartition_not_found(self):
)
self.assertIs(s, s_orig)

def test_apply_formatting_topmost(self):
s = AnsiString.join('This ', AnsiString('string', AnsiFormat.BOLD))
s += AnsiString(' contains ') + AnsiString('multiple', AnsiFormat.BG_BLUE)
s += ' color settings across different ranges'
s.apply_formatting([AnsiFormat.FG_ORANGE, AnsiFormat.ITALIC], 21, 35)
s.apply_formatting(AnsiFormat.FG_BLUE, 21, 44)
self.assertEqual(str(s), 'This \x1b[1mstring\x1b[m contains \x1b[44;34;3mmultiple\x1b[49m color\x1b[23m settings\x1b[m across different ranges')

def test_apply_formatting_not_topmost(self):
s = AnsiString.join('This ', AnsiString('string', AnsiFormat.BOLD))
s += AnsiString(' contains ') + AnsiString('multiple', AnsiFormat.BG_BLUE)
s += ' color settings across different ranges'
s.apply_formatting([AnsiFormat.FG_ORANGE, AnsiFormat.ITALIC], 21, 35)
s.apply_formatting(AnsiFormat.FG_BLUE, 21, 44, topmost=False) # Should be ignored until index 35
self.assertEqual(str(s), 'This \x1b[1mstring\x1b[m contains \x1b[38;5;214;44;3mmultiple\x1b[49m color\x1b[0;34m settings\x1b[m across different ranges')

def test_apply_formatting_not_topmost2(self):
s = AnsiString.join('This ', AnsiString('string', AnsiFormat.BOLD))
s += AnsiString(' contains ') + AnsiString('multiple', AnsiFormat.BG_BLUE)
s += ' color settings across different ranges'
s.apply_formatting([AnsiFormat.FG_ORANGE, AnsiFormat.ITALIC], 21, 35)
s.apply_formatting(AnsiFormat.FG_BLUE, 30, 35, topmost=False) # Should be ignored
self.assertEqual(str(s), 'This \x1b[1mstring\x1b[m contains \x1b[44;38;5;214;3mmultiple\x1b[49m color\x1b[m settings across different ranges')

def test_get_item_edge_case(self):
# There used to be a bug where if a single character was retrieved right before the index where a new format was
Expand Down

0 comments on commit 911d445

Please sign in to comment.