aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/scopes.ts
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-10-24 16:25:23 +0100
committerSeivan Heidari <[email protected]>2019-10-24 16:25:23 +0100
commit3e8616cf6df5ba6e5dceba8b834dc63c20bac4d4 (patch)
treebce2c26d159b4c48eceb3ddce5a3c51cbbda904f /editors/code/src/scopes.ts
parent95cf5c86fae3adf3bb38521905bf357450125709 (diff)
Proof of concept theming and 'tokenColorCustomizations' support.
Diffstat (limited to 'editors/code/src/scopes.ts')
-rw-r--r--editors/code/src/scopes.ts142
1 files changed, 142 insertions, 0 deletions
diff --git a/editors/code/src/scopes.ts b/editors/code/src/scopes.ts
new file mode 100644
index 000000000..19d309828
--- /dev/null
+++ b/editors/code/src/scopes.ts
@@ -0,0 +1,142 @@
1import * as fs from 'fs'
2import * as jsonc from 'jsonc-parser'
3import * as path from 'path'
4import * as vscode from 'vscode'
5
6
7
8export interface TextMateRule {
9 scope: string | string[]
10 settings: TextMateRuleSettings
11}
12
13export interface TextMateRuleSettings {
14 foreground: string | undefined
15 background: string | undefined
16 fontStyle: string | undefined
17}
18
19// Current theme colors
20const colors = new Map<string, TextMateRuleSettings>()
21
22export function find(scope: string): TextMateRuleSettings | undefined {
23 return colors.get(scope)
24}
25
26// Load all textmate scopes in the currently active theme
27export function load() {
28 // Remove any previous theme
29 colors.clear()
30 // Find out current color theme
31 const themeName = vscode.workspace.getConfiguration('workbench').get('colorTheme')
32
33 if (typeof themeName !== 'string') {
34 console.warn('workbench.colorTheme is', themeName)
35 return
36 }
37 // Try to load colors from that theme
38 try {
39 loadThemeNamed(themeName)
40 } catch (e) {
41 console.warn('failed to load theme', themeName, e)
42 }
43}
44
45// Find current theme on disk
46function loadThemeNamed(themeName: string) {
47 for (const extension of vscode.extensions.all) {
48 const extensionPath: string = extension.extensionPath
49 const extensionPackageJsonPath: string = path.join(extensionPath, 'package.json')
50 if (!checkFileExists(extensionPackageJsonPath)) {
51 continue
52 }
53 const packageJsonText: string = readFileText(extensionPackageJsonPath)
54 const packageJson: any = jsonc.parse(packageJsonText)
55 if (packageJson.contributes && packageJson.contributes.themes) {
56 for (const theme of packageJson.contributes.themes) {
57 const id = theme.id || theme.label
58 if (id === themeName) {
59 const themeRelativePath: string = theme.path
60 const themeFullPath: string = path.join(extensionPath, themeRelativePath)
61 loadThemeFile(themeFullPath)
62 }
63 }
64 }
65
66 const customization: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations');
67 if (customization && customization.textMateRules) {
68 loadColors(customization.textMateRules)
69 }
70 }
71}
72
73function loadThemeFile(themePath: string) {
74 if (checkFileExists(themePath)) {
75 const themeContentText: string = readFileText(themePath)
76 const themeContent: any = jsonc.parse(themeContentText)
77
78 if (themeContent && themeContent.tokenColors) {
79 loadColors(themeContent.tokenColors)
80 if (themeContent.include) {
81 // parse included theme file
82 const includedThemePath: string = path.join(path.dirname(themePath), themeContent.include)
83 loadThemeFile(includedThemePath)
84 }
85 }
86 }
87}
88function mergeRuleSettings(defaultRule: TextMateRuleSettings, override: TextMateRuleSettings): TextMateRuleSettings {
89 const mergedRule = defaultRule;
90 if (override.background) {
91 mergedRule.background = override.background
92 }
93 if (override.foreground) {
94 mergedRule.foreground = override.foreground
95 }
96 if (override.background) {
97 mergedRule.fontStyle = override.fontStyle
98 }
99 return mergedRule;
100}
101
102function loadColors(textMateRules: TextMateRule[]): void {
103 for (const rule of textMateRules) {
104
105 if (typeof rule.scope === 'string') {
106 const existingRule = colors.get(rule.scope);
107 if (existingRule) {
108 colors.set(rule.scope, mergeRuleSettings(existingRule, rule.settings))
109 }
110 else {
111 colors.set(rule.scope, rule.settings)
112 }
113 } else if (rule.scope instanceof Array) {
114 for (const scope of rule.scope) {
115 const existingRule = colors.get(scope);
116 if (existingRule) {
117 colors.set(scope, mergeRuleSettings(existingRule, rule.settings))
118 }
119 else {
120 colors.set(scope, rule.settings)
121 }
122 }
123 }
124 }
125}
126
127function checkFileExists(filePath: string): boolean {
128
129 const stats = fs.statSync(filePath);
130 if (stats && stats.isFile()) {
131 return true;
132 } else {
133 console.warn('no such file', filePath)
134 return false;
135 }
136
137
138}
139
140function readFileText(filePath: string, encoding: string = 'utf8'): string {
141 return fs.readFileSync(filePath, encoding);
142} \ No newline at end of file