@opensumi/ide-theme 2.21.13 → 2.22.0
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/lib/browser/icon-theme-data.js.map +1 -1
- package/lib/browser/icon-theme-store.js.map +1 -1
- package/lib/browser/icon.service.d.ts +3 -1
- package/lib/browser/icon.service.d.ts.map +1 -1
- package/lib/browser/icon.service.js +56 -24
- package/lib/browser/icon.service.js.map +1 -1
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/semantic-tokens-registry.js.map +1 -1
- package/lib/browser/style.service.js.map +1 -1
- package/lib/browser/theme-data.js +7 -7
- package/lib/browser/theme-data.js.map +1 -1
- package/lib/browser/theme-store.js.map +1 -1
- package/lib/browser/theme.contribution.js +3 -3
- package/lib/browser/theme.contribution.js.map +1 -1
- package/lib/browser/workbench.theme.service.js +2 -2
- package/lib/browser/workbench.theme.service.js.map +1 -1
- package/lib/common/color-tokens/basic-color.d.ts +1 -1
- package/lib/common/color-tokens/basic-color.d.ts.map +1 -1
- package/lib/common/color-tokens/editor.d.ts +13 -0
- package/lib/common/color-tokens/editor.d.ts.map +1 -1
- package/lib/common/color-tokens/editor.js +35 -1
- package/lib/common/color-tokens/editor.js.map +1 -1
- package/lib/common/color.js +40 -40
- package/lib/common/color.js.map +1 -1
- package/lib/common/mocks/theme.service.js.map +1 -1
- package/lib/common/plistParser.js +40 -40
- package/lib/common/plistParser.js.map +1 -1
- package/lib/common/semantic-tokens-registry.d.ts +7 -7
- package/lib/common/semantic-tokens-registry.d.ts.map +1 -1
- package/lib/common/theme.service.d.ts +26 -6
- package/lib/common/theme.service.d.ts.map +1 -1
- package/lib/common/theme.service.js.map +1 -1
- package/package.json +11 -10
- package/src/browser/default-theme.ts +547 -0
- package/src/browser/icon-theme-data.ts +294 -0
- package/src/browser/icon-theme-store.ts +38 -0
- package/src/browser/icon.less +15 -0
- package/src/browser/icon.service.ts +457 -0
- package/src/browser/index.ts +45 -0
- package/src/browser/semantic-tokens-registry.ts +217 -0
- package/src/browser/style.service.ts +51 -0
- package/src/browser/theme-data.ts +719 -0
- package/src/browser/theme-store.ts +95 -0
- package/src/browser/theme.contribution.ts +343 -0
- package/src/browser/workbench.theme.service.ts +703 -0
- package/src/common/color-registry.ts +52 -0
- package/src/common/color-tokens/activity-bar.ts +122 -0
- package/src/common/color-tokens/badge.ts +31 -0
- package/src/common/color-tokens/base.ts +90 -0
- package/src/common/color-tokens/basic-color.ts +9 -0
- package/src/common/color-tokens/breadcrumb.ts +60 -0
- package/src/common/color-tokens/button.ts +69 -0
- package/src/common/color-tokens/charts.ts +68 -0
- package/src/common/color-tokens/checkbox.ts +23 -0
- package/src/common/color-tokens/custom/actionbar.ts +51 -0
- package/src/common/color-tokens/custom/activity-bar.ts +16 -0
- package/src/common/color-tokens/custom/badge.ts +30 -0
- package/src/common/color-tokens/custom/base.ts +111 -0
- package/src/common/color-tokens/custom/button.ts +359 -0
- package/src/common/color-tokens/custom/checkbox.ts +36 -0
- package/src/common/color-tokens/custom/decoration.ts +71 -0
- package/src/common/color-tokens/custom/editor.ts +27 -0
- package/src/common/color-tokens/custom/extension.ts +9 -0
- package/src/common/color-tokens/custom/icon.ts +30 -0
- package/src/common/color-tokens/custom/index.ts +26 -0
- package/src/common/color-tokens/custom/input.ts +48 -0
- package/src/common/color-tokens/custom/menu.ts +61 -0
- package/src/common/color-tokens/custom/modal.ts +57 -0
- package/src/common/color-tokens/custom/notification.ts +16 -0
- package/src/common/color-tokens/custom/panel.ts +112 -0
- package/src/common/color-tokens/custom/popover.ts +28 -0
- package/src/common/color-tokens/custom/select.ts +155 -0
- package/src/common/color-tokens/custom/settings.ts +32 -0
- package/src/common/color-tokens/custom/statusbar.ts +16 -0
- package/src/common/color-tokens/custom/tab.ts +31 -0
- package/src/common/color-tokens/custom/tooltip.ts +55 -0
- package/src/common/color-tokens/custom/tree.ts +106 -0
- package/src/common/color-tokens/debug.ts +103 -0
- package/src/common/color-tokens/debugToolbar.ts +134 -0
- package/src/common/color-tokens/dropdown.ts +27 -0
- package/src/common/color-tokens/editor.ts +945 -0
- package/src/common/color-tokens/index.ts +35 -0
- package/src/common/color-tokens/input.ts +105 -0
- package/src/common/color-tokens/list-tree.ts +205 -0
- package/src/common/color-tokens/menu-bar.ts +43 -0
- package/src/common/color-tokens/menu.ts +53 -0
- package/src/common/color-tokens/merge-conflict.ts +145 -0
- package/src/common/color-tokens/minimap.ts +99 -0
- package/src/common/color-tokens/notification.ts +169 -0
- package/src/common/color-tokens/panel.ts +177 -0
- package/src/common/color-tokens/pick-view.ts +96 -0
- package/src/common/color-tokens/picker.ts +15 -0
- package/src/common/color-tokens/progress-bar.ts +12 -0
- package/src/common/color-tokens/quick-input.ts +57 -0
- package/src/common/color-tokens/scrollbar.ts +42 -0
- package/src/common/color-tokens/settings.ts +126 -0
- package/src/common/color-tokens/sidebar.ts +121 -0
- package/src/common/color-tokens/snippet.ts +33 -0
- package/src/common/color-tokens/status-bar.ts +350 -0
- package/src/common/color-tokens/tab.ts +346 -0
- package/src/common/color-tokens/testing.ts +105 -0
- package/src/common/color-tokens/text.ts +41 -0
- package/src/common/color-tokens/title-bar.ts +62 -0
- package/src/common/color-tokens/toolbar.ts +28 -0
- package/src/common/color-tokens/welcome-page.ts +27 -0
- package/src/common/color.ts +647 -0
- package/src/common/default-themes.ts +273 -0
- package/src/common/event.ts +9 -0
- package/src/common/index.ts +8 -0
- package/src/common/mocks/theme.service.ts +55 -0
- package/src/common/plistParser.ts +525 -0
- package/src/common/semantic-tokens-registry.ts +439 -0
- package/src/common/style.ts +9 -0
- package/src/common/theme.service.ts +363 -0
- package/src/common/themeCompatibility.ts +95 -0
- package/src/common/utils.ts +195 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
import { IRawThemeSetting } from 'vscode-textmate';
|
|
2
|
+
|
|
3
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
4
|
+
import {
|
|
5
|
+
URI,
|
|
6
|
+
localize,
|
|
7
|
+
parseWithComments,
|
|
8
|
+
ILogger,
|
|
9
|
+
IReporterService,
|
|
10
|
+
REPORT_NAME,
|
|
11
|
+
isString,
|
|
12
|
+
CharCode,
|
|
13
|
+
isBoolean,
|
|
14
|
+
} from '@opensumi/ide-core-browser';
|
|
15
|
+
import { IFileServiceClient } from '@opensumi/ide-file-service/lib/common';
|
|
16
|
+
import * as monaco from '@opensumi/monaco-editor-core/esm/vs/editor/editor.api';
|
|
17
|
+
|
|
18
|
+
import { Color } from '../common/color';
|
|
19
|
+
import { editorBackground, editorForeground } from '../common/color-tokens/editor';
|
|
20
|
+
import { parse as parsePList } from '../common/plistParser';
|
|
21
|
+
import {
|
|
22
|
+
createMatchers,
|
|
23
|
+
ISemanticTokenRegistry,
|
|
24
|
+
ITextMateThemingRule,
|
|
25
|
+
Matcher,
|
|
26
|
+
MatcherWithPriority,
|
|
27
|
+
nameMatcher,
|
|
28
|
+
noMatch,
|
|
29
|
+
parseClassifierString,
|
|
30
|
+
ProbeScope,
|
|
31
|
+
SemanticTokenRule,
|
|
32
|
+
TextMateThemingRuleDefinitions,
|
|
33
|
+
TokenStyle,
|
|
34
|
+
TokenStyleDefinition,
|
|
35
|
+
TokenStyleDefinitions,
|
|
36
|
+
TokenStyleValue,
|
|
37
|
+
} from '../common/semantic-tokens-registry';
|
|
38
|
+
import {
|
|
39
|
+
ITokenThemeRule,
|
|
40
|
+
IColors,
|
|
41
|
+
BuiltinTheme,
|
|
42
|
+
ITokenColorizationRule,
|
|
43
|
+
IColorMap,
|
|
44
|
+
getThemeType,
|
|
45
|
+
IThemeData,
|
|
46
|
+
ColorScheme,
|
|
47
|
+
ISemanticTokenColorizationSetting,
|
|
48
|
+
VS_LIGHT_THEME_NAME,
|
|
49
|
+
HC_BLACK_THEME_NAME,
|
|
50
|
+
HC_LIGHT_THEME_NAME,
|
|
51
|
+
} from '../common/theme.service';
|
|
52
|
+
import { convertSettings } from '../common/themeCompatibility';
|
|
53
|
+
|
|
54
|
+
function getScopeMatcher(rule: ITextMateThemingRule): Matcher<ProbeScope> {
|
|
55
|
+
const ruleScope = rule.scope;
|
|
56
|
+
if (!ruleScope || !rule.settings) {
|
|
57
|
+
return noMatch;
|
|
58
|
+
}
|
|
59
|
+
const matchers: MatcherWithPriority<ProbeScope>[] = [];
|
|
60
|
+
if (Array.isArray(ruleScope)) {
|
|
61
|
+
for (const rs of ruleScope) {
|
|
62
|
+
createMatchers(rs, nameMatcher, matchers);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
createMatchers(ruleScope, nameMatcher, matchers);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (matchers.length === 0) {
|
|
69
|
+
return noMatch;
|
|
70
|
+
}
|
|
71
|
+
return (scope: ProbeScope) => {
|
|
72
|
+
let max = matchers[0].matcher(scope);
|
|
73
|
+
for (let i = 1; i < matchers.length; i++) {
|
|
74
|
+
max = Math.max(max, matchers[i].matcher(scope));
|
|
75
|
+
}
|
|
76
|
+
return max;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isSemanticTokenColorizationSetting(style: any): style is ISemanticTokenColorizationSetting {
|
|
81
|
+
return (
|
|
82
|
+
style &&
|
|
83
|
+
(isString(style.foreground) ||
|
|
84
|
+
isString(style.fontStyle) ||
|
|
85
|
+
isBoolean(style.italic) ||
|
|
86
|
+
isBoolean(style.underline) ||
|
|
87
|
+
isBoolean(style.bold))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@Injectable({ multiple: true })
|
|
92
|
+
export class ThemeData implements IThemeData {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
themeSettings: IRawThemeSetting[] = [];
|
|
96
|
+
colors: IColors = {};
|
|
97
|
+
encodedTokensColors: string[] = [];
|
|
98
|
+
rules: ITokenThemeRule[] = [];
|
|
99
|
+
base: BuiltinTheme = 'vs-dark';
|
|
100
|
+
inherit = false;
|
|
101
|
+
|
|
102
|
+
colorMap: IColorMap = {};
|
|
103
|
+
private hasDefaultTokens = false;
|
|
104
|
+
private customSettings: IRawThemeSetting[] = [];
|
|
105
|
+
|
|
106
|
+
private semanticHighlighting?: boolean;
|
|
107
|
+
|
|
108
|
+
private themeTokenScopeMatchers: Matcher<ProbeScope>[] | undefined;
|
|
109
|
+
|
|
110
|
+
private tokenColorIndex: TokenColorIndex | undefined = undefined; // created on demand
|
|
111
|
+
|
|
112
|
+
private semanticTokenRules: SemanticTokenRule[] = [];
|
|
113
|
+
|
|
114
|
+
@Autowired(IFileServiceClient)
|
|
115
|
+
private fileServiceClient: IFileServiceClient;
|
|
116
|
+
|
|
117
|
+
@Autowired(ILogger)
|
|
118
|
+
private readonly logger: ILogger;
|
|
119
|
+
|
|
120
|
+
@Autowired(IReporterService)
|
|
121
|
+
private reporter: IReporterService;
|
|
122
|
+
|
|
123
|
+
@Autowired(ISemanticTokenRegistry)
|
|
124
|
+
protected readonly semanticTokenRegistry: ISemanticTokenRegistry;
|
|
125
|
+
|
|
126
|
+
public initializeFromData(data) {
|
|
127
|
+
this.id = data.id;
|
|
128
|
+
this.name = data.name;
|
|
129
|
+
this.colors = data.colors;
|
|
130
|
+
this.encodedTokensColors = data.encodedTokensColors;
|
|
131
|
+
this.themeSettings = data.themeSettings;
|
|
132
|
+
this.rules = data.rules;
|
|
133
|
+
this.base = data.base;
|
|
134
|
+
this.inherit = data.inherit;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get type(): ColorScheme {
|
|
138
|
+
switch (this.base) {
|
|
139
|
+
case VS_LIGHT_THEME_NAME:
|
|
140
|
+
return ColorScheme.LIGHT;
|
|
141
|
+
case HC_BLACK_THEME_NAME:
|
|
142
|
+
return ColorScheme.HIGH_CONTRAST_DARK;
|
|
143
|
+
case HC_LIGHT_THEME_NAME:
|
|
144
|
+
return ColorScheme.HIGH_CONTRAST_LIGHT;
|
|
145
|
+
default:
|
|
146
|
+
return ColorScheme.DARK;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public async initializeThemeData(id: string, name: string, base: string, themeLocation: URI) {
|
|
151
|
+
this.id = id;
|
|
152
|
+
this.name = name;
|
|
153
|
+
this.base = base as BuiltinTheme;
|
|
154
|
+
await this.loadColorTheme(themeLocation, this.themeSettings, this.colorMap);
|
|
155
|
+
// eslint-disable-next-line guard-for-in
|
|
156
|
+
for (const key in this.colorMap) {
|
|
157
|
+
this.colors[key] = Color.Format.CSS.formatHexA(this.colorMap[key]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public loadCustomTokens(customSettings: ITokenColorizationRule[]) {
|
|
162
|
+
this.rules = [];
|
|
163
|
+
// const affectedScopes: string[] = customSettings.map((setting) => setting.scope).filter((t) => !!t);
|
|
164
|
+
this.doInitTokenRules();
|
|
165
|
+
for (const setting of customSettings) {
|
|
166
|
+
this.transform(setting, (rule) => {
|
|
167
|
+
const existIndex = this.rules.findIndex((item) => item.token === rule.token);
|
|
168
|
+
if (existIndex > -1) {
|
|
169
|
+
this.rules.splice(existIndex, 1, rule);
|
|
170
|
+
} else {
|
|
171
|
+
this.rules.push(rule);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
this.customSettings = customSettings;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public get settings() {
|
|
179
|
+
return this.themeSettings.concat(this.customSettings);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public get tokenColors(): IRawThemeSetting[] {
|
|
183
|
+
const result: IRawThemeSetting[] = [];
|
|
184
|
+
const foreground = this.colorMap[editorForeground];
|
|
185
|
+
const background = this.colorMap[editorBackground];
|
|
186
|
+
result.push({
|
|
187
|
+
settings: {
|
|
188
|
+
foreground: normalizeColor(foreground),
|
|
189
|
+
background: normalizeColor(background),
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
let hasDefaultTokens = false;
|
|
194
|
+
function addRule(rule: ITextMateThemingRule) {
|
|
195
|
+
if (rule.scope && rule.settings) {
|
|
196
|
+
if (rule.scope === 'token.info-token') {
|
|
197
|
+
hasDefaultTokens = true;
|
|
198
|
+
}
|
|
199
|
+
result.push({
|
|
200
|
+
scope: rule.scope,
|
|
201
|
+
settings: {
|
|
202
|
+
foreground: normalizeColor(rule.settings.foreground),
|
|
203
|
+
background: normalizeColor(rule.settings.background),
|
|
204
|
+
fontStyle: rule.settings.fontStyle,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.settings.map(addRule);
|
|
210
|
+
if (!hasDefaultTokens) {
|
|
211
|
+
defaultThemeColors[this.type].forEach(addRule);
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// transform settings & init rules
|
|
217
|
+
protected doInitTokenRules() {
|
|
218
|
+
for (const setting of this.themeSettings) {
|
|
219
|
+
this.transform(setting, (rule) => this.rules.push(rule));
|
|
220
|
+
}
|
|
221
|
+
if (!this.hasDefaultTokens) {
|
|
222
|
+
defaultThemeColors[getThemeType(this.base)].forEach((setting) => {
|
|
223
|
+
this.transform(setting, (rule) => this.rules.push(rule));
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private safeParseJSON(content) {
|
|
229
|
+
let json;
|
|
230
|
+
try {
|
|
231
|
+
json = parseWithComments(content);
|
|
232
|
+
return json;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
return this.logger.error('Theme data parse error.', content);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private readSemanticTokenRule(
|
|
239
|
+
selectorString: string,
|
|
240
|
+
settings: ISemanticTokenColorizationSetting | string | boolean | undefined,
|
|
241
|
+
): SemanticTokenRule | undefined {
|
|
242
|
+
const selector = this.semanticTokenRegistry.parseTokenSelector(selectorString);
|
|
243
|
+
let style: TokenStyle | undefined;
|
|
244
|
+
if (typeof settings === 'string') {
|
|
245
|
+
style = TokenStyle.fromSettings(settings, undefined);
|
|
246
|
+
} else if (isSemanticTokenColorizationSetting(settings)) {
|
|
247
|
+
style = TokenStyle.fromSettings(
|
|
248
|
+
settings.foreground,
|
|
249
|
+
settings.fontStyle,
|
|
250
|
+
settings.bold,
|
|
251
|
+
settings.underline,
|
|
252
|
+
settings.italic,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
if (style) {
|
|
256
|
+
return { selector, style };
|
|
257
|
+
}
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private async loadColorTheme(
|
|
262
|
+
themeLocation: URI,
|
|
263
|
+
resultRules: ITokenColorizationRule[],
|
|
264
|
+
resultColors: IColorMap,
|
|
265
|
+
): Promise<any> {
|
|
266
|
+
const timer = this.reporter.time(REPORT_NAME.THEME_LOAD);
|
|
267
|
+
const ret = await this.fileServiceClient.readFile(themeLocation.toString());
|
|
268
|
+
const themeContent = ret.content.toString();
|
|
269
|
+
timer.timeEnd(themeLocation.toString());
|
|
270
|
+
const themeLocationPath = themeLocation.path.toString();
|
|
271
|
+
if (/\.json$/.test(themeLocationPath)) {
|
|
272
|
+
const theme = this.safeParseJSON(themeContent);
|
|
273
|
+
let includeCompletes: Promise<any> = Promise.resolve(null);
|
|
274
|
+
if (theme.include) {
|
|
275
|
+
this.inherit = true;
|
|
276
|
+
// http 的不作支持
|
|
277
|
+
const includePath = themeLocation.path.dir.join(theme.include.replace(/^\.\//, ''));
|
|
278
|
+
const includeLocation = themeLocation.withPath(includePath);
|
|
279
|
+
includeCompletes = this.loadColorTheme(includeLocation, resultRules, resultColors);
|
|
280
|
+
}
|
|
281
|
+
await includeCompletes;
|
|
282
|
+
// settings
|
|
283
|
+
if (Array.isArray(theme.settings)) {
|
|
284
|
+
convertSettings(theme.settings, resultRules, resultColors);
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
// semanticHighlighting enable/disabled
|
|
288
|
+
this.semanticHighlighting = theme.semanticHighlighting;
|
|
289
|
+
|
|
290
|
+
// semanticTokenColors
|
|
291
|
+
const semanticTokenColors = theme.semanticTokenColors;
|
|
292
|
+
if (semanticTokenColors && typeof semanticTokenColors === 'object') {
|
|
293
|
+
// eslint-disable-next-line guard-for-in
|
|
294
|
+
for (const key in semanticTokenColors) {
|
|
295
|
+
try {
|
|
296
|
+
const rule = this.readSemanticTokenRule(key, semanticTokenColors[key]);
|
|
297
|
+
if (rule) {
|
|
298
|
+
this.semanticTokenRules.push(rule);
|
|
299
|
+
}
|
|
300
|
+
} catch (err) {
|
|
301
|
+
// ignore error
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// colors
|
|
307
|
+
const colors = theme.colors;
|
|
308
|
+
if (colors) {
|
|
309
|
+
if (typeof colors !== 'object') {
|
|
310
|
+
return Promise.reject(
|
|
311
|
+
new Error(
|
|
312
|
+
localize(
|
|
313
|
+
'error.invalidformat.colors',
|
|
314
|
+
"Problem parsing color theme file: {0}. Property 'colors' is not of type 'object'.",
|
|
315
|
+
themeLocation.toString(),
|
|
316
|
+
),
|
|
317
|
+
),
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
// new JSON color themes format
|
|
321
|
+
// eslint-disable-next-line guard-for-in
|
|
322
|
+
for (const colorId in colors) {
|
|
323
|
+
const colorHex = colors[colorId];
|
|
324
|
+
if (typeof colorHex === 'string') {
|
|
325
|
+
// ignore colors tht are null
|
|
326
|
+
resultColors[colorId] = Color.fromHex(colors[colorId]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// tokenColors
|
|
331
|
+
const tokenColors = theme.tokenColors;
|
|
332
|
+
if (tokenColors) {
|
|
333
|
+
if (Array.isArray(tokenColors)) {
|
|
334
|
+
resultRules.push(...tokenColors);
|
|
335
|
+
return null;
|
|
336
|
+
} else if (typeof tokenColors === 'string') {
|
|
337
|
+
const tokenPath = themeLocation.path.dir.join(tokenColors.replace(/^\.\//, ''));
|
|
338
|
+
const tokenLocation = themeLocation.withPath(tokenPath);
|
|
339
|
+
// tmTheme
|
|
340
|
+
return this.loadSyntaxTokens(tokenLocation);
|
|
341
|
+
} else {
|
|
342
|
+
return Promise.reject(
|
|
343
|
+
new Error(
|
|
344
|
+
localize(
|
|
345
|
+
'error.invalidformat.tokenColors',
|
|
346
|
+
"Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file",
|
|
347
|
+
themeLocation.toString(),
|
|
348
|
+
),
|
|
349
|
+
),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return null;
|
|
355
|
+
} else {
|
|
356
|
+
return this.loadSyntaxTokens(themeLocation);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private async loadSyntaxTokens(themeLocation: URI): Promise<ITokenColorizationRule[]> {
|
|
361
|
+
const ret = await this.fileServiceClient.readFile(themeLocation.toString());
|
|
362
|
+
try {
|
|
363
|
+
const theme = parsePList(ret.content.toString());
|
|
364
|
+
const settings = theme.settings;
|
|
365
|
+
if (!Array.isArray(settings)) {
|
|
366
|
+
return Promise.reject(
|
|
367
|
+
new Error(
|
|
368
|
+
localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array."),
|
|
369
|
+
),
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
convertSettings(settings, this.themeSettings, this.colorMap);
|
|
373
|
+
return Promise.resolve(settings);
|
|
374
|
+
} catch (e) {
|
|
375
|
+
return Promise.reject(new Error(localize('error.cannotparse', 'Problems parsing tmTheme file: {0}', e.message)));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 将 ITokenColorizationRule 转化为 ITokenThemeRule
|
|
380
|
+
protected transform(tokenColor: ITokenColorizationRule, acceptor: (rule: monaco.editor.ITokenThemeRule) => void) {
|
|
381
|
+
if (tokenColor.scope && tokenColor.settings && tokenColor.scope === 'token.info-token') {
|
|
382
|
+
this.hasDefaultTokens = true;
|
|
383
|
+
}
|
|
384
|
+
if (typeof tokenColor.scope === 'undefined') {
|
|
385
|
+
tokenColor.scope = [''];
|
|
386
|
+
} else if (typeof tokenColor.scope === 'string') {
|
|
387
|
+
// tokenColor.scope = tokenColor.scope.split(',').map((scope: string) => scope.trim()); // ?
|
|
388
|
+
tokenColor.scope = [tokenColor.scope];
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
for (const scope of tokenColor.scope) {
|
|
392
|
+
// Converting numbers into a format that monaco understands
|
|
393
|
+
const settings = Object.keys(tokenColor.settings).reduce((previous: { [key: string]: string }, current) => {
|
|
394
|
+
let value: string = tokenColor.settings[current];
|
|
395
|
+
if (current !== 'foreground' && current !== 'background' && current !== 'fontStyle') {
|
|
396
|
+
delete tokenColor.settings[current];
|
|
397
|
+
return previous;
|
|
398
|
+
}
|
|
399
|
+
if (current !== 'fontStyle' && typeof value === 'string') {
|
|
400
|
+
if (value.indexOf('#') === -1) {
|
|
401
|
+
// 兼容 white、red 类型色值
|
|
402
|
+
const color = Color[value];
|
|
403
|
+
if (color) {
|
|
404
|
+
value = Color.Format.CSS.formatHex(color);
|
|
405
|
+
tokenColor.settings[current] = value;
|
|
406
|
+
} else {
|
|
407
|
+
// 去掉主题瞎写的值
|
|
408
|
+
delete tokenColor.settings[current];
|
|
409
|
+
return previous;
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
const color = Color.fromHex(value);
|
|
413
|
+
value = Color.Format.CSS.formatHex(color);
|
|
414
|
+
// 主题只会识别 Hex 的色值
|
|
415
|
+
tokenColor.settings[current] = value;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
previous[current] = value;
|
|
419
|
+
return previous;
|
|
420
|
+
}, {});
|
|
421
|
+
|
|
422
|
+
acceptor({
|
|
423
|
+
...settings,
|
|
424
|
+
token: scope,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
public getTokenColorIndex(): TokenColorIndex {
|
|
430
|
+
// collect all colors that tokens can have
|
|
431
|
+
if (!this.tokenColorIndex) {
|
|
432
|
+
const index = new TokenColorIndex();
|
|
433
|
+
|
|
434
|
+
for (const color of this.encodedTokensColors) {
|
|
435
|
+
index.add(color);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
this.tokenColors.forEach((rule) => {
|
|
439
|
+
index.add(rule.settings.foreground);
|
|
440
|
+
index.add(rule.settings.background);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
this.semanticTokenRules.forEach((r) => index.add(r.style.foreground));
|
|
444
|
+
this.semanticTokenRegistry.getTokenStylingDefaultRules().forEach((r) => {
|
|
445
|
+
const defaultColor = r.defaults[this.type];
|
|
446
|
+
if (defaultColor && typeof defaultColor === 'object') {
|
|
447
|
+
index.add(defaultColor.foreground);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
this.tokenColorIndex = index;
|
|
452
|
+
}
|
|
453
|
+
return this.tokenColorIndex;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
public getTokenStyle(
|
|
457
|
+
type: string,
|
|
458
|
+
modifiers: string[],
|
|
459
|
+
language: string,
|
|
460
|
+
useDefault = true,
|
|
461
|
+
definitions: TokenStyleDefinitions = {},
|
|
462
|
+
): TokenStyle | undefined {
|
|
463
|
+
const result: any = {
|
|
464
|
+
foreground: undefined,
|
|
465
|
+
bold: undefined,
|
|
466
|
+
underline: undefined,
|
|
467
|
+
italic: undefined,
|
|
468
|
+
};
|
|
469
|
+
const score = {
|
|
470
|
+
foreground: -1,
|
|
471
|
+
bold: -1,
|
|
472
|
+
underline: -1,
|
|
473
|
+
italic: -1,
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
let hasUndefinedStyleProperty = false;
|
|
477
|
+
// eslint-disable-next-line guard-for-in
|
|
478
|
+
for (const k in score) {
|
|
479
|
+
const key = k as keyof TokenStyle;
|
|
480
|
+
if (score[key] === -1) {
|
|
481
|
+
hasUndefinedStyleProperty = true;
|
|
482
|
+
} else {
|
|
483
|
+
score[key] = Number.MAX_VALUE; // set it to the max, so it won't be replaced by a default
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function _processStyle(matchScore: number, style: TokenStyle, definition: TokenStyleDefinition) {
|
|
488
|
+
if (style.foreground && score.foreground <= matchScore) {
|
|
489
|
+
score.foreground = matchScore;
|
|
490
|
+
result.foreground = style.foreground;
|
|
491
|
+
definitions.foreground = definition;
|
|
492
|
+
}
|
|
493
|
+
for (const p of ['bold', 'underline', 'italic']) {
|
|
494
|
+
const property = p as keyof TokenStyle;
|
|
495
|
+
const info = style[property];
|
|
496
|
+
if (info !== undefined) {
|
|
497
|
+
if (score[property] <= matchScore) {
|
|
498
|
+
score[property] = matchScore;
|
|
499
|
+
result[property] = info;
|
|
500
|
+
definitions[property] = definition;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function _processSemanticTokenRule(rule: SemanticTokenRule) {
|
|
507
|
+
const matchScore = rule.selector.match(type, modifiers, language);
|
|
508
|
+
if (matchScore >= 0) {
|
|
509
|
+
_processStyle(matchScore, rule.style, rule);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
this.semanticTokenRules.forEach(_processSemanticTokenRule);
|
|
514
|
+
|
|
515
|
+
if (hasUndefinedStyleProperty) {
|
|
516
|
+
for (const rule of this.semanticTokenRegistry.getTokenStylingDefaultRules()) {
|
|
517
|
+
const matchScore = rule.selector.match(type, modifiers, language);
|
|
518
|
+
if (matchScore >= 0) {
|
|
519
|
+
let style: TokenStyle | undefined;
|
|
520
|
+
if (rule.defaults.scopesToProbe) {
|
|
521
|
+
style = this.resolveScopes(rule.defaults.scopesToProbe);
|
|
522
|
+
if (style) {
|
|
523
|
+
_processStyle(matchScore, style, rule.defaults.scopesToProbe);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (!style && useDefault !== false) {
|
|
528
|
+
const tokenStyleValue = rule.defaults[this.type];
|
|
529
|
+
style = this.resolveTokenStyleValue(tokenStyleValue);
|
|
530
|
+
if (style) {
|
|
531
|
+
_processStyle(matchScore, style, tokenStyleValue!);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return TokenStyle.fromData(result);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* @param tokenStyleValue Resolve a tokenStyleValue in the context of a theme
|
|
543
|
+
*/
|
|
544
|
+
public resolveTokenStyleValue(tokenStyleValue: TokenStyleValue | undefined): TokenStyle | undefined {
|
|
545
|
+
if (tokenStyleValue === undefined) {
|
|
546
|
+
return undefined;
|
|
547
|
+
} else if (typeof tokenStyleValue === 'string') {
|
|
548
|
+
const { type, modifiers, language } = parseClassifierString(tokenStyleValue, '');
|
|
549
|
+
return this.getTokenStyle(type, modifiers, language);
|
|
550
|
+
} else if (typeof tokenStyleValue === 'object') {
|
|
551
|
+
return tokenStyleValue;
|
|
552
|
+
}
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
public resolveScopes(scopes: ProbeScope[], definitions?: TextMateThemingRuleDefinitions): TokenStyle | undefined {
|
|
557
|
+
if (!this.themeTokenScopeMatchers) {
|
|
558
|
+
this.themeTokenScopeMatchers = this.themeSettings.map(getScopeMatcher);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
for (const scope of scopes) {
|
|
562
|
+
let foreground: string | undefined;
|
|
563
|
+
let fontStyle: string | undefined;
|
|
564
|
+
let foregroundScore = -1;
|
|
565
|
+
let fontStyleScore = -1;
|
|
566
|
+
let fontStyleThemingRule: ITextMateThemingRule | undefined;
|
|
567
|
+
let foregroundThemingRule: ITextMateThemingRule | undefined;
|
|
568
|
+
|
|
569
|
+
function findTokenStyleForScopeInScopes(
|
|
570
|
+
scopeMatchers: Matcher<ProbeScope>[],
|
|
571
|
+
themingRules: ITextMateThemingRule[],
|
|
572
|
+
) {
|
|
573
|
+
for (let i = 0; i < scopeMatchers.length; i++) {
|
|
574
|
+
const score = scopeMatchers[i](scope);
|
|
575
|
+
if (score >= 0) {
|
|
576
|
+
const themingRule = themingRules[i];
|
|
577
|
+
const settings = themingRules[i].settings;
|
|
578
|
+
if (score >= foregroundScore && settings.foreground) {
|
|
579
|
+
foreground = settings.foreground;
|
|
580
|
+
foregroundScore = score;
|
|
581
|
+
foregroundThemingRule = themingRule;
|
|
582
|
+
}
|
|
583
|
+
if (score >= fontStyleScore && isString(settings.fontStyle)) {
|
|
584
|
+
fontStyle = settings.fontStyle;
|
|
585
|
+
fontStyleScore = score;
|
|
586
|
+
fontStyleThemingRule = themingRule;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeSettings);
|
|
593
|
+
|
|
594
|
+
if (foreground !== undefined || fontStyle !== undefined) {
|
|
595
|
+
if (definitions) {
|
|
596
|
+
definitions.foreground = foregroundThemingRule;
|
|
597
|
+
definitions.bold = definitions.italic = definitions.underline = fontStyleThemingRule;
|
|
598
|
+
definitions.scope = scope;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return TokenStyle.fromSettings(foreground, fontStyle);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return undefined;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function normalizeColor(color: string | Color | undefined | null): string | undefined {
|
|
609
|
+
if (!color) {
|
|
610
|
+
return undefined;
|
|
611
|
+
}
|
|
612
|
+
if (typeof color !== 'string') {
|
|
613
|
+
color = Color.Format.CSS.formatHexA(color, true);
|
|
614
|
+
}
|
|
615
|
+
const len = color.length;
|
|
616
|
+
if (color.charCodeAt(0) !== CharCode.Hash || (len !== 4 && len !== 5 && len !== 7 && len !== 9)) {
|
|
617
|
+
return undefined;
|
|
618
|
+
}
|
|
619
|
+
const result = [CharCode.Hash];
|
|
620
|
+
|
|
621
|
+
for (let i = 1; i < len; i++) {
|
|
622
|
+
const upper = hexUpper(color.charCodeAt(i));
|
|
623
|
+
if (!upper) {
|
|
624
|
+
return undefined;
|
|
625
|
+
}
|
|
626
|
+
result.push(upper);
|
|
627
|
+
if (len === 4 || len === 5) {
|
|
628
|
+
result.push(upper);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (result.length === 9 && result[7] === CharCode.F && result[8] === CharCode.F) {
|
|
633
|
+
result.length = 7;
|
|
634
|
+
}
|
|
635
|
+
return String.fromCharCode(...result);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function hexUpper(charCode: CharCode): number {
|
|
639
|
+
if (
|
|
640
|
+
(charCode >= CharCode.Digit0 && charCode <= CharCode.Digit9) ||
|
|
641
|
+
(charCode >= CharCode.A && charCode <= CharCode.F)
|
|
642
|
+
) {
|
|
643
|
+
return charCode;
|
|
644
|
+
} else if (charCode >= CharCode.a && charCode <= CharCode.f) {
|
|
645
|
+
return charCode - CharCode.a + CharCode.A;
|
|
646
|
+
}
|
|
647
|
+
return 0;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
class TokenColorIndex {
|
|
651
|
+
private _lastColorId: number;
|
|
652
|
+
private _id2color: string[];
|
|
653
|
+
private _color2id: { [color: string]: number };
|
|
654
|
+
|
|
655
|
+
constructor() {
|
|
656
|
+
this._lastColorId = 0;
|
|
657
|
+
this._id2color = [];
|
|
658
|
+
this._color2id = Object.create(null);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
public add(color: string | Color | undefined): number {
|
|
662
|
+
color = normalizeColor(color);
|
|
663
|
+
if (color === undefined) {
|
|
664
|
+
return 0;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
let value = this._color2id[color];
|
|
668
|
+
if (value) {
|
|
669
|
+
return value;
|
|
670
|
+
}
|
|
671
|
+
value = ++this._lastColorId;
|
|
672
|
+
this._color2id[color] = value;
|
|
673
|
+
this._id2color[value] = color;
|
|
674
|
+
return value;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
public get(color: string | Color | undefined): number {
|
|
678
|
+
color = normalizeColor(color);
|
|
679
|
+
if (color === undefined) {
|
|
680
|
+
return 0;
|
|
681
|
+
}
|
|
682
|
+
const value = this._color2id[color];
|
|
683
|
+
if (value) {
|
|
684
|
+
return value;
|
|
685
|
+
}
|
|
686
|
+
return 0;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
public asArray(): string[] {
|
|
690
|
+
return this._id2color.slice(0);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = {
|
|
695
|
+
light: [
|
|
696
|
+
{ scope: 'token.info-token', settings: { foreground: '#316bcd' } },
|
|
697
|
+
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
|
|
698
|
+
{ scope: 'token.error-token', settings: { foreground: '#cd3131' } },
|
|
699
|
+
{ scope: 'token.debug-token', settings: { foreground: '#800080' } },
|
|
700
|
+
],
|
|
701
|
+
dark: [
|
|
702
|
+
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
|
|
703
|
+
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
|
|
704
|
+
{ scope: 'token.error-token', settings: { foreground: '#f44747' } },
|
|
705
|
+
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } },
|
|
706
|
+
],
|
|
707
|
+
hcLight: [
|
|
708
|
+
{ scope: 'token.info-token', settings: { foreground: '#316bcd' } },
|
|
709
|
+
{ scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
|
|
710
|
+
{ scope: 'token.error-token', settings: { foreground: '#cd3131' } },
|
|
711
|
+
{ scope: 'token.debug-token', settings: { foreground: '#800080' } },
|
|
712
|
+
],
|
|
713
|
+
hcDark: [
|
|
714
|
+
{ scope: 'token.info-token', settings: { foreground: '#6796e6' } },
|
|
715
|
+
{ scope: 'token.warn-token', settings: { foreground: '#008000' } },
|
|
716
|
+
{ scope: 'token.error-token', settings: { foreground: '#FF0000' } },
|
|
717
|
+
{ scope: 'token.debug-token', settings: { foreground: '#b267e6' } },
|
|
718
|
+
],
|
|
719
|
+
};
|