Commit f80cf91d authored by nick zheng's avatar nick zheng

Merge branch 'beta' into 'master'

Beta

See merge request !200
parents c76b82ab 66de222c
......@@ -36,6 +36,7 @@
"lodash-es": "^4.17.21",
"marked": "^15.0.0",
"marked-highlight": "^2.2.1",
"marked-katex-extension": "^5.1.4",
"mitt": "^3.0.1",
"nanoid": "^5.0.7",
"pinia": "^2.2.2",
......
This diff is collapsed.
......@@ -8,7 +8,7 @@ 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'
import markedKatex, { MarkedKatexOptions } from 'marked-katex-extension'
interface Props {
rawTextContent: string
......@@ -52,6 +52,15 @@ const articleContainerStyle = computed(() => {
}
})
const katexDelimiters = (text: string) => {
/**
* 1. 将 \(...\) 和 \\(...\\) 转为 $...$ 以支持行内公式
* 2. 将 \[...\] 和 \\[...\\] 转为 $$...$$ 以支持块级公式
*/
const replaceKatexText = text.replace(/\\\\\(|\\\\\)|\\\(|\\\)/g, '$').replace(/\\\\\[|\\\\\]|\\\[|\\\]/g, '$$$$')
return replaceKatexText
}
const textContentParser = throttle(
(text: string) => {
;(marked.parse(text) as Promise<string>).then((res) => {
......@@ -63,7 +72,8 @@ const textContentParser = throttle(
)
watchEffect(() => {
textContentParser(props.rawTextContent)
const text = katexDelimiters(props.rawTextContent)
textContentParser(text)
})
function getRenderTextContent() {
......
/**
* @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