From ebb11040858a7c140a2224b5d62099be3dc9eca9 Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Sat, 24 Jan 2026 19:02:50 +0000 Subject: [PATCH] Allow same box-drawing chars to merge, break on different ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same box-drawing characters (like ───) can now merge into a single tspan, but different box-drawing characters (like │╯) are kept separate for precise positioning. This reduces SVG size while maintaining alignment at character transitions. --- src/textual_webterm/svg_exporter.py | 31 ++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/textual_webterm/svg_exporter.py b/src/textual_webterm/svg_exporter.py index 580ea03..0dc33f0 100644 --- a/src/textual_webterm/svg_exporter.py +++ b/src/textual_webterm/svg_exporter.py @@ -266,6 +266,27 @@ def _is_box_drawing(char: str) -> bool: return 0x2500 <= code <= 0x259F or 0x25A0 <= code <= 0x25FF +def _should_break_span(current_text: str, new_char: str) -> bool: + """Check if we should break the span before adding new_char. + + Box-drawing characters should not merge with different box-drawing chars + or with regular text, but same box-drawing chars can merge (e.g., ─────). + """ + if not current_text: + return False + + last_char = current_text[-1] + curr_is_box = _is_box_drawing(last_char) + new_is_box = _is_box_drawing(new_char) + + # If transitioning between box and non-box, break + if curr_is_box != new_is_box: + return True + + # If both are box-drawing but different characters, break + return curr_is_box and new_is_box and last_char != new_char + + def _build_row_spans( row_data: list[CharData], default_fg: str, @@ -297,15 +318,15 @@ def _build_row_spans( 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 should break the span (for box-drawing character boundaries) + should_break = current_span is not None and _should_break_span( + current_span["text"], char_data + ) # Check if we can extend current span if ( current_span is not None - and not is_box - and not prev_is_box + and not should_break and current_span["fg"] == fg and current_span["bg"] == bg and current_span["bold"] == char["bold"]