diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-31 13:11:49 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-31 13:11:49 +0000 |
commit | 46952985a087db5be5ca846b5109fccae8845df2 (patch) | |
tree | bb62a5d32f3999cd1bc430cef64ce13320f8132b /editors/code | |
parent | 7c4d4e113bc039712aa3996e57eaef19d12bd9ff (diff) | |
parent | 26bd7a896b4bbc4a2432df47dceff939aac921fa (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.ts | 123 | ||||
-rw-r--r-- | editors/code/src/config.ts | 4 | ||||
-rw-r--r-- | editors/code/src/highlighting.ts | 106 | ||||
-rw-r--r-- | editors/code/src/scopes.ts | 108 | ||||
-rw-r--r-- | editors/code/src/scopes_mapper.ts | 78 |
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 @@ | |||
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'; | ||
5 | |||
6 | export interface TextMateRuleSettings { | ||
7 | foreground?: string; | ||
8 | background?: string; | ||
9 | fontStyle?: string; | ||
10 | } | ||
11 | |||
12 | export 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 | |||
61 | function 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 | |||
89 | function 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 | |||
109 | interface TextMateRule { | ||
110 | scope: string | string[]; | ||
111 | settings: TextMateRuleSettings; | ||
112 | } | ||
113 | |||
114 | function 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 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as scopesMapper from './scopes_mapper'; | ||
3 | 2 | ||
4 | const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; | 3 | const 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'; | |||
3 | import * as seedrandom_ from 'seedrandom'; | 3 | import * as seedrandom_ from 'seedrandom'; |
4 | const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207 | 4 | const seedrandom = seedrandom_; // https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207 |
5 | 5 | ||
6 | import { loadThemeColors, TextMateRuleSettings } from './scopes'; | 6 | import { ColorTheme, TextMateRuleSettings } from './color_theme'; |
7 | import * as scopesMapper from './scopes_mapper'; | ||
8 | 7 | ||
9 | import { Ctx } from './ctx'; | 8 | import { Ctx } from './ctx'; |
10 | 9 | ||
@@ -168,69 +167,16 @@ class Highlighter { | |||
168 | } | 167 | } |
169 | } | 168 | } |
170 | 169 | ||
171 | function initDecorations(): Map< | 170 | function 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 | ||
236 | function createDecorationFromTextmate( | 182 | function 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`. | ||
218 | const 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 @@ | |||
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'; | ||
5 | |||
6 | export interface TextMateRuleSettings { | ||
7 | foreground?: string; | ||
8 | background?: string; | ||
9 | fontStyle?: string; | ||
10 | } | ||
11 | |||
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') | ||
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 | |||
26 | function 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 | |||
54 | function 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 | |||
74 | interface TextMateRule { | ||
75 | scope: string | string[]; | ||
76 | settings: TextMateRuleSettings; | ||
77 | } | ||
78 | |||
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' | ||
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 | |||
92 | function 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 | |||
103 | function 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 @@ | |||
1 | import * as vscode from 'vscode'; | ||
2 | import { TextMateRuleSettings } from './scopes'; | ||
3 | |||
4 | let mappings = new Map<string, string[]>(); | ||
5 | |||
6 | const 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 | |||
46 | export function find(scope: string): string[] { | ||
47 | return mappings.get(scope) || []; | ||
48 | } | ||
49 | |||
50 | export 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 | |||
59 | function isString(value: any): value is string { | ||
60 | return typeof value === 'string'; | ||
61 | } | ||
62 | |||
63 | function isArrayOfString(value: any): value is string[] { | ||
64 | return Array.isArray(value) && value.every(item => isString(item)); | ||
65 | } | ||
66 | |||
67 | export 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 | } | ||