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:
+1
-1
@@ -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"
|
||||||
|
|||||||
@@ -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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user