| import katex from 'katex'; |
|
|
| const DELIMITER_LIST = [ |
| { left: '$$', right: '$$', display: false }, |
| { left: '$', right: '$', display: false }, |
| { left: '\\pu{', right: '}', display: false }, |
| { left: '\\ce{', right: '}', display: false }, |
| { left: '\\(', right: '\\)', display: false }, |
| { left: '( ', right: ' )', display: false }, |
| { left: '\\[', right: '\\]', display: true }, |
| { left: '[ ', right: ' ]', display: true } |
| ]; |
|
|
| |
| |
| |
| |
|
|
| |
| |
|
|
| let inlinePatterns = []; |
| let blockPatterns = []; |
|
|
| function escapeRegex(string) { |
| return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); |
| } |
|
|
| function generateRegexRules(delimiters) { |
| delimiters.forEach((delimiter) => { |
| const { left, right } = delimiter; |
| |
| const escapedLeft = escapeRegex(left); |
| const escapedRight = escapeRegex(right); |
|
|
| |
| |
| inlinePatterns.push( |
| `${escapedLeft}((?:\\\\.|[^\\\\\\n])*?(?:\\\\.|[^\\\\\\n${escapedRight}]))${escapedRight}` |
| ); |
|
|
| |
| |
| blockPatterns.push(`${escapedLeft}\n((?:\\\\[^]|[^\\\\])+?)\n${escapedRight}`); |
| }); |
|
|
| const inlineRule = new RegExp(`^(${inlinePatterns.join('|')})(?=[\\s?!.,:?!。,:]|$)`, 'u'); |
| const blockRule = new RegExp(`^(${blockPatterns.join('|')})(?:\n|$)`, 'u'); |
|
|
| return { inlineRule, blockRule }; |
| } |
|
|
| const { inlineRule, blockRule } = generateRegexRules(DELIMITER_LIST); |
|
|
| export default function (options = {}) { |
| return { |
| extensions: [ |
| inlineKatex(options, createRenderer(options, false)), |
| blockKatex(options, createRenderer(options, true)) |
| ] |
| }; |
| } |
|
|
| function createRenderer(options, newlineAfter) { |
| return (token) => |
| katex.renderToString(token.text, { ...options, displayMode: token.displayMode }) + |
| (newlineAfter ? '\n' : ''); |
| } |
|
|
| function inlineKatex(options, renderer) { |
| const ruleReg = inlineRule; |
| return { |
| name: 'inlineKatex', |
| level: 'inline', |
| start(src) { |
| let index; |
| let indexSrc = src; |
|
|
| while (indexSrc) { |
| index = indexSrc.indexOf('$'); |
| if (index === -1) { |
| return; |
| } |
| const f = index === 0 || indexSrc.charAt(index - 1) === ' '; |
| if (f) { |
| const possibleKatex = indexSrc.substring(index); |
|
|
| if (possibleKatex.match(ruleReg)) { |
| return index; |
| } |
| } |
|
|
| indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, ''); |
| } |
| }, |
| tokenizer(src, tokens) { |
| const match = src.match(ruleReg); |
|
|
| if (match) { |
| const text = match |
| .slice(2) |
| .filter((item) => item) |
| .find((item) => item.trim()); |
|
|
| return { |
| type: 'inlineKatex', |
| raw: match[0], |
| text: text |
| }; |
| } |
| }, |
| renderer |
| }; |
| } |
|
|
| function blockKatex(options, renderer) { |
| return { |
| name: 'blockKatex', |
| level: 'block', |
| tokenizer(src, tokens) { |
| const match = src.match(blockRule); |
|
|
| if (match) { |
| const text = match |
| .slice(2) |
| .filter((item) => item) |
| .find((item) => item.trim()); |
|
|
| return { |
| type: 'blockKatex', |
| raw: match[0], |
| text: text |
| }; |
| } |
| }, |
| renderer |
| }; |
| } |
|
|