aboutsummaryrefslogtreecommitdiff
path: root/editors/code
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code')
-rw-r--r--editors/code/package.json10
-rw-r--r--editors/code/src/client.ts1
-rw-r--r--editors/code/src/config.ts2
-rw-r--r--editors/code/src/highlighting.ts255
-rw-r--r--editors/code/src/main.ts4
5 files changed, 0 insertions, 272 deletions
diff --git a/editors/code/package.json b/editors/code/package.json
index 1d90e4298..946145df8 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -182,16 +182,6 @@
182 "default": false, 182 "default": false,
183 "description": "Use proposed semantic tokens API for syntax highlighting" 183 "description": "Use proposed semantic tokens API for syntax highlighting"
184 }, 184 },
185 "rust-analyzer.highlightingOn": {
186 "type": "boolean",
187 "default": false,
188 "description": "Highlight Rust code (overrides built-in syntax highlighting)"
189 },
190 "rust-analyzer.rainbowHighlightingOn": {
191 "type": "boolean",
192 "default": false,
193 "description": "When highlighting Rust code, use a unique color per identifier"
194 },
195 "rust-analyzer.featureFlags": { 185 "rust-analyzer.featureFlags": {
196 "type": "object", 186 "type": "object",
197 "default": {}, 187 "default": {},
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index f909f8db2..8ddc1cdca 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -7,7 +7,6 @@ import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-
7 7
8export function configToServerOptions(config: Config) { 8export function configToServerOptions(config: Config) {
9 return { 9 return {
10 publishDecorations: !config.highlightingSemanticTokens,
11 lruCapacity: config.lruCapacity, 10 lruCapacity: config.lruCapacity,
12 11
13 inlayHintsType: config.inlayHints.typeHints, 12 inlayHintsType: config.inlayHints.typeHints,
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 501997fef..c37c6276b 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -71,8 +71,6 @@ export class Config {
71 get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; } 71 get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; }
72 get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; } 72 get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; }
73 get highlightingSemanticTokens() { return this.cfg.get<boolean>("highlighting.semanticTokens")!; } 73 get highlightingSemanticTokens() { return this.cfg.get<boolean>("highlighting.semanticTokens")!; }
74 get highlightingOn() { return this.cfg.get<boolean>("highlightingOn")!; }
75 get rainbowHighlightingOn() { return this.cfg.get<boolean>("rainbowHighlightingOn")!; }
76 get lruCapacity() { return this.cfg.get<null | number>("lruCapacity")!; } 74 get lruCapacity() { return this.cfg.get<null | number>("lruCapacity")!; }
77 get excludeGlobs() { return this.cfg.get<string[]>("excludeGlobs")!; } 75 get excludeGlobs() { return this.cfg.get<string[]>("excludeGlobs")!; }
78 get useClientWatching() { return this.cfg.get<boolean>("useClientWatching")!; } 76 get useClientWatching() { return this.cfg.get<boolean>("useClientWatching")!; }
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
deleted file mode 100644
index ea2dfc0e3..000000000
--- a/editors/code/src/highlighting.ts
+++ /dev/null
@@ -1,255 +0,0 @@
1import * as vscode from 'vscode';
2import * as ra from './rust-analyzer-api';
3
4import { ColorTheme, TextMateRuleSettings } from './color_theme';
5
6import { Ctx } from './ctx';
7import { sendRequestWithRetry, isRustDocument } from './util';
8
9export function activateHighlighting(ctx: Ctx) {
10 const highlighter = new Highlighter(ctx);
11
12 ctx.client.onNotification(ra.publishDecorations, params => {
13 if (!ctx.config.highlightingOn) return;
14
15 const targetEditor = vscode.window.visibleTextEditors.find(
16 editor => {
17 const unescapedUri = unescape(
18 editor.document.uri.toString(),
19 );
20 // Unescaped URI looks like:
21 // file:///c:/Workspace/ra-test/src/main.rs
22 return unescapedUri === params.uri;
23 },
24 );
25 if (!targetEditor) return;
26
27 highlighter.setHighlights(targetEditor, params.decorations);
28 });
29
30
31 vscode.workspace.onDidChangeConfiguration(
32 _ => highlighter.removeHighlights(),
33 null,
34 ctx.subscriptions,
35 );
36
37 vscode.window.onDidChangeActiveTextEditor(
38 async (editor: vscode.TextEditor | undefined) => {
39 if (!editor || !isRustDocument(editor.document)) return;
40 if (!ctx.config.highlightingOn) return;
41 const client = ctx.client;
42 if (!client) return;
43
44 const decorations = await sendRequestWithRetry(
45 client,
46 ra.decorationsRequest,
47 { uri: editor.document.uri.toString() },
48 );
49 highlighter.setHighlights(editor, decorations);
50 },
51 null,
52 ctx.subscriptions,
53 );
54}
55
56// Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76
57function fancify(seed: string, shade: 'light' | 'dark') {
58 const random = randomU32Numbers(hashString(seed));
59 const randomInt = (min: number, max: number) => {
60 return Math.abs(random()) % (max - min + 1) + min;
61 };
62
63 const h = randomInt(0, 360);
64 const s = randomInt(42, 98);
65 const l = shade === 'light' ? randomInt(15, 40) : randomInt(40, 90);
66 return `hsl(${h},${s}%,${l}%)`;
67}
68
69class Highlighter {
70 private ctx: Ctx;
71 private decorations: Map<
72 string,
73 vscode.TextEditorDecorationType
74 > | null = null;
75
76 constructor(ctx: Ctx) {
77 this.ctx = ctx;
78 }
79
80 public removeHighlights() {
81 if (this.decorations == null) {
82 return;
83 }
84
85 // Decorations are removed when the object is disposed
86 for (const decoration of this.decorations.values()) {
87 decoration.dispose();
88 }
89
90 this.decorations = null;
91 }
92
93 public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]) {
94 const client = this.ctx.client;
95 if (!client) return;
96 // Initialize decorations if necessary
97 //
98 // Note: decoration objects need to be kept around so we can dispose them
99 // if the user disables syntax highlighting
100 if (this.decorations == null) {
101 this.decorations = initDecorations();
102 }
103
104 const byTag: Map<string, vscode.Range[]> = new Map();
105 const colorfulIdents: Map<
106 string,
107 [vscode.Range[], boolean]
108 > = new Map();
109 const rainbowTime = this.ctx.config.rainbowHighlightingOn;
110
111 for (const tag of this.decorations.keys()) {
112 byTag.set(tag, []);
113 }
114
115 for (const d of highlights) {
116 if (!byTag.get(d.tag)) {
117 continue;
118 }
119
120 if (rainbowTime && d.bindingHash) {
121 if (!colorfulIdents.has(d.bindingHash)) {
122 const mut = d.tag.endsWith('.mut');
123 colorfulIdents.set(d.bindingHash, [[], mut]);
124 }
125 colorfulIdents
126 .get(d.bindingHash)![0]
127 .push(
128 client.protocol2CodeConverter.asRange(d.range),
129 );
130 } else {
131 byTag
132 .get(d.tag)!
133 .push(
134 client.protocol2CodeConverter.asRange(d.range),
135 );
136 }
137 }
138
139 for (const tag of byTag.keys()) {
140 const dec = this.decorations.get(
141 tag,
142 ) as vscode.TextEditorDecorationType;
143 const ranges = byTag.get(tag)!;
144 editor.setDecorations(dec, ranges);
145 }
146
147 for (const [hash, [ranges, mut]] of colorfulIdents.entries()) {
148 const textDecoration = mut ? 'underline' : undefined;
149 const dec = vscode.window.createTextEditorDecorationType({
150 light: { color: fancify(hash, 'light'), textDecoration },
151 dark: { color: fancify(hash, 'dark'), textDecoration },
152 });
153 editor.setDecorations(dec, ranges);
154 }
155 }
156}
157
158function initDecorations(): Map<string, vscode.TextEditorDecorationType> {
159 const theme = ColorTheme.load();
160 const res = new Map();
161 TAG_TO_SCOPES.forEach((scopes, tag) => {
162 // We are going to axe this soon, so don't try to detect unknown tags.
163 // Users should switch to the new semantic tokens implementation.
164 if (!scopes) return;
165 const rule = theme.lookup(scopes);
166 const decor = createDecorationFromTextmate(rule);
167 res.set(tag, decor);
168 });
169 return res;
170}
171
172function createDecorationFromTextmate(
173 themeStyle: TextMateRuleSettings,
174): vscode.TextEditorDecorationType {
175 const decorationOptions: vscode.DecorationRenderOptions = {};
176 decorationOptions.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen;
177
178 if (themeStyle.foreground) {
179 decorationOptions.color = themeStyle.foreground;
180 }
181
182 if (themeStyle.background) {
183 decorationOptions.backgroundColor = themeStyle.background;
184 }
185
186 if (themeStyle.fontStyle) {
187 const parts: string[] = themeStyle.fontStyle.split(' ');
188 parts.forEach(part => {
189 switch (part) {
190 case 'italic':
191 decorationOptions.fontStyle = 'italic';
192 break;
193 case 'bold':
194 decorationOptions.fontWeight = 'bold';
195 break;
196 case 'underline':
197 decorationOptions.textDecoration = 'underline';
198 break;
199 default:
200 break;
201 }
202 });
203 }
204 return vscode.window.createTextEditorDecorationType(decorationOptions);
205}
206
207// sync with tags from `syntax_highlighting.rs`.
208const TAG_TO_SCOPES = new Map<string, string[]>([
209 ["field", ["entity.name.field"]],
210 ["function", ["entity.name.function"]],
211 ["module", ["entity.name.module"]],
212 ["constant", ["entity.name.constant"]],
213 ["macro", ["entity.name.macro"]],
214
215 ["variable", ["variable"]],
216 ["variable.mutable", ["variable", "meta.mutable"]],
217
218 ["type", ["entity.name.type"]],
219 ["type.builtin", ["entity.name.type", "support.type.primitive"]],
220 ["type.self", ["entity.name.type.parameter.self"]],
221 ["type.param", ["entity.name.type.parameter", "entity.name.type.param.rust"]],
222 ["type.lifetime", ["entity.name.type.lifetime", "entity.name.lifetime.rust"]],
223
224 ["literal.byte", ["constant.character.byte"]],
225 ["literal.char", ["constant.character.rust"]],
226 ["numeric_literal", ["constant.numeric"]],
227
228 ["comment", ["comment"]],
229 ["string_literal", ["string.quoted"]],
230 ["attribute", ["meta.attribute.rust"]],
231
232 ["keyword", ["keyword"]],
233 ["keyword.unsafe", ["keyword.other.unsafe"]],
234 ["keyword.control", ["keyword.control"]],
235]);
236
237function randomU32Numbers(seed: number) {
238 let random = seed | 0;
239 return () => {
240 random ^= random << 13;
241 random ^= random >> 17;
242 random ^= random << 5;
243 random |= 0;
244 return random;
245 };
246}
247
248function hashString(str: string): number {
249 let res = 0;
250 for (let i = 0; i < str.length; ++i) {
251 const c = str.codePointAt(i)!;
252 res = (res * 31 + c) & ~0;
253 }
254 return res;
255}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 7ba16120c..4f3b89f44 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -7,7 +7,6 @@ import * as commands from './commands';
7import { activateInlayHints } from './inlay_hints'; 7import { activateInlayHints } from './inlay_hints';
8import { activateStatusDisplay } from './status_display'; 8import { activateStatusDisplay } from './status_display';
9import { Ctx } from './ctx'; 9import { Ctx } from './ctx';
10import { activateHighlighting } from './highlighting';
11import { Config, NIGHTLY_TAG } from './config'; 10import { Config, NIGHTLY_TAG } from './config';
12import { log, assert } from './util'; 11import { log, assert } from './util';
13import { PersistentState } from './persistent_state'; 12import { PersistentState } from './persistent_state';
@@ -97,9 +96,6 @@ export async function activate(context: vscode.ExtensionContext) {
97 96
98 activateStatusDisplay(ctx); 97 activateStatusDisplay(ctx);
99 98
100 if (!ctx.config.highlightingSemanticTokens) {
101 activateHighlighting(ctx);
102 }
103 activateInlayHints(ctx); 99 activateInlayHints(ctx);
104 100
105 vscode.workspace.onDidChangeConfiguration( 101 vscode.workspace.onDidChangeConfiguration(