aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/main_loop.rs20
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs35
-rw-r--r--crates/rust-analyzer/src/req.rs32
-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
9 files changed, 3 insertions, 359 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3c8f55f1e..602423919 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -16,7 +16,6 @@ use serde::Deserialize;
16#[derive(Debug, Clone)] 16#[derive(Debug, Clone)]
17pub struct Config { 17pub struct Config {
18 pub client_caps: ClientCapsConfig, 18 pub client_caps: ClientCapsConfig,
19 pub publish_decorations: bool,
20 pub publish_diagnostics: bool, 19 pub publish_diagnostics: bool,
21 pub notifications: NotificationsConfig, 20 pub notifications: NotificationsConfig,
22 pub inlay_hints: InlayHintsConfig, 21 pub inlay_hints: InlayHintsConfig,
@@ -60,7 +59,6 @@ pub struct ClientCapsConfig {
60impl Default for Config { 59impl Default for Config {
61 fn default() -> Self { 60 fn default() -> Self {
62 Config { 61 Config {
63 publish_decorations: false,
64 publish_diagnostics: true, 62 publish_diagnostics: true,
65 notifications: NotificationsConfig { 63 notifications: NotificationsConfig {
66 workspace_loaded: true, 64 workspace_loaded: true,
@@ -105,7 +103,6 @@ impl Config {
105 *self = Default::default(); 103 *self = Default::default();
106 self.client_caps = client_caps; 104 self.client_caps = client_caps;
107 105
108 set(value, "/publishDecorations", &mut self.publish_decorations);
109 set(value, "/excludeGlobs", &mut self.exclude_globs); 106 set(value, "/excludeGlobs", &mut self.exclude_globs);
110 set(value, "/useClientWatching", &mut self.use_client_watching); 107 set(value, "/useClientWatching", &mut self.use_client_watching);
111 set(value, "/lruCapacity", &mut self.lru_capacity); 108 set(value, "/lruCapacity", &mut self.lru_capacity);
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 45ae0ad9d..47fef59d4 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -250,9 +250,7 @@ impl fmt::Debug for Event {
250 } 250 }
251 } 251 }
252 Event::Task(Task::Notify(not)) => { 252 Event::Task(Task::Notify(not)) => {
253 if notification_is::<req::PublishDecorations>(not) 253 if notification_is::<req::PublishDiagnostics>(not) {
254 || notification_is::<req::PublishDiagnostics>(not)
255 {
256 return debug_verbose_not(not, f); 254 return debug_verbose_not(not, f);
257 } 255 }
258 } 256 }
@@ -427,7 +425,6 @@ fn loop_turn(
427 update_file_notifications_on_threadpool( 425 update_file_notifications_on_threadpool(
428 pool, 426 pool,
429 world_state.snapshot(), 427 world_state.snapshot(),
430 world_state.config.publish_decorations,
431 task_sender.clone(), 428 task_sender.clone(),
432 loop_state.subscriptions.subscriptions(), 429 loop_state.subscriptions.subscriptions(),
433 ) 430 )
@@ -508,7 +505,6 @@ fn on_request(
508 .on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)? 505 .on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)?
509 .on::<req::ParentModule>(handlers::handle_parent_module)? 506 .on::<req::ParentModule>(handlers::handle_parent_module)?
510 .on::<req::Runnables>(handlers::handle_runnables)? 507 .on::<req::Runnables>(handlers::handle_runnables)?
511 .on::<req::DecorationsRequest>(handlers::handle_decorations)?
512 .on::<req::Completion>(handlers::handle_completion)? 508 .on::<req::Completion>(handlers::handle_completion)?
513 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 509 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
514 .on::<req::CodeLensRequest>(handlers::handle_code_lens)? 510 .on::<req::CodeLensRequest>(handlers::handle_code_lens)?
@@ -884,7 +880,6 @@ where
884fn update_file_notifications_on_threadpool( 880fn update_file_notifications_on_threadpool(
885 pool: &ThreadPool, 881 pool: &ThreadPool,
886 world: WorldSnapshot, 882 world: WorldSnapshot,
887 publish_decorations: bool,
888 task_sender: Sender<Task>, 883 task_sender: Sender<Task>,
889 subscriptions: Vec<FileId>, 884 subscriptions: Vec<FileId>,
890) { 885) {
@@ -904,19 +899,6 @@ fn update_file_notifications_on_threadpool(
904 } 899 }
905 } 900 }
906 } 901 }
907 if publish_decorations {
908 match handlers::publish_decorations(&world, file_id) {
909 Err(e) => {
910 if !is_canceled(&e) {
911 log::error!("failed to compute decorations: {:?}", e);
912 }
913 }
914 Ok(params) => {
915 let not = notification_new::<req::PublishDecorations>(params);
916 task_sender.send(Task::Notify(not)).unwrap();
917 }
918 }
919 }
920 } 902 }
921 }); 903 });
922} 904}
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 23e48c089..db620dca3 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -38,7 +38,7 @@ use crate::{
38 }, 38 },
39 diagnostics::DiagnosticTask, 39 diagnostics::DiagnosticTask,
40 from_json, 40 from_json,
41 req::{self, Decoration, InlayHint, InlayHintsParams}, 41 req::{self, InlayHint, InlayHintsParams},
42 semantic_tokens::SemanticTokensBuilder, 42 semantic_tokens::SemanticTokensBuilder,
43 world::WorldSnapshot, 43 world::WorldSnapshot,
44 LspError, Result, 44 LspError, Result,
@@ -389,15 +389,6 @@ pub fn handle_runnables(
389 Ok(res) 389 Ok(res)
390} 390}
391 391
392pub fn handle_decorations(
393 world: WorldSnapshot,
394 params: TextDocumentIdentifier,
395) -> Result<Vec<Decoration>> {
396 let _p = profile("handle_decorations");
397 let file_id = params.try_conv_with(&world)?;
398 highlight(&world, file_id)
399}
400
401pub fn handle_completion( 392pub fn handle_completion(
402 world: WorldSnapshot, 393 world: WorldSnapshot,
403 params: req::CompletionParams, 394 params: req::CompletionParams,
@@ -970,15 +961,6 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia
970 Ok(DiagnosticTask::SetNative(file_id, diagnostics)) 961 Ok(DiagnosticTask::SetNative(file_id, diagnostics))
971} 962}
972 963
973pub fn publish_decorations(
974 world: &WorldSnapshot,
975 file_id: FileId,
976) -> Result<req::PublishDecorationsParams> {
977 let _p = profile("publish_decorations");
978 let uri = world.file_id_to_uri(file_id)?;
979 Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? })
980}
981
982fn to_lsp_runnable( 964fn to_lsp_runnable(
983 world: &WorldSnapshot, 965 world: &WorldSnapshot,
984 file_id: FileId, 966 file_id: FileId,
@@ -1008,21 +990,6 @@ fn to_lsp_runnable(
1008 }) 990 })
1009} 991}
1010 992
1011fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> {
1012 let line_index = world.analysis().file_line_index(file_id)?;
1013 let res = world
1014 .analysis()
1015 .highlight(file_id)?
1016 .into_iter()
1017 .map(|h| Decoration {
1018 range: h.range.conv_with(&line_index),
1019 tag: h.highlight.to_string(),
1020 binding_hash: h.binding_hash.map(|x| x.to_string()),
1021 })
1022 .collect();
1023 Ok(res)
1024}
1025
1026pub fn handle_inlay_hints( 993pub fn handle_inlay_hints(
1027 world: WorldSnapshot, 994 world: WorldSnapshot,
1028 params: InlayHintsParams, 995 params: InlayHintsParams,
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs
index 994f0ed61..ce799a683 100644
--- a/crates/rust-analyzer/src/req.rs
+++ b/crates/rust-analyzer/src/req.rs
@@ -1,6 +1,6 @@
1//! Defines `rust-analyzer` specific custom messages. 1//! Defines `rust-analyzer` specific custom messages.
2 2
3use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 3use lsp_types::{Location, Position, Range, TextDocumentIdentifier};
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5use serde::{Deserialize, Serialize}; 5use serde::{Deserialize, Serialize};
6 6
@@ -86,36 +86,6 @@ pub struct FindMatchingBraceParams {
86 pub offsets: Vec<Position>, 86 pub offsets: Vec<Position>,
87} 87}
88 88
89pub enum DecorationsRequest {}
90
91impl Request for DecorationsRequest {
92 type Params = TextDocumentIdentifier;
93 type Result = Vec<Decoration>;
94 const METHOD: &'static str = "rust-analyzer/decorationsRequest";
95}
96
97pub enum PublishDecorations {}
98
99impl Notification for PublishDecorations {
100 type Params = PublishDecorationsParams;
101 const METHOD: &'static str = "rust-analyzer/publishDecorations";
102}
103
104#[derive(Deserialize, Serialize, Debug)]
105#[serde(rename_all = "camelCase")]
106pub struct PublishDecorationsParams {
107 pub uri: Url,
108 pub decorations: Vec<Decoration>,
109}
110
111#[derive(Deserialize, Serialize, Debug)]
112#[serde(rename_all = "camelCase")]
113pub struct Decoration {
114 pub range: Range,
115 pub tag: String,
116 pub binding_hash: Option<String>,
117}
118
119pub enum ParentModule {} 89pub enum ParentModule {}
120 90
121impl Request for ParentModule { 91impl Request for ParentModule {
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(