Skip to content

Commit 3319e6c

Browse files
committed
feat: static code highlighting and integrate it on plugin page and ref page
1 parent 5aaedfa commit 3319e6c

File tree

8 files changed

+440
-244
lines changed

8 files changed

+440
-244
lines changed

src/cm/themes/index.js

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,35 @@ import tokyoNight, { config as tokyoNightConfig } from "./tokyoNight";
1313
import tokyoNightDay, { config as tokyoNightDayConfig } from "./tokyoNightDay";
1414
import vscodeDark, { config as vscodeDarkConfig } from "./vscodeDark";
1515

16-
// Registry of CodeMirror editor themes
17-
// key: id, value: { id, caption, isDark, getExtension: () => Extension[] }
16+
const oneDarkConfig = {
17+
name: "one_dark",
18+
dark: true,
19+
background: "#282c34",
20+
foreground: "#abb2bf",
21+
keyword: "#c678dd",
22+
string: "#98c379",
23+
number: "#d19a66",
24+
comment: "#5c6370",
25+
function: "#61afef",
26+
variable: "#e06c75",
27+
type: "#e5c07b",
28+
class: "#e5c07b",
29+
constant: "#d19a66",
30+
operator: "#56b6c2",
31+
invalid: "#ff6b6b",
32+
};
33+
1834
const themes = new Map();
1935

20-
export function addTheme(id, caption, isDark, getExtension) {
36+
export function addTheme(id, caption, isDark, getExtension, config = null) {
2137
const key = String(id).toLowerCase();
2238
if (themes.has(key)) return;
2339
themes.set(key, {
2440
id: key,
2541
caption: caption || id,
2642
isDark: !!isDark,
2743
getExtension,
44+
config: config || null,
2845
});
2946
}
3047

@@ -37,54 +54,94 @@ export function getThemeById(id) {
3754
return themes.get(String(id).toLowerCase()) || null;
3855
}
3956

57+
export function getThemeConfig(id) {
58+
if (!id) return oneDarkConfig;
59+
const theme = themes.get(String(id).toLowerCase());
60+
return theme?.config || oneDarkConfig;
61+
}
62+
4063
export function removeTheme(id) {
4164
if (!id) return;
4265
themes.delete(String(id).toLowerCase());
4366
}
4467

45-
// Register built-ins
46-
addTheme("one_dark", "One Dark", true, () => [oneDark]);
47-
addTheme(auraConfig.name, "Aura", !!auraConfig.dark, () => aura());
68+
addTheme("one_dark", "One Dark", true, () => [oneDark], oneDarkConfig);
69+
addTheme(auraConfig.name, "Aura", !!auraConfig.dark, () => aura(), auraConfig);
4870
addTheme(
4971
noctisLilacConfig.name,
5072
noctisLilacConfig.caption || "Noctis Lilac",
5173
!!noctisLilacConfig.dark,
5274
() => noctisLilac(),
75+
noctisLilacConfig,
76+
);
77+
addTheme(
78+
draculaConfig.name,
79+
"Dracula",
80+
!!draculaConfig.dark,
81+
() => dracula(),
82+
draculaConfig,
5383
);
54-
addTheme(draculaConfig.name, "Dracula", !!draculaConfig.dark, () => dracula());
55-
addTheme(githubDarkConfig.name, "GitHub Dark", !!githubDarkConfig.dark, () =>
56-
githubDark(),
84+
addTheme(
85+
githubDarkConfig.name,
86+
"GitHub Dark",
87+
!!githubDarkConfig.dark,
88+
() => githubDark(),
89+
githubDarkConfig,
5790
);
58-
addTheme(githubLightConfig.name, "GitHub Light", !!githubLightConfig.dark, () =>
59-
githubLight(),
91+
addTheme(
92+
githubLightConfig.name,
93+
"GitHub Light",
94+
!!githubLightConfig.dark,
95+
() => githubLight(),
96+
githubLightConfig,
6097
);
6198
addTheme(
6299
solarizedDarkConfig.name,
63100
"Solarized Dark",
64101
!!solarizedDarkConfig.dark,
65102
() => solarizedDark(),
103+
solarizedDarkConfig,
66104
);
67105
addTheme(
68106
solarizedLightConfig.name,
69107
"Solarized Light",
70108
!!solarizedLightConfig.dark,
71109
() => solarizedLight(),
110+
solarizedLightConfig,
72111
);
73112
addTheme(
74113
tokyoNightDayConfig.name,
75114
"Tokyo Night Day",
76115
!!tokyoNightDayConfig.dark,
77116
() => tokyoNightDay(),
117+
tokyoNightDayConfig,
78118
);
79-
addTheme(tokyoNightConfig.name, "Tokyo Night", !!tokyoNightConfig.dark, () =>
80-
tokyoNight(),
119+
addTheme(
120+
tokyoNightConfig.name,
121+
"Tokyo Night",
122+
!!tokyoNightConfig.dark,
123+
() => tokyoNight(),
124+
tokyoNightConfig,
81125
);
82-
addTheme(noctisLilacConfig.name, "Noctis Lilac", !!noctisLilacConfig.dark, () =>
83-
noctisLilac(),
126+
addTheme(
127+
monokaiConfig.name,
128+
"Monokai",
129+
!!monokaiConfig.dark,
130+
() => monokai(),
131+
monokaiConfig,
84132
);
85-
addTheme(monokaiConfig.name, "Monokai", !!monokaiConfig.dark, () => monokai());
86-
addTheme(vscodeDarkConfig.name, "VS Code Dark", !!vscodeDarkConfig.dark, () =>
87-
vscodeDark(),
133+
addTheme(
134+
vscodeDarkConfig.name,
135+
"VS Code Dark",
136+
!!vscodeDarkConfig.dark,
137+
() => vscodeDark(),
138+
vscodeDarkConfig,
88139
);
89140

90-
export default { getThemes, getThemeById, addTheme, removeTheme };
141+
export default {
142+
getThemes,
143+
getThemeById,
144+
getThemeConfig,
145+
addTheme,
146+
removeTheme,
147+
};

src/components/referencesPanel/styles.scss

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -377,109 +377,4 @@
377377
}
378378
}
379379
}
380-
}
381-
382-
.ref-preview {
383-
.tok-keyword {
384-
color: #c678dd;
385-
}
386-
387-
.tok-operator {
388-
color: #56b6c2;
389-
}
390-
391-
.tok-number {
392-
color: #d19a66;
393-
}
394-
395-
.tok-string {
396-
color: #98c379;
397-
}
398-
399-
.tok-comment {
400-
color: #5c6370;
401-
font-style: italic;
402-
}
403-
404-
.tok-variableName {
405-
color: #e06c75;
406-
}
407-
408-
.tok-propertyName {
409-
color: #61afef;
410-
}
411-
412-
.tok-typeName {
413-
color: #e5c07b;
414-
}
415-
416-
.tok-className {
417-
color: #e5c07b;
418-
}
419-
420-
.tok-function {
421-
color: #61afef;
422-
}
423-
424-
.tok-bool {
425-
color: #d19a66;
426-
}
427-
428-
.tok-null {
429-
color: #d19a66;
430-
}
431-
432-
.tok-punctuation {
433-
color: #abb2bf;
434-
}
435-
436-
.tok-definition {
437-
color: #e06c75;
438-
}
439-
440-
.tok-labelName {
441-
color: #e06c75;
442-
}
443-
444-
.tok-namespace {
445-
color: #e5c07b;
446-
}
447-
448-
.tok-macroName {
449-
color: #c678dd;
450-
}
451-
452-
.tok-atom {
453-
color: #d19a66;
454-
}
455-
456-
.tok-meta {
457-
color: #abb2bf;
458-
}
459-
460-
.tok-heading {
461-
color: #e06c75;
462-
font-weight: bold;
463-
}
464-
465-
.tok-link {
466-
color: #61afef;
467-
text-decoration: underline;
468-
}
469-
470-
.tok-strikethrough {
471-
text-decoration: line-through;
472-
}
473-
474-
.tok-emphasis {
475-
font-style: italic;
476-
}
477-
478-
.tok-strong {
479-
font-weight: bold;
480-
}
481-
482-
.tok-invalid {
483-
color: #ff6b6b;
484-
}
485380
}

src/components/referencesPanel/utils.js

Lines changed: 6 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { EditorView } from "@codemirror/view";
2-
import { classHighlighter, highlightCode } from "@lezer/highlight";
3-
import { getModeForPath } from "cm/modelist";
42
import Sidebar from "components/sidebar";
5-
import DOMPurify from "dompurify";
63
import openFile from "lib/openFile";
4+
import {
5+
clearHighlightCache,
6+
highlightLine,
7+
sanitize,
8+
} from "utils/codeHighlight";
79
import helpers from "utils/helpers";
810

9-
export function sanitize(text) {
10-
if (!text) return "";
11-
return DOMPurify.sanitize(text, { ALLOWED_TAGS: [] });
12-
}
11+
export { sanitize, clearHighlightCache };
1312

1413
export function getFilename(uri) {
1514
if (!uri) return "";
@@ -27,85 +26,6 @@ export function escapeRegExp(string) {
2726
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2827
}
2928

30-
const highlightCache = new Map();
31-
32-
async function getLanguageParser(uri) {
33-
const mode = getModeForPath(uri);
34-
if (!mode?.languageExtension) return null;
35-
36-
try {
37-
const langExt = await mode.languageExtension();
38-
if (!langExt) return null;
39-
40-
const langArray = Array.isArray(langExt) ? langExt : [langExt];
41-
for (const ext of langArray) {
42-
if (ext && typeof ext === "object" && "language" in ext) {
43-
return ext.language.parser;
44-
}
45-
}
46-
} catch (e) {
47-
console.warn("Failed to get language parser for", uri, e);
48-
}
49-
return null;
50-
}
51-
52-
async function highlightLine(text, uri, symbolName) {
53-
if (!text || !text.trim()) return "";
54-
55-
const cacheKey = `${uri}:${text}`;
56-
if (highlightCache.has(cacheKey)) {
57-
return highlightCache.get(cacheKey);
58-
}
59-
60-
const trimmedText = text.trim();
61-
62-
try {
63-
const parser = await getLanguageParser(uri);
64-
if (parser) {
65-
const tree = parser.parse(trimmedText);
66-
let result = "";
67-
68-
highlightCode(
69-
trimmedText,
70-
tree,
71-
classHighlighter,
72-
(code, classes) => {
73-
if (classes) {
74-
result += `<span class="${classes}">${sanitize(code)}</span>`;
75-
} else {
76-
result += sanitize(code);
77-
}
78-
},
79-
() => {},
80-
);
81-
82-
if (result) {
83-
const highlighted = addSymbolHighlight(result, symbolName);
84-
highlightCache.set(cacheKey, highlighted);
85-
return highlighted;
86-
}
87-
}
88-
} catch (e) {
89-
console.warn("Highlighting failed for", uri, e);
90-
}
91-
92-
const escaped = sanitize(trimmedText);
93-
const highlighted = addSymbolHighlight(escaped, symbolName);
94-
highlightCache.set(cacheKey, highlighted);
95-
return highlighted;
96-
}
97-
98-
function addSymbolHighlight(html, symbol) {
99-
if (!symbol) return html;
100-
const escapedSymbol = escapeRegExp(sanitize(symbol));
101-
const regex = new RegExp(`(${escapedSymbol})`, "gi");
102-
return html.replace(regex, '<span class="symbol-match">$1</span>');
103-
}
104-
105-
export function clearHighlightCache() {
106-
highlightCache.clear();
107-
}
108-
10929
export function groupReferencesByFile(references) {
11030
const grouped = {};
11131
for (const ref of references) {

src/lib/acode.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,13 @@ export default class Acode {
107107

108108
// CodeMirror editor theme API for plugins
109109
const editorThemesModule = {
110-
register: (id, caption, isDark, getExtension) =>
111-
cmThemeRegistry.addTheme(id, caption, isDark, getExtension),
110+
register: (id, caption, isDark, getExtension, config = null) =>
111+
cmThemeRegistry.addTheme(id, caption, isDark, getExtension, config),
112112
unregister: (id) => cmThemeRegistry.removeTheme(id),
113113
list: () => cmThemeRegistry.getThemes(),
114114
apply: (id) => editorManager?.editor?.setTheme?.(id),
115115
get: (id) => cmThemeRegistry.getThemeById(id),
116+
getConfig: (id) => cmThemeRegistry.getThemeConfig(id),
116117
};
117118

118119
const sidebarAppsModule = {

0 commit comments

Comments
 (0)