diff options
author | 2022-01-31 19:14:07 -0300 | |
---|---|---|
committer | 2022-01-31 16:14:07 -0600 | |
commit | 6fe1b0279fce5a7a0e90ff79746ea0b641da3e21 (patch) | |
tree | c2924bfd3e2c131d135cc8b2ceecbec310c6be56 /packages/markdown/remark/src | |
parent | 618a16f59d4037cff1665110f0ed111a96a96437 (diff) | |
download | astro-6fe1b0279fce5a7a0e90ff79746ea0b641da3e21.tar.gz astro-6fe1b0279fce5a7a0e90ff79746ea0b641da3e21.tar.zst astro-6fe1b0279fce5a7a0e90ff79746ea0b641da3e21.zip |
Add Shiki as an alternative to Prism (#2497)
* [ci] yarn format
* Added shiki to markdown-remark
* Upgraded astro shiki
* Added minimal example
* Changed defaults to match <Code />
* Replace `shiki` with `astro` classes
* Added documentation
* Updated Astro code to use new `codeToHtml`
* Added changesets
* Added basic test
* Updated tests a bit
Co-authored-by: JuanM04 <JuanM04@users.noreply.github.com>
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r-- | packages/markdown/remark/src/index.ts | 10 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-shiki.ts | 23 | ||||
-rw-r--r-- | packages/markdown/remark/src/types.ts | 5 |
3 files changed, 36 insertions, 2 deletions
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index e8242279a..78d645227 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -9,6 +9,7 @@ import { remarkJsx, loadRemarkJsx } from './remark-jsx.js'; import rehypeJsx from './rehype-jsx.js'; import rehypeEscape from './rehype-escape.js'; import remarkPrism from './remark-prism.js'; +import remarkShiki from './remark-shiki.js'; import remarkUnwrap from './remark-unwrap.js'; import { loadPlugins } from './load-plugins.js'; @@ -37,6 +38,8 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp let { remarkPlugins = [], rehypePlugins = [] } = opts ?? {}; const scopedClassName = opts?.$?.scopedClassName; const mode = opts?.mode ?? 'mdx'; + const syntaxHighlight = opts?.syntaxHighlight ?? 'prism'; + const shikiTheme = opts?.shikiTheme ?? 'github-dark'; const isMDX = mode === 'mdx'; const { headers, rehypeCollectHeaders } = createCollectHeaders(); @@ -64,7 +67,12 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp parser.use([scopedStyles(scopedClassName)]); } - parser.use([remarkPrism(scopedClassName)]); + if (syntaxHighlight === 'prism') { + parser.use([remarkPrism(scopedClassName)]); + } else if (syntaxHighlight === 'shiki') { + parser.use([await remarkShiki(shikiTheme)]); + } + parser.use([[markdownToHtml as any, { allowDangerousHtml: true, passThrough: ['raw', 'mdxTextExpression', 'mdxJsxTextElement', 'mdxJsxFlowElement'] }]]); loadedRehypePlugins.forEach(([plugin, opts]) => { diff --git a/packages/markdown/remark/src/remark-shiki.ts b/packages/markdown/remark/src/remark-shiki.ts new file mode 100644 index 000000000..5becad76d --- /dev/null +++ b/packages/markdown/remark/src/remark-shiki.ts @@ -0,0 +1,23 @@ +import shiki from 'shiki'; +import { visit } from 'unist-util-visit'; + +const remarkShiki = async (theme: shiki.Theme) => { + const highlighter = await shiki.getHighlighter({ theme }); + + return () => (tree: any) => { + visit(tree, 'code', (node) => { + let html = highlighter.codeToHtml(node.value, { lang: node.lang ?? 'plaintext' }); + + // Replace "shiki" class naming with "astro". + html = html.replace('<pre class="shiki"', '<pre class="astro-code"'); + // Replace "shiki" css variable naming with "astro". + html = html.replace(/style="(background-)?color: var\(--shiki-/g, 'style="$1color: var(--astro-code-'); + + node.type = 'html'; + node.value = html; + node.children = []; + }); + }; +}; + +export default remarkShiki; diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index 541d3ff27..043594c9c 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -1,10 +1,13 @@ -import * as unified from 'unified'; +import type * as unified from 'unified'; +import type * as shiki from 'shiki'; export type UnifiedPluginImport = Promise<{ default: unified.Plugin }>; export type Plugin = string | [string, any] | UnifiedPluginImport | [UnifiedPluginImport, any]; export interface AstroMarkdownOptions { mode?: 'md' | 'mdx'; + syntaxHighlight?: 'prism' | 'shiki' | false; + shikiTheme?: shiki.Theme; remarkPlugins?: Plugin[]; rehypePlugins?: Plugin[]; } |