{
+ const codeBlockRegex = /([\s\S]*?)<\/code><\/pre>/g
+ const matches = [...html.matchAll(codeBlockRegex)]
+ if (matches.length === 0) return html
+
+ const highlighter = await getSharedHighlighter({ themes: ["OpenCode"], langs: [] })
+
+ let result = html
+ for (const match of matches) {
+ const [fullMatch, lang, escapedCode] = match
+ const code = escapedCode
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/&/g, "&")
+ .replace(/"/g, '"')
+ .replace(/'/g, "'")
+
+ let language = lang || "text"
+ if (!(language in bundledLanguages)) {
+ language = "text"
+ }
+ if (!highlighter.getLoadedLanguages().includes(language)) {
+ await highlighter.loadLanguage(language as BundledLanguage)
+ }
+
+ const highlighted = highlighter.codeToHtml(code, {
+ lang: language,
+ theme: "OpenCode",
+ tabindex: false,
+ })
+ result = result.replace(fullMatch, () => highlighted)
+ }
+
+ return result
+}
+
+export type NativeMarkdownParser = (markdown: string) => Promise
+
export const { use: useMarked, provider: MarkedProvider } = createSimpleContext({
name: "Marked",
- init: () => {
- return marked.use(
+ init: (props: { nativeParser?: NativeMarkdownParser }) => {
+ const jsParser = marked.use(
{
renderer: {
link({ href, title, text }) {
@@ -407,5 +493,18 @@ export const { use: useMarked, provider: MarkedProvider } = createSimpleContext(
},
}),
)
+
+ if (props.nativeParser) {
+ const nativeParser = props.nativeParser
+ return {
+ async parse(markdown: string): Promise {
+ const html = await nativeParser(markdown)
+ const withMath = renderMathExpressions(html)
+ return highlightCodeBlocks(withMath)
+ },
+ }
+ }
+
+ return jsParser
},
})