Handle corrupted horizontal box chars with threshold-based detection

Changed _is_all_horizontal_box_drawing to _is_mostly_horizontal_box_drawing
with 80% threshold. This handles cases where terminal data has occasional
corrupted characters (like U+FFFD replacement chars) mixed in with
horizontal line characters.

Version bump to 0.3.9
This commit is contained in:
GitHub Copilot
2026-01-24 19:25:37 +00:00
parent d8d3885efb
commit b896464c81
3 changed files with 34 additions and 20 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "textual-webterm" name = "textual-webterm"
version = "0.3.8" version = "0.3.9"
description = "Serve terminal sessions over the web" description = "Serve terminal sessions over the web"
authors = ["Will McGugan <will@textualize.io>"] authors = ["Will McGugan <will@textualize.io>"]
license = "MIT" license = "MIT"
+11 -4
View File
@@ -224,7 +224,8 @@ def render_terminal_svg(
# For horizontal box-drawing spans, use textLength to ensure correct width # For horizontal box-drawing spans, use textLength to ensure correct width
# This prevents gaps caused by font rendering of ─ being narrower than char_width # This prevents gaps caused by font rendering of ─ being narrower than char_width
if _is_all_horizontal_box_drawing(text) and len(text) > 1: # Use "mostly" check to handle occasional corrupted chars (like U+FFFD)
if _is_mostly_horizontal_box_drawing(text) and len(text) > 1:
span_width = columns * char_width span_width = columns * char_width
attrs.append(f'textLength="{span_width:.1f}"') attrs.append(f'textLength="{span_width:.1f}"')
attrs.append('lengthAdjust="spacing"') attrs.append('lengthAdjust="spacing"')
@@ -291,11 +292,17 @@ _HORIZONTAL_BOX_CHARS = {
} }
def _is_all_horizontal_box_drawing(text: str) -> bool: def _is_mostly_horizontal_box_drawing(text: str, threshold: float = 0.8) -> bool:
"""Check if text consists entirely of horizontal box-drawing characters.""" """Check if text is mostly horizontal box-drawing characters.
Returns True if at least threshold (default 80%) of chars are horizontal
box-drawing chars. This handles cases where terminal data has occasional
corrupted chars (like replacement char U+FFFD) mixed in.
"""
if not text: if not text:
return False return False
return all(ord(c) in _HORIZONTAL_BOX_CHARS for c in text) horizontal_count = sum(1 for c in text if ord(c) in _HORIZONTAL_BOX_CHARS)
return horizontal_count / len(text) >= threshold
def _should_break_span(current_text: str, new_char: str) -> bool: def _should_break_span(current_text: str, new_char: str) -> bool:
+22 -15
View File
@@ -10,8 +10,8 @@ from textual_webterm.svg_exporter import (
_build_row_spans, _build_row_spans,
_color_to_hex, _color_to_hex,
_escape_xml, _escape_xml,
_is_all_horizontal_box_drawing,
_is_box_drawing_vertical_or_corner, _is_box_drawing_vertical_or_corner,
_is_mostly_horizontal_box_drawing,
_should_break_span, _should_break_span,
render_terminal_svg, render_terminal_svg,
) )
@@ -389,26 +389,33 @@ class TestBoxDrawingHelpers:
assert _should_break_span("", "") is False assert _should_break_span("", "") is False
assert _should_break_span("", "") is False assert _should_break_span("", "") is False
def test_is_all_horizontal_box_drawing_empty(self) -> None: def test_is_mostly_horizontal_box_drawing_empty(self) -> None:
"""Empty string returns False.""" """Empty string returns False."""
assert _is_all_horizontal_box_drawing("") is False assert _is_mostly_horizontal_box_drawing("") is False
def test_is_all_horizontal_box_drawing_normal_text(self) -> None: def test_is_mostly_horizontal_box_drawing_normal_text(self) -> None:
"""Normal text returns False.""" """Normal text returns False."""
assert _is_all_horizontal_box_drawing("Hello") is False assert _is_mostly_horizontal_box_drawing("Hello") is False
assert _is_all_horizontal_box_drawing("ABC") is False assert _is_mostly_horizontal_box_drawing("ABC") is False
def test_is_all_horizontal_box_drawing_horizontal_lines(self) -> None: def test_is_mostly_horizontal_box_drawing_horizontal_lines(self) -> None:
"""Horizontal box chars return True.""" """Horizontal box chars return True."""
assert _is_all_horizontal_box_drawing("") is True assert _is_mostly_horizontal_box_drawing("") is True
assert _is_all_horizontal_box_drawing("───") is True assert _is_mostly_horizontal_box_drawing("───") is True
assert _is_all_horizontal_box_drawing("━━━") is True assert _is_mostly_horizontal_box_drawing("━━━") is True
assert _is_all_horizontal_box_drawing("═══") is True assert _is_mostly_horizontal_box_drawing("═══") is True
def test_is_all_horizontal_box_drawing_mixed(self) -> None: def test_is_mostly_horizontal_box_drawing_with_corruption(self) -> None:
"""Mixed content returns False.""" """Mostly horizontal with some corrupted chars returns True."""
assert _is_all_horizontal_box_drawing("─A─") is False # 90% horizontal (9 out of 10)
assert _is_all_horizontal_box_drawing("│──") is False # vertical at start assert _is_mostly_horizontal_box_drawing("─────────X") is True
# With replacement chars (like U+FFFD)
assert _is_mostly_horizontal_box_drawing("───\ufffd───") is True
def test_is_mostly_horizontal_box_drawing_mixed(self) -> None:
"""Mixed content below threshold returns False."""
assert _is_mostly_horizontal_box_drawing("─A─") is False # 66% horizontal
assert _is_mostly_horizontal_box_drawing("│──") is False # vertical at start
class TestRenderTerminalSvg: class TestRenderTerminalSvg: