score
This commit is contained in:
@@ -353,37 +353,93 @@ marked.use({
|
||||
renderer,
|
||||
})
|
||||
|
||||
function decodeHTMLEntities(text: string): string {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
}
|
||||
|
||||
function renderMarkdown(text: string): string {
|
||||
if (!text) return ''
|
||||
|
||||
// 0. Extract and protect Mermaid blocks
|
||||
const mermaidBlocks: string[] = []
|
||||
let processed = text.replace(/```mermaid\r?\\n([\s\S]*?)\r?\\n```/g, (match, code) => {
|
||||
let workingText = text
|
||||
workingText = workingText.replace(/```mermaid\r?\\n([\s\S]*?)\r?\\n```/g, (match, code) => {
|
||||
const placeholder = `MERMAIDBLOCKPLACEHOLDER${mermaidBlocks.length}`
|
||||
mermaidBlocks.push(code.trim())
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// 1. Render display math $$...$$
|
||||
processed = processed.replace(/\$\$([\s\S]+?)\$\$/g, (match, math) => {
|
||||
try {
|
||||
return `<div class="math-display">${katex.renderToString(math.trim(), { displayMode: true, throwOnError: false })}</div>`
|
||||
} catch (e) {
|
||||
return match
|
||||
}
|
||||
const mathBlocks: { placeholder: string; isBlock: boolean; rawExpr: string; renderedHtml: string }[] = []
|
||||
let placeholderCount = 0
|
||||
|
||||
// Normalize slash/backslash ctdot representations to standard cdots
|
||||
workingText = workingText
|
||||
.replace(/\\ctdot/g, '\\cdots')
|
||||
.replace(/\/ctdot/g, '\\cdots')
|
||||
|
||||
// 1. Extract block math: $$...$$ and \[...\]
|
||||
workingText = workingText.replace(/\$\$(.*?)\$\$/gs, (match, expr) => {
|
||||
const placeholder = `MATHBLOCKPLACEHOLDER${placeholderCount++}`
|
||||
mathBlocks.push({ placeholder, isBlock: true, rawExpr: expr, renderedHtml: '' })
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// 2. Render inline math $...$
|
||||
processed = processed.replace(/\$([^\n]+?)\$/g, (match, math) => {
|
||||
try {
|
||||
return `<span class="math-inline">${katex.renderToString(math.trim(), { displayMode: false, throwOnError: false })}</span>`
|
||||
} catch (e) {
|
||||
return match
|
||||
}
|
||||
workingText = workingText.replace(/\\\[(.*?)\\\]/gs, (match, expr) => {
|
||||
const placeholder = `MATHBLOCKPLACEHOLDER${placeholderCount++}`
|
||||
mathBlocks.push({ placeholder, isBlock: true, rawExpr: expr, renderedHtml: '' })
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// 3. Render markdown
|
||||
let html = marked.parse(processed) as string
|
||||
// 2. Extract inline math: $...$ and \(...\)
|
||||
workingText = workingText.replace(/(?<!\$)\$([^\$]+)\$(?!\$)/g, (match, expr) => {
|
||||
const placeholder = `INLINEMATHPLACEHOLDER${placeholderCount++}`
|
||||
mathBlocks.push({ placeholder, isBlock: false, rawExpr: expr, renderedHtml: '' })
|
||||
return placeholder
|
||||
})
|
||||
|
||||
workingText = workingText.replace(/\\\(.*?\\\)/g, (match) => {
|
||||
const expr = match.slice(2, -2)
|
||||
const placeholder = `INLINEMATHPLACEHOLDER${placeholderCount++}`
|
||||
mathBlocks.push({ placeholder, isBlock: false, rawExpr: expr, renderedHtml: '' })
|
||||
return placeholder
|
||||
})
|
||||
|
||||
// 3. Render Markdown with marked.parse
|
||||
let html = ''
|
||||
try {
|
||||
html = marked.parse(workingText) as string
|
||||
} catch (e) {
|
||||
console.error("Markdown parsing failed:", e)
|
||||
html = workingText
|
||||
}
|
||||
|
||||
// 4. Render KaTeX and swap placeholders
|
||||
for (const block of mathBlocks) {
|
||||
try {
|
||||
let cleanExpr = decodeHTMLEntities(block.rawExpr.trim())
|
||||
cleanExpr = cleanExpr.replace(/\\ctdot/g, '\\cdots').replace(/\/ctdot/g, '\\cdots')
|
||||
const rendered = katex.renderToString(cleanExpr, {
|
||||
displayMode: block.isBlock,
|
||||
throwOnError: false
|
||||
})
|
||||
block.renderedHtml = block.isBlock
|
||||
? `<div class="math-display">${rendered}</div>`
|
||||
: `<span class="math-inline">${rendered}</span>`
|
||||
} catch (err) {
|
||||
console.error("KaTeX parse error for expr:", block.rawExpr, err)
|
||||
const delim = block.isBlock ? '$$' : '$'
|
||||
block.renderedHtml = block.isBlock
|
||||
? `<div class="math-display">${delim}${block.rawExpr}${delim}</div>`
|
||||
: `<span class="math-inline">${delim}${block.rawExpr}${delim}</span>`
|
||||
}
|
||||
|
||||
html = html.replace(block.placeholder, block.renderedHtml)
|
||||
}
|
||||
|
||||
// 5. Restore protected Mermaid blocks
|
||||
mermaidBlocks.forEach((code, idx) => {
|
||||
|
||||
Reference in New Issue
Block a user