Files
zui/frontend/src/lib/syntaxHighlight.tsx

56 lines
1.6 KiB
TypeScript

/**
* Syntax highlighting for the code editor: Prism + prism-react-renderer + Nunjucks.
* Nunjucks ({{ }}, {% %}, {# #}) is always applied so the editor supports templating everywhere.
* Ensure prismSetup.ts is imported once in main.tsx, and prism theme: import 'prismjs/themes/prism.css'
*/
import React from 'react'
import Prism from 'prismjs'
import type { Grammar } from 'prismjs'
import { tokenizeWithNunjucks } from '@/lib/nunjucksTokenizer'
export type HighlightLanguage = 'javascript' | 'markdown' | 'plantuml'
const prismLang: Record<HighlightLanguage, string> = {
javascript: 'javascript',
markdown: 'markdown',
plantuml: 'plantuml',
}
function getGrammar(language: HighlightLanguage): Grammar {
const lang = prismLang[language]
const g = (Prism.languages as Record<string, Grammar>)[lang]
return g ?? {}
}
/**
* Returns highlighted code as React nodes with Nunjucks support.
* Used by the shared CodeEditor so all usages get the same features (base language + Nunjucks).
*/
export function highlight(
code: string,
language: HighlightLanguage
): React.ReactNode {
const grammar = getGrammar(language)
const lines = tokenizeWithNunjucks(code, grammar)
return (
<>
{lines.map((lineTokens, i) => (
<div key={i} className="token-line">
{lineTokens.length > 0 ? (
lineTokens.map((token, j) => (
<span
key={j}
className={`token ${token.types.join(' ')}`}
>
{token.content}
</span>
))
) : (
<span className="token">&#8203;</span>
)}
</div>
))}
</>
)
}