Fix/expand chatui code highlighting 扩展 chatui 代码高亮 (#9892)

* fix: expand common language syntax highlighting

* fix: wire limited Shiki languages into ChatUI

* fix: register bundled aliases for chat code blocks

* fix: include Go grammar in T2I Shiki runtime
This commit is contained in:
AtQiYu
2026-09-02 22:32:47 +08:00
committed by GitHub
parent 6ee1ddd4fd
commit 9115cc2945
5 changed files with 152 additions and 17 deletions
File diff suppressed because one or more lines are too long
@@ -23,15 +23,28 @@ const shikiRequire = createRequire(require.resolve("shiki/package.json"));
const languageSpecs = [
["bash", "bash"],
["c", "c"],
["css", "css"],
["cpp", "cpp"],
["csharp", "csharp"],
["dart", "dart"],
["go", "go"],
["html", "html"],
["javascript", "javascript"],
["json", "json"],
["jsx", "jsx"],
["kotlin", "kotlin"],
["lua", "lua"],
["markdown", "markdown"],
["php", "php"],
["powershell", "powershell"],
["python", "python"],
["r", "r"],
["ruby", "ruby"],
["rust", "rust"],
["scala", "scala"],
["sql", "sql"],
["swift", "swift"],
["tsx", "tsx"],
["typescript", "typescript"],
["xml", "xml"],
@@ -49,13 +62,24 @@ const builtInLanguageSpecs = ["text"];
const languageAliases = {
bat: "powershell",
"c++": "cpp",
cc: "cpp",
cjs: "javascript",
cxx: "cpp",
console: "bash",
cts: "typescript",
cs: "csharp",
dockerfile: "bash",
golang: "go",
h: "c",
"h++": "cpp",
hh: "cpp",
hpp: "cpp",
env: "bash",
htm: "html",
js: "javascript",
kt: "kotlin",
kts: "kotlin",
md: "markdown",
mjs: "javascript",
mts: "typescript",
@@ -64,6 +88,7 @@ const languageAliases = {
ps1: "powershell",
pwsh: "powershell",
py: "python",
rs: "rust",
shell: "bash",
shellscript: "bash",
sh: "bash",
@@ -17,6 +17,7 @@
import { computed, inject, type Ref, useAttrs } from "vue";
import { MarkdownCodeBlockNode } from "markstream-vue";
import { copyToClipboard } from "@/utils/clipboard";
import { LIMITED_SHIKI_LANGUAGES, LIMITED_SHIKI_LANGUAGE_ALIASES } from "@/utils/shikiLimitedBundle";
defineOptions({
inheritAttrs: false,
@@ -57,6 +58,10 @@ const attrs = useAttrs();
const forwardedBindings = computed(() => ({
...attrs,
...props,
langs: Array.from(new Set([
...LIMITED_SHIKI_LANGUAGES.map((language) => language.name),
...Object.values(LIMITED_SHIKI_LANGUAGE_ALIASES),
])),
isDark: effectiveIsDark.value,
}));
const themeRenderKey = computed(() => (effectiveIsDark.value ? "dark" : "light"));
+39
View File
@@ -1,19 +1,32 @@
import { createHighlighterCore } from "shiki/core";
import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
import bash from "shiki/langs/bash.mjs";
import c from "shiki/langs/c.mjs";
import css from "shiki/langs/css.mjs";
import cpp from "shiki/langs/cpp.mjs";
import csharp from "shiki/langs/csharp.mjs";
import dart from "shiki/langs/dart.mjs";
import diff from "shiki/langs/diff.mjs";
import dockerfile from "shiki/langs/dockerfile.mjs";
import go from "shiki/langs/go.mjs";
import html from "shiki/langs/html.mjs";
import ini from "shiki/langs/ini.mjs";
import java from "shiki/langs/java.mjs";
import javascript from "shiki/langs/javascript.mjs";
import json from "shiki/langs/json.mjs";
import jsx from "shiki/langs/jsx.mjs";
import kotlin from "shiki/langs/kotlin.mjs";
import lua from "shiki/langs/lua.mjs";
import markdown from "shiki/langs/markdown.mjs";
import php from "shiki/langs/php.mjs";
import powershell from "shiki/langs/powershell.mjs";
import python from "shiki/langs/python.mjs";
import r from "shiki/langs/r.mjs";
import ruby from "shiki/langs/ruby.mjs";
import rust from "shiki/langs/rust.mjs";
import scala from "shiki/langs/scala.mjs";
import sql from "shiki/langs/sql.mjs";
import swift from "shiki/langs/swift.mjs";
import tsx from "shiki/langs/tsx.mjs";
import typescript from "shiki/langs/typescript.mjs";
import vue from "shiki/langs/vue.mjs";
@@ -26,19 +39,32 @@ import vitesseLight from "shiki/themes/vitesse-light.mjs";
export const LIMITED_SHIKI_LANGUAGES = [
...bash,
...c,
...css,
...cpp,
...csharp,
...dart,
...diff,
...dockerfile,
...go,
...html,
...ini,
...java,
...javascript,
...json,
...jsx,
...kotlin,
...lua,
...markdown,
...php,
...powershell,
...python,
...r,
...ruby,
...rust,
...scala,
...sql,
...swift,
...tsx,
...typescript,
...vue,
@@ -57,12 +83,23 @@ const BUILT_IN_LANGUAGES = ["text", "plaintext", "plain"];
export const LIMITED_SHIKI_LANGUAGE_ALIASES = {
bat: "powershell",
"c++": "cpp",
cc: "cpp",
cjs: "javascript",
cxx: "cpp",
console: "bash",
cts: "typescript",
cs: "csharp",
docker: "dockerfile",
golang: "go",
h: "c",
"h++": "cpp",
hh: "cpp",
hpp: "cpp",
htm: "html",
js: "javascript",
kt: "kotlin",
kts: "kotlin",
md: "markdown",
mjs: "javascript",
mts: "typescript",
@@ -71,6 +108,7 @@ export const LIMITED_SHIKI_LANGUAGE_ALIASES = {
ps1: "powershell",
pwsh: "powershell",
py: "python",
rs: "rust",
shell: "bash",
shellscript: "bash",
sh: "bash",
@@ -120,6 +158,7 @@ export function normalizeLimitedShikiLanguage(language) {
const normalized = String(language || "text")
.trim()
.split(/\s+/, 1)[0]
.split(":", 1)[0]
.toLowerCase();
if (!normalized) return "text";
@@ -0,0 +1,66 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
LIMITED_SHIKI_SUPPORTED_LANGUAGES,
createHighlighter,
normalizeLimitedShikiLanguage,
} from "../src/utils/shikiLimitedBundle.js";
const languageCases = {
c: ["c", "h"],
cpp: ["cpp", "c++", "cc", "cxx", "h++", "hh", "hpp"],
csharp: ["csharp", "cs"],
dart: ["dart"],
go: ["go", "golang"],
kotlin: ["kotlin", "kt", "kts"],
lua: ["lua"],
php: ["php"],
r: ["r"],
ruby: ["ruby"],
rust: ["rust", "rs"],
scala: ["scala"],
swift: ["swift"],
};
test("normalizes aliases for the expanded language set", () => {
for (const [language, aliases] of Object.entries(languageCases)) {
assert.equal(normalizeLimitedShikiLanguage(language), language);
for (const alias of aliases) {
assert.equal(normalizeLimitedShikiLanguage(alias), language, alias);
}
assert.ok(LIMITED_SHIKI_SUPPORTED_LANGUAGES.has(language), language);
}
assert.equal(normalizeLimitedShikiLanguage("unknown-language"), "text");
assert.equal(normalizeLimitedShikiLanguage("c extra"), "c");
assert.equal(normalizeLimitedShikiLanguage("rust:rust"), "rust");
});
test("highlights every expanded language with Shiki tokens", async () => {
const highlighter = await createHighlighter({ themes: ["github-light"] });
const samples = {
c: "int main() { return 0; }",
cpp: "std::vector<int> values;",
csharp: "public class Sample {}",
dart: "void main() {}",
go: "package main\nfunc main() {}",
kotlin: "fun main() {}",
lua: "local value = 1",
php: "<?php echo 'ok';",
r: "value <- 1",
ruby: "puts 'ok'",
rust: "fn main() {}",
scala: "object Main extends App {}",
swift: "let value = 1",
};
for (const [language, code] of Object.entries(samples)) {
assert.equal(highlighter.getLanguage(language)?.name, language, language);
const html = highlighter.codeToHtml(code, {
lang: language,
theme: "github-light",
});
assert.match(html, /<span[^>]+style=/, language);
}
});