Skip to content

Commit fd12cf3

Browse files
bluetoothbotbdraco
andauthored
Prevent color bleed and stale prefix on mid-message new entries (#1680)
Co-authored-by: Bluetooth Devices Bot <nick@openhomefoundation.org>
1 parent 8c440b5 commit fd12cf3

2 files changed

Lines changed: 63 additions & 2 deletions

File tree

aioesphomeapi/log_parser.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,15 @@ def parse_log_message(
193193
# Empty line
194194
result.append("")
195195
continue
196-
if not line[0].isspace(): # If line starts with whitespace, it's a continuation
196+
if not line[0].isspace():
197197
# This is a new log entry within the same message
198-
result.append(f"{timestamp}{line}")
198+
new_entry = f"{timestamp}{line}"
199+
if not strip_ansi_escapes and _needs_reset(line):
200+
new_entry += ANSI_RESET
201+
# Re-extract prefix/color so any later continuation lines in
202+
# this same message inherit from the new entry, not the original.
203+
prefix, color_code, _ = _extract_prefix_and_color(line, strip_ansi_escapes)
204+
result.append(new_entry)
199205
continue
200206
# Apply timestamp, color, prefix, and the continuation line
201207
result.append(

tests/test_log_parser.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,61 @@ def test_color_bleeding_prevention() -> None:
380380
)
381381

382382

383+
def test_mid_message_new_entry_color_bleed_prevention() -> None:
384+
"""Color on a mid-message new entry without trailing reset must not bleed."""
385+
text = (
386+
"\033[0;35m[C][a:022]: First entry\033[0m\n"
387+
" Continuation of first\n"
388+
"\033[0;32m[I][b:023]: Second entry without inline reset"
389+
)
390+
timestamp = "[09:00:00.000]"
391+
result = parse_log_message(text, timestamp)
392+
393+
assert len(result) == 3
394+
assert result[0] == "[09:00:00.000]\033[0;35m[C][a:022]: First entry\033[0m"
395+
assert (
396+
result[1]
397+
== "[09:00:00.000]\033[0;35m[C][a:022]: Continuation of first\033[0m"
398+
)
399+
# Mid-message new entry: reset must be appended so color cannot bleed
400+
assert (
401+
result[2]
402+
== "[09:00:00.000]\033[0;32m[I][b:023]: Second entry without inline reset\033[0m"
403+
)
404+
405+
406+
def test_mid_message_new_entry_continuation_uses_new_prefix() -> None:
407+
"""Continuation following a mid-message new entry inherits the new prefix/color."""
408+
text = (
409+
"\033[0;35m[C][a:022]: First entry\033[0m\n"
410+
"\033[0;32m[I][b:023]: Second entry\n"
411+
" continuation of second"
412+
)
413+
timestamp = "[09:00:00.000]"
414+
result = parse_log_message(text, timestamp)
415+
416+
assert len(result) == 3
417+
assert result[0] == "[09:00:00.000]\033[0;35m[C][a:022]: First entry\033[0m"
418+
# Mid-message new entry — reset added
419+
assert result[1] == "[09:00:00.000]\033[0;32m[I][b:023]: Second entry\033[0m"
420+
# Continuation must inherit the new entry's prefix and color, not the first's
421+
assert (
422+
result[2]
423+
== "[09:00:00.000]\033[0;32m[I][b:023]: continuation of second\033[0m"
424+
)
425+
426+
427+
def test_mid_message_new_entry_strip_ansi() -> None:
428+
"""strip_ansi_escapes path keeps mid-message new entries clean."""
429+
text = "\033[0;35m[C][a:022]: First entry\n\033[0;32m[I][b:023]: Second entry"
430+
timestamp = "[09:00:00.000]"
431+
result = parse_log_message(text, timestamp, strip_ansi_escapes=True)
432+
433+
assert len(result) == 2
434+
assert result[0] == "[09:00:00.000][C][a:022]: First entry"
435+
assert result[1] == "[09:00:00.000][I][b:023]: Second entry"
436+
437+
383438
# Tests for LogParser
384439

385440

0 commit comments

Comments
 (0)