diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md
index 7520d722..1d59336e 100644
--- a/docs/guide/markdown.md
+++ b/docs/guide/markdown.md
@@ -651,6 +651,34 @@ export default config
:::
+You can also [import snippets](#import-code-snippets) in code groups:
+
+**Input**
+
+```md
+::: code-group
+
+
+
+<<< @/snippets/snippet.js
+
+
+
+<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
+
+:::
+```
+
+**Output**
+
+::: code-group
+
+<<< @/snippets/snippet.js
+
+<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]
+
+:::
+
## Markdown File Inclusion
You can include a markdown file in another markdown file like this:
diff --git a/src/node/markdown/plugins/lineNumbers.ts b/src/node/markdown/plugins/lineNumbers.ts
index a1830b8f..73efa944 100644
--- a/src/node/markdown/plugins/lineNumbers.ts
+++ b/src/node/markdown/plugins/lineNumbers.ts
@@ -24,8 +24,13 @@ export const lineNumberPlugin = (md: MarkdownIt, enable = false) => {
)
const lines = code.split('\n')
- const lineNumbersCode = [...Array(lines.length - 1)]
- .map((line, index) => `${index + 1}
`)
+
+ const lineNumbersCode = [
+ ...Array(
+ lines.length - (lines.at(-1) === `` ? 1 : 0)
+ )
+ ]
+ .map((_, index) => `${index + 1}
`)
.join('')
const lineNumbersWrapperCode = `
${lineNumbersCode}
`
diff --git a/src/node/markdown/plugins/preWrapper.ts b/src/node/markdown/plugins/preWrapper.ts
index 10f57d2d..62320477 100644
--- a/src/node/markdown/plugins/preWrapper.ts
+++ b/src/node/markdown/plugins/preWrapper.ts
@@ -3,11 +3,15 @@ import type MarkdownIt from 'markdown-it'
export function preWrapperPlugin(md: MarkdownIt) {
const fence = md.renderer.rules.fence!
md.renderer.rules.fence = (...args) => {
- const { info } = args[0][args[1]]
- const lang = extractLang(info)
+ const [tokens, idx] = args
+ const token = tokens[idx]
+ // remove title from info
+ token.info = token.info.replace(/\[.*\]/, '')
+
+ const lang = extractLang(token.info)
const rawCode = fence(...args)
return `${lang}${rawCode}
`
}
}
@@ -19,7 +23,7 @@ export function extractTitle(info: string) {
const extractLang = (info: string) => {
return info
.trim()
- .replace(/:(no-)?line-numbers$/, '')
+ .replace(/:(no-)?line-numbers({| |$).*/, '')
.replace(/(-vue|{| ).*$/, '')
.replace(/^vue-html$/, 'template')
}
diff --git a/src/node/markdown/plugins/snippet.ts b/src/node/markdown/plugins/snippet.ts
index 7d822969..f0b0bf52 100644
--- a/src/node/markdown/plugins/snippet.ts
+++ b/src/node/markdown/plugins/snippet.ts
@@ -95,10 +95,10 @@ export const snippetPlugin = (md: MarkdownIt, srcDir: string) => {
* where #region and {meta} are optional
* and meta can be like '1,2,4-6 lang', 'lang' or '1,2,4-6'
*
- * captures: ['/path/to/file.extension', 'extension', '#region', '{meta}']
+ * captures: ['/path/to/file.extension', 'extension', '#region', '{meta}', '[title]']
*/
const rawPathRegexp =
- /^(.+(?:\.([a-z0-9]+)))(?:(#[\w-]+))?(?: ?(?:{(\d+(?:[,-]\d+)*)? ?(\S+)?}))?$/
+ /^(.+(?:\.([a-z0-9]+)))(?:(#[\w-]+))?(?: ?(?:{(\d+(?:[,-]\d+)*)? ?(\S+)?}))? ?(?:\[(.+)\])?$/
const rawPath = state.src
.slice(start, end)
@@ -106,13 +106,23 @@ export const snippetPlugin = (md: MarkdownIt, srcDir: string) => {
.replace(/^@/, srcDir)
.trim()
- const [filename = '', extension = '', region = '', lines = '', lang = ''] =
- (rawPathRegexp.exec(rawPath) || []).slice(1)
+ const [
+ filename = '',
+ extension = '',
+ region = '',
+ lines = '',
+ lang = '',
+ rawTitle = ''
+ ] = (rawPathRegexp.exec(rawPath) || []).slice(1)
+
+ const title = rawTitle || filename.split('/').at(-1) || ''
state.line = startLine + 1
const token = state.push('fence', 'code', 0)
- token.info = `${lang || extension}${lines ? `{${lines}}` : ''}`
+ token.info = `${lang || extension}${lines ? `{${lines}}` : ''}${
+ title ? `[${title}]` : ''
+ }`
// @ts-ignore
token.src = path.resolve(filename) + region