@codingame/monaco-vscode-theme-service-override 1.82.4 → 1.82.5-next.1

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.
@@ -0,0 +1,866 @@
1
+ import { basename } from 'monaco-editor/esm/vs/base/common/path.js';
2
+ import * as json from 'monaco-editor/esm/vs/base/common/json.js';
3
+ import { Color } from 'monaco-editor/esm/vs/base/common/color.js';
4
+ import { THEME_SCOPE_OPEN_PAREN, THEME_SCOPE_CLOSE_PAREN, THEME_SCOPE_WILDCARD, themeScopeRegex, ExtensionData, VS_HC_LIGHT_THEME, VS_HC_THEME, VS_LIGHT_THEME } from 'vscode/vscode/vs/workbench/services/themes/common/workbenchThemeService';
5
+ import { convertSettings } from './themeCompatibility.js';
6
+ import * as nls from 'monaco-editor/esm/vs/nls.js';
7
+ import * as types from 'monaco-editor/esm/vs/base/common/types.js';
8
+ import * as resources from 'monaco-editor/esm/vs/base/common/resources.js';
9
+ import { Extensions, editorForeground, editorBackground } from 'monaco-editor/esm/vs/platform/theme/common/colorRegistry.js';
10
+ import { getThemeTypeSelector } from 'monaco-editor/esm/vs/platform/theme/common/themeService.js';
11
+ import { Registry } from 'monaco-editor/esm/vs/platform/registry/common/platform.js';
12
+ import { getParseErrorMessage } from 'vscode/vscode/vs/base/common/jsonErrorMessages';
13
+ import { parse } from './plistParser.js';
14
+ import { getTokenClassificationRegistry, TokenStyle, parseClassifierString, SemanticTokenRule } from 'vscode/vscode/vs/platform/theme/common/tokenClassificationRegistry';
15
+ import { createMatchers } from './textMateScopeMatcher.js';
16
+ import { ColorScheme } from 'monaco-editor/esm/vs/platform/theme/common/theme.js';
17
+
18
+ const colorRegistry = ( Registry.as(Extensions.ColorContribution));
19
+ const tokenClassificationRegistry = getTokenClassificationRegistry();
20
+ const tokenGroupToScopesMap = {
21
+ comments: ['comment', 'punctuation.definition.comment'],
22
+ strings: ['string', 'meta.embedded.assembly'],
23
+ keywords: ['keyword - keyword.operator', 'keyword.control', 'storage', 'storage.type'],
24
+ numbers: ['constant.numeric'],
25
+ types: ['entity.name.type', 'entity.name.class', 'support.type', 'support.class'],
26
+ functions: ['entity.name.function', 'support.function'],
27
+ variables: ['variable', 'entity.name.variable']
28
+ };
29
+ class ColorThemeData {
30
+ static { this.STORAGE_KEY = 'colorThemeData'; }
31
+ constructor(id, label, settingsId) {
32
+ this.themeTokenColors = [];
33
+ this.customTokenColors = [];
34
+ this.colorMap = {};
35
+ this.customColorMap = {};
36
+ this.semanticTokenRules = [];
37
+ this.customSemanticTokenRules = [];
38
+ this.textMateThemingRules = undefined;
39
+ this.tokenColorIndex = undefined;
40
+ this.id = id;
41
+ this.label = label;
42
+ this.settingsId = settingsId;
43
+ this.isLoaded = false;
44
+ }
45
+ get semanticHighlighting() {
46
+ if (this.customSemanticHighlighting !== undefined) {
47
+ return this.customSemanticHighlighting;
48
+ }
49
+ if (this.customSemanticHighlightingDeprecated !== undefined) {
50
+ return this.customSemanticHighlightingDeprecated;
51
+ }
52
+ return !!this.themeSemanticHighlighting;
53
+ }
54
+ get tokenColors() {
55
+ if (!this.textMateThemingRules) {
56
+ const result = [];
57
+ const foreground = this.getColor(editorForeground) || this.getDefault(editorForeground);
58
+ const background = this.getColor(editorBackground) || this.getDefault(editorBackground);
59
+ result.push({
60
+ settings: {
61
+ foreground: normalizeColor(foreground),
62
+ background: normalizeColor(background)
63
+ }
64
+ });
65
+ let hasDefaultTokens = false;
66
+ function addRule(rule) {
67
+ if (rule.scope && rule.settings) {
68
+ if (rule.scope === 'token.info-token') {
69
+ hasDefaultTokens = true;
70
+ }
71
+ result.push({ scope: rule.scope, settings: { foreground: normalizeColor(rule.settings.foreground), background: normalizeColor(rule.settings.background), fontStyle: rule.settings.fontStyle } });
72
+ }
73
+ }
74
+ this.themeTokenColors.forEach(addRule);
75
+ this.customTokenColors.forEach(addRule);
76
+ if (!hasDefaultTokens) {
77
+ defaultThemeColors[this.type].forEach(addRule);
78
+ }
79
+ this.textMateThemingRules = result;
80
+ }
81
+ return this.textMateThemingRules;
82
+ }
83
+ getColor(colorId, useDefault) {
84
+ let color = this.customColorMap[colorId];
85
+ if (color) {
86
+ return color;
87
+ }
88
+ color = this.colorMap[colorId];
89
+ if (useDefault !== false && types.isUndefined(color)) {
90
+ color = this.getDefault(colorId);
91
+ }
92
+ return color;
93
+ }
94
+ getTokenStyle(type, modifiers, language, useDefault = true, definitions = {}) {
95
+ const result = {
96
+ foreground: undefined,
97
+ bold: undefined,
98
+ underline: undefined,
99
+ strikethrough: undefined,
100
+ italic: undefined
101
+ };
102
+ const score = {
103
+ foreground: -1,
104
+ bold: -1,
105
+ underline: -1,
106
+ strikethrough: -1,
107
+ italic: -1
108
+ };
109
+ function _processStyle(matchScore, style, definition) {
110
+ if (style.foreground && score.foreground <= matchScore) {
111
+ score.foreground = matchScore;
112
+ result.foreground = style.foreground;
113
+ definitions.foreground = definition;
114
+ }
115
+ for (const p of ['bold', 'underline', 'strikethrough', 'italic']) {
116
+ const property = p;
117
+ const info = style[property];
118
+ if (info !== undefined) {
119
+ if (score[property] <= matchScore) {
120
+ score[property] = matchScore;
121
+ result[property] = info;
122
+ definitions[property] = definition;
123
+ }
124
+ }
125
+ }
126
+ }
127
+ function _processSemanticTokenRule(rule) {
128
+ const matchScore = rule.selector.match(type, modifiers, language);
129
+ if (matchScore >= 0) {
130
+ _processStyle(matchScore, rule.style, rule);
131
+ }
132
+ }
133
+ this.semanticTokenRules.forEach(_processSemanticTokenRule);
134
+ this.customSemanticTokenRules.forEach(_processSemanticTokenRule);
135
+ let hasUndefinedStyleProperty = false;
136
+ for (const k in score) {
137
+ const key = k;
138
+ if (score[key] === -1) {
139
+ hasUndefinedStyleProperty = true;
140
+ }
141
+ else {
142
+ score[key] = Number.MAX_VALUE;
143
+ }
144
+ }
145
+ if (hasUndefinedStyleProperty) {
146
+ for (const rule of tokenClassificationRegistry.getTokenStylingDefaultRules()) {
147
+ const matchScore = rule.selector.match(type, modifiers, language);
148
+ if (matchScore >= 0) {
149
+ let style;
150
+ if (rule.defaults.scopesToProbe) {
151
+ style = this.resolveScopes(rule.defaults.scopesToProbe);
152
+ if (style) {
153
+ _processStyle(matchScore, style, rule.defaults.scopesToProbe);
154
+ }
155
+ }
156
+ if (!style && useDefault !== false) {
157
+ const tokenStyleValue = rule.defaults[this.type];
158
+ style = this.resolveTokenStyleValue(tokenStyleValue);
159
+ if (style) {
160
+ _processStyle(matchScore, style, tokenStyleValue);
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ return TokenStyle.fromData(result);
167
+ }
168
+ resolveTokenStyleValue(tokenStyleValue) {
169
+ if (tokenStyleValue === undefined) {
170
+ return undefined;
171
+ }
172
+ else if (typeof tokenStyleValue === 'string') {
173
+ const { type, modifiers, language } = parseClassifierString(tokenStyleValue, '');
174
+ return this.getTokenStyle(type, modifiers, language);
175
+ }
176
+ else if (typeof tokenStyleValue === 'object') {
177
+ return tokenStyleValue;
178
+ }
179
+ return undefined;
180
+ }
181
+ getTokenColorIndex() {
182
+ if (!this.tokenColorIndex) {
183
+ const index = ( new TokenColorIndex());
184
+ this.tokenColors.forEach(rule => {
185
+ index.add(rule.settings.foreground);
186
+ index.add(rule.settings.background);
187
+ });
188
+ this.semanticTokenRules.forEach(r => index.add(r.style.foreground));
189
+ tokenClassificationRegistry.getTokenStylingDefaultRules().forEach(r => {
190
+ const defaultColor = r.defaults[this.type];
191
+ if (defaultColor && typeof defaultColor === 'object') {
192
+ index.add(defaultColor.foreground);
193
+ }
194
+ });
195
+ this.customSemanticTokenRules.forEach(r => index.add(r.style.foreground));
196
+ this.tokenColorIndex = index;
197
+ }
198
+ return this.tokenColorIndex;
199
+ }
200
+ get tokenColorMap() {
201
+ return this.getTokenColorIndex().asArray();
202
+ }
203
+ getTokenStyleMetadata(typeWithLanguage, modifiers, defaultLanguage, useDefault = true, definitions = {}) {
204
+ const { type, language } = parseClassifierString(typeWithLanguage, defaultLanguage);
205
+ const style = this.getTokenStyle(type, modifiers, language, useDefault, definitions);
206
+ if (!style) {
207
+ return undefined;
208
+ }
209
+ return {
210
+ foreground: this.getTokenColorIndex().get(style.foreground),
211
+ bold: style.bold,
212
+ underline: style.underline,
213
+ strikethrough: style.strikethrough,
214
+ italic: style.italic,
215
+ };
216
+ }
217
+ getTokenStylingRuleScope(rule) {
218
+ if (this.customSemanticTokenRules.indexOf(rule) !== -1) {
219
+ return 'setting';
220
+ }
221
+ if (this.semanticTokenRules.indexOf(rule) !== -1) {
222
+ return 'theme';
223
+ }
224
+ return undefined;
225
+ }
226
+ getDefault(colorId) {
227
+ return colorRegistry.resolveDefaultColor(colorId, this);
228
+ }
229
+ resolveScopes(scopes, definitions) {
230
+ if (!this.themeTokenScopeMatchers) {
231
+ this.themeTokenScopeMatchers = ( this.themeTokenColors.map(getScopeMatcher));
232
+ }
233
+ if (!this.customTokenScopeMatchers) {
234
+ this.customTokenScopeMatchers = ( this.customTokenColors.map(getScopeMatcher));
235
+ }
236
+ for (const scope of scopes) {
237
+ let foreground = undefined;
238
+ let fontStyle = undefined;
239
+ let foregroundScore = -1;
240
+ let fontStyleScore = -1;
241
+ let fontStyleThemingRule = undefined;
242
+ let foregroundThemingRule = undefined;
243
+ function findTokenStyleForScopeInScopes(scopeMatchers, themingRules) {
244
+ for (let i = 0; i < scopeMatchers.length; i++) {
245
+ const score = scopeMatchers[i](scope);
246
+ if (score >= 0) {
247
+ const themingRule = themingRules[i];
248
+ const settings = themingRules[i].settings;
249
+ if (score >= foregroundScore && settings.foreground) {
250
+ foreground = settings.foreground;
251
+ foregroundScore = score;
252
+ foregroundThemingRule = themingRule;
253
+ }
254
+ if (score >= fontStyleScore && types.isString(settings.fontStyle)) {
255
+ fontStyle = settings.fontStyle;
256
+ fontStyleScore = score;
257
+ fontStyleThemingRule = themingRule;
258
+ }
259
+ }
260
+ }
261
+ }
262
+ findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors);
263
+ findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors);
264
+ if (foreground !== undefined || fontStyle !== undefined) {
265
+ if (definitions) {
266
+ definitions.foreground = foregroundThemingRule;
267
+ definitions.bold = definitions.italic = definitions.underline = definitions.strikethrough = fontStyleThemingRule;
268
+ definitions.scope = scope;
269
+ }
270
+ return TokenStyle.fromSettings(foreground, fontStyle);
271
+ }
272
+ }
273
+ return undefined;
274
+ }
275
+ defines(colorId) {
276
+ return this.customColorMap.hasOwnProperty(colorId) || this.colorMap.hasOwnProperty(colorId);
277
+ }
278
+ setCustomizations(settings) {
279
+ this.setCustomColors(settings.colorCustomizations);
280
+ this.setCustomTokenColors(settings.tokenColorCustomizations);
281
+ this.setCustomSemanticTokenColors(settings.semanticTokenColorCustomizations);
282
+ }
283
+ setCustomColors(colors) {
284
+ this.customColorMap = {};
285
+ this.overwriteCustomColors(colors);
286
+ const themeSpecificColors = this.getThemeSpecificColors(colors);
287
+ if (types.isObject(themeSpecificColors)) {
288
+ this.overwriteCustomColors(themeSpecificColors);
289
+ }
290
+ this.tokenColorIndex = undefined;
291
+ this.textMateThemingRules = undefined;
292
+ this.customTokenScopeMatchers = undefined;
293
+ }
294
+ overwriteCustomColors(colors) {
295
+ for (const id in colors) {
296
+ const colorVal = colors[id];
297
+ if (typeof colorVal === 'string') {
298
+ this.customColorMap[id] = ( Color.fromHex(colorVal));
299
+ }
300
+ }
301
+ }
302
+ setCustomTokenColors(customTokenColors) {
303
+ this.customTokenColors = [];
304
+ this.customSemanticHighlightingDeprecated = undefined;
305
+ this.addCustomTokenColors(customTokenColors);
306
+ const themeSpecificTokenColors = this.getThemeSpecificColors(customTokenColors);
307
+ if (types.isObject(themeSpecificTokenColors)) {
308
+ this.addCustomTokenColors(themeSpecificTokenColors);
309
+ }
310
+ this.tokenColorIndex = undefined;
311
+ this.textMateThemingRules = undefined;
312
+ this.customTokenScopeMatchers = undefined;
313
+ }
314
+ setCustomSemanticTokenColors(semanticTokenColors) {
315
+ this.customSemanticTokenRules = [];
316
+ this.customSemanticHighlighting = undefined;
317
+ if (semanticTokenColors) {
318
+ this.customSemanticHighlighting = semanticTokenColors.enabled;
319
+ if (semanticTokenColors.rules) {
320
+ this.readSemanticTokenRules(semanticTokenColors.rules);
321
+ }
322
+ const themeSpecificColors = this.getThemeSpecificColors(semanticTokenColors);
323
+ if (types.isObject(themeSpecificColors)) {
324
+ if (themeSpecificColors.enabled !== undefined) {
325
+ this.customSemanticHighlighting = themeSpecificColors.enabled;
326
+ }
327
+ if (themeSpecificColors.rules) {
328
+ this.readSemanticTokenRules(themeSpecificColors.rules);
329
+ }
330
+ }
331
+ }
332
+ this.tokenColorIndex = undefined;
333
+ this.textMateThemingRules = undefined;
334
+ }
335
+ isThemeScope(key) {
336
+ return key.charAt(0) === THEME_SCOPE_OPEN_PAREN && key.charAt(key.length - 1) === THEME_SCOPE_CLOSE_PAREN;
337
+ }
338
+ isThemeScopeMatch(themeId) {
339
+ const themeIdFirstChar = themeId.charAt(0);
340
+ const themeIdLastChar = themeId.charAt(themeId.length - 1);
341
+ const themeIdPrefix = themeId.slice(0, -1);
342
+ const themeIdInfix = themeId.slice(1, -1);
343
+ const themeIdSuffix = themeId.slice(1);
344
+ return themeId === this.settingsId
345
+ || (this.settingsId.includes(themeIdInfix) && themeIdFirstChar === THEME_SCOPE_WILDCARD && themeIdLastChar === THEME_SCOPE_WILDCARD)
346
+ || (this.settingsId.startsWith(themeIdPrefix) && themeIdLastChar === THEME_SCOPE_WILDCARD)
347
+ || (this.settingsId.endsWith(themeIdSuffix) && themeIdFirstChar === THEME_SCOPE_WILDCARD);
348
+ }
349
+ getThemeSpecificColors(colors) {
350
+ let themeSpecificColors;
351
+ for (const key in colors) {
352
+ const scopedColors = colors[key];
353
+ if (this.isThemeScope(key) && scopedColors instanceof Object && !Array.isArray(scopedColors)) {
354
+ const themeScopeList = key.match(themeScopeRegex) || [];
355
+ for (const themeScope of themeScopeList) {
356
+ const themeId = themeScope.substring(1, themeScope.length - 1);
357
+ if (this.isThemeScopeMatch(themeId)) {
358
+ if (!themeSpecificColors) {
359
+ themeSpecificColors = {};
360
+ }
361
+ const scopedThemeSpecificColors = scopedColors;
362
+ for (const subkey in scopedThemeSpecificColors) {
363
+ const originalColors = themeSpecificColors[subkey];
364
+ const overrideColors = scopedThemeSpecificColors[subkey];
365
+ if (Array.isArray(originalColors) && Array.isArray(overrideColors)) {
366
+ themeSpecificColors[subkey] = originalColors.concat(overrideColors);
367
+ }
368
+ else if (overrideColors) {
369
+ themeSpecificColors[subkey] = overrideColors;
370
+ }
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ return themeSpecificColors;
377
+ }
378
+ readSemanticTokenRules(tokenStylingRuleSection) {
379
+ for (const key in tokenStylingRuleSection) {
380
+ if (!this.isThemeScope(key)) {
381
+ try {
382
+ const rule = readSemanticTokenRule(key, tokenStylingRuleSection[key]);
383
+ if (rule) {
384
+ this.customSemanticTokenRules.push(rule);
385
+ }
386
+ }
387
+ catch (e) {
388
+ }
389
+ }
390
+ }
391
+ }
392
+ addCustomTokenColors(customTokenColors) {
393
+ for (const tokenGroup in tokenGroupToScopesMap) {
394
+ const group = tokenGroup;
395
+ const value = customTokenColors[group];
396
+ if (value) {
397
+ const settings = typeof value === 'string' ? { foreground: value } : value;
398
+ const scopes = tokenGroupToScopesMap[group];
399
+ for (const scope of scopes) {
400
+ this.customTokenColors.push({ scope, settings });
401
+ }
402
+ }
403
+ }
404
+ if (Array.isArray(customTokenColors.textMateRules)) {
405
+ for (const rule of customTokenColors.textMateRules) {
406
+ if (rule.scope && rule.settings) {
407
+ this.customTokenColors.push(rule);
408
+ }
409
+ }
410
+ }
411
+ if (customTokenColors.semanticHighlighting !== undefined) {
412
+ this.customSemanticHighlightingDeprecated = customTokenColors.semanticHighlighting;
413
+ }
414
+ }
415
+ ensureLoaded(extensionResourceLoaderService) {
416
+ return !this.isLoaded ? this.load(extensionResourceLoaderService) : Promise.resolve(undefined);
417
+ }
418
+ reload(extensionResourceLoaderService) {
419
+ return this.load(extensionResourceLoaderService);
420
+ }
421
+ load(extensionResourceLoaderService) {
422
+ if (!this.location) {
423
+ return Promise.resolve(undefined);
424
+ }
425
+ this.themeTokenColors = [];
426
+ this.clearCaches();
427
+ const result = {
428
+ colors: {},
429
+ textMateRules: [],
430
+ semanticTokenRules: [],
431
+ semanticHighlighting: false
432
+ };
433
+ return _loadColorTheme(extensionResourceLoaderService, this.location, result).then(_ => {
434
+ this.isLoaded = true;
435
+ this.semanticTokenRules = result.semanticTokenRules;
436
+ this.colorMap = result.colors;
437
+ this.themeTokenColors = result.textMateRules;
438
+ this.themeSemanticHighlighting = result.semanticHighlighting;
439
+ });
440
+ }
441
+ clearCaches() {
442
+ this.tokenColorIndex = undefined;
443
+ this.textMateThemingRules = undefined;
444
+ this.themeTokenScopeMatchers = undefined;
445
+ this.customTokenScopeMatchers = undefined;
446
+ }
447
+ toStorage(storageService) {
448
+ const colorMapData = {};
449
+ for (const key in this.colorMap) {
450
+ colorMapData[key] = Color.Format.CSS.formatHexA(this.colorMap[key], true);
451
+ }
452
+ const value = JSON.stringify({
453
+ id: this.id,
454
+ label: this.label,
455
+ settingsId: this.settingsId,
456
+ themeTokenColors: ( this.themeTokenColors.map(tc => ({ settings: tc.settings, scope: tc.scope }))),
457
+ semanticTokenRules: ( this.semanticTokenRules.map(SemanticTokenRule.toJSONObject)),
458
+ extensionData: ExtensionData.toJSONObject(this.extensionData),
459
+ themeSemanticHighlighting: this.themeSemanticHighlighting,
460
+ colorMap: colorMapData,
461
+ watch: this.watch
462
+ });
463
+ storageService.store(ColorThemeData.STORAGE_KEY, value, 0 , 0 );
464
+ }
465
+ get baseTheme() {
466
+ return this.classNames[0];
467
+ }
468
+ get classNames() {
469
+ return this.id.split(' ');
470
+ }
471
+ get type() {
472
+ switch (this.baseTheme) {
473
+ case VS_LIGHT_THEME: return ColorScheme.LIGHT;
474
+ case VS_HC_THEME: return ColorScheme.HIGH_CONTRAST_DARK;
475
+ case VS_HC_LIGHT_THEME: return ColorScheme.HIGH_CONTRAST_LIGHT;
476
+ default: return ColorScheme.DARK;
477
+ }
478
+ }
479
+ static createUnloadedThemeForThemeType(themeType, colorMap) {
480
+ return ColorThemeData.createUnloadedTheme(getThemeTypeSelector(themeType), colorMap);
481
+ }
482
+ static createUnloadedTheme(id, colorMap) {
483
+ const themeData = ( new ColorThemeData(id, '', '__' + id));
484
+ themeData.isLoaded = false;
485
+ themeData.themeTokenColors = [];
486
+ themeData.watch = false;
487
+ if (colorMap) {
488
+ for (const id in colorMap) {
489
+ themeData.colorMap[id] = ( Color.fromHex(colorMap[id]));
490
+ }
491
+ }
492
+ return themeData;
493
+ }
494
+ static createLoadedEmptyTheme(id, settingsId) {
495
+ const themeData = ( new ColorThemeData(id, '', settingsId));
496
+ themeData.isLoaded = true;
497
+ themeData.themeTokenColors = [];
498
+ themeData.watch = false;
499
+ return themeData;
500
+ }
501
+ static fromStorageData(storageService) {
502
+ const input = storageService.get(ColorThemeData.STORAGE_KEY, 0 );
503
+ if (!input) {
504
+ return undefined;
505
+ }
506
+ try {
507
+ const data = JSON.parse(input);
508
+ const theme = ( new ColorThemeData('', '', ''));
509
+ for (const key in data) {
510
+ switch (key) {
511
+ case 'colorMap': {
512
+ const colorMapData = data[key];
513
+ for (const id in colorMapData) {
514
+ theme.colorMap[id] = ( Color.fromHex(colorMapData[id]));
515
+ }
516
+ break;
517
+ }
518
+ case 'themeTokenColors':
519
+ case 'id':
520
+ case 'label':
521
+ case 'settingsId':
522
+ case 'watch':
523
+ case 'themeSemanticHighlighting':
524
+ theme[key] = data[key];
525
+ break;
526
+ case 'semanticTokenRules': {
527
+ const rulesData = data[key];
528
+ if (Array.isArray(rulesData)) {
529
+ for (const d of rulesData) {
530
+ const rule = SemanticTokenRule.fromJSONObject(tokenClassificationRegistry, d);
531
+ if (rule) {
532
+ theme.semanticTokenRules.push(rule);
533
+ }
534
+ }
535
+ }
536
+ break;
537
+ }
538
+ case 'location':
539
+ break;
540
+ case 'extensionData':
541
+ theme.extensionData = ExtensionData.fromJSONObject(data.extensionData);
542
+ break;
543
+ }
544
+ }
545
+ if (!theme.id || !theme.settingsId) {
546
+ return undefined;
547
+ }
548
+ return theme;
549
+ }
550
+ catch (e) {
551
+ return undefined;
552
+ }
553
+ }
554
+ static fromExtensionTheme(theme, colorThemeLocation, extensionData) {
555
+ const baseTheme = theme['uiTheme'] || 'vs-dark';
556
+ const themeSelector = toCSSSelector(extensionData.extensionId, theme.path);
557
+ const id = `${baseTheme} ${themeSelector}`;
558
+ const label = theme.label || basename(theme.path);
559
+ const settingsId = theme.id || label;
560
+ const themeData = ( new ColorThemeData(id, label, settingsId));
561
+ themeData.description = theme.description;
562
+ themeData.watch = theme._watch === true;
563
+ themeData.location = colorThemeLocation;
564
+ themeData.extensionData = extensionData;
565
+ themeData.isLoaded = false;
566
+ return themeData;
567
+ }
568
+ }
569
+ function toCSSSelector(extensionId, path) {
570
+ if (path.startsWith('./')) {
571
+ path = path.substr(2);
572
+ }
573
+ let str = `${extensionId}-${path}`;
574
+ str = str.replace(/[^_a-zA-Z0-9-]/g, '-');
575
+ if (str.charAt(0).match(/[0-9-]/)) {
576
+ str = '_' + str;
577
+ }
578
+ return str;
579
+ }
580
+ async function _loadColorTheme(extensionResourceLoaderService, themeLocation, result) {
581
+ if (resources.extname(themeLocation) === '.json') {
582
+ const content = await extensionResourceLoaderService.readExtensionResource(themeLocation);
583
+ const errors = [];
584
+ const contentValue = json.parse(content, errors);
585
+ if (errors.length > 0) {
586
+ return Promise.reject(( new Error(( nls.localize(
587
+ 'error.cannotparsejson',
588
+ "Problems parsing JSON theme file: {0}",
589
+ ( errors.map(e => getParseErrorMessage(e.error))).join(', ')
590
+ )))));
591
+ }
592
+ else if (json.getNodeType(contentValue) !== 'object') {
593
+ return Promise.reject(( new Error(( nls.localize(
594
+ 'error.invalidformat',
595
+ "Invalid format for JSON theme file: Object expected."
596
+ )))));
597
+ }
598
+ if (contentValue.include) {
599
+ await _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), result);
600
+ }
601
+ if (Array.isArray(contentValue.settings)) {
602
+ convertSettings(contentValue.settings, result);
603
+ return null;
604
+ }
605
+ result.semanticHighlighting = result.semanticHighlighting || contentValue.semanticHighlighting;
606
+ const colors = contentValue.colors;
607
+ if (colors) {
608
+ if (typeof colors !== 'object') {
609
+ return Promise.reject(( new Error(( nls.localize(
610
+ { key: 'error.invalidformat.colors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] },
611
+ "Problem parsing color theme file: {0}. Property 'colors' is not of type 'object'.",
612
+ ( themeLocation.toString())
613
+ )))));
614
+ }
615
+ for (const colorId in colors) {
616
+ const colorHex = colors[colorId];
617
+ if (typeof colorHex === 'string') {
618
+ result.colors[colorId] = ( Color.fromHex(colors[colorId]));
619
+ }
620
+ }
621
+ }
622
+ const tokenColors = contentValue.tokenColors;
623
+ if (tokenColors) {
624
+ if (Array.isArray(tokenColors)) {
625
+ result.textMateRules.push(...tokenColors);
626
+ }
627
+ else if (typeof tokenColors === 'string') {
628
+ await _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), result);
629
+ }
630
+ else {
631
+ return Promise.reject(( new Error(( nls.localize(
632
+ { key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] },
633
+ "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file",
634
+ ( themeLocation.toString())
635
+ )))));
636
+ }
637
+ }
638
+ const semanticTokenColors = contentValue.semanticTokenColors;
639
+ if (semanticTokenColors && typeof semanticTokenColors === 'object') {
640
+ for (const key in semanticTokenColors) {
641
+ try {
642
+ const rule = readSemanticTokenRule(key, semanticTokenColors[key]);
643
+ if (rule) {
644
+ result.semanticTokenRules.push(rule);
645
+ }
646
+ }
647
+ catch (e) {
648
+ return Promise.reject(( new Error(( nls.localize(
649
+ { key: 'error.invalidformat.semanticTokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] },
650
+ "Problem parsing color theme file: {0}. Property 'semanticTokenColors' contains a invalid selector",
651
+ ( themeLocation.toString())
652
+ )))));
653
+ }
654
+ }
655
+ }
656
+ }
657
+ else {
658
+ return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, result);
659
+ }
660
+ }
661
+ function _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, result) {
662
+ return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => {
663
+ try {
664
+ const contentValue = parse(content);
665
+ const settings = contentValue.settings;
666
+ if (!Array.isArray(settings)) {
667
+ return Promise.reject(( new Error(( nls.localize(
668
+ 'error.plist.invalidformat',
669
+ "Problem parsing tmTheme file: {0}. 'settings' is not array."
670
+ )))));
671
+ }
672
+ convertSettings(settings, result);
673
+ return Promise.resolve(null);
674
+ }
675
+ catch (e) {
676
+ return Promise.reject(( new Error(( nls.localize('error.cannotparse', "Problems parsing tmTheme file: {0}", e.message)))));
677
+ }
678
+ }, error => {
679
+ return Promise.reject(( new Error(( nls.localize(
680
+ 'error.cannotload',
681
+ "Problems loading tmTheme file {0}: {1}",
682
+ ( themeLocation.toString()),
683
+ error.message
684
+ )))));
685
+ });
686
+ }
687
+ const defaultThemeColors = {
688
+ 'light': [
689
+ { scope: 'token.info-token', settings: { foreground: '#316bcd' } },
690
+ { scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
691
+ { scope: 'token.error-token', settings: { foreground: '#cd3131' } },
692
+ { scope: 'token.debug-token', settings: { foreground: '#800080' } }
693
+ ],
694
+ 'dark': [
695
+ { scope: 'token.info-token', settings: { foreground: '#6796e6' } },
696
+ { scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
697
+ { scope: 'token.error-token', settings: { foreground: '#f44747' } },
698
+ { scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
699
+ ],
700
+ 'hcLight': [
701
+ { scope: 'token.info-token', settings: { foreground: '#316bcd' } },
702
+ { scope: 'token.warn-token', settings: { foreground: '#cd9731' } },
703
+ { scope: 'token.error-token', settings: { foreground: '#cd3131' } },
704
+ { scope: 'token.debug-token', settings: { foreground: '#800080' } }
705
+ ],
706
+ 'hcDark': [
707
+ { scope: 'token.info-token', settings: { foreground: '#6796e6' } },
708
+ { scope: 'token.warn-token', settings: { foreground: '#008000' } },
709
+ { scope: 'token.error-token', settings: { foreground: '#FF0000' } },
710
+ { scope: 'token.debug-token', settings: { foreground: '#b267e6' } }
711
+ ]
712
+ };
713
+ const noMatch = (_scope) => -1;
714
+ function nameMatcher(identifers, scope) {
715
+ function findInIdents(s, lastIndent) {
716
+ for (let i = lastIndent - 1; i >= 0; i--) {
717
+ if (scopesAreMatching(s, identifers[i])) {
718
+ return i;
719
+ }
720
+ }
721
+ return -1;
722
+ }
723
+ if (scope.length < identifers.length) {
724
+ return -1;
725
+ }
726
+ let lastScopeIndex = scope.length - 1;
727
+ let lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], identifers.length);
728
+ if (lastIdentifierIndex >= 0) {
729
+ const score = (lastIdentifierIndex + 1) * 0x10000 + identifers[lastIdentifierIndex].length;
730
+ while (lastScopeIndex >= 0) {
731
+ lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], lastIdentifierIndex);
732
+ if (lastIdentifierIndex === -1) {
733
+ return -1;
734
+ }
735
+ }
736
+ return score;
737
+ }
738
+ return -1;
739
+ }
740
+ function scopesAreMatching(thisScopeName, scopeName) {
741
+ if (!thisScopeName) {
742
+ return false;
743
+ }
744
+ if (thisScopeName === scopeName) {
745
+ return true;
746
+ }
747
+ const len = scopeName.length;
748
+ return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === '.';
749
+ }
750
+ function getScopeMatcher(rule) {
751
+ const ruleScope = rule.scope;
752
+ if (!ruleScope || !rule.settings) {
753
+ return noMatch;
754
+ }
755
+ const matchers = [];
756
+ if (Array.isArray(ruleScope)) {
757
+ for (const rs of ruleScope) {
758
+ createMatchers(rs, nameMatcher, matchers);
759
+ }
760
+ }
761
+ else {
762
+ createMatchers(ruleScope, nameMatcher, matchers);
763
+ }
764
+ if (matchers.length === 0) {
765
+ return noMatch;
766
+ }
767
+ return (scope) => {
768
+ let max = matchers[0].matcher(scope);
769
+ for (let i = 1; i < matchers.length; i++) {
770
+ max = Math.max(max, matchers[i].matcher(scope));
771
+ }
772
+ return max;
773
+ };
774
+ }
775
+ function readSemanticTokenRule(selectorString, settings) {
776
+ const selector = tokenClassificationRegistry.parseTokenSelector(selectorString);
777
+ let style;
778
+ if (typeof settings === 'string') {
779
+ style = TokenStyle.fromSettings(settings, undefined);
780
+ }
781
+ else if (isSemanticTokenColorizationSetting(settings)) {
782
+ style = TokenStyle.fromSettings(settings.foreground, settings.fontStyle, settings.bold, settings.underline, settings.strikethrough, settings.italic);
783
+ }
784
+ if (style) {
785
+ return { selector, style };
786
+ }
787
+ return undefined;
788
+ }
789
+ function isSemanticTokenColorizationSetting(style) {
790
+ return style && (types.isString(style.foreground) || types.isString(style.fontStyle) || types.isBoolean(style.italic)
791
+ || types.isBoolean(style.underline) || types.isBoolean(style.strikethrough) || types.isBoolean(style.bold));
792
+ }
793
+ class TokenColorIndex {
794
+ constructor() {
795
+ this._lastColorId = 0;
796
+ this._id2color = [];
797
+ this._color2id = Object.create(null);
798
+ }
799
+ add(color) {
800
+ color = normalizeColor(color);
801
+ if (color === undefined) {
802
+ return 0;
803
+ }
804
+ let value = this._color2id[color];
805
+ if (value) {
806
+ return value;
807
+ }
808
+ value = ++this._lastColorId;
809
+ this._color2id[color] = value;
810
+ this._id2color[value] = color;
811
+ return value;
812
+ }
813
+ get(color) {
814
+ color = normalizeColor(color);
815
+ if (color === undefined) {
816
+ return 0;
817
+ }
818
+ const value = this._color2id[color];
819
+ if (value) {
820
+ return value;
821
+ }
822
+ console.log(`Color ${color} not in index.`);
823
+ return 0;
824
+ }
825
+ asArray() {
826
+ return this._id2color.slice(0);
827
+ }
828
+ }
829
+ function normalizeColor(color) {
830
+ if (!color) {
831
+ return undefined;
832
+ }
833
+ if (typeof color !== 'string') {
834
+ color = Color.Format.CSS.formatHexA(color, true);
835
+ }
836
+ const len = color.length;
837
+ if (color.charCodeAt(0) !== 35 || (len !== 4 && len !== 5 && len !== 7 && len !== 9)) {
838
+ return undefined;
839
+ }
840
+ const result = [35 ];
841
+ for (let i = 1; i < len; i++) {
842
+ const upper = hexUpper(color.charCodeAt(i));
843
+ if (!upper) {
844
+ return undefined;
845
+ }
846
+ result.push(upper);
847
+ if (len === 4 || len === 5) {
848
+ result.push(upper);
849
+ }
850
+ }
851
+ if (result.length === 9 && result[7] === 70 && result[8] === 70 ) {
852
+ result.length = 7;
853
+ }
854
+ return String.fromCharCode(...result);
855
+ }
856
+ function hexUpper(charCode) {
857
+ if (charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 70 ) {
858
+ return charCode;
859
+ }
860
+ else if (charCode >= 97 && charCode <= 102 ) {
861
+ return charCode - 97 + 65 ;
862
+ }
863
+ return 0;
864
+ }
865
+
866
+ export { ColorThemeData };