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