diff options
-rw-r--r-- | crates/ra_ide/src/snapshots/highlighting.html | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/snapshots/rainbow_highlighting.html | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 27 | ||||
-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 |
8 files changed, 187 insertions, 271 deletions
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index a097cf8e8..1d130544f 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -38,12 +38,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
38 | <span class="keyword">fn</span> <span class="function">main</span>() { | 38 | <span class="keyword">fn</span> <span class="function">main</span>() { |
39 | <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal.numeric">92</span>); | 39 | <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal.numeric">92</span>); |
40 | 40 | ||
41 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); | 41 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = Vec::new(); |
42 | <span class="keyword.control">if</span> <span class="keyword">true</span> { | 42 | <span class="keyword.control">if</span> <span class="keyword">true</span> { |
43 | <span class="keyword">let</span> <span class="variable">x</span> = <span class="literal.numeric">92</span>; | 43 | <span class="keyword">let</span> <span class="variable">x</span> = <span class="literal.numeric">92</span>; |
44 | <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> }); | 44 | <span class="variable.mut">vec</span>.push(<span class="type">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> }); |
45 | } | 45 | } |
46 | <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); } | 46 | <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.set_len(<span class="literal.numeric">0</span>); } |
47 | 47 | ||
48 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal.numeric">42</span>; | 48 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal.numeric">42</span>; |
49 | <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>; | 49 | <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>; |
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 110556c09..d90ee8540 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html | |||
@@ -25,11 +25,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
25 | </style> | 25 | </style> |
26 | <pre><code><span class="keyword">fn</span> <span class="function">main</span>() { | 26 | <pre><code><span class="keyword">fn</span> <span class="function">main</span>() { |
27 | <span class="keyword">let</span> <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>; | 27 | <span class="keyword">let</span> <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>; |
28 | <span class="keyword">let</span> <span class="variable" data-binding-hash="14702933417323009544" style="color: hsl(108,90%,49%);">x</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>(); | 28 | <span class="keyword">let</span> <span class="variable" data-binding-hash="14702933417323009544" style="color: hsl(108,90%,49%);">x</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.to_string(); |
29 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5443150872754369068" style="color: hsl(215,43%,43%);">y</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>(); | 29 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5443150872754369068" style="color: hsl(215,43%,43%);">y</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.to_string(); |
30 | 30 | ||
31 | <span class="keyword">let</span> <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span> = <span class="string">"other color please!"</span>; | 31 | <span class="keyword">let</span> <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span> = <span class="string">"other color please!"</span>; |
32 | <span class="keyword">let</span> <span class="variable" data-binding-hash="2073121142529774969" style="color: hsl(320,43%,74%);">y</span> = <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span>.<span class="text">to_string</span>(); | 32 | <span class="keyword">let</span> <span class="variable" data-binding-hash="2073121142529774969" style="color: hsl(320,43%,74%);">y</span> = <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span>.to_string(); |
33 | } | 33 | } |
34 | 34 | ||
35 | <span class="keyword">fn</span> <span class="function">bar</span>() { | 35 | <span class="keyword">fn</span> <span class="function">bar</span>() { |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 0228ee7e9..56a36f587 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -20,13 +20,13 @@ pub mod tags { | |||
20 | pub(crate) const FIELD: &str = "field"; | 20 | pub(crate) const FIELD: &str = "field"; |
21 | pub(crate) const FUNCTION: &str = "function"; | 21 | pub(crate) const FUNCTION: &str = "function"; |
22 | pub(crate) const MODULE: &str = "module"; | 22 | pub(crate) const MODULE: &str = "module"; |
23 | pub(crate) const TYPE: &str = "type"; | ||
24 | pub(crate) const CONSTANT: &str = "constant"; | 23 | pub(crate) const CONSTANT: &str = "constant"; |
25 | pub(crate) const MACRO: &str = "macro"; | 24 | pub(crate) const MACRO: &str = "macro"; |
25 | |||
26 | pub(crate) const VARIABLE: &str = "variable"; | 26 | pub(crate) const VARIABLE: &str = "variable"; |
27 | pub(crate) const VARIABLE_MUT: &str = "variable.mut"; | 27 | pub(crate) const VARIABLE_MUT: &str = "variable.mut"; |
28 | pub(crate) const TEXT: &str = "text"; | ||
29 | 28 | ||
29 | pub(crate) const TYPE: &str = "type"; | ||
30 | pub(crate) const TYPE_BUILTIN: &str = "type.builtin"; | 30 | pub(crate) const TYPE_BUILTIN: &str = "type.builtin"; |
31 | pub(crate) const TYPE_SELF: &str = "type.self"; | 31 | pub(crate) const TYPE_SELF: &str = "type.self"; |
32 | pub(crate) const TYPE_PARAM: &str = "type.param"; | 32 | pub(crate) const TYPE_PARAM: &str = "type.param"; |
@@ -35,13 +35,14 @@ pub mod tags { | |||
35 | pub(crate) const LITERAL_BYTE: &str = "literal.byte"; | 35 | pub(crate) const LITERAL_BYTE: &str = "literal.byte"; |
36 | pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric"; | 36 | pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric"; |
37 | pub(crate) const LITERAL_CHAR: &str = "literal.char"; | 37 | pub(crate) const LITERAL_CHAR: &str = "literal.char"; |
38 | |||
38 | pub(crate) const LITERAL_COMMENT: &str = "comment"; | 39 | pub(crate) const LITERAL_COMMENT: &str = "comment"; |
39 | pub(crate) const LITERAL_STRING: &str = "string"; | 40 | pub(crate) const LITERAL_STRING: &str = "string"; |
40 | pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute"; | 41 | pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute"; |
41 | 42 | ||
43 | pub(crate) const KEYWORD: &str = "keyword"; | ||
42 | pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe"; | 44 | pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe"; |
43 | pub(crate) const KEYWORD_CONTROL: &str = "keyword.control"; | 45 | pub(crate) const KEYWORD_CONTROL: &str = "keyword.control"; |
44 | pub(crate) const KEYWORD: &str = "keyword"; | ||
45 | } | 46 | } |
46 | 47 | ||
47 | #[derive(Debug)] | 48 | #[derive(Debug)] |
@@ -109,15 +110,21 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
109 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); | 110 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); |
110 | let name_kind = | 111 | let name_kind = |
111 | classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind); | 112 | classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind); |
113 | match name_kind { | ||
114 | Some(name_kind) => { | ||
115 | if let Local(local) = &name_kind { | ||
116 | if let Some(name) = local.name(db) { | ||
117 | let shadow_count = | ||
118 | bindings_shadow_count.entry(name.clone()).or_default(); | ||
119 | binding_hash = | ||
120 | Some(calc_binding_hash(file_id, &name, *shadow_count)) | ||
121 | } | ||
122 | }; | ||
112 | 123 | ||
113 | if let Some(Local(local)) = &name_kind { | 124 | highlight_name(db, name_kind) |
114 | if let Some(name) = local.name(db) { | ||
115 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | ||
116 | binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count)) | ||
117 | } | 125 | } |
118 | }; | 126 | _ => continue, |
119 | 127 | } | |
120 | name_kind.map_or(tags::TEXT, |it| highlight_name(db, it)) | ||
121 | } | 128 | } |
122 | NAME => { | 129 | NAME => { |
123 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); | 130 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); |
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 | } | ||