aboutsummaryrefslogtreecommitdiff
path: root/editors/code
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-31 13:11:49 +0000
committerGitHub <[email protected]>2019-12-31 13:11:49 +0000
commit46952985a087db5be5ca846b5109fccae8845df2 (patch)
treebb62a5d32f3999cd1bc430cef64ce13320f8132b /editors/code
parent7c4d4e113bc039712aa3996e57eaef19d12bd9ff (diff)
parent26bd7a896b4bbc4a2432df47dceff939aac921fa (diff)
Merge #2702
2702: Drop support for legacy colorization r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'editors/code')
-rw-r--r--editors/code/src/color_theme.ts123
-rw-r--r--editors/code/src/config.ts4
-rw-r--r--editors/code/src/highlighting.ts106
-rw-r--r--editors/code/src/scopes.ts108
-rw-r--r--editors/code/src/scopes_mapper.ts78
5 files changed, 164 insertions, 255 deletions
diff --git a/editors/code/src/color_theme.ts b/editors/code/src/color_theme.ts
new file mode 100644
index 000000000..1df7eba7a
--- /dev/null
+++ b/editors/code/src/color_theme.ts
@@ -0,0 +1,123 @@
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
12export class ColorTheme {
13 private rules: Map<string, TextMateRuleSettings> = new Map();
14
15 static load(): ColorTheme {
16 // Find out current color theme
17 const themeName = vscode.workspace
18 .getConfiguration('workbench')
19 .get('colorTheme');
20
21 if (typeof themeName !== 'string') {
22 // console.warn('workbench.colorTheme is', themeName)
23 return new ColorTheme();
24 }
25 return loadThemeNamed(themeName);
26 }
27
28 static fromRules(rules: TextMateRule[]): ColorTheme {
29 const res = new ColorTheme();
30 for (const rule of rules) {
31 const scopes = typeof rule.scope === 'string'
32 ? [rule.scope]
33 : rule.scope;
34 for (const scope of scopes) {
35 res.rules.set(scope, rule.settings)
36 }
37 }
38 return res
39 }
40
41 lookup(scopes: string[]): TextMateRuleSettings {
42 let res: TextMateRuleSettings = {}
43 for (const scope of scopes) {
44 this.rules.forEach((value, key) => {
45 if (scope.startsWith(key)) {
46 res = mergeRuleSettings(res, value)
47 }
48 })
49 }
50 return res
51 }
52
53 mergeFrom(other: ColorTheme) {
54 other.rules.forEach((value, key) => {
55 const merged = mergeRuleSettings(this.rules.get(key), value)
56 this.rules.set(key, merged)
57 })
58 }
59}
60
61function loadThemeNamed(themeName: string): ColorTheme {
62 function isTheme(extension: vscode.Extension<any>): boolean {
63 return (
64 extension.extensionKind === vscode.ExtensionKind.UI &&
65 extension.packageJSON.contributes &&
66 extension.packageJSON.contributes.themes
67 );
68 }
69
70 let themePaths = vscode.extensions.all
71 .filter(isTheme)
72 .flatMap(ext => {
73 return ext.packageJSON.contributes.themes
74 .filter((it: any) => (it.id || it.label) === themeName)
75 .map((it: any) => path.join(ext.extensionPath, it.path));
76 })
77
78 const res = new ColorTheme();
79 for (const themePath of themePaths) {
80 res.mergeFrom(loadThemeFile(themePath))
81 }
82
83 const customizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations');
84 res.mergeFrom(ColorTheme.fromRules(customizations?.textMateRules ?? []))
85
86 return res;
87}
88
89function loadThemeFile(themePath: string): ColorTheme {
90 let text;
91 try {
92 text = fs.readFileSync(themePath, 'utf8')
93 } catch {
94 return new ColorTheme();
95 }
96 const obj = jsonc.parse(text);
97 const tokenColors = obj?.tokenColors ?? [];
98 const res = ColorTheme.fromRules(tokenColors);
99
100 for (const include in obj?.include ?? []) {
101 const includePath = path.join(path.dirname(themePath), include);
102 const tmp = loadThemeFile(includePath);
103 res.mergeFrom(tmp);
104 }
105
106 return res;
107}
108
109interface TextMateRule {
110 scope: string | string[];
111 settings: TextMateRuleSettings;
112}
113
114function mergeRuleSettings(
115 defaultSetting: TextMateRuleSettings | undefined,
116 override: TextMateRuleSettings,
117): TextMateRuleSettings {
118 return {
119 foreground: override.foreground ?? defaultSetting?.foreground,
120 background: override.background ?? defaultSetting?.background,
121 fontStyle: override.fontStyle ?? defaultSetting?.fontStyle,
122 }
123}
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index f63d1ddce..ccb0ee2b7 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -1,5 +1,4 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as scopesMapper from './scopes_mapper';
3 2
4const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; 3const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
5 4
@@ -58,9 +57,6 @@ export class Config {
58 57
59 if (config.has('highlightingOn')) { 58 if (config.has('highlightingOn')) {
60 this.highlightingOn = config.get('highlightingOn') as boolean; 59 this.highlightingOn = config.get('highlightingOn') as boolean;
61 if (this.highlightingOn) {
62 scopesMapper.load();
63 }
64 } 60 }
65 61
66 if (config.has('rainbowHighlightingOn')) { 62 if (config.has('rainbowHighlightingOn')) {
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
index 5e9cbe0de..d383d87ef 100644
--- a/editors/code/src/highlighting.ts
+++ b/editors/code/src/highlighting.ts
@@ -3,8 +3,7 @@ import * as lc from 'vscode-languageclient';
3import * as seedrandom_ from 'seedrandom'; 3import * as seedrandom_ from 'seedrandom';
4const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207 4const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207
5 5
6import { loadThemeColors, TextMateRuleSettings } from './scopes'; 6import { ColorTheme, TextMateRuleSettings } from './color_theme';
7import * as scopesMapper from './scopes_mapper';
8 7
9import { Ctx } from './ctx'; 8import { Ctx } from './ctx';
10 9
@@ -168,69 +167,16 @@ class Highlighter {
168 } 167 }
169} 168}
170 169
171function initDecorations(): Map< 170function initDecorations(): Map<string, vscode.TextEditorDecorationType> {
172 string, 171 const theme = ColorTheme.load();
173 vscode.TextEditorDecorationType 172 const res = new Map()
174> { 173 TAG_TO_SCOPES.forEach((scopes, tag) => {
175 const themeColors = loadThemeColors(); 174 if (!scopes) throw `unmapped tag: ${tag}`
176 175 let rule = theme.lookup(scopes)
177 const decoration = ( 176 const decor = createDecorationFromTextmate(rule);
178 tag: string, 177 res.set(tag, decor)
179 textDecoration?: string, 178 })
180 ): [string, vscode.TextEditorDecorationType] => { 179 return res;
181 const rule = scopesMapper.toRule(tag, it => themeColors.get(it));
182
183 if (rule) {
184 const decor = createDecorationFromTextmate(rule);
185 return [tag, decor];
186 } else {
187 const fallBackTag = 'ralsp.' + tag;
188 // console.log(' ');
189 // console.log('Missing theme for: <"' + tag + '"> for following mapped scopes:');
190 // console.log(scopesMapper.find(tag));
191 // console.log('Falling back to values defined in: ' + fallBackTag);
192 // console.log(' ');
193 const color = new vscode.ThemeColor(fallBackTag);
194 const decor = vscode.window.createTextEditorDecorationType({
195 color,
196 textDecoration,
197 });
198 return [tag, decor];
199 }
200 };
201
202 const decorations: Iterable<[
203 string,
204 vscode.TextEditorDecorationType,
205 ]> = [
206 decoration('comment'),
207 decoration('string'),
208 decoration('keyword'),
209 decoration('keyword.control'),
210 decoration('keyword.unsafe'),
211 decoration('function'),
212 decoration('parameter'),
213 decoration('constant'),
214 decoration('type.builtin'),
215 decoration('type.generic'),
216 decoration('type.lifetime'),
217 decoration('type.param'),
218 decoration('type.self'),
219 decoration('type'),
220 decoration('text'),
221 decoration('attribute'),
222 decoration('literal'),
223 decoration('literal.numeric'),
224 decoration('literal.char'),
225 decoration('literal.byte'),
226 decoration('macro'),
227 decoration('variable'),
228 decoration('variable.mut', 'underline'),
229 decoration('field'),
230 decoration('module'),
231 ];
232
233 return new Map<string, vscode.TextEditorDecorationType>(decorations);
234} 180}
235 181
236function createDecorationFromTextmate( 182function createDecorationFromTextmate(
@@ -267,3 +213,33 @@ function createDecorationFromTextmate(
267 } 213 }
268 return vscode.window.createTextEditorDecorationType(decorationOptions); 214 return vscode.window.createTextEditorDecorationType(decorationOptions);
269} 215}
216
217// sync with tags from `syntax_highlighting.rs`.
218const TAG_TO_SCOPES = new Map<string, string[]>([
219 ["field", ["entity.name.field"]],
220 ["function", ["entity.name.function"]],
221 ["module", ["entity.name.module"]],
222 ["constant", ["entity.name.constant"]],
223 ["macro", ["entity.name.macro"]],
224
225 ["variable", ["variable"]],
226 ["variable.mut", ["variable", "meta.mutable"]],
227
228 ["type", ["entity.name.type"]],
229 ["type.builtin", ["entity.name.type", "support.type.primitive"]],
230 ["type.self", ["entity.name.type.parameter.self"]],
231 ["type.param", ["entity.name.type.parameter"]],
232 ["type.lifetime", ["entity.name.type.lifetime"]],
233
234 ["literal.byte", ["constant.character.byte"]],
235 ["literal.char", ["constant.character"]],
236 ["literal.numeric", ["constant.numeric"]],
237
238 ["comment", ["comment"]],
239 ["string", ["string.quoted"]],
240 ["attribute", ["meta.attribute"]],
241
242 ["keyword", ["keyword"]],
243 ["keyword.unsafe", ["keyword.other.unsafe"]],
244 ["keyword.control", ["keyword.control"]],
245]);
diff --git a/editors/code/src/scopes.ts b/editors/code/src/scopes.ts
deleted file mode 100644
index 73fabbf54..000000000
--- a/editors/code/src/scopes.ts
+++ /dev/null
@@ -1,108 +0,0 @@
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}
diff --git a/editors/code/src/scopes_mapper.ts b/editors/code/src/scopes_mapper.ts
deleted file mode 100644
index e738fa239..000000000
--- a/editors/code/src/scopes_mapper.ts
+++ /dev/null
@@ -1,78 +0,0 @@
1import * as vscode from 'vscode';
2import { TextMateRuleSettings } from './scopes';
3
4let mappings = new Map<string, string[]>();
5
6const defaultMapping = new Map<string, string[]>([
7 [
8 'comment',
9 [
10 'comment',
11 'comment.block',
12 'comment.line',
13 'comment.block.documentation',
14 ],
15 ],
16 ['string', ['string']],
17 ['keyword', ['keyword']],
18 ['keyword.control', ['keyword.control', 'keyword', 'keyword.other']],
19 [
20 'keyword.unsafe',
21 ['storage.modifier', 'keyword.other', 'keyword.control', 'keyword'],
22 ],
23 ['function', ['entity.name.function']],
24 ['parameter', ['variable.parameter']],
25 ['constant', ['constant', 'variable']],
26 ['type', ['entity.name.type']],
27 ['builtin', ['variable.language', 'support.type', 'support.type']],
28 ['text', ['string', 'string.quoted', 'string.regexp']],
29 ['attribute', ['keyword']],
30 ['literal', ['string', 'string.quoted', 'string.regexp']],
31 ['macro', ['entity.name.function', 'keyword.other', 'entity.name.macro']],
32 ['variable', ['variable']],
33 ['variable.mut', ['variable', 'storage.modifier']],
34 [
35 'field',
36 [
37 'variable.object.property',
38 'meta.field.declaration',
39 'meta.definition.property',
40 'variable.other',
41 ],
42 ],
43 ['module', ['entity.name.section', 'entity.other']],
44]);
45
46export function find(scope: string): string[] {
47 return mappings.get(scope) || [];
48}
49
50export function toRule(
51 scope: string,
52 intoRule: (scope: string) => TextMateRuleSettings | undefined,
53): TextMateRuleSettings | undefined {
54 return find(scope)
55 .map(intoRule)
56 .filter(rule => rule !== undefined)[0];
57}
58
59function isString(value: any): value is string {
60 return typeof value === 'string';
61}
62
63function isArrayOfString(value: any): value is string[] {
64 return Array.isArray(value) && value.every(item => isString(item));
65}
66
67export function load() {
68 const rawConfig: { [key: string]: any } =
69 vscode.workspace
70 .getConfiguration('rust-analyzer')
71 .get('scopeMappings') || {};
72
73 mappings = Object.entries(rawConfig)
74 .filter(([_, value]) => isString(value) || isArrayOfString(value))
75 .reduce((list, [key, value]: [string, string | string[]]) => {
76 return list.set(key, isString(value) ? [value] : value);
77 }, defaultMapping);
78}