Commit d75a3637 authored by nick zheng's avatar nick zheng

chore: markdown渲染支持katex格式

parent 818694c5
......@@ -2,13 +2,13 @@
import { computed, ref, watchEffect } from 'vue'
import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight'
import markedKatex, { MarkedKatexOptions } from 'marked-katex-extension'
import 'katex/dist/katex.min.css'
import { throttle } from 'lodash-es'
import DOMPurify from 'dompurify'
import hljs from 'highlight.js'
import 'highlight.js/styles/panda-syntax-light.css'
import 'github-markdown-css'
import markedKatex, { MarkedKatexOptions } from './plugins/katex'
interface Props {
rawTextContent: string
......
/**
* @file katex.ts
* @description markdown渲染插件,用于解析渲染katex数学公式, 依赖katex库, 请确保已经引入katex库
* @description 该插件支持公式行内公式$...$、\(...\)和块内公式$$...$$、\[...\]两种形式
*/
import katex, { KatexOptions } from 'katex'
import { MarkedExtension, TokenizerAndRendererExtension, Tokens } from 'marked'
export interface MarkedKatexOptions extends KatexOptions {
nonStandard?: boolean
}
const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\\$]))\1(?=[\s?!\\.,:?!。,:]|$)/
const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\\$]))\1/
const blockRule = /^(?:(\${2})\n([\s\S]+?)\n\1|\\\[([\s\S]+?)\\\](?:\n|$))/
export default function (options: MarkedKatexOptions = {}): MarkedExtension {
return {
extensions: [
inlineKatex(options, createRenderer(options, false)),
blockKatex(options, createRenderer(options, true)),
],
}
}
function createRenderer(options: MarkedKatexOptions, newlineAfter: boolean) {
return (token: Tokens.Generic) => {
return katex.renderToString(token.text, { ...options, displayMode: token.displayMode }) + (newlineAfter ? '\n' : '')
}
}
function inlineKatex(
options: MarkedKatexOptions,
renderer: (token: Tokens.Generic) => string,
): TokenizerAndRendererExtension {
const nonStandard = options && options.nonStandard
const ruleReg = nonStandard ? inlineRuleNonStandard : inlineRule
return {
name: 'inlineKatex',
level: 'inline',
start(src: string) {
let index
let indexSrc = src
while (indexSrc) {
index = indexSrc.search(/(?:\\\(|\$)/)
if (index === -1) {
return
}
const char = indexSrc[index]
const possibleKatex = indexSrc.substring(index)
const isParen = char === '\\' && indexSrc[index + 1] === '('
const isDollar = char === '$'
const f = nonStandard ? true : index === 0 || indexSrc.charAt(index - 1).match(/\s/)
if (f) {
if (isDollar && possibleKatex.match(ruleReg)) {
return index
} else if (isParen && possibleKatex.match(/^\\\(((?:\\[^]|[^\\\n)])*?)\\\)/)) {
return index
}
}
indexSrc = indexSrc.substring(index + (isParen ? 2 : 1))
}
},
tokenizer(src: string) {
const dollarMatch = src.match(ruleReg)
if (dollarMatch) {
return {
type: 'inlineKatex',
raw: dollarMatch[0],
text: dollarMatch[2].trim(),
displayMode: dollarMatch[1].length === 2,
}
}
// 匹配\(...\)包裹的内容
const parenMatch = src.match(/^\\\(((?:\\[^]|[^\\\n)])*?)\\\)/)
if (parenMatch) {
return {
type: 'inlineKatex',
raw: parenMatch[0],
text: parenMatch[1].trim(),
displayMode: false,
}
}
},
renderer,
}
}
function blockKatex(
_options: KatexOptions,
renderer: (token: Tokens.Generic) => string,
): TokenizerAndRendererExtension {
return {
name: 'blockKatex',
level: 'block',
tokenizer(src: string) {
const match = src.match(blockRule)
if (match) {
// 处理 $$...$$
if (match[1]) {
return {
type: 'blockKatex',
raw: match[0],
text: match[2].trim(),
displayMode: true,
}
} else {
// 处理 \[...\]
return {
type: 'blockKatex',
raw: match[0],
text: match[3].trim(),
displayMode: true,
}
}
}
return undefined
},
renderer,
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment