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":