aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/load_theme_colors.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/load_theme_colors.ts')
-rw-r--r--editors/code/src/load_theme_colors.ts108
1 files changed, 108 insertions, 0 deletions
diff --git a/editors/code/src/load_theme_colors.ts b/editors/code/src/load_theme_colors.ts
new file mode 100644
index 000000000..73fabbf54
--- /dev/null
+++ b/editors/code/src/load_theme_colors.ts
@@ -0,0 +1,108 @@
1import * as fs from 'fs';
2import * as jsonc from 'jsonc-parser';
3import * as path from 'path';
4import * as vscode from 'vscode';
5
6export interface TextMateRuleSettings {
7 foreground?: string;
8 background?: string;
9 fontStyle?: string;
10}
11
12// Load all textmate scopes in the currently active theme
13export function loadThemeColors(): Map<string, TextMateRuleSettings> {
14 // Find out current color theme
15 const themeName = vscode.workspace
16 .getConfiguration('workbench')
17 .get('colorTheme');
18
19 if (typeof themeName !== 'string') {
20 // console.warn('workbench.colorTheme is', themeName)
21 return new Map();
22 }
23 return loadThemeNamed(themeName);
24}
25
26function loadThemeNamed(themeName: string): Map<string, TextMateRuleSettings> {
27 function isTheme(extension: vscode.Extension<any>): boolean {
28 return (
29 extension.extensionKind === vscode.ExtensionKind.UI &&
30 extension.packageJSON.contributes &&
31 extension.packageJSON.contributes.themes
32 );
33 }
34
35 let themePaths = vscode.extensions.all
36 .filter(isTheme)
37 .flatMap(ext => {
38 return ext.packageJSON.contributes.themes
39 .filter((it: any) => (it.id || it.label) === themeName)
40 .map((it: any) => path.join(ext.extensionPath, it.path));
41 })
42
43 const res = new Map();
44 for (const themePath of themePaths) {
45 mergeInto(res, loadThemeFile(themePath))
46 }
47
48 const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations');
49 mergeInto(res, loadColors(customizations?.textMateRules ?? []))
50
51 return res;
52}
53
54function loadThemeFile(themePath: string): Map<string, TextMateRuleSettings> {
55 let text;
56 try {
57 text = fs.readFileSync(themePath, 'utf8')
58 } catch {
59 return new Map();
60 }
61 const obj = jsonc.parse(text);
62 const tokenColors = obj?.tokenColors ?? [];
63 const res = loadColors(tokenColors);
64
65 for (const include in obj?.include ?? []) {
66 const includePath = path.join(path.dirname(themePath), include);
67 const tmp = loadThemeFile(includePath);
68 mergeInto(res, tmp);
69 }
70
71 return res;
72}
73
74interface TextMateRule {
75 scope: string | string[];
76 settings: TextMateRuleSettings;
77}
78
79function loadColors(textMateRules: TextMateRule[]): Map<string, TextMateRuleSettings> {
80 const res = new Map();
81 for (const rule of textMateRules) {
82 const scopes = typeof rule.scope === 'string'
83 ? [rule.scope]
84 : rule.scope;
85 for (const scope of scopes) {
86 res.set(scope, rule.settings)
87 }
88 }
89 return res
90}
91
92function mergeRuleSettings(
93 defaultSetting: TextMateRuleSettings | undefined,
94 override: TextMateRuleSettings,
95): TextMateRuleSettings {
96 return {
97 foreground: defaultSetting?.foreground ?? override.foreground,
98 background: defaultSetting?.background ?? override.background,
99 fontStyle: defaultSetting?.fontStyle ?? override.fontStyle,
100 }
101}
102
103function mergeInto(dst: Map<string, TextMateRuleSettings>, addition: Map<string, TextMateRuleSettings>) {
104 addition.forEach((value, key) => {
105 const merged = mergeRuleSettings(dst.get(key), value)
106 dst.set(key, merged)
107 })
108}