123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import katex from 'katex';
- const DELIMITER_LIST = [
- { left: '$$', right: '$$', display: true },
- { left: '$', right: '$', display: false },
- { left: '\\pu{', right: '}', display: false },
- { left: '\\ce{', right: '}', display: false },
- { left: '\\(', right: '\\)', display: false },
- { left: '\\[', right: '\\]', display: true },
- { left: '\\begin{equation}', right: '\\end{equation}', display: true }
- ];
- // const DELIMITER_LIST = [
- // { left: '$$', right: '$$', display: false },
- // { left: '$', right: '$', display: false },
- // ];
- // const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
- // const blockRule = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;
- let inlinePatterns = [];
- let blockPatterns = [];
- function escapeRegex(string) {
- return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
- }
- function generateRegexRules(delimiters) {
- delimiters.forEach((delimiter) => {
- const { left, right, display } = delimiter;
- // Ensure regex-safe delimiters
- const escapedLeft = escapeRegex(left);
- const escapedRight = escapeRegex(right);
- if (!display) {
- // For inline delimiters, we match everything
- inlinePatterns.push(`${escapedLeft}((?:\\\\[^]|[^\\\\])+?)${escapedRight}`);
- } else {
- // Block delimiters doubles as inline delimiters when not followed by a newline
- inlinePatterns.push(`${escapedLeft}(?!\\n)((?:\\\\[^]|[^\\\\])+?)(?!\\n)${escapedRight}`);
- blockPatterns.push(`${escapedLeft}\\n((?:\\\\[^]|[^\\\\])+?)\\n${escapedRight}`);
- }
- });
- // Math formulas can end in special characters
- const inlineRule = new RegExp(
- `^(${inlinePatterns.join('|')})(?=[\\s?。,!-\/:-@[-\`{-~]|$)`,
- 'u'
- );
- const blockRule = new RegExp(`^(${blockPatterns.join('|')})(?=[\\s?。,!-\/:-@[-\`{-~]|$)`, 'u');
- return { inlineRule, blockRule };
- }
- const { inlineRule, blockRule } = generateRegexRules(DELIMITER_LIST);
- export default function (options = {}) {
- return {
- extensions: [inlineKatex(options), blockKatex(options)]
- };
- }
- function katexStart(src, displayMode: boolean) {
- let ruleReg = displayMode ? blockRule : inlineRule;
- let indexSrc = src;
- while (indexSrc) {
- let index = -1;
- let startIndex = -1;
- let startDelimiter = '';
- let endDelimiter = '';
- for (let delimiter of DELIMITER_LIST) {
- if (delimiter.display !== displayMode) {
- continue;
- }
- startIndex = indexSrc.indexOf(delimiter.left);
- if (startIndex === -1) {
- continue;
- }
- index = startIndex;
- startDelimiter = delimiter.left;
- endDelimiter = delimiter.right;
- }
- if (index === -1) {
- return;
- }
- // Check if the delimiter is preceded by a special character.
- // If it does, then it's potentially a math formula.
- const f = index === 0 || indexSrc.charAt(index - 1).match(/[\s?。,!-\/:-@[-`{-~]/);
- if (f) {
- const possibleKatex = indexSrc.substring(index);
- if (possibleKatex.match(ruleReg)) {
- return index;
- }
- }
- indexSrc = indexSrc.substring(index + startDelimiter.length).replace(endDelimiter, '');
- }
- }
- function katexTokenizer(src, tokens, displayMode: boolean) {
- let ruleReg = displayMode ? blockRule : inlineRule;
- let type = displayMode ? 'blockKatex' : 'inlineKatex';
- const match = src.match(ruleReg);
- if (match) {
- const text = match
- .slice(2)
- .filter((item) => item)
- .find((item) => item.trim());
- return {
- type,
- raw: match[0],
- text: text,
- displayMode
- };
- }
- }
- function inlineKatex(options) {
- return {
- name: 'inlineKatex',
- level: 'inline',
- start(src) {
- return katexStart(src, false);
- },
- tokenizer(src, tokens) {
- return katexTokenizer(src, tokens, false);
- }
- };
- }
- function blockKatex(options) {
- return {
- name: 'blockKatex',
- level: 'block',
- start(src) {
- return katexStart(src, true);
- },
- tokenizer(src, tokens) {
- return katexTokenizer(src, tokens, true);
- }
- };
- }
|