fix(editor): 支持完整 Shiki 语言并修复语言标识与图标展示
This commit is contained in:
@@ -1,18 +1,8 @@
|
||||
import DOMPurify from 'dompurify'
|
||||
import { marked } from 'marked'
|
||||
import { createHighlighterCore } from 'shiki/core'
|
||||
import { createJavaScriptRegexEngine } from '@shikijs/engine-javascript'
|
||||
import css from '@shikijs/langs/css'
|
||||
import c from '@shikijs/langs/c'
|
||||
import cpp from '@shikijs/langs/cpp'
|
||||
import html from '@shikijs/langs/html'
|
||||
import javascript from '@shikijs/langs/javascript'
|
||||
import json from '@shikijs/langs/json'
|
||||
import markdown from '@shikijs/langs/markdown'
|
||||
import python from '@shikijs/langs/python'
|
||||
import shell from '@shikijs/langs/shellscript'
|
||||
import sql from '@shikijs/langs/sql'
|
||||
import typescript from '@shikijs/langs/typescript'
|
||||
import { createOnigurumaEngine } from 'shiki/engine/oniguruma'
|
||||
import { bundledLanguagesInfo } from 'shiki/langs'
|
||||
import githubDark from '@shikijs/themes/github-dark'
|
||||
import githubLight from '@shikijs/themes/github-light'
|
||||
|
||||
@@ -21,30 +11,46 @@ marked.setOptions({ gfm: true, breaks: true })
|
||||
// Highlighter 是昂贵的单例;复用初始化 Promise,避免每个代码块重复加载语法与主题。
|
||||
const highlighter = createHighlighterCore({
|
||||
themes: [githubLight, githubDark],
|
||||
langs: [markdown, html, css, javascript, typescript, json, python, shell, sql, c, cpp],
|
||||
engine: createJavaScriptRegexEngine(),
|
||||
langs: [],
|
||||
engine: createOnigurumaEngine(import('shiki/wasm')),
|
||||
})
|
||||
|
||||
const languageAliases: Record<string, string> = {
|
||||
bash: 'shell', js: 'javascript', md: 'markdown', plaintext: 'text', py: 'python', sh: 'shell', ts: 'typescript',
|
||||
const languageAliases = new Map(bundledLanguagesInfo.flatMap(info =>
|
||||
[info.id, info.name, ...(info.aliases ?? [])].map(alias => [alias.toLowerCase(), info.id] as const),
|
||||
))
|
||||
const languageLoads = new Map<string, Promise<void>>()
|
||||
const languageLoaders = new Map(bundledLanguagesInfo.map(info => [info.id, info.import]))
|
||||
|
||||
async function loadCodeLanguage(requestedLanguage: string) {
|
||||
const shiki = await highlighter
|
||||
const language = languageAliases.get(requestedLanguage.toLowerCase())
|
||||
if (!language) return { shiki, language: 'text' as const }
|
||||
let loading = languageLoads.get(language)
|
||||
if (!loading) {
|
||||
loading = shiki.loadLanguage(languageLoaders.get(language)!).catch(error => {
|
||||
languageLoads.delete(language)
|
||||
throw error
|
||||
})
|
||||
languageLoads.set(language, loading)
|
||||
}
|
||||
await loading
|
||||
return { shiki, language }
|
||||
}
|
||||
|
||||
export async function highlightCode(source: string, requestedLanguage = 'text'): Promise<string> {
|
||||
const shiki = await highlighter
|
||||
const language = languageAliases[requestedLanguage] ?? requestedLanguage
|
||||
const loadedLanguage = shiki.getLoadedLanguages().includes(language as never) ? language : 'markdown'
|
||||
const { shiki, language } = await loadCodeLanguage(requestedLanguage)
|
||||
return shiki.codeToHtml(source, {
|
||||
lang: loadedLanguage,
|
||||
lang: language,
|
||||
themes: { light: 'github-light', dark: 'github-dark' },
|
||||
defaultColor: false,
|
||||
})
|
||||
}
|
||||
|
||||
/** Share the initialized grammar/theme registry with editable code blocks. */
|
||||
export async function getCodeTokenizer(theme: 'github-light' | 'github-dark') {
|
||||
const shiki = await highlighter
|
||||
export async function getCodeTokenizer(theme: 'github-light' | 'github-dark', requestedLanguage = 'text') {
|
||||
const { shiki } = await loadCodeLanguage(requestedLanguage)
|
||||
return (source: string, requestedLanguage: string) => {
|
||||
const language = languageAliases[requestedLanguage] ?? requestedLanguage
|
||||
const language = languageAliases.get(requestedLanguage.toLowerCase()) ?? 'text'
|
||||
return shiki.codeToTokens(source, {
|
||||
lang: shiki.getLoadedLanguages().includes(language as never) ? language : 'text',
|
||||
theme,
|
||||
|
||||
Reference in New Issue
Block a user