diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-29 16:49:40 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-29 16:49:40 +0000 |
commit | 232785251bc80bc32c2ab52b624ecffbf5e35185 (patch) | |
tree | 6f8005b895d4005a9c6997d65f6994260bbbca12 /editors/code/src/scopes_mapper.ts | |
parent | 523b4cbc602447b14202dd2520f84241bb07c4e2 (diff) | |
parent | 25537d294cb7a3e01d2329a7d07b469d734fc829 (diff) |
Merge #2061
2061: Theme loading and "editor.tokenColorCustomizations" support. r=matklad a=seivan
Fixes: [Issue#1294](https://github.com/rust-analyzer/rust-analyzer/issues/1294#issuecomment-497450325)
TODO:
- [x] Load themes
- [x] Load existing `ralsp`-prefixed overrides from `"workbench.colorCustomizations"`.
- [x] Load overrides from `"editor.tokenColorCustomizations.textMateRules"`.
- [x] Use RA tags to load `vscode.DecorationRenderOptions` (colors) from theme & overrides.
- [x] Map RA tags to common TextMate scopes before loading colors.
- [x] Add default scope mappings in extension.
- [x] Cache mappings between settings updates.
- [x] Add scope mapping configuration manifest in `package.json`
- [x] Load configurable scope mappings from settings.
- [x] Load JSON Scheme for text mate scope rules in settings.
- [x] Update [Readme](https://github.com/seivan/rust-analyzer/blob/feature/themes/docs/user/README.md#settings).
Borrowed the theme loading (`scopes.ts`) from `Tree Sitter` with some modifications to reading `"editor.tokenColorCustomizations"` for merging with loaded themes and had to remove the async portions to be able to load it from settings updates.
~Just a PoC and an idea I toyed around with a lot of room for improvement.~
For starters, certain keywords aren't part of the standard TextMate grammar, so it still reads colors from the `ralsp` prefixed values in `"workbench.colorCustomizations"`.
But I think there's more value making the extension work with existing themes by maping some of the decoration tags to existing key or keys.
<img width="453" alt="Screenshot 2019-11-09 at 17 43 18" src="https://user-images.githubusercontent.com/55424/68531968-71b4e380-0318-11ea-924e-cdbb8d5eae06.png">
<img width="780" alt="Screenshot 2019-11-09 at 17 41 45" src="https://user-images.githubusercontent.com/55424/68531950-4b8f4380-0318-11ea-8f85-24a84efaf23b.png">
<img width="468" alt="Screenshot 2019-11-09 at 17 40 29" src="https://user-images.githubusercontent.com/55424/68531952-51852480-0318-11ea-800a-6ae9215f5368.png">
These will merge with the default ones coming with the extension, so you don't have to implement all of them and works well with overrides defined in settings.
```jsonc
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "keyword",
"settings": {
"fontStyle": "bold",
}
},
]
},
```
Edit: The idea is to work with 90% of the themes out there by working within existing scopes available that are generally styled. It's not to say I want to erase the custom Rust scopes - those should still remain and eventually worked into a custom grammar bundle for Rust specific themes that target those, I just want to make it work with generic themes offered on the market place for now.
A custom grammar bundle and themes for Rust specific scopes is out of... scope for this PR.
We'll make another round to tackle those issues.
Current fallbacks implemented
```typescript
[
'comment',
[
'comment',
'comment.block',
'comment.line',
'comment.block.documentation'
]
],
['string', ['string']],
['keyword', ['keyword']],
['keyword.control', ['keyword.control', 'keyword', 'keyword.other']],
[
'keyword.unsafe',
['storage.modifier', 'keyword.other', 'keyword.control', 'keyword']
],
['function', ['entity.name.function']],
['parameter', ['variable.parameter']],
['constant', ['constant', 'variable']],
['type', ['entity.name.type']],
['builtin', ['variable.language', 'support.type', 'support.type']],
['text', ['string', 'string.quoted', 'string.regexp']],
['attribute', ['keyword']],
['literal', ['string', 'string.quoted', 'string.regexp']],
['macro', ['support.other']],
['variable', ['variable']],
['variable.mut', ['variable', 'storage.modifier']],
[
'field',
[
'variable.object.property',
'meta.field.declaration',
'meta.definition.property',
'variable.other'
]
],
['module', ['entity.name.section', 'entity.other']]
```
Co-authored-by: Seivan Heidari <[email protected]>
Diffstat (limited to 'editors/code/src/scopes_mapper.ts')
-rw-r--r-- | editors/code/src/scopes_mapper.ts | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/editors/code/src/scopes_mapper.ts b/editors/code/src/scopes_mapper.ts new file mode 100644 index 000000000..e738fa239 --- /dev/null +++ b/editors/code/src/scopes_mapper.ts | |||
@@ -0,0 +1,78 @@ | |||
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 | } | ||