import katex from 'katex'; import extensionSvc from '../services/extensionSvc'; function texMath(state, silent) { let startMathPos = state.pos; if (state.src.charCodeAt(startMathPos) !== 0x24 /* $ */) { return false; } // Parse tex math according to http://pandoc.org/README.html#math let endMarker = '$'; startMathPos += 1; const afterStartMarker = state.src.charCodeAt(startMathPos); if (afterStartMarker === 0x24 /* $ */) { endMarker = '$$'; startMathPos += 1; if (state.src.charCodeAt(startMathPos) === 0x24 /* $ */) { // 3 markers are too much return false; } } else if ( // Skip if opening $ is succeeded by a space character afterStartMarker === 0x20 /* space */ || afterStartMarker === 0x09 /* \t */ || afterStartMarker === 0x0a /* \n */ ) { return false; } const endMarkerPos = state.src.indexOf(endMarker, startMathPos); if (endMarkerPos === -1) { return false; } if (state.src.charCodeAt(endMarkerPos - 1) === 0x5C /* \ */) { return false; } const nextPos = endMarkerPos + endMarker.length; if (endMarker.length === 1) { // Skip if $ is preceded by a space character const beforeEndMarker = state.src.charCodeAt(endMarkerPos - 1); if (beforeEndMarker === 0x20 /* space */ || beforeEndMarker === 0x09 /* \t */ || beforeEndMarker === 0x0a /* \n */) { return false; } // Skip if closing $ is succeeded by a digit (eg $5 $10 ...) const suffix = state.src.charCodeAt(nextPos); if (suffix >= 0x30 && suffix < 0x3A) { return false; } } if (!silent) { const token = state.push(endMarker.length === 1 ? 'inline_math' : 'display_math', '', 0); token.content = state.src.slice(startMathPos, endMarkerPos); } state.pos = nextPos; return true; } extensionSvc.onGetOptions((options, properties) => { options.math = properties.extensions.katex.enabled; }); extensionSvc.onInitConverter(2, (markdown, options) => { if (options.math) { markdown.use((md) => { md.inline.ruler.push('texMath', texMath); }); markdown.renderer.rules.inline_math = (tokens, idx) => `${markdown.utils.escapeHtml(tokens[idx].content)}`; markdown.renderer.rules.display_math = (tokens, idx) => `${markdown.utils.escapeHtml(tokens[idx].content)}`; } }); extensionSvc.onSectionPreview((elt) => { const highlighter = displayMode => (katexElt) => { if (!katexElt.highlighted) { try { katex.render(katexElt.textContent, katexElt, { displayMode }); } catch (e) { katexElt.textContent = `${e.message}`; } } katexElt.highlighted = true; }; elt.querySelectorAll('.katex--inline').cl_each(highlighter(false)); elt.querySelectorAll('.katex--display').cl_each(highlighter(true)); });