Skip to content

Commit

Permalink
Fixed some issues related to function code sequence detection
Browse files Browse the repository at this point in the history
  • Loading branch information
James Smith authored and James Smith committed Nov 20, 2024
1 parent f8f8a6b commit a4b0b4b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
7 changes: 7 additions & 0 deletions src/ansi_string/ansi_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,17 @@ def parsable(self) -> bool:
return False

# Check all know multi-code functions for valid length
fn_found = False
for fn in _AnsiControlFn:
if codes[0:len(fn.setup_seq)] == fn.setup_seq:
self._parsable = (len(codes) == fn.total_seq_count)
return self._parsable
elif codes[0] == fn.setup_seq[0]:
fn_found = True

# Function code was found but didn't match any setup sequence
if fn_found:
return False

# Otherwise, the length must be 1
self._parsable = (len(codes) == 1)
Expand Down
46 changes: 25 additions & 21 deletions src/ansi_string/ansi_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

from typing import Any, Union, List, Dict, Tuple
from .ansi_format import (
ansi_sep, ansi_graphic_rendition_code_end, ansi_control_sequence_introducer, ansi_term_ord_range, AnsiSetting
ansi_sep, ansi_graphic_rendition_code_end, ansi_control_sequence_introducer, ansi_term_ord_range, AnsiSetting,
_AnsiControlFn
)
from .ansi_param import AnsiParam, AnsiParamEffect, AnsiParamEffectFn

Expand Down Expand Up @@ -103,36 +104,39 @@ def parse_graphic_sequence(
items = [item.strip() for item in sequence.split(ansi_sep)]
else:
items = sequence
idx = 0
# Attempt to make each value an integer
for idx, value in enumerate(items):
try:
items[idx] = int(value)
except ValueError:
pass

left_in_set = 0
current_set = []
while idx < len(items):
try:
int_value = int(items[idx])
except:
int_value = None
finally:
for idx, value in enumerate(items):
if isinstance(value, int):
if not current_set:
left_in_set = 1
if (
int_value == AnsiParam.FG_SET.value or
int_value == AnsiParam.BG_SET.value or
int_value == AnsiParam.SET_UNDERLINE_COLOR.value
):
if idx + 1 < len(items):
if str(items[idx + 1]) == "5":
left_in_set = 3
elif str(items[ idx + 1]) == "2":
left_in_set = 5
if int_value:
current_set.append(int_value)
# Check all know multi-code functions for expected items in set
fn_set = False
fn_found = False
for fn in _AnsiControlFn:
if items[idx : idx+len(fn.setup_seq)] == fn.setup_seq:
left_in_set = fn.total_seq_count
fn_set = True
elif value == fn.setup_seq[0]:
fn_found = True
if fn_found and not fn_set and not add_dangling:
# Skip this value - it's a function code that doesn't supply a valid setup sequence
continue
if value:
current_set.append(value)
else:
current_set.append(items[idx])
left_in_set -= 1
if left_in_set <= 0:
output.append(AnsiSetting(current_set))
current_set = []
idx += 1
if current_set and add_dangling:
output.append(AnsiSetting(current_set))
return output
Expand Down
12 changes: 9 additions & 3 deletions tests/test_ansi_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,17 @@ def test_custom_formatting(self):
s = AnsiString('This string contains custom formatting', '[38;2;175;95;95')
self.assertEqual(str(s), '\x1b[38;2;175;95;95mThis string contains custom formatting\x1b[m')
self.assertTrue(s.is_optimizable()) # Optimizable because this was a valid settings group
# Simplification should not change anything
s.simplify()
self.assertEqual(str(s), '\x1b[38;2;175;95;95mThis string contains custom formatting\x1b[m')
self.assertTrue(s.is_optimizable())

def test_custom_formatting2(self):
s = AnsiString('This string contains custom formatting', '[38;10;175;95;95')
self.assertEqual(str(s), '\x1b[38;10;175;95;95mThis string contains custom formatting\x1b[m')
self.assertFalse(s.is_optimizable()) # Not optimizable because "10" is an invalid value
s = AnsiString('This string contains custom formatting', '[38')
self.assertEqual(str(s), '\x1b[38mThis string contains custom formatting\x1b[m')
self.assertFalse(s.is_optimizable()) # Not optimizable because code 38 should be followed by at least 1 value
s.simplify()
self.assertEqual(str(s), 'This string contains custom formatting')

def test_custom_formatting3(self):
# Will be used verbatim and won't throw an exception because it starts with '['
Expand Down

0 comments on commit a4b0b4b

Please sign in to comment.