56 lines
1.6 KiB
TypeScript
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">​</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</>
|
|
)
|
|
}
|