From 2b0a45b3379f6eabe18f31af1f24570ec100476d Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 7 Mar 2026 08:35:33 +0000 Subject: [PATCH] Fix code block rendering: escape newlines/tabs in syntax highlighter output highlight_sx/python/bash produced SX string literals with literal newline and tab characters, breaking the wire format parser. Add centralized _escape() helper that properly escapes \n, \t, \r (plus existing \\ and " escaping). Code blocks now render with correct indentation and syntax highlighting in both server and client renders. Co-Authored-By: Claude Opus 4.6 --- sx/content/highlight.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sx/content/highlight.py b/sx/content/highlight.py index 40e0615..1515eb5 100644 --- a/sx/content/highlight.py +++ b/sx/content/highlight.py @@ -8,12 +8,22 @@ from __future__ import annotations import re +def _escape(text: str) -> str: + """Escape a token for embedding in an SX string literal.""" + return (text + .replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n") + .replace("\t", "\\t") + .replace("\r", "\\r")) + + def highlight_sx(code: str) -> str: """Highlight s-expression source code as sx with Tailwind spans.""" tokens = _tokenize_sx(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string": @@ -94,7 +104,7 @@ def highlight_python(code: str) -> str: tokens = _tokenize_python(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string": @@ -176,7 +186,7 @@ def highlight_bash(code: str) -> str: tokens = _tokenize_bash(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string":