Bonsai-Chat-WebGPU / src /lib /code-highlighter.ts
Valeriy Selitskiy
Release v1.2.2 interactive chat workspace
21ad36a
Raw
History Blame Contribute Delete
3.98 kB
import { createHighlighterCore } from 'shiki/core';
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
export type CodeTheme = 'light' | 'dark';
const LANGUAGE_LOADERS = {
bash: () => import('@shikijs/langs/bash'),
c: () => import('@shikijs/langs/c'),
cpp: () => import('@shikijs/langs/cpp'),
csharp: () => import('@shikijs/langs/csharp'),
css: () => import('@shikijs/langs/css'),
dart: () => import('@shikijs/langs/dart'),
diff: () => import('@shikijs/langs/diff'),
dockerfile: () => import('@shikijs/langs/dockerfile'),
go: () => import('@shikijs/langs/go'),
graphql: () => import('@shikijs/langs/graphql'),
html: () => import('@shikijs/langs/html'),
java: () => import('@shikijs/langs/java'),
javascript: () => import('@shikijs/langs/javascript'),
json: () => import('@shikijs/langs/json'),
jsonc: () => import('@shikijs/langs/jsonc'),
jsx: () => import('@shikijs/langs/jsx'),
kotlin: () => import('@shikijs/langs/kotlin'),
less: () => import('@shikijs/langs/less'),
lua: () => import('@shikijs/langs/lua'),
markdown: () => import('@shikijs/langs/markdown'),
mdx: () => import('@shikijs/langs/mdx'),
nginx: () => import('@shikijs/langs/nginx'),
perl: () => import('@shikijs/langs/perl'),
php: () => import('@shikijs/langs/php'),
powershell: () => import('@shikijs/langs/powershell'),
python: () => import('@shikijs/langs/python'),
r: () => import('@shikijs/langs/r'),
regex: () => import('@shikijs/langs/regex'),
ruby: () => import('@shikijs/langs/ruby'),
rust: () => import('@shikijs/langs/rust'),
scala: () => import('@shikijs/langs/scala'),
scss: () => import('@shikijs/langs/scss'),
shellscript: () => import('@shikijs/langs/shellscript'),
sql: () => import('@shikijs/langs/sql'),
swift: () => import('@shikijs/langs/swift'),
toml: () => import('@shikijs/langs/toml'),
tsx: () => import('@shikijs/langs/tsx'),
typescript: () => import('@shikijs/langs/typescript'),
xml: () => import('@shikijs/langs/xml'),
yaml: () => import('@shikijs/langs/yaml'),
} as const;
type SupportedCodeLanguage = keyof typeof LANGUAGE_LOADERS;
export type HighlightLanguage = SupportedCodeLanguage | 'text';
const LANGUAGE_ALIASES: Readonly<Record<string, SupportedCodeLanguage>> = {
'c#': 'csharp',
'c++': 'cpp',
bat: 'shellscript',
cmd: 'shellscript',
cs: 'csharp',
docker: 'dockerfile',
gql: 'graphql',
htm: 'html',
js: 'javascript',
md: 'markdown',
ps1: 'powershell',
py: 'python',
rb: 'ruby',
rs: 'rust',
sh: 'bash',
shell: 'shellscript',
ts: 'typescript',
yml: 'yaml',
};
const THEME_NAMES: Record<CodeTheme, 'github-light' | 'github-dark'> = {
light: 'github-light',
dark: 'github-dark',
};
const highlighterPromise = createHighlighterCore({
themes: [
import('@shikijs/themes/github-light'),
import('@shikijs/themes/github-dark'),
],
langs: [],
engine: createJavaScriptRegexEngine(),
});
const languagePromises = new Map<SupportedCodeLanguage, Promise<void>>();
export function normalizeCodeLanguage(value: string): HighlightLanguage {
const candidate = value.trim().toLowerCase();
if (!candidate || ['text', 'txt', 'plain', 'plaintext'].includes(candidate)) return 'text';
const aliased = LANGUAGE_ALIASES[candidate] ?? candidate;
return Object.hasOwn(LANGUAGE_LOADERS, aliased)
? aliased as SupportedCodeLanguage
: 'text';
}
export function codeThemeName(theme: CodeTheme): 'github-light' | 'github-dark' {
return THEME_NAMES[theme];
}
export async function getCodeHighlighter(language: HighlightLanguage) {
const highlighter = await highlighterPromise;
if (language === 'text' || highlighter.getLoadedLanguages().includes(language)) return highlighter;
let loading = languagePromises.get(language);
if (!loading) {
loading = highlighter.loadLanguage(LANGUAGE_LOADERS[language]()).then(() => undefined);
languagePromises.set(language, loading);
}
await loading;
return highlighter;
}