@celestia-island/hikari 0.55.159 → 0.55.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/composables/languageForPath.test.ts +86 -0
- package/src/composables/useHighlight.ts +119 -0
- package/src/index.ts +1 -1
- package/src/styles/highlightPalette.contract.test.ts +91 -0
- package/src/styles/index.scss +5 -1
- package/src/styles/theme/highlight.scss +117 -0
- package/src/styles/vendoredSync.test.ts +2 -0
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { languageForPath } from "./useHighlight";
|
|
4
|
+
import { LANGUAGE_LOADERS } from "./highlightLanguages";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `languageForPath` is the ONE mapping from a file path to a highlight.js
|
|
8
|
+
* language — shared so a diff pane, a file browser and a markdown fence
|
|
9
|
+
* all derive the same language from the same path. Its two contracts:
|
|
10
|
+
* every non-empty answer must be a language the lazy loader can actually
|
|
11
|
+
* load (otherwise the promise is a lie), and unknown paths must answer ""
|
|
12
|
+
* (callers treat "" as plaintext/auto-detect, never as an error).
|
|
13
|
+
*/
|
|
14
|
+
describe("languageForPath", () => {
|
|
15
|
+
it("maps the common extensions onto canonical ids", () => {
|
|
16
|
+
expect(languageForPath("crates/scheduler/src/main.rs")).toBe("rust");
|
|
17
|
+
expect(languageForPath("src/index.ts")).toBe("typescript");
|
|
18
|
+
expect(languageForPath("App.tsx")).toBe("typescript");
|
|
19
|
+
expect(languageForPath("script.js")).toBe("javascript");
|
|
20
|
+
expect(languageForPath("world.toml")).toBe("toml");
|
|
21
|
+
expect(languageForPath("Cargo.toml")).toBe("toml");
|
|
22
|
+
expect(languageForPath("config/world.yml")).toBe("yaml");
|
|
23
|
+
expect(languageForPath("run.sh")).toBe("bash");
|
|
24
|
+
expect(languageForPath("notes.md")).toBe("markdown");
|
|
25
|
+
expect(languageForPath("query.sql")).toBe("sql");
|
|
26
|
+
expect(languageForPath("theme.scss")).toBe("scss");
|
|
27
|
+
expect(languageForPath("index.html")).toBe("xml");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("is case-insensitive on name and extension", () => {
|
|
31
|
+
expect(languageForPath("src/Main.RS")).toBe("rust");
|
|
32
|
+
expect(languageForPath("Dockerfile")).toBe("dockerfile");
|
|
33
|
+
expect(languageForPath("Makefile")).toBe("makefile");
|
|
34
|
+
expect(languageForPath("CMakeLists.txt")).toBe("cmake");
|
|
35
|
+
expect(languageForPath("Jenkinsfile")).toBe("groovy");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("keeps dotted stems like Dockerfile.dev on their dialect", () => {
|
|
39
|
+
expect(languageForPath("deploy/Dockerfile.dev")).toBe("dockerfile");
|
|
40
|
+
expect(languageForPath("dockerfile.prod")).toBe("dockerfile");
|
|
41
|
+
expect(languageForPath("Makefile.am")).toBe("makefile");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("answers \"\" for unknown or extensionless paths, not a guess", () => {
|
|
45
|
+
expect(languageForPath("bin/run")).toBe("");
|
|
46
|
+
expect(languageForPath("README")).toBe("");
|
|
47
|
+
expect(languageForPath("data.xyzzy")).toBe("");
|
|
48
|
+
expect(languageForPath("")).toBe("");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("every mapped id is a language the loader actually has", () => {
|
|
52
|
+
const loaders = new Set(Object.keys(LANGUAGE_LOADERS));
|
|
53
|
+
expect(loaders.size).toBeGreaterThan(50); // positive control
|
|
54
|
+
const probes = [
|
|
55
|
+
"a.rs", "a.ts", "a.tsx", "a.js", "a.json", "a.py", "a.rb", "a.go",
|
|
56
|
+
"a.java", "a.kt", "a.scala", "a.groovy", "a.c", "a.h", "a.cpp",
|
|
57
|
+
"a.hpp", "a.cs", "a.fs", "a.php", "a.swift", "a.m", "a.mm",
|
|
58
|
+
"a.dart", "a.ex", "a.erl", "a.hs", "a.elm", "a.lua", "a.pl",
|
|
59
|
+
"a.r", "a.jl", "a.nim", "a.cr", "a.ml", "a.vb", "a.pas", "a.bas",
|
|
60
|
+
"a.f90", "a.coffee", "a.ls", "a.clj", "a.scm", "a.el", "a.xml",
|
|
61
|
+
"a.html", "a.vue", "a.hbs", "a.twig", "a.haml", "a.erb", "a.dust",
|
|
62
|
+
"a.css", "a.scss", "a.less", "a.yml", "a.yaml", "a.toml", "a.ini",
|
|
63
|
+
"a.cfg", "a.properties", "a.env", "a.md", "a.graphql", "a.gql",
|
|
64
|
+
"a.http", "a.sh", "a.zsh", "a.ps1", "a.bat", "a.cmd", "a.mk",
|
|
65
|
+
"a.cmake", "a.awk", "a.tcl", "a.vim", "a.sql", "a.psql", "a.proto",
|
|
66
|
+
"a.thrift", "a.glsl", "a.vert", "a.frag", "a.wasm", "a.asm",
|
|
67
|
+
"a.v", "a.sv", "a.vhd", "a.vhdl", "a.tex", "a.sty", "a.diff",
|
|
68
|
+
"a.patch", "a.txt", "a.log", "Dockerfile", "Makefile", "Jenkinsfile",
|
|
69
|
+
"CMakeLists.txt", "Cargo.lock", ".gitignore", ".env", ".bashrc",
|
|
70
|
+
];
|
|
71
|
+
const mapped = probes
|
|
72
|
+
.map((p) => languageForPath(p))
|
|
73
|
+
.filter((id): id is string => id !== "");
|
|
74
|
+
// Each probe resolves to SOMETHING (the table is broad)…
|
|
75
|
+
expect(mapped.length).toBe(probes.length);
|
|
76
|
+
// …and every answer is loadable — no lying promises.
|
|
77
|
+
for (const id of mapped) {
|
|
78
|
+
expect(loaders, `languageForPath answered "${id}", which no loader provides`).toContain(id);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("does not fall off the path on dots in directories", () => {
|
|
83
|
+
expect(languageForPath("my.dir/stuff/main.rs")).toBe("rust");
|
|
84
|
+
expect(languageForPath("v1.2/config.yaml")).toBe("yaml");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -84,6 +84,125 @@ function ensureAutoLangs(): void {
|
|
|
84
84
|
for (const l of AUTO_LANGS) loadLanguage(l);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/** Whole filenames (lowercased) that carry no useful extension, or whose
|
|
88
|
+
* dialect is decided by the name: `Dockerfile.dev`, `CMakeLists.txt`. */
|
|
89
|
+
const PATH_FILENAME_LANG: Record<string, string> = {
|
|
90
|
+
dockerfile: "dockerfile",
|
|
91
|
+
makefile: "makefile",
|
|
92
|
+
gnumakefile: "makefile",
|
|
93
|
+
"cmakelists.txt": "cmake",
|
|
94
|
+
jenkinsfile: "groovy",
|
|
95
|
+
nginx: "nginx",
|
|
96
|
+
"cargo.lock": "toml",
|
|
97
|
+
".env": "ini",
|
|
98
|
+
".gitignore": "ini",
|
|
99
|
+
".gitattributes": "ini",
|
|
100
|
+
".gitmodules": "ini",
|
|
101
|
+
".editorconfig": "ini",
|
|
102
|
+
".bashrc": "bash",
|
|
103
|
+
".zshrc": "bash",
|
|
104
|
+
".profile": "bash",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/** Extension (lowercased) → canonical highlight.js language id. Only ids
|
|
108
|
+
* that exist in LANGUAGE_LOADERS: anything else would render plaintext
|
|
109
|
+
* anyway, just with a misleading promise attached. */
|
|
110
|
+
const EXT_TABLE: Record<string, string> = {
|
|
111
|
+
rs: "rust",
|
|
112
|
+
ts: "typescript", tsx: "typescript", mts: "typescript", cts: "typescript",
|
|
113
|
+
js: "javascript", jsx: "javascript", mjs: "javascript", cjs: "javascript",
|
|
114
|
+
json: "json", jsonc: "json",
|
|
115
|
+
py: "python", pyi: "python", pyw: "python",
|
|
116
|
+
rb: "ruby",
|
|
117
|
+
go: "go",
|
|
118
|
+
java: "java",
|
|
119
|
+
kt: "kotlin", kts: "kotlin",
|
|
120
|
+
scala: "scala", sc: "scala",
|
|
121
|
+
groovy: "groovy", gradle: "groovy",
|
|
122
|
+
c: "c", h: "c",
|
|
123
|
+
cpp: "cpp", cc: "cpp", cxx: "cpp", hpp: "cpp", hh: "cpp", hxx: "cpp",
|
|
124
|
+
cs: "csharp",
|
|
125
|
+
fs: "fsharp", fsx: "fsharp",
|
|
126
|
+
php: "php",
|
|
127
|
+
swift: "swift",
|
|
128
|
+
m: "objectivec", mm: "objectivec",
|
|
129
|
+
dart: "dart",
|
|
130
|
+
ex: "elixir", exs: "elixir",
|
|
131
|
+
erl: "erlang", hrl: "erlang",
|
|
132
|
+
hs: "haskell", lhs: "haskell",
|
|
133
|
+
elm: "elm",
|
|
134
|
+
lua: "lua",
|
|
135
|
+
pl: "perl", pm: "perl",
|
|
136
|
+
r: "r",
|
|
137
|
+
jl: "julia",
|
|
138
|
+
nim: "nim",
|
|
139
|
+
cr: "crystal",
|
|
140
|
+
ml: "ocaml", mli: "ocaml", mll: "ocaml", mly: "ocaml",
|
|
141
|
+
vb: "vbnet",
|
|
142
|
+
pas: "delphi", dpr: "delphi",
|
|
143
|
+
bas: "basic",
|
|
144
|
+
f: "fortran", f90: "fortran", f95: "fortran", f03: "fortran", for: "fortran",
|
|
145
|
+
coffee: "coffeescript",
|
|
146
|
+
ls: "livescript",
|
|
147
|
+
clj: "clojure", cljs: "clojure", cljc: "clojure", edn: "clojure",
|
|
148
|
+
scm: "scheme", ss: "scheme", el: "lisp", lisp: "lisp",
|
|
149
|
+
xml: "xml", html: "xml", htm: "xml", svg: "xml", vue: "xml", xhtml: "xml",
|
|
150
|
+
cshtml: "xml", jsp: "xml", erb: "erb", ejs: "xml",
|
|
151
|
+
hbs: "handlebars", handlebars: "handlebars",
|
|
152
|
+
twig: "twig",
|
|
153
|
+
haml: "haml",
|
|
154
|
+
dust: "dust",
|
|
155
|
+
css: "css", scss: "scss", less: "less",
|
|
156
|
+
yml: "yaml", yaml: "yaml",
|
|
157
|
+
toml: "toml",
|
|
158
|
+
ini: "ini", cfg: "ini", conf: "ini", properties: "properties", env: "ini",
|
|
159
|
+
md: "markdown", markdown: "markdown",
|
|
160
|
+
graphql: "graphql", gql: "graphql",
|
|
161
|
+
http: "http",
|
|
162
|
+
sh: "bash", bash: "bash", zsh: "bash", shell: "bash", fish: "bash",
|
|
163
|
+
ps1: "powershell", psm1: "powershell",
|
|
164
|
+
bat: "dos", cmd: "dos",
|
|
165
|
+
mk: "makefile",
|
|
166
|
+
cmake: "cmake",
|
|
167
|
+
dockerfile: "dockerfile",
|
|
168
|
+
nginx: "nginx",
|
|
169
|
+
awk: "awk",
|
|
170
|
+
tcl: "tcl",
|
|
171
|
+
vim: "vim",
|
|
172
|
+
sql: "sql", psql: "pgsql",
|
|
173
|
+
proto: "protobuf",
|
|
174
|
+
thrift: "thrift",
|
|
175
|
+
glsl: "glsl", vert: "glsl", frag: "glsl", geom: "glsl",
|
|
176
|
+
wasm: "wasm",
|
|
177
|
+
asm: "x86asm",
|
|
178
|
+
v: "verilog", sv: "verilog",
|
|
179
|
+
vhd: "vhdl", vhdl: "vhdl",
|
|
180
|
+
tex: "latex", sty: "latex",
|
|
181
|
+
diff: "diff", patch: "diff",
|
|
182
|
+
txt: "plaintext", text: "plaintext", log: "plaintext",
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* A file path → the canonical highlight.js language id for it, or "" when
|
|
187
|
+
* nothing sensible is known (callers pass "" as "no language" and the
|
|
188
|
+
* block renders plaintext or auto-detects). One mapping for every code
|
|
189
|
+
* surface — diff panes, file browsers, markdown fences — so the same
|
|
190
|
+
* path always highlights the same way; aliases are resolved by
|
|
191
|
+
* `normalize()` at highlight time, so the table lists canonical ids.
|
|
192
|
+
*/
|
|
193
|
+
export function languageForPath(path: string): string {
|
|
194
|
+
const name = path.split("/").pop()?.trim().toLowerCase() ?? "";
|
|
195
|
+
if (!name) return "";
|
|
196
|
+
// Extensionless build scripts: `Dockerfile`, `Jenkinsfile`, `Makefile`.
|
|
197
|
+
const bare = PATH_FILENAME_LANG[name];
|
|
198
|
+
if (bare) return bare;
|
|
199
|
+
// `Dockerfile.dev` / `dockerfile.prod` — the dialect IS the stem.
|
|
200
|
+
if (name.startsWith("dockerfile")) return "dockerfile";
|
|
201
|
+
if (name.startsWith("makefile")) return "makefile";
|
|
202
|
+
const ext = name.includes(".") ? name.split(".").pop()! : "";
|
|
203
|
+
return EXT_TABLE[ext] ?? "";
|
|
204
|
+
}
|
|
205
|
+
|
|
87
206
|
/**
|
|
88
207
|
* Highlight `code` for the given language (or auto-detect when omitted).
|
|
89
208
|
* Returns highlight.js HTML when the grammar is ready, otherwise an
|
package/src/index.ts
CHANGED
|
@@ -460,7 +460,7 @@ export type { OriginProbe } from "./utils/connectivity";
|
|
|
460
460
|
export { probeHealthEndpoint } from "./utils/healthProbe";
|
|
461
461
|
export type { HealthProbeBody, HealthProbeResult } from "./utils/healthProbe";
|
|
462
462
|
|
|
463
|
-
export { highlight, useHighlight } from "./composables/useHighlight";
|
|
463
|
+
export { highlight, languageForPath, useHighlight } from "./composables/useHighlight";
|
|
464
464
|
export { LANGUAGE_LOADERS } from "./composables/highlightLanguages";
|
|
465
465
|
export {
|
|
466
466
|
iconByName,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The syntax-palette contract (theme/highlight.scss).
|
|
9
|
+
*
|
|
10
|
+
* `useHighlight()` emits `.hljs-*` spans; this sheet is the ONLY thing
|
|
11
|
+
* that colours them, so the pairs documented in channels.scss must stay
|
|
12
|
+
* mapped to their `--code-*` tokens — if a restyle ever swaps a var() for
|
|
13
|
+
* a bare hex, themed hosts stop flipping light/dark for that class and
|
|
14
|
+
* the sheet silently forks the palette the host owns.
|
|
15
|
+
*
|
|
16
|
+
* Assertions run on the BODY (comment lines stripped): the header and
|
|
17
|
+
* inline comments deliberately NAME the classes they explain, so matching
|
|
18
|
+
* against the raw sheet would hit prose instead of rules.
|
|
19
|
+
*/
|
|
20
|
+
const body = readFileSync(
|
|
21
|
+
resolve(dirname(fileURLToPath(import.meta.url)), "theme/highlight.scss"),
|
|
22
|
+
"utf-8",
|
|
23
|
+
)
|
|
24
|
+
.split("\n")
|
|
25
|
+
.filter((line) => !line.trim().startsWith("//"))
|
|
26
|
+
.join("\n");
|
|
27
|
+
|
|
28
|
+
/** Pull one declaration block by a selector fragment (regex-escaped). */
|
|
29
|
+
function blockFor(selector: string): string {
|
|
30
|
+
const esc = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
const re = new RegExp(
|
|
32
|
+
String.raw`\.hljs-${esc}\b[\s\S]*?\{([^}]*)\}`,
|
|
33
|
+
);
|
|
34
|
+
const m = re.exec(body);
|
|
35
|
+
expect(m, `positive control: the .hljs-${selector} rule exists`).not.toBeNull();
|
|
36
|
+
return m![1];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("highlight palette (theme/highlight.scss)", () => {
|
|
40
|
+
it("rides the --code-* family for every colour, One Dark as fallback", () => {
|
|
41
|
+
const colorRules = body.match(/color:\s*[^;]+;/g) ?? [];
|
|
42
|
+
expect(colorRules.length).toBeGreaterThan(5); // positive control
|
|
43
|
+
for (const rule of colorRules) {
|
|
44
|
+
expect(
|
|
45
|
+
rule,
|
|
46
|
+
`every colour must ride the token family: "${rule}"`,
|
|
47
|
+
).toMatch(/color:\s*var\(--code-[a-z]+,\s*#[0-9a-fA-F]{6}\);/);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("keeps the pairs channels.scss documents canonical", () => {
|
|
52
|
+
expect(blockFor("keyword")).toContain("var(--code-keyword, #c678dd)");
|
|
53
|
+
expect(blockFor("selector-tag")).toContain("var(--code-keyword, #c678dd)");
|
|
54
|
+
expect(blockFor("built_in")).toContain("var(--code-builtin, #c678dd)");
|
|
55
|
+
expect(blockFor("string")).toContain("var(--code-string, #98c379)");
|
|
56
|
+
expect(blockFor("number")).toContain("var(--code-number, #d19a66)");
|
|
57
|
+
expect(blockFor("literal")).toContain("var(--code-number, #d19a66)");
|
|
58
|
+
expect(blockFor("attr")).toContain("var(--code-number, #d19a66)");
|
|
59
|
+
expect(blockFor("title.function_")).toContain("var(--code-function, #61afef)");
|
|
60
|
+
expect(blockFor("type")).toContain("var(--code-type, #e5c07b)");
|
|
61
|
+
expect(blockFor("title.class_")).toContain("var(--code-type, #e5c07b)");
|
|
62
|
+
expect(blockFor("variable")).toContain("var(--code-variable, #e06c75)");
|
|
63
|
+
expect(blockFor("template-variable")).toContain("var(--code-variable, #e06c75)");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("renders comments grey AND italic, as documented", () => {
|
|
67
|
+
const b = blockFor("comment");
|
|
68
|
+
expect(b).toContain("var(--code-comment, #5c6370)");
|
|
69
|
+
expect(b).toMatch(/font-style:\s*italic/);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("does not paint backgrounds or the .hljs base — surfaces own those", () => {
|
|
73
|
+
expect(body).not.toMatch(/background[^;{]*:/);
|
|
74
|
+
expect(body).not.toMatch(/^\.hljs\s*\{/m);
|
|
75
|
+
// The diff classes belong to the diff surfaces, not the palette.
|
|
76
|
+
expect(body).not.toContain(".hljs-addition");
|
|
77
|
+
expect(body).not.toContain(".hljs-deletion");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("is actually composed into the styles entry — a sheet nobody @uses is dead", () => {
|
|
81
|
+
const entry = readFileSync(
|
|
82
|
+
resolve(dirname(fileURLToPath(import.meta.url)), "index.scss"),
|
|
83
|
+
"utf-8",
|
|
84
|
+
);
|
|
85
|
+
expect(
|
|
86
|
+
entry.match(/@use\s+"\.\/theme\/[^"]+\.scss";/g) ?? [],
|
|
87
|
+
"positive control: the entry composes theme sheets",
|
|
88
|
+
).toContain("@use \"./theme/channels.scss\";");
|
|
89
|
+
expect(entry).toContain('@use "./theme/highlight.scss";');
|
|
90
|
+
});
|
|
91
|
+
});
|
package/src/styles/index.scss
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
// 3. theme/scrollbar.scss — the shared overlay-scrollbar chrome
|
|
13
13
|
// (.hk-scrollbar-track/thumb) that attachOverlayScrollbars() attaches
|
|
14
14
|
// to every scroll region (vendored from packages/theme/styles).
|
|
15
|
-
// 4.
|
|
15
|
+
// 4. theme/highlight.scss — the syntax palette: colours the .hljs-*
|
|
16
|
+
// spans useHighlight() emits, riding the --code-* family the host
|
|
17
|
+
// theme owns (vendored from packages/theme/styles).
|
|
18
|
+
// 5. admin-tokens.scss — the plana-ui shared surface: layout tokens,
|
|
16
19
|
// brand-color aliases and the shared admin component classes.
|
|
17
20
|
//
|
|
18
21
|
// initTheme() (runtime) writes only deltas against this base into a
|
|
@@ -28,4 +31,5 @@
|
|
|
28
31
|
@use "./theme/channels.scss";
|
|
29
32
|
@use "./theme/scale.scss";
|
|
30
33
|
@use "./theme/scrollbar.scss";
|
|
34
|
+
@use "./theme/highlight.scss";
|
|
31
35
|
@use "./admin-tokens.scss";
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Vendored from packages/theme/styles/_highlight.scss so npm registry
|
|
2
|
+
// installs can resolve it — the exports map only exposes ./styles/*.
|
|
3
|
+
// This sheet is what COLOURS the `.hljs-*` spans that useHighlight() and
|
|
4
|
+
// any other highlight.js driver emit; without it the grammars load and
|
|
5
|
+
// the code still renders monochrome (infra without a palette).
|
|
6
|
+
// Edit the upstream file, then re-copy; do not hand-edit here.
|
|
7
|
+
|
|
8
|
+
// _highlight.scss — the syntax palette for highlight.js output.
|
|
9
|
+
//
|
|
10
|
+
// `useHighlight()` (and anything else driving highlight.js) emits
|
|
11
|
+
// `.hljs-*` spans; this sheet is what actually COLOURS them. Without it
|
|
12
|
+
// the grammars load, the spans land in the DOM, and the code stays
|
|
13
|
+
// monochrome — infra without a palette.
|
|
14
|
+
//
|
|
15
|
+
// Every colour rides the `--code-*` family documented in channels.scss
|
|
16
|
+
// (the family the host theme owns; extend it only by adding a token with
|
|
17
|
+
// a fallback equal to the current visual). The fallbacks here are the
|
|
18
|
+
// canonical One Dark values, so a standalone/themeless consumer renders
|
|
19
|
+
// like One Dark and a themed host (which defines `--code-*` in both
|
|
20
|
+
// modes) flips light/dark automatically — no `.hljs-*` rule anywhere in
|
|
21
|
+
// this sheet hardcodes a palette colour outside a var() fallback.
|
|
22
|
+
//
|
|
23
|
+
// The explicit pairs from the channels.scss doc block are canonical:
|
|
24
|
+
// keyword ← .hljs-keyword / .hljs-selector-tag
|
|
25
|
+
// builtin ← .hljs-built_in
|
|
26
|
+
// string ← .hljs-string
|
|
27
|
+
// number ← .hljs-number / .hljs-literal / .hljs-attr
|
|
28
|
+
// comment ← .hljs-comment / .hljs-doctag (grey, italic)
|
|
29
|
+
// function ← .hljs-title.function_
|
|
30
|
+
// type ← .hljs-type / class titles
|
|
31
|
+
// variable ← .hljs-variable / .hljs-template-variable
|
|
32
|
+
// The remaining highlight.js classes are bucketed to the nearest of the
|
|
33
|
+
// same eight by judgement (the canonical pairs above are exact); the
|
|
34
|
+
// goal is that every span lands in the family, not that each bucket
|
|
35
|
+
// matches One Dark's own file class-for-class.
|
|
36
|
+
//
|
|
37
|
+
// Deliberately NOT set: `.hljs` base colour/background and the
|
|
38
|
+
// `.hljs-addition` / `.hljs-deletion` diff classes — containers (diff
|
|
39
|
+
// panes, markdown fences) own their surfaces, and a palette layer that
|
|
40
|
+
// painted backgrounds would fight them.
|
|
41
|
+
|
|
42
|
+
// keyword — purple
|
|
43
|
+
.hljs-keyword,
|
|
44
|
+
.hljs-selector-tag,
|
|
45
|
+
.hljs-formula {
|
|
46
|
+
color: var(--code-keyword, #c678dd);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// builtin — purple in dark, blue in light
|
|
50
|
+
.hljs-built_in,
|
|
51
|
+
.hljs-selector-id,
|
|
52
|
+
.hljs-symbol,
|
|
53
|
+
.hljs-bullet,
|
|
54
|
+
.hljs-link,
|
|
55
|
+
.hljs-meta {
|
|
56
|
+
color: var(--code-builtin, #c678dd);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// string — green
|
|
60
|
+
.hljs-string,
|
|
61
|
+
.hljs-regexp,
|
|
62
|
+
.hljs-attribute,
|
|
63
|
+
.hljs-meta .hljs-string {
|
|
64
|
+
color: var(--code-string, #98c379);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// number — orange in dark, blue in light
|
|
68
|
+
.hljs-number,
|
|
69
|
+
.hljs-literal,
|
|
70
|
+
.hljs-attr,
|
|
71
|
+
.hljs-property,
|
|
72
|
+
.hljs-selector-class,
|
|
73
|
+
.hljs-selector-attr,
|
|
74
|
+
.hljs-selector-pseudo {
|
|
75
|
+
color: var(--code-number, #d19a66);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// comment — grey, italic
|
|
79
|
+
.hljs-comment,
|
|
80
|
+
.hljs-quote,
|
|
81
|
+
.hljs-doctag {
|
|
82
|
+
color: var(--code-comment, #5c6370);
|
|
83
|
+
font-style: italic;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// function — blue
|
|
87
|
+
.hljs-title,
|
|
88
|
+
.hljs-title.function_,
|
|
89
|
+
.hljs-title.function_.invoke__,
|
|
90
|
+
.hljs-section {
|
|
91
|
+
color: var(--code-function, #61afef);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// type — yellow in dark, green in light
|
|
95
|
+
.hljs-type,
|
|
96
|
+
.hljs-title.class_,
|
|
97
|
+
.hljs-class .hljs-title {
|
|
98
|
+
color: var(--code-type, #e5c07b);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// variable — red in dark, orange in light
|
|
102
|
+
.hljs-variable,
|
|
103
|
+
.hljs-template-variable,
|
|
104
|
+
.hljs-subst,
|
|
105
|
+
.hljs-name,
|
|
106
|
+
.hljs-tag {
|
|
107
|
+
color: var(--code-variable, #e06c75);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Non-colour emphasis classes: keep the shapes highlight.js intends.
|
|
111
|
+
.hljs-emphasis {
|
|
112
|
+
font-style: italic;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.hljs-strong {
|
|
116
|
+
font-weight: bold;
|
|
117
|
+
}
|
|
@@ -52,6 +52,8 @@ const VENDORED_FROM_VUE: Array<[string, string]> = [
|
|
|
52
52
|
// (packages/theme/styles) and is vendored here so npm consumers can
|
|
53
53
|
// resolve it — the exports map only exposes ./styles/*.
|
|
54
54
|
["theme/scrollbar.scss", "../../theme/styles/_scrollbar.scss"],
|
|
55
|
+
// The syntax palette for .hljs-* spans lives there for the same reason.
|
|
56
|
+
["theme/highlight.scss", "../../theme/styles/_highlight.scss"],
|
|
55
57
|
];
|
|
56
58
|
|
|
57
59
|
|