feat(tui): per-language syntax highlighting in markdown code fences

Adds a minimal hand-rolled highlighter for ts/js/jsx/tsx, py, sh/bash, go, rust,
json, yaml, sql. Recognizes whole-line comments, single/double/backtick strings,
numbers, and per-language keyword sets. Unknown langs fall through to the current
plain rendering; the existing diff-specific colorization is preserved.

Closes the §8 "Markdown syntax highlighting is missing (only diff gets colored)"
finding from the TUI v2 audit without pulling in a highlighter library.
This commit is contained in:
Brooklyn Nicholson 2026-04-18 09:48:38 -05:00
parent 5e148ca3d0
commit f8becbfbea
3 changed files with 180 additions and 0 deletions

View file

@ -1,6 +1,7 @@
import { Box, Text } from '@hermes/ink'
import { memo, type ReactNode, useMemo } from 'react'
import { highlightLine, isHighlightable } from '../lib/syntax.js'
import type { Theme } from '../theme.js'
const FENCE_RE = /^\s*(`{3,}|~{3,})(.*)$/
@ -282,11 +283,28 @@ function MdImpl({ compact, t, text }: MdProps) {
start('code')
const isDiff = lang === 'diff'
const highlighted = !isDiff && isHighlightable(lang)
nodes.push(
<Box flexDirection="column" key={key} paddingLeft={2}>
{lang && !isDiff && <Text color={t.color.dim}>{'─ ' + lang}</Text>}
{block.map((l, j) => {
if (highlighted) {
return (
<Text key={j}>
{highlightLine(l, lang, t).map(([color, text], k) =>
color ? (
<Text color={color} key={k}>
{text}
</Text>
) : (
<Text key={k}>{text}</Text>
)
)}
</Text>
)
}
const add = isDiff && l.startsWith('+')
const del = isDiff && l.startsWith('-')
const hunk = isDiff && l.startsWith('@@')