diff --git a/docs/en/guide/markdown.md b/docs/en/guide/markdown.md index c3342474..e1be3e6b 100644 --- a/docs/en/guide/markdown.md +++ b/docs/en/guide/markdown.md @@ -365,7 +365,7 @@ export default { A [list of valid languages](https://shiki.style/languages) is available on Shiki's repository. -You may also customize syntax highlight theme in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details. +You may also customize syntax highlight theme, configure language aliases, and set custom language labels in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details. ## Line Highlighting in Code Blocks diff --git a/docs/zh/guide/markdown.md b/docs/zh/guide/markdown.md index cda368ee..a401774c 100644 --- a/docs/zh/guide/markdown.md +++ b/docs/zh/guide/markdown.md @@ -343,7 +343,7 @@ export default { 在 Shiki 的代码仓库中,可以找到[合法的编程语言列表](https://shiki.style/languages)。 -还可以全局配置中自定义语法高亮主题。有关详细信息,参见 [`markdown` 选项](../reference/site-config#markdown)得到更多信息。 +还可以在全局配置中自定义语法高亮主题、配置语言别名和自定义语言标签。有关详细信息,参见 [`markdown` 选项](../reference/site-config#markdown)得到更多信息。 ## 在代码块中实现行高亮 {#line-highlighting-in-code-blocks} diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 7e6d09e8..be4b8250 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -87,12 +87,37 @@ export interface MarkdownOptions extends Options { */ languages?: (LanguageInput | BuiltinLanguage)[] /** - * Custom language aliases. + * Custom language aliases for syntax highlighting. + * Maps custom language names to existing languages. + * Alias lookup is case-insensitive and underscores in language names are displayed as spaces. + * + * @example + * + * Maps `my_lang` to use Python syntax highlighting. + * ```js + * { 'my_lang': 'python' } + * ``` + * + * Usage in markdown: + * ````md + * ```My_Lang + * # This will be highlighted as Python code + * # and will show "My Lang" as the language label + * print("Hello, World!") + * ``` + * ```` * - * @example { 'my-lang': 'js' } * @see https://shiki.style/guide/load-lang#custom-language-aliases */ languageAlias?: Record + /** + * Custom language labels for display. + * Overrides the default language label shown in code blocks. + * Keys are case-insensitive. + * + * @example { 'vue': 'Vue SFC' } + */ + languageLabel?: Record /** * Show line numbers in code blocks * @default false @@ -249,7 +274,10 @@ export async function createMarkdownRenderer( // custom plugins md.use(componentPlugin, { ...options.component }) .use(highlightLinePlugin) - .use(preWrapperPlugin, { codeCopyButtonTitle }) + .use(preWrapperPlugin, { + codeCopyButtonTitle, + languageLabel: options.languageLabel + }) .use(snippetPlugin, srcDir) .use(containerPlugin, options.container) .use(imagePlugin, options.image) diff --git a/src/node/markdown/plugins/highlight.ts b/src/node/markdown/plugins/highlight.ts index f1285ed7..8f427823 100644 --- a/src/node/markdown/plugins/highlight.ts +++ b/src/node/markdown/plugins/highlight.ts @@ -59,16 +59,18 @@ export async function highlight( codeTransformers: userTransformers = [] } = options + const langAlias = Object.fromEntries( + Object.entries(options.languageAlias || {}) // + .map(([k, v]) => [k.toLowerCase(), v]) + ) + const highlighter = await createHighlighter({ themes: typeof theme === 'object' && 'light' in theme && 'dark' in theme ? [theme.light, theme.dark] : [theme], - langs: [ - ...(options.languages || []), - ...Object.values(options.languageAlias || {}) - ], - langAlias: options.languageAlias + langs: [...(options.languages || []), ...Object.values(langAlias)], + langAlias }) await options?.shikiSetup?.(highlighter) diff --git a/src/node/markdown/plugins/preWrapper.ts b/src/node/markdown/plugins/preWrapper.ts index e7d553b3..b75fa618 100644 --- a/src/node/markdown/plugins/preWrapper.ts +++ b/src/node/markdown/plugins/preWrapper.ts @@ -2,9 +2,15 @@ import type { MarkdownItAsync } from 'markdown-it-async' export interface Options { codeCopyButtonTitle: string + languageLabel?: Record } export function preWrapperPlugin(md: MarkdownItAsync, options: Options) { + const langLabel = Object.fromEntries( + Object.entries(options.languageLabel || {}) // + .map(([k, v]) => [k.toLowerCase(), v]) + ) + const fence = md.renderer.rules.fence! md.renderer.rules.fence = (...args) => { const [tokens, idx] = args @@ -17,11 +23,12 @@ export function preWrapperPlugin(md: MarkdownItAsync, options: Options) { token.info = token.info.replace(/ active$/, '').replace(/ active /, ' ') const lang = extractLang(token.info) + const label = langLabel[lang.toLowerCase()] || lang.replace(/_/g, ' ') return ( `
` + `` + - `${lang}` + + `${label}` + fence(...args) + '
' )