diff --git a/docs/guide/using-vue.md b/docs/guide/using-vue.md index 502cb829e217..43c75245e370 100644 --- a/docs/guide/using-vue.md +++ b/docs/guide/using-vue.md @@ -62,7 +62,7 @@ const { page } = useData() ## Escaping -By default, fenced code blocks are automatically wrapped with `v-pre`. To display raw mustaches or Vue-specific syntax inside inline code snippets or plain text, you need to wrap a paragraph with the `v-pre` custom container: +By default, fenced code blocks are automatically wrapped with `v-pre`, unless you have set some language with `-vue` suffix like `js-vue` (in that case you can use Vue-style interpolation inside fences). To display raw mustaches or Vue-specific syntax inside inline code snippets or plain text, you need to wrap a paragraph with the `v-pre` custom container: **Input** diff --git a/src/node/markdown/plugins/highlight.ts b/src/node/markdown/plugins/highlight.ts index 186d9bc93447..291473ec8935 100644 --- a/src/node/markdown/plugins/highlight.ts +++ b/src/node/markdown/plugins/highlight.ts @@ -10,6 +10,9 @@ import { type Processor } from 'shiki-processor' import type { ThemeOptions } from '../markdown' +import { customAlphabet } from 'nanoid' + +const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10) /** * 2 steps: @@ -75,6 +78,7 @@ export async function highlight( const preRE = /^/ const vueRE = /-vue$/ const lineNoRE = /:(no-)?line-numbers$/ + const mustacheRE = /\{\{.*?\}\}/g return (str: string, lang: string, attrs: string) => { const vPre = vueRE.test(lang) ? '' : 'v-pre' @@ -87,13 +91,36 @@ export async function highlight( .replace(preRE, (_, attributes) => `
`)
         .replace(styleRE, (_, style) => _.replace(style, ''))
 
+    const mustaches = new Map()
+
+    const removeMustache = (s: string) => {
+      if (vPre) return s
+      return s.replace(mustacheRE, (match) => {
+        let marker = mustaches.get(match)
+        if (!marker) {
+          marker = nanoid()
+          mustaches.set(match, marker)
+        }
+        return marker
+      })
+    }
+
+    const restoreMustache = (s: string) => {
+      mustaches.forEach((marker, match) => {
+        s = s.replaceAll(marker, match)
+      })
+      return s
+    }
+
     if (hasSingleTheme) {
       return cleanup(
-        highlighter.codeToHtml(str, {
-          lang,
-          lineOptions,
-          theme: getThemeName(theme)
-        })
+        restoreMustache(
+          highlighter.codeToHtml(removeMustache(str), {
+            lang,
+            lineOptions,
+            theme: getThemeName(theme)
+          })
+        )
       )
     }