Skip to content

feat: add syntax highlighting to code blocks - #84

Open
smrnjeet222 wants to merge 1 commit into
jfernandez:mainfrom
smrnjeet222:feat/syntax-highlighting
Open

feat: add syntax highlighting to code blocks#84
smrnjeet222 wants to merge 1 commit into
jfernandez:mainfrom
smrnjeet222:feat/syntax-highlighting

Conversation

@smrnjeet222

@smrnjeet222 smrnjeet222 commented Jul 27, 2026

Copy link
Copy Markdown

Closes #24.

Fenced code blocks are highlighted server-side with syntect. Output is class-based, so one pre-rendered copy of the HTML serves all five themes and theme switching stays client-side.

Approach

  • syntect emits hl--prefixed scope classes instead of inline styles. Token colors are CSS vars (--hl-keyword, --hl-string, ...) redefined per data-theme - GitHub light/dark palettes for those two themes, Catppuccin palettes for the other three.
  • The markdown crate exposes no code-block hook, so highlight_code_blocks rewrites <pre><code class="language-*"> in the generated HTML.
  • Mermaid blocks are skipped; the client renderer reads their textContent verbatim. Unknown and no-language blocks pass through untouched.
  • Syntax set comes from two-face rather than syntect's defaults, which lack TypeScript, TOML, and Dockerfile. A small alias table covers fence labels syntect won't resolve (shell, golang, c++, yml, kt).

Cost

  • Binary: 5.1MB → 7.3MB release.
  • Startup: one-time ~200ms SyntaxSet deserialize on the first file containing a code block (56ms → 264ms to first response). Cached after that.
  • Both deps are pure Rust (regex-fancy, no oniguruma), so no C toolchain - the single-binary holds.

Tests
44 pass, clippy -D warnings clean, fmt clean. 7 new tests cover entity
decode/re-encode, alias resolution, scope classes, and the three skip cases.

Highlight fenced code blocks server-side with syntect. Class-based
output keeps a single pre-rendered copy of the HTML valid for all five
themes; token colors are CSS vars redefined per data-theme, so theme
switching stays client-side and instant.

The markdown crate exposes no hook for code block output, so blocks are
rewritten in the generated HTML. Mermaid blocks are skipped because the
client-side renderer reads their textContent verbatim.

Syntax set comes from two-face instead of syntect's defaults, which lack
TypeScript, TOML, and Dockerfile.

Costs 2.2MB of binary size and a one-time ~200ms SyntaxSet load on the
first file containing a code block.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add code syntax highlighting

1 participant