Explorar o código

fix(app): only allow \(...\) syntax for inline latex (#34850)

Brendan Allan hai 2 meses
pai
achega
5fecf7ae9e
Modificáronse 1 ficheiros con 55 adicións e 9 borrados
  1. 55 9
      packages/ui/src/context/marked.tsx

+ 55 - 9
packages/ui/src/context/marked.tsx

@@ -1,5 +1,4 @@
-import { marked } from "marked"
-import markedKatex from "marked-katex-extension"
+import { marked, type MarkedExtension, type Tokens } from "marked"
 import markedShiki from "marked-shiki"
 import markedShiki from "marked-shiki"
 import katex from "katex"
 import katex from "katex"
 import { bundledLanguages, type BundledLanguage } from "shiki"
 import { bundledLanguages, type BundledLanguage } from "shiki"
@@ -395,8 +394,8 @@ function renderMathInText(text: string): string {
     }
     }
   })
   })
 
 
-  // Inline math: $...$
-  const inlineMathRegex = /(?<!\$)\$(?!\$)((?:[^$\\]|\\.)+?)\$(?!\$)/g
+  // Inline math: \(...\)
+  const inlineMathRegex = /\\\(((?:\\.|[^\\\n])*?)\\\)/g
   result = result.replace(inlineMathRegex, (_, math) => {
   result = result.replace(inlineMathRegex, (_, math) => {
     try {
     try {
       return katex.renderToString(math, {
       return katex.renderToString(math, {
@@ -404,13 +403,63 @@ function renderMathInText(text: string): string {
         throwOnError: false,
         throwOnError: false,
       })
       })
     } catch {
     } catch {
-      return `$${math}$`
+      return `\\(${math}\\)`
     }
     }
   })
   })
 
 
   return result
   return result
 }
 }
 
 
+const inlineMathRegex = /^\\\(((?:\\.|[^\\\n])*?)\\\)/
+const blockMathRegex = /^\$\$\n([\s\S]+?)\n\$\$(?:\n|$)/
+
+const katexExtension: MarkedExtension = {
+  extensions: [
+    {
+      name: "inlineKatex",
+      level: "inline",
+      start(src) {
+        const index = src.indexOf("\\(")
+        if (index === -1) return
+        return index
+      },
+      tokenizer(src) {
+        const match = src.match(inlineMathRegex)
+        if (!match) return
+        return {
+          type: "inlineKatex",
+          raw: match[0],
+          text: match[1].trim(),
+          displayMode: false,
+        }
+      },
+      renderer: renderKatexToken,
+    },
+    {
+      name: "blockKatex",
+      level: "block",
+      tokenizer(src) {
+        const match = src.match(blockMathRegex)
+        if (!match) return
+        return {
+          type: "blockKatex",
+          raw: match[0],
+          text: match[1].trim(),
+          displayMode: true,
+        }
+      },
+      renderer: renderKatexToken,
+    },
+  ],
+}
+
+function renderKatexToken(token: Tokens.Generic) {
+  return katex.renderToString(typeof token.text === "string" ? token.text : "", {
+    displayMode: token.displayMode === true,
+    throwOnError: false,
+  })
+}
+
 function renderMathExpressions(html: string): string {
 function renderMathExpressions(html: string): string {
   // Split on code/pre/kbd tags to avoid processing their contents
   // Split on code/pre/kbd tags to avoid processing their contents
   const codeBlockPattern = /(<(?:pre|code|kbd)[^>]*>[\s\S]*?<\/(?:pre|code|kbd)>)/gi
   const codeBlockPattern = /(<(?:pre|code|kbd)[^>]*>[\s\S]*?<\/(?:pre|code|kbd)>)/gi
@@ -480,10 +529,7 @@ export const { use: useMarked, provider: MarkedProvider } = createSimpleContext(
           },
           },
         },
         },
       },
       },
-      markedKatex({
-        throwOnError: false,
-        nonStandard: true,
-      }),
+      katexExtension,
       markedShiki({
       markedShiki({
         async highlight(code, lang) {
         async highlight(code, lang) {
           const highlighter = await getSharedHighlighter({
           const highlighter = await getSharedHighlighter({