|
|
import katex from "katex"; |
|
|
|
|
|
|
|
|
|
|
|
function isValidDelim(state, pos) { |
|
|
var prevChar, |
|
|
nextChar, |
|
|
max = state.posMax, |
|
|
can_open = true, |
|
|
can_close = true; |
|
|
|
|
|
prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1; |
|
|
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1; |
|
|
|
|
|
|
|
|
if (state.src[pos] === "$") { |
|
|
if ( |
|
|
prevChar === 0x20 || |
|
|
prevChar === 0x09 || |
|
|
(nextChar >= 0x30 && nextChar <= 0x39) |
|
|
) { |
|
|
can_close = false; |
|
|
} |
|
|
if (nextChar === 0x20 || nextChar === 0x09 ) { |
|
|
can_open = false; |
|
|
} |
|
|
} |
|
|
|
|
|
return { |
|
|
can_open: can_open, |
|
|
can_close: can_close, |
|
|
}; |
|
|
} |
|
|
|
|
|
function math_inline(state, silent) { |
|
|
var start, match, token, res, pos, esc_count; |
|
|
|
|
|
|
|
|
if ( |
|
|
state.src[state.pos] !== "$" && |
|
|
(state.src[state.pos] !== "\\" || state.src[state.pos + 1] !== "(") |
|
|
) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
if (state.src[state.pos] === "\\" && state.src[state.pos + 1] === "(") { |
|
|
start = state.pos + 2; |
|
|
match = start; |
|
|
while ((match = state.src.indexOf("\\)", match)) !== -1) { |
|
|
pos = match - 1; |
|
|
while (state.src[pos] === "\\") { |
|
|
pos -= 1; |
|
|
} |
|
|
if ((match - pos) % 2 == 1) { |
|
|
break; |
|
|
} |
|
|
match += 1; |
|
|
} |
|
|
|
|
|
if (match === -1) { |
|
|
if (!silent) { |
|
|
state.pending += "\\("; |
|
|
} |
|
|
state.pos = start; |
|
|
return true; |
|
|
} |
|
|
|
|
|
if (!silent) { |
|
|
token = state.push("math_inline", "math", 0); |
|
|
token.markup = "\\("; |
|
|
token.content = state.src.slice(start, match); |
|
|
} |
|
|
|
|
|
state.pos = match + 2; |
|
|
return true; |
|
|
} |
|
|
|
|
|
res = isValidDelim(state, state.pos); |
|
|
if (!res.can_open) { |
|
|
if (!silent) { |
|
|
state.pending += "$"; |
|
|
} |
|
|
state.pos += 1; |
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
start = state.pos + 1; |
|
|
match = start; |
|
|
while ((match = state.src.indexOf("$", match)) !== -1) { |
|
|
|
|
|
|
|
|
pos = match - 1; |
|
|
while (state.src[pos] === "\\") { |
|
|
pos -= 1; |
|
|
} |
|
|
|
|
|
|
|
|
if ((match - pos) % 2 == 1) { |
|
|
break; |
|
|
} |
|
|
match += 1; |
|
|
} |
|
|
|
|
|
|
|
|
if (match === -1) { |
|
|
if (!silent) { |
|
|
state.pending += "$"; |
|
|
} |
|
|
state.pos = start; |
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
if (match - start === 0) { |
|
|
if (!silent) { |
|
|
state.pending += "$$"; |
|
|
} |
|
|
state.pos = start + 1; |
|
|
return true; |
|
|
} |
|
|
|
|
|
|
|
|
res = isValidDelim(state, match); |
|
|
if (!res.can_close) { |
|
|
if (!silent) { |
|
|
state.pending += "$"; |
|
|
} |
|
|
state.pos = start; |
|
|
return true; |
|
|
} |
|
|
|
|
|
if (!silent) { |
|
|
token = state.push("math_inline", "math", 0); |
|
|
token.markup = "$"; |
|
|
token.content = state.src.slice(start, match); |
|
|
} |
|
|
|
|
|
state.pos = match + 1; |
|
|
return true; |
|
|
} |
|
|
|
|
|
function math_block(state, start, end, silent) { |
|
|
var firstLine, |
|
|
lastLine, |
|
|
next, |
|
|
lastPos, |
|
|
found = false, |
|
|
token, |
|
|
pos = state.bMarks[start] + state.tShift[start], |
|
|
max = state.eMarks[start]; |
|
|
|
|
|
|
|
|
if (pos + 1 > max) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
let openDelim = state.src.slice(pos, pos + 2); |
|
|
let isDoubleDollar = openDelim === "$$"; |
|
|
let isLatexBracket = openDelim === "\\["; |
|
|
|
|
|
if (!isDoubleDollar && !isLatexBracket) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
let delimiter, posAdjust; |
|
|
if (isDoubleDollar) { |
|
|
delimiter = "$$"; |
|
|
posAdjust = 2; |
|
|
} else if (isLatexBracket) { |
|
|
delimiter = "\\]"; |
|
|
posAdjust = 2; |
|
|
} |
|
|
|
|
|
pos += posAdjust; |
|
|
firstLine = state.src.slice(pos, max); |
|
|
|
|
|
if (silent) { |
|
|
return true; |
|
|
} |
|
|
if (firstLine.trim().slice(-delimiter.length) === delimiter) { |
|
|
|
|
|
firstLine = firstLine.trim().slice(0, -delimiter.length); |
|
|
found = true; |
|
|
} |
|
|
|
|
|
for (next = start; !found; ) { |
|
|
next++; |
|
|
|
|
|
if (next >= end) { |
|
|
break; |
|
|
} |
|
|
|
|
|
pos = state.bMarks[next] + state.tShift[next]; |
|
|
max = state.eMarks[next]; |
|
|
|
|
|
if (pos < max && state.tShift[next] < state.blkIndent) { |
|
|
|
|
|
break; |
|
|
} |
|
|
|
|
|
if ( |
|
|
state.src.slice(pos, max).trim().slice(-delimiter.length) === delimiter |
|
|
) { |
|
|
lastPos = state.src.slice(0, max).lastIndexOf(delimiter); |
|
|
lastLine = state.src.slice(pos, lastPos); |
|
|
found = true; |
|
|
} |
|
|
} |
|
|
|
|
|
state.line = next + 1; |
|
|
|
|
|
token = state.push("math_block", "math", 0); |
|
|
token.block = true; |
|
|
token.content = |
|
|
(firstLine && firstLine.trim() ? firstLine + "\n" : "") + |
|
|
state.getLines(start + 1, next, state.tShift[start], true) + |
|
|
(lastLine && lastLine.trim() ? lastLine : ""); |
|
|
token.map = [start, state.line]; |
|
|
token.markup = delimiter; |
|
|
return true; |
|
|
} |
|
|
|
|
|
export default function math_plugin(md, options) { |
|
|
|
|
|
options = options || {}; |
|
|
|
|
|
var katexInline = function (latex) { |
|
|
options.displayMode = false; |
|
|
try { |
|
|
latex = latex |
|
|
.replace(/^\[(.*)\]$/, "$1") |
|
|
.replace(/^\\\((.*)\\\)$/, "$1") |
|
|
.replace(/^\\\[(.*)\\\]$/, "$1"); |
|
|
return katex.renderToString(latex, options); |
|
|
} catch (error) { |
|
|
if (options.throwOnError) { |
|
|
console.log(error); |
|
|
} |
|
|
return latex; |
|
|
} |
|
|
}; |
|
|
|
|
|
var inlineRenderer = function (tokens, idx) { |
|
|
return katexInline(tokens[idx].content); |
|
|
}; |
|
|
|
|
|
var katexBlock = function (latex) { |
|
|
options.displayMode = true; |
|
|
try { |
|
|
|
|
|
latex = latex.replace(/^\[(.*)\]$/, "$1").replace(/^\\\[(.*)\\\]$/, "$1"); |
|
|
return "<p>" + katex.renderToString(latex, options) + "</p>"; |
|
|
} catch (error) { |
|
|
if (options.throwOnError) { |
|
|
console.log(error); |
|
|
} |
|
|
return latex; |
|
|
} |
|
|
}; |
|
|
|
|
|
var blockRenderer = function (tokens, idx) { |
|
|
return katexBlock(tokens[idx].content) + "\n"; |
|
|
}; |
|
|
|
|
|
md.inline.ruler.after("escape", "math_inline", math_inline); |
|
|
md.block.ruler.after("blockquote", "math_block", math_block, { |
|
|
alt: ["paragraph", "reference", "blockquote", "list"], |
|
|
}); |
|
|
md.renderer.rules.math_inline = inlineRenderer; |
|
|
md.renderer.rules.math_block = blockRenderer; |
|
|
} |
|
|
|