WaveCut/Bonsai-Chat-WebGPU
5
1import { createHighlighterCore } from 'shiki/core';2import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';3 4export type CodeTheme = 'light' | 'dark';5 6const LANGUAGE_LOADERS = {7 bash: () => import('@shikijs/langs/bash'),8 c: () => import('@shikijs/langs/c'),9 cpp: () => import('@shikijs/langs/cpp'),10 csharp: () => import('@shikijs/langs/csharp'),11 css: () => import('@shikijs/langs/css'),12 dart: () => import('@shikijs/langs/dart'),13 diff: () => import('@shikijs/langs/diff'),14 dockerfile: () => import('@shikijs/langs/dockerfile'),15 go: () => import('@shikijs/langs/go'),16 graphql: () => import('@shikijs/langs/graphql'),17 html: () => import('@shikijs/langs/html'),18 java: () => import('@shikijs/langs/java'),19 javascript: () => import('@shikijs/langs/javascript'),20 json: () => import('@shikijs/langs/json'),21 jsonc: () => import('@shikijs/langs/jsonc'),22 jsx: () => import('@shikijs/langs/jsx'),23 kotlin: () => import('@shikijs/langs/kotlin'),24 less: () => import('@shikijs/langs/less'),25 lua: () => import('@shikijs/langs/lua'),26 markdown: () => import('@shikijs/langs/markdown'),27 mdx: () => import('@shikijs/langs/mdx'),28 nginx: () => import('@shikijs/langs/nginx'),29 perl: () => import('@shikijs/langs/perl'),30 php: () => import('@shikijs/langs/php'),31 powershell: () => import('@shikijs/langs/powershell'),32 python: () => import('@shikijs/langs/python'),33 r: () => import('@shikijs/langs/r'),34 regex: () => import('@shikijs/langs/regex'),35 ruby: () => import('@shikijs/langs/ruby'),36 rust: () => import('@shikijs/langs/rust'),37 scala: () => import('@shikijs/langs/scala'),38 scss: () => import('@shikijs/langs/scss'),39 shellscript: () => import('@shikijs/langs/shellscript'),40 sql: () => import('@shikijs/langs/sql'),41 swift: () => import('@shikijs/langs/swift'),42 toml: () => import('@shikijs/langs/toml'),43 tsx: () => import('@shikijs/langs/tsx'),44 typescript: () => import('@shikijs/langs/typescript'),45 xml: () => import('@shikijs/langs/xml'),46 yaml: () => import('@shikijs/langs/yaml'),47} as const;48 49type SupportedCodeLanguage = keyof typeof LANGUAGE_LOADERS;50export type HighlightLanguage = SupportedCodeLanguage | 'text';51 52const LANGUAGE_ALIASES: Readonly<Record<string, SupportedCodeLanguage>> = {53 'c#': 'csharp',54 'c++': 'cpp',55 bat: 'shellscript',56 cmd: 'shellscript',57 cs: 'csharp',58 docker: 'dockerfile',59 gql: 'graphql',60 htm: 'html',61 js: 'javascript',62 md: 'markdown',63 ps1: 'powershell',64 py: 'python',65 rb: 'ruby',66 rs: 'rust',67 sh: 'bash',68 shell: 'shellscript',69 ts: 'typescript',70 yml: 'yaml',71};72 73const THEME_NAMES: Record<CodeTheme, 'github-light' | 'github-dark'> = {74 light: 'github-light',75 dark: 'github-dark',76};77 78const highlighterPromise = createHighlighterCore({79 themes: [80 import('@shikijs/themes/github-light'),81 import('@shikijs/themes/github-dark'),82 ],83 langs: [],84 engine: createJavaScriptRegexEngine(),85});86const languagePromises = new Map<SupportedCodeLanguage, Promise<void>>();87 88export function normalizeCodeLanguage(value: string): HighlightLanguage {89 const candidate = value.trim().toLowerCase();90 if (!candidate || ['text', 'txt', 'plain', 'plaintext'].includes(candidate)) return 'text';91 const aliased = LANGUAGE_ALIASES[candidate] ?? candidate;92 return Object.hasOwn(LANGUAGE_LOADERS, aliased)93 ? aliased as SupportedCodeLanguage94 : 'text';95}96 97export function codeThemeName(theme: CodeTheme): 'github-light' | 'github-dark' {98 return THEME_NAMES[theme];99}100 101export async function getCodeHighlighter(language: HighlightLanguage) {102 const highlighter = await highlighterPromise;103 if (language === 'text' || highlighter.getLoadedLanguages().includes(language)) return highlighter;104 let loading = languagePromises.get(language);105 if (!loading) {106 loading = highlighter.loadLanguage(LANGUAGE_LOADERS[language]()).then(() => undefined);107 languagePromises.set(language, loading);108 }109 await loading;110 return highlighter;111}112 