Skip to content

Commit

Permalink
feat(build): support interpolation inside code blocks (#1759)
Browse files Browse the repository at this point in the history
  • Loading branch information
brc-dd authored Jan 4, 2023
1 parent 4ac8c04 commit 3b7ff8d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 6 deletions.
2 changes: 1 addition & 1 deletion docs/guide/using-vue.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**

Expand Down
37 changes: 32 additions & 5 deletions src/node/markdown/plugins/highlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -75,6 +78,7 @@ export async function highlight(
const preRE = /^<pre(.*?)>/
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'
Expand All @@ -87,13 +91,36 @@ export async function highlight(
.replace(preRE, (_, attributes) => `<pre ${vPre}${attributes}>`)
.replace(styleRE, (_, style) => _.replace(style, ''))

const mustaches = new Map<string, string>()

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)
})
)
)
}

Expand Down

0 comments on commit 3b7ff8d

Please sign in to comment.