Don't merge box-drawing characters for precise positioning

Box-drawing and block element characters (U+2500-U+259F, U+25A0-U+25FF)
are now rendered as individual tspans with their own x positions to
prevent visual misalignment caused by font rendering variations.
This commit is contained in:
GitHub Copilot
2026-01-24 18:58:19 +00:00
parent 259f88917c
commit ba1f89af54
2 changed files with 22 additions and 2 deletions
+17
View File
@@ -255,6 +255,17 @@ class _Span(TypedDict):
has_bg: bool has_bg: bool
def _is_box_drawing(char: str) -> bool:
"""Check if character is a box-drawing or block element that needs precise positioning."""
if not char:
return False
code = ord(char[0])
# Box Drawing: U+2500-U+257F
# Block Elements: U+2580-U+259F
# Geometric Shapes (some): U+25A0-U+25FF
return 0x2500 <= code <= 0x259F or 0x25A0 <= code <= 0x25FF
def _build_row_spans( def _build_row_spans(
row_data: list[CharData], row_data: list[CharData],
default_fg: str, default_fg: str,
@@ -286,9 +297,15 @@ def _build_row_spans(
has_bg = bg != default_bg has_bg = bg != default_bg
# Don't merge box-drawing characters - they need precise x positioning
is_box = _is_box_drawing(char_data)
prev_is_box = current_span is not None and _is_box_drawing(current_span["text"][-1:])
# Check if we can extend current span # Check if we can extend current span
if ( if (
current_span is not None current_span is not None
and not is_box
and not prev_is_box
and current_span["fg"] == fg and current_span["fg"] == fg
and current_span["bg"] == bg and current_span["bg"] == bg
and current_span["bold"] == char["bold"] and current_span["bold"] == char["bold"]
+5 -2
View File
@@ -716,14 +716,17 @@ class TestEdgeCases:
assert "A中B🎉C" in svg assert "A中B🎉C" in svg
def test_special_unicode_blocks(self) -> None: def test_special_unicode_blocks(self) -> None:
"""Unicode box drawing characters render.""" """Unicode box drawing characters render (separately for precise positioning)."""
buffer = [[ buffer = [[
self._char(""), self._char(""),
self._char(""), self._char(""),
self._char(""), self._char(""),
]] ]]
svg = render_terminal_svg(buffer, width=3, height=1) svg = render_terminal_svg(buffer, width=3, height=1)
assert "┌─┐" in svg # Box drawing chars are rendered separately for precise x positioning
assert "" in svg
assert "" in svg
assert "" in svg
def test_ansi_bright_colors(self) -> None: def test_ansi_bright_colors(self) -> None:
"""All bright ANSI colors render.""" """All bright ANSI colors render."""