From 75f18e47334933b642d14b8b69b372cb1ebd4244 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 23 Nov 2023 13:54:30 +0100 Subject: [PATCH] feat: migrate to shikiji (#3237) --- .../markdown-extensions.test.ts | 10 +- docs/.vitepress/config.ts | 10 +- docs/guide/markdown.md | 26 +- docs/reference/site-config.md | 84 +---- package.json | 4 +- pnpm-lock.yaml | 308 ++++++++++++++++-- .../styles/components/vp-code.css | 8 +- src/node/markdown/markdown.ts | 126 ++++++- src/node/markdown/plugins/highlight.ts | 114 ++++--- template/markdown-examples.md | 4 +- 10 files changed, 486 insertions(+), 208 deletions(-) diff --git a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts index aa1f6ff2a195..42a8989140ab 100644 --- a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts +++ b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts @@ -163,19 +163,19 @@ describe('Line Numbers', () => { describe('Import Code Snippets', () => { test('basic', async () => { const lines = page.locator('#basic-code-snippet + div code > span') - expect(await lines.count()).toBe(22) + expect(await lines.count()).toBe(11) }) test('specify region', async () => { const lines = page.locator('#specify-region + div code > span') - expect(await lines.count()).toBe(6) + expect(await lines.count()).toBe(3) }) test('with other features', async () => { const div = page.locator('#with-other-features + div') expect(await getClassList(div)).toContain('line-numbers-mode') const lines = div.locator('code > span') - expect(await lines.count()).toBe(6) + expect(await lines.count()).toBe(3) expect(await getClassList(lines.nth(0))).toContain('highlighted') }) }) @@ -216,10 +216,10 @@ describe('Code Groups', () => { // blocks const blocks = div.locator('.blocks > div') - expect(await blocks.nth(0).locator('code > span').count()).toBe(22) + expect(await blocks.nth(0).locator('code > span').count()).toBe(11) expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode') expect(await getClassList(blocks.nth(1))).toContain('language-ts') - expect(await blocks.nth(1).locator('code > span').count()).toBe(6) + expect(await blocks.nth(1).locator('code > span').count()).toBe(3) expect( await getClassList(blocks.nth(1).locator('code > span').nth(0)) ).toContain('highlighted') diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 4818af45e282..500c583ec27b 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -13,7 +13,15 @@ export default defineConfig({ cleanUrls: true, markdown: { - math: true + math: true, + codeTransformers: [ + // We use `[!!code` in demo to prevent transformation, here we revert it back. + { + postprocess(code) { + return code.replace(/\[\!\!code/g, '[!code') + } + } + ] }, sitemap: { diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md index 3756235d1709..8806bd649b56 100644 --- a/docs/guide/markdown.md +++ b/docs/guide/markdown.md @@ -80,7 +80,7 @@ For more details, see [Frontmatter](../reference/frontmatter-config). **Input** -``` +```md | Tables | Are | Cool | | ------------- | :-----------: | ----: | | col 3 is | right-aligned | $1600 | @@ -265,7 +265,7 @@ Wraps in a
## Syntax Highlighting in Code Blocks -VitePress uses [Shiki](https://shiki.matsu.io/) to highlight language syntax in Markdown code blocks, using coloured text. Shiki supports a wide variety of programming languages. All you need to do is append a valid language alias to the beginning backticks for the code block: +VitePress uses [Shikiji](https://github.com/antfu/shikiji) (an improved version of [Shiki](https://shiki.matsu.io/)) to highlight language syntax in Markdown code blocks, using coloured text. Shiki supports a wide variety of programming languages. All you need to do is append a valid language alias to the beginning backticks for the code block: **Input** @@ -377,7 +377,7 @@ export default { // Highlighted } ``` -Alternatively, it's possible to highlight directly in the line by using the `// [!code hl]` comment. +Alternatively, it's possible to highlight directly in the line by using the `// [!code hightlight]` comment. **Input** @@ -386,7 +386,7 @@ Alternatively, it's possible to highlight directly in the line by using the `// export default { data () { return { - msg: 'Highlighted!' // [!code hl] + msg: 'Highlighted!' // [!!code highlight] } } } @@ -399,7 +399,7 @@ export default { export default { data() { return { - msg: 'Highlighted!' // [!code hl] + msg: 'Highlighted!' // [!code highlight] } } } @@ -413,14 +413,12 @@ Additionally, you can define a number of lines to focus using `// [!code focus:< **Input** -Note that only one space is required after `!code`, here are two to prevent processing. - ```` ```js export default { data () { return { - msg: 'Focused!' // [!code focus] + msg: 'Focused!' // [!!code focus] } } } @@ -445,15 +443,13 @@ Adding the `// [!code --]` or `// [!code ++]` comments on a line will create a d **Input** -Note that only one space is required after `!code`, here are two to prevent processing. - ```` ```js export default { data () { return { - msg: 'Removed' // [!code --] - msg: 'Added' // [!code ++] + msg: 'Removed' // [!!code --] + msg: 'Added' // [!!code ++] } } } @@ -479,15 +475,13 @@ Adding the `// [!code warning]` or `// [!code error]` comments on a line will co **Input** -Note that only one space is required after `!code`, here are two to prevent processing. - ```` ```js export default { data () { return { - msg: 'Error', // [!code error] - msg: 'Warning' // [!code warning] + msg: 'Error', // [!!code error] + msg: 'Warning' // [!!code warning] } } } diff --git a/docs/reference/site-config.md b/docs/reference/site-config.md index c6838c503059..b5e124d2d981 100644 --- a/docs/reference/site-config.md +++ b/docs/reference/site-config.md @@ -454,7 +454,7 @@ When using the default theme, enabling this option will display each page's last - Type: `MarkdownOption` -Configure Markdown parser options. VitePress uses [Markdown-it](https://github.com/markdown-it/markdown-it) as the parser, and [Shiki](https://shiki.matsu.io/) to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs. +Configure Markdown parser options. VitePress uses [Markdown-it](https://github.com/markdown-it/markdown-it) as the parser, and [Shikiji](https://github.com/antfu/shikiji) (an improved version of [Shiki](https://shiki.matsu.io/)) to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs. ```js export default { @@ -462,87 +462,7 @@ export default { } ``` -Below are all the options that you can have in this object: - -```ts -interface MarkdownOptions extends MarkdownIt.Options { - // Custom theme for syntax highlighting. - // You can use an existing theme. - // See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes - // Or add your own theme. - // See: https://github.com/shikijs/shiki/blob/main/docs/themes.md#loading-theme - theme?: - | Shiki.IThemeRegistration - | { light: Shiki.IThemeRegistration; dark: Shiki.IThemeRegistration } - - // Enable line numbers in code block. - lineNumbers?: boolean - - // Add support for your own languages. - // https://github.com/shikijs/shiki/blob/main/docs/languages.md#supporting-your-own-languages-with-shiki - languages?: Shiki.ILanguageRegistration[] - - // markdown-it-anchor plugin options. - // See: https://github.com/valeriangalliat/markdown-it-anchor#usage - anchor?: anchorPlugin.AnchorOptions - - // markdown-it-attrs plugin options. - // See: https://github.com/arve0/markdown-it-attrs - attrs?: { - leftDelimiter?: string - rightDelimiter?: string - allowedAttributes?: Array - disable?: boolean - } - - // specify default language for syntax highlighter - defaultHighlightLang?: string - - // @mdit-vue/plugin-frontmatter plugin options. - // See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter#options - frontmatter?: FrontmatterPluginOptions - - // @mdit-vue/plugin-headers plugin options. - // See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers#options - headers?: HeadersPluginOptions | boolean - - // @mdit-vue/plugin-sfc plugin options. - // See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc#options - sfc?: SfcPluginOptions - - // @mdit-vue/plugin-toc plugin options. - // See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options - toc?: TocPluginOptions - - // @mdit-vue/plugin-component plugin options. - // See: https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component#options - component?: ComponentPluginOptions - - // Configure the Markdown-it instance. - config?: (md: MarkdownIt) => void - - // Same as `config` but will be applied before all other plugins. - preConfig?: (md: MarkdownIt) => void - - // Disable cache (experimental) - cache?: boolean - - // Math support (experimental) - // You need to install `markdown-it-mathjax3` and set `math` to `true` to enable it. - // You can also pass options to `markdown-it-mathjax3` here. - // See: https://github.com/tani/markdown-it-mathjax3#customization - math?: boolean | any - - // Global custom container titles - container?: { - infoLabel?: string - tipLabel?: string - warningLabel?: string - dangerLabel?: string - detailsLabel?: string - } -} -``` +Check the [type declaration and jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) for all the options available. ### vite diff --git a/package.json b/package.json index 61bfb5445b5b..c1d3f9c76fa2 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,8 @@ "mark.js": "8.11.1", "minisearch": "^6.2.0", "mrmime": "^1.0.1", - "shiki": "^0.14.5", + "shikiji": "^0.7.2", + "shikiji-transformers": "^0.7.2", "vite": "^5.0.0", "vue": "^3.3.8" }, @@ -187,7 +188,6 @@ "rollup-plugin-dts": "^6.1.0", "rollup-plugin-esbuild": "^6.1.0", "semver": "^7.5.4", - "shiki-processor": "^0.1.3", "simple-git-hooks": "^2.9.0", "sirv": "^2.0.3", "sitemap": "^7.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8016659f609..7593fd335990 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,9 +44,12 @@ importers: mrmime: specifier: ^1.0.1 version: 1.0.1 - shiki: - specifier: ^0.14.5 - version: 0.14.5 + shikiji: + specifier: ^0.7.2 + version: 0.7.2 + shikiji-transformers: + specifier: ^0.7.2 + version: 0.7.2 vite: specifier: ^5.0.0 version: 5.0.0(@types/node@20.9.1) @@ -261,9 +264,6 @@ importers: semver: specifier: ^7.5.4 version: 7.5.4 - shiki-processor: - specifier: ^0.1.3 - version: 0.1.3(shiki@0.14.5) simple-git-hooks: specifier: ^2.9.0 version: 2.9.0 @@ -1121,6 +1121,12 @@ packages: '@types/node': 20.9.1 dev: true + /@types/hast@3.0.3: + resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} + dependencies: + '@types/unist': 3.0.2 + dev: false + /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} dev: true @@ -1180,6 +1186,12 @@ packages: '@types/linkify-it': 3.0.5 '@types/mdurl': 1.0.5 + /@types/mdast@4.0.3: + resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} + dependencies: + '@types/unist': 3.0.2 + dev: false + /@types/mdurl@1.0.5: resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} @@ -1268,10 +1280,18 @@ packages: resolution: {integrity: sha512-m04Om5Gz6kbjUwAQ7XJJQ30OdEFsSmAVsvn4NYwcTRyMVpKKa1aPuESw1n2CxS5fYkOQv3nHgDKeNa8e76fUkw==} dev: true + /@types/unist@3.0.2: + resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + dev: false + /@types/web-bluetooth@0.0.20: resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} dev: false + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + dev: false + /@vitejs/plugin-vue@4.5.0(vite@5.0.0)(vue@3.3.8): resolution: {integrity: sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1590,9 +1610,6 @@ packages: engines: {node: '>=12'} dev: true - /ansi-sequence-parser@1.1.1: - resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} - /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1761,6 +1778,10 @@ packages: set-function-length: 1.1.1 dev: true + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: false + /chai@4.3.10: resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} engines: {node: '>=4'} @@ -1788,6 +1809,14 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: false + + /character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + dev: false + /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} dependencies: @@ -1884,6 +1913,10 @@ packages: delayed-stream: 1.0.0 dev: true + /comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: false + /commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2177,6 +2210,17 @@ packages: engines: {node: '>=0.4.0'} dev: true + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: false + + /devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dependencies: + dequal: 2.0.3 + dev: false + /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2244,6 +2288,11 @@ packages: engines: {node: '>=0.12'} dev: true + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -2681,6 +2730,88 @@ packages: function-bind: 1.1.2 dev: true + /hast-util-from-parse5@8.0.1: + resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + devlop: 1.1.0 + hastscript: 8.0.0 + property-information: 6.4.0 + vfile: 6.0.1 + vfile-location: 5.0.2 + web-namespaces: 2.0.1 + dev: false + + /hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + dependencies: + '@types/hast': 3.0.3 + dev: false + + /hast-util-raw@9.0.1: + resolution: {integrity: sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + '@ungap/structured-clone': 1.2.0 + hast-util-from-parse5: 8.0.1 + hast-util-to-parse5: 8.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.0.2 + parse5: 7.1.2 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.1 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: false + + /hast-util-to-html@9.0.0: + resolution: {integrity: sha512-IVGhNgg7vANuUA2XKrT6sOIIPgaYZnmLx3l/CCOAK0PtgfoHrZwX7jCSYyFxHTrGmC6S9q8aQQekjp4JPZF+cw==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-raw: 9.0.1 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.0.2 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.3 + zwitch: 2.0.4 + dev: false + + /hast-util-to-parse5@8.0.0: + resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} + dependencies: + '@types/hast': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: false + + /hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + dependencies: + '@types/hast': 3.0.3 + dev: false + + /hastscript@8.0.0: + resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} + dependencies: + '@types/hast': 3.0.3 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + dev: false + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -2697,6 +2828,10 @@ packages: lru-cache: 10.0.2 dev: true + /html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + dev: false + /htmlparser2@5.0.1: resolution: {integrity: sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==} dependencies: @@ -2979,6 +3114,7 @@ packages: /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -3215,6 +3351,19 @@ packages: speech-rule-engine: 4.0.7 dev: true + /mdast-util-to-hast@13.0.2: + resolution: {integrity: sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==} + dependencies: + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + '@ungap/structured-clone': 1.2.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.0 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + dev: false + /mdurl@1.0.1: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} dev: true @@ -3246,6 +3395,33 @@ packages: resolution: {integrity: sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==} dev: true + /micromark-util-character@2.0.1: + resolution: {integrity: sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==} + dependencies: + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-encode@2.0.0: + resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + dev: false + + /micromark-util-sanitize-uri@2.0.0: + resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + dependencies: + micromark-util-character: 2.0.1 + micromark-util-encode: 2.0.0 + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-symbol@2.0.0: + resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + dev: false + + /micromark-util-types@2.0.0: + resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + dev: false + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -3542,6 +3718,12 @@ packages: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: true + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: false + /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: true @@ -3704,6 +3886,10 @@ packages: sisteransi: 1.0.5 dev: true + /property-information@6.4.0: + resolution: {integrity: sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==} + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true @@ -3977,21 +4163,17 @@ packages: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} dev: true - /shiki-processor@0.1.3(shiki@0.14.5): - resolution: {integrity: sha512-oZqVFKweklwt+fj6yUPb+ffrCpYYoJ4RYxNt7w1+aoHetHq5ZaN6oX6+4HrypOi0s/O6A2neBpn+Xf6bM4KfsQ==} - peerDependencies: - shiki: 0.x + /shikiji-transformers@0.7.2: + resolution: {integrity: sha512-Nxg79GL++TvMjprCwhKzXWA4UFTP4fP3jZrkJAkUnSchqV20T2emyy/NgNhNjeX69JoUqTbB82rfVASj5Vec9Q==} dependencies: - shiki: 0.14.5 - dev: true + shikiji: 0.7.2 + dev: false - /shiki@0.14.5: - resolution: {integrity: sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==} + /shikiji@0.7.2: + resolution: {integrity: sha512-gOaq7lqi3zSqGm+pMVxDD9NXA6myj5/7s7ZXgJcGdM5eHa49FrUPV46C5nl13rZnN3ZDjEmqF8ZPpNJjXeiBrQ==} dependencies: - ansi-sequence-parser: 1.1.1 - jsonc-parser: 3.2.0 - vscode-oniguruma: 1.7.0 - vscode-textmate: 8.0.0 + hast-util-to-html: 9.0.0 + dev: false /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} @@ -4070,6 +4252,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: false + /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: @@ -4188,6 +4374,13 @@ packages: safe-buffer: 5.2.1 dev: true + /stringify-entities@4.0.3: + resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: false + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4299,6 +4492,10 @@ packages: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: false + /trouter@3.2.1: resolution: {integrity: sha512-oY3CmIiEYOe1YMEzh++I67lrNOUldtCeuLL0vRPydvQLHZpSJ03B5dgDFlpFsiriMq6e//NDjjopjUzXOztHow==} engines: {node: '>=6'} @@ -4401,6 +4598,39 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + dependencies: + '@types/unist': 3.0.2 + dev: false + + /unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + dependencies: + '@types/unist': 3.0.2 + dev: false + + /unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + dependencies: + '@types/unist': 3.0.2 + dev: false + + /unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + dev: false + + /unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + dev: false + /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -4427,6 +4657,28 @@ packages: engines: {node: '>= 0.8'} dev: true + /vfile-location@5.0.2: + resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==} + dependencies: + '@types/unist': 3.0.2 + vfile: 6.0.1 + dev: false + + /vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + dev: false + + /vfile@6.0.1: + resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + dev: false + /vite-node@1.0.0-beta.5(@types/node@20.9.1)(supports-color@9.4.0): resolution: {integrity: sha512-iXm+GTJbR9R6V/bCM1+LQqIohL/tncZVNGIcTtzpYThBD8yiTkDPvEjy1Mf7KFACtG3qY/0VDMrkuMtqG/JFhg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -4540,12 +4792,6 @@ packages: - terser dev: true - /vscode-oniguruma@1.7.0: - resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} - - /vscode-textmate@8.0.0: - resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} - /vue-demi@0.14.6(vue@3.3.8): resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} engines: {node: '>=12'} @@ -4610,6 +4856,10 @@ packages: - debug dev: true + /web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + dev: false + /web-resource-inliner@6.0.1: resolution: {integrity: sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==} engines: {node: '>=10.0.0'} @@ -4728,3 +4978,7 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} dev: true + + /zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: false diff --git a/src/client/theme-default/styles/components/vp-code.css b/src/client/theme-default/styles/components/vp-code.css index ee74e5b27d70..1ff9429b4ac1 100644 --- a/src/client/theme-default/styles/components/vp-code.css +++ b/src/client/theme-default/styles/components/vp-code.css @@ -1,7 +1,7 @@ -.dark .vp-code-light { - display: none; +.dark .vp-code span { + color: var(--shiki-dark, inherit); } -html:not(.dark) .vp-code-dark { - display: none; +html:not(.dark) .vp-code span { + color: var(--shiki-light, inherit); } diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 3ec80b9cba5e..67c631a1c567 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -18,7 +18,6 @@ import MarkdownIt from 'markdown-it' import anchorPlugin from 'markdown-it-anchor' import attrsPlugin from 'markdown-it-attrs' import emojiPlugin from 'markdown-it-emoji' -import type { ILanguageRegistration, IThemeRegistration } from 'shiki' import type { Logger } from 'vite' import { containerPlugin, type ContainerOptions } from './plugins/containers' import { highlight } from './plugins/highlight' @@ -28,36 +27,139 @@ import { lineNumberPlugin } from './plugins/lineNumbers' import { linkPlugin } from './plugins/link' import { preWrapperPlugin } from './plugins/preWrapper' import { snippetPlugin } from './plugins/snippet' +import type { + ThemeRegistration, + BuiltinTheme, + LanguageInput, + ShikijiTransformer +} from 'shikiji' export type { Header } from '../shared' export type ThemeOptions = - | IThemeRegistration - | { light: IThemeRegistration; dark: IThemeRegistration } + | ThemeRegistration + | BuiltinTheme + | { + light: ThemeRegistration | BuiltinTheme + dark: ThemeRegistration | BuiltinTheme + } export interface MarkdownOptions extends MarkdownIt.Options { - lineNumbers?: boolean + /* ==================== General Options ==================== */ + + /** + * Setup markdown-it instance before applying plugins + */ preConfig?: (md: MarkdownIt) => void + /** + * Setup markdown-it instance + */ config?: (md: MarkdownIt) => void + /** + * Disable cache (experimental) + */ + cache?: boolean + externalLinks?: Record + + /* ==================== Syntax Highlighting ==================== */ + + /** + * Custom theme for syntax highlighting. + * + * You can also pass an object with `light` and `dark` themes to support dual themes. + * + * @example { theme: 'github-dark' } + * @example { theme: { light: 'github-light', dark: 'github-dark' } } + * + * You can use an existing theme. + * @see https://github.com/antfu/shikiji/blob/main/docs/themes.md#all-themes + * Or add your own theme. + * @see https://github.com/antfu/shikiji/blob/main/docs/themes.md#load-custom-themes + */ + theme?: ThemeOptions + /** + * Languages for syntax highlighting. + * @see https://github.com/antfu/shikiji/blob/main/docs/languages.md#all-themes + */ + languages?: LanguageInput[] + /** + * Custom language aliases. + * + * @example { 'my-lang': 'js' } + * @see https://github.com/antfu/shikiji/tree/main#custom-language-aliases + */ + languageAlias?: Record + /** + * Show line numbers in code blocks + * @default false + */ + lineNumbers?: boolean + /** + * Fallback language when the specified language is not available. + */ + defaultHighlightLang?: string + /** + * Transformers applied to code blocks + * @see https://github.com/antfu/shikiji#hast-transformers + */ + codeTransformers?: ShikijiTransformer[] + + /* ==================== Markdown It Plugins ==================== */ + + /** + * Options for `markdown-it-anchor` + * @see https://github.com/valeriangalliat/markdown-it-anchor + */ anchor?: anchorPlugin.AnchorOptions + /** + * Options for `markdown-it-attrs` + * @see https://github.com/arve0/markdown-it-attrs + */ attrs?: { leftDelimiter?: string rightDelimiter?: string allowedAttributes?: Array disable?: boolean } - defaultHighlightLang?: string + /** + * Options for `@mdit-vue/plugin-frontmatter` + * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter + */ frontmatter?: FrontmatterPluginOptions + /** + * Options for `@mdit-vue/plugin-headers` + * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers + */ headers?: HeadersPluginOptions | boolean + /** + * Options for `@mdit-vue/plugin-sfc` + * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc + */ sfc?: SfcPluginOptions - theme?: ThemeOptions - languages?: ILanguageRegistration[] + /** + * Options for `@mdit-vue/plugin-toc` + * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc + */ toc?: TocPluginOptions - externalLinks?: Record - cache?: boolean + /** + * Options for `@mdit-vue/plugin-component` + * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component + */ component?: ComponentPluginOptions - math?: boolean | any + /** + * Options for `markdown-it-container` + * @see https://github.com/markdown-it/markdown-it-container + */ container?: ContainerOptions + /** + * Math support (experimental) + * + * You need to install `markdown-it-mathjax3` and set `math` to `true` to enable it. + * You can also pass options to `markdown-it-mathjax3` here. + * @default false + * @see https://vitepress.dev/guide/markdown#math-equations + */ + math?: boolean | any } export type MarkdownRenderer = MarkdownIt @@ -80,7 +182,9 @@ export const createMarkdownRenderer = async ( theme, options.languages, options.defaultHighlightLang, - logger + logger, + options.codeTransformers, + options.languageAlias )), ...options }) diff --git a/src/node/markdown/plugins/highlight.ts b/src/node/markdown/plugins/highlight.ts index 524632864a88..da9524ab604e 100644 --- a/src/node/markdown/plugins/highlight.ts +++ b/src/node/markdown/plugins/highlight.ts @@ -1,23 +1,23 @@ import { customAlphabet } from 'nanoid' import c from 'picocolors' +import type { LanguageInput, ShikijiTransformer } from 'shikiji' import { - BUNDLED_LANGUAGES, - type HtmlRendererOptions, - type ILanguageRegistration, - type IThemeRegistration -} from 'shiki' -import { - addClass, - createDiffProcessor, - createFocusProcessor, - createHighlightProcessor, - createRangeProcessor, - defineProcessor, + bundledLanguages, getHighlighter, - type Processor -} from 'shiki-processor' + addClassToHast, + isPlaintext as isPlainLang, + isSpecialLang +} from 'shikiji' import type { Logger } from 'vite' import type { ThemeOptions } from '../markdown' +import { + transformerCompactLineOptions, + transformerNotationDiff, + transformerNotationErrorLevel, + transformerNotationFocus, + transformerNotationHighlight, + type TransformerCompactLineOption +} from 'shikiji-transformers' const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10) @@ -29,7 +29,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10) * 2. convert line numbers into line options: * [{ line: number, classes: string[] }] */ -const attrsToLines = (attrs: string): HtmlRendererOptions['lineOptions'] => { +const attrsToLines = (attrs: string): TransformerCompactLineOption[] => { attrs = attrs.replace(/^(?:\[.*?\])?.*?([\d,-]+).*/, '$1').trim() const result: number[] = [] if (!attrs) { @@ -53,37 +53,38 @@ const attrsToLines = (attrs: string): HtmlRendererOptions['lineOptions'] => { })) } -const errorLevelProcessor = defineProcessor({ - name: 'error-level', - handler: createRangeProcessor({ - error: ['highlighted', 'error'], - warning: ['highlighted', 'warning'] - }) -}) - export async function highlight( theme: ThemeOptions, - languages: ILanguageRegistration[] = [], + languages?: LanguageInput[], defaultLang: string = '', - logger: Pick = console + logger: Pick = console, + userTransformers: ShikijiTransformer[] = [], + languageAlias: Record = {} ): Promise<(str: string, lang: string, attrs: string) => string> { - const hasSingleTheme = typeof theme === 'string' || 'name' in theme - const getThemeName = (themeValue: IThemeRegistration) => - typeof themeValue === 'string' ? themeValue : themeValue.name - - const processors: Processor[] = [ - createFocusProcessor(), - createHighlightProcessor({ hasHighlightClass: 'highlighted' }), - createDiffProcessor(), - errorLevelProcessor - ] - const highlighter = await getHighlighter({ - themes: hasSingleTheme ? [theme] : [theme.dark, theme.light], - langs: [...BUNDLED_LANGUAGES, ...languages], - processors + themes: + typeof theme === 'string' || 'name' in theme + ? [theme] + : [theme.light, theme.dark], + langs: languages?.length ? languages : Object.keys(bundledLanguages), + langAlias: languageAlias }) + const transformers: ShikijiTransformer[] = [ + transformerNotationDiff(), + transformerNotationFocus({ + classActiveLine: 'has-focus', + classActivePre: 'has-focused-lines' + }), + transformerNotationHighlight(), + transformerNotationErrorLevel(), + { + pre(node) { + addClassToHast(node, 'vp-code') + } + } + ] + const styleRE = /]*(style=".*?")/ const preRE = /^/ const vueRE = /-vue$/ @@ -102,7 +103,7 @@ export async function highlight( if (lang) { const langLoaded = highlighter.getLoadedLanguages().includes(lang as any) - if (!langLoaded && !['ansi', 'plaintext', 'txt', 'text'].includes(lang)) { + if (!langLoaded && !isPlainLang(lang) && !isSpecialLang(lang)) { logger.warn( c.yellow( `\nThe language '${lang}' is not loaded, falling back to '${ @@ -155,24 +156,21 @@ export async function highlight( str = removeMustache(str).trimEnd() - const codeToHtml = (theme: IThemeRegistration) => { - const res = - lang === 'ansi' - ? highlighter.ansiToHtml(str, { - lineOptions, - theme: getThemeName(theme) - }) - : highlighter.codeToHtml(str, { - lang, - lineOptions, - theme: getThemeName(theme) - }) - return fillEmptyHighlightedLine(cleanup(restoreMustache(res))) - } + const highlighted = highlighter.codeToHtml(str, { + lang, + transformers: [ + ...transformers, + transformerCompactLineOptions(lineOptions), + ...userTransformers + ], + ...(typeof theme === 'string' || 'name' in theme + ? { theme } + : { + themes: theme, + defaultColor: false + }) + }) - if (hasSingleTheme) return codeToHtml(theme) - const dark = addClass(codeToHtml(theme.dark), 'vp-code-dark', 'pre') - const light = addClass(codeToHtml(theme.light), 'vp-code-light', 'pre') - return dark + light + return fillEmptyHighlightedLine(cleanup(restoreMustache(highlighted))) } } diff --git a/template/markdown-examples.md b/template/markdown-examples.md index 8e55eb8add18..3ea9aa9f2aeb 100644 --- a/template/markdown-examples.md +++ b/template/markdown-examples.md @@ -4,11 +4,11 @@ This page demonstrates some of the built-in markdown extensions provided by Vite ## Syntax Highlighting -VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting: +VitePress provides Syntax Highlighting powered by [Shikiji](https://github.com/antfu/shikiji), with additional features like line-highlighting: **Input** -```` +````md ```js{4} export default { data () {