@@ -11,34 +11,37 @@ import abbr from 'markdown-it-abbr';
1111import deflist from 'markdown-it-deflist' ;
1212import linkAttributes from 'markdown-it-link-attributes' ;
1313import taskLists from 'markdown-it-task-lists' ;
14- import katex from 'katex' ;
14+ import markdownItKatex from 'markdown-it- katex' ;
1515import 'katex/dist/katex.min.css' ;
16+ import mermaid from 'mermaid' ;
1617
18+ // 初始化 mermaid
19+ // if (typeof window !== 'undefined') {
20+ // mermaid.initialize({
21+ // startOnLoad: true,
22+ // theme: 'default',
23+ // securityLevel: 'loose'
24+ // });
25+ // }
1726
18- // 自定义数学公式渲染
19- // @ts -ignore
20- const renderMath = ( md ) => {
21- const defaultRender = md . renderer . rules . text ;
22- md . renderer . rules . text = ( tokens : {
23- [ x : string ] : any ;
24- } , idx : string | number , options : any , env : any , self : any ) => {
25- const token = tokens [ idx ] ;
26- const match = token . content . match ( / ( \$ \$ ? ) ( [ \s \S ] * ?) \1/ g) ;
27- if ( match ) {
28- match . forEach ( ( m : string ) => {
29- const isBlock = m . startsWith ( '$$' ) ;
30- const tex = m . slice ( 2 , - 2 ) ;
31- try {
32- const html = katex . renderToString ( tex , { displayMode : isBlock } ) ;
33- token . content = token . content . replace ( m , html ) ;
34- } catch ( e : any ) {
35- token . content = token . content . replace ( m , `<span class="error">Error rendering math: ${ e . message } </span>` ) ;
36- }
37- } ) ;
38- }
39- return defaultRender ( tokens , idx , options , env , self ) ;
40- } ;
41- } ;
27+ function preprocessLatex ( text : string ) : string {
28+ // 1. 先将 ```latex 代码块的内容提取出来(保留原始内容)
29+ text = text . replace ( / ` ` ` l a t e x \s * ( [ \s \S ] * ?) ` ` ` / g, ( _match , content ) => {
30+ return '\n' + content . trim ( ) + '\n' ;
31+ } ) ;
32+
33+ // 2. 统一将 \[ ... \] 转换为 $$...$$(LaTeX 块级公式)
34+ text = text . replace ( / \\ \[ ( [ \s \S ] * ?) \\ \] / g, ( _match , formula ) => {
35+ return '$$' + formula . trim ( ) + '$$' ;
36+ } ) ;
37+
38+ // 3. 将 \( ... \) 转换为 $...$(LaTeX 行内公式)
39+ text = text . replace ( / \\ \( ( [ \s \S ] * ?) \\ \) / g, ( _match , formula ) => {
40+ return '$' + formula . trim ( ) + '$' ;
41+ } ) ;
42+
43+ return text ;
44+ }
4245
4346// 创建 markdown-it 实例并加载插件
4447const md = new MarkdownIt ( {
@@ -47,6 +50,12 @@ const md = new MarkdownIt({
4750 linkify : true ,
4851 typographer : true ,
4952 highlight : ( str : string , lang : string ) => {
53+ // 处理 mermaid 图表
54+ if ( lang === 'mermaid' ) {
55+ return `<div class="mermaid">${ str } </div>` ;
56+ }
57+
58+ // 处理代码高亮
5059 if ( lang && hljs . getLanguage ( lang ) ) {
5160 return `<pre class="hljs"><code>${ hljs . highlight ( str , { language : lang } ) . value } </code></pre>` ;
5261 }
@@ -63,6 +72,26 @@ const md = new MarkdownIt({
6372 . use ( deflist )
6473 . use ( linkAttributes , { attrs : { target : '_blank' , rel : 'noopener' } } )
6574 . use ( taskLists )
66- . use ( renderMath ) ;
75+ . use ( markdownItKatex , {
76+ throwOnError : false ,
77+ errorColor : '#cc0000'
78+ } ) ;
79+
80+ // 重写 render 方法,添加预处理
81+ const originalRender = md . render . bind ( md ) ;
82+ md . render = function ( text : string , env ?: any ) : string {
83+ const preprocessedText = preprocessLatex ( text ) ;
84+ const html = originalRender ( preprocessedText , env ) ;
85+
86+ if ( html . indexOf ( '<div class="mermaid">' ) !== - 1 ) {
87+ setTimeout ( ( ) => {
88+ mermaid . run ( {
89+ querySelector : '.mermaid'
90+ } ) ;
91+ } , 0 ) ;
92+ }
93+
94+ return html ;
95+ } ;
6796
6897export default md ;
0 commit comments