1 import * as fs from 'fs';
2 import * as jsonc from 'jsonc-parser';
3 import * as path from 'path';
4 import * as vscode from 'vscode';
6 export interface TextMateRuleSettings {
12 // Load all textmate scopes in the currently active theme
13 export function loadThemeColors(): Map<string, TextMateRuleSettings> {
14 // Find out current color theme
15 const themeName = vscode.workspace
16 .getConfiguration('workbench')
19 if (typeof themeName !== 'string') {
20 // console.warn('workbench.colorTheme is', themeName)
23 return loadThemeNamed(themeName);
26 function loadThemeNamed(themeName: string): Map<string, TextMateRuleSettings> {
27 function isTheme(extension: vscode.Extension<any>): boolean {
29 extension.extensionKind === vscode.ExtensionKind.UI &&
30 extension.packageJSON.contributes &&
31 extension.packageJSON.contributes.themes
35 let themePaths = vscode.extensions.all
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));
43 const res = new Map();
44 for (const themePath of themePaths) {
45 mergeInto(res, loadThemeFile(themePath))
48 const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations');
49 mergeInto(res, loadColors(customizations?.textMateRules ?? []))
54 function loadThemeFile(themePath: string): Map<string, TextMateRuleSettings> {
57 text = fs.readFileSync(themePath, 'utf8')
61 const obj = jsonc.parse(text);
62 const tokenColors = obj?.tokenColors ?? [];
63 const res = loadColors(tokenColors);
65 for (const include in obj?.include ?? []) {
66 const includePath = path.join(path.dirname(themePath), include);
67 const tmp = loadThemeFile(includePath);
74 interface TextMateRule {
75 scope: string | string[];
76 settings: TextMateRuleSettings;
79 function loadColors(textMateRules: TextMateRule[]): Map<string, TextMateRuleSettings> {
80 const res = new Map();
81 for (const rule of textMateRules) {
82 const scopes = typeof rule.scope === 'string'
85 for (const scope of scopes) {
86 res.set(scope, rule.settings)
92 function mergeRuleSettings(
93 defaultSetting: TextMateRuleSettings | undefined,
94 override: TextMateRuleSettings,
95 ): TextMateRuleSettings {
97 foreground: defaultSetting?.foreground ?? override.foreground,
98 background: defaultSetting?.background ?? override.background,
99 fontStyle: defaultSetting?.fontStyle ?? override.fontStyle,
103 function mergeInto(dst: Map<string, TextMateRuleSettings>, addition: Map<string, TextMateRuleSettings>) {
104 addition.forEach((value, key) => {
105 const merged = mergeRuleSettings(dst.get(key), value)