aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-25 18:42:55 +0100
committerbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-07-25 18:42:55 +0100
commit4647e89defd367a92d00d3bbb11c2463408bb3ad (patch)
treeb1d01cf8f7751daad61ee16fef82e616f55a8261
parentceb16591deef2190daaf5eb9a6480f20dc5d169c (diff)
parentf1ba963a3097106ad6daa41d04c51b7f2d418d8c (diff)
Merge #1586
1586: Add type decorators r=matklad a=SomeoneToIgnore A follow-up of https://github.com/rust-analyzer/rust-analyzer/pull/1549 Now the frontend shows inlay hints as VS Code Decorators: <img width="666" alt="image" src="https://user-images.githubusercontent.com/2690773/61802687-918fcc80-ae39-11e9-97b0-3195ab467393.png"> <img width="893" alt="image" src="https://user-images.githubusercontent.com/2690773/61802688-93599000-ae39-11e9-8bcb-4512e22aa3ed.png"> A few notes on the implementation: * I could not find a normal way to run and display the hints for the file that's already open in the VS Code when it starts. The updating code runs ok, but does not actually show anything. Seems like I miss some event that I could add a handler to. I've also experimented with `setTimeout` and it worked, but this is too ugly. The hints appear now when a new file is open or when some change is done in the existing file. * If there's a `dbg!` used in the lsp_server, the frontend starts receiving change events that contain the string from the `dbg!` output. It should not be the case in a real life, but I've decided to cover this case, just in case. * For bigger files, ~500 lines, the decorators start to blink, when updated, this does not seem to be very much of a problem for me at this particular stage of the feature development and can be optimized later. In the worst case, those decorators can be turned off in settings. * Cursor movement is rather non-intuitive on the right edge of the decorator. Seems like a thing to fix in the VS Code, not in the plugin. Co-authored-by: Kirill Bulatov <[email protected]>
-rw-r--r--editors/code/package.json14
-rw-r--r--editors/code/src/commands/index.ts4
-rw-r--r--editors/code/src/commands/inlay_hints.ts104
-rw-r--r--editors/code/src/config.ts5
-rw-r--r--editors/code/src/extension.ts24
5 files changed, 150 insertions, 1 deletions
diff --git a/editors/code/package.json b/editors/code/package.json
index fd30c7946..060a3a247 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -238,6 +238,11 @@
238 "type": "number", 238 "type": "number",
239 "default": null, 239 "default": null,
240 "description": "Number of syntax trees rust-analyzer keeps in memory" 240 "description": "Number of syntax trees rust-analyzer keeps in memory"
241 },
242 "rust-analyzer.displayInlayHints": {
243 "type": "boolean",
244 "default": true,
245 "description": "Display additional type information in the editor"
241 } 246 }
242 } 247 }
243 }, 248 },
@@ -444,6 +449,15 @@
444 "light": "#000000", 449 "light": "#000000",
445 "highContrast": "#FFFFFF" 450 "highContrast": "#FFFFFF"
446 } 451 }
452 },
453 {
454 "id": "ralsp.inlayHint",
455 "description": "Color for inlay hints",
456 "defaults": {
457 "dark": "#A0A0A0F0",
458 "light": "#747474",
459 "highContrast": "#BEBEBE"
460 }
447 } 461 }
448 ] 462 ]
449 } 463 }
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 194658497..c194bd2ea 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -1,5 +1,6 @@
1import * as analyzerStatus from './analyzer_status'; 1import * as analyzerStatus from './analyzer_status';
2import * as applySourceChange from './apply_source_change'; 2import * as applySourceChange from './apply_source_change';
3import * as inlayHints from './inlay_hints';
3import * as joinLines from './join_lines'; 4import * as joinLines from './join_lines';
4import * as matchingBrace from './matching_brace'; 5import * as matchingBrace from './matching_brace';
5import * as onEnter from './on_enter'; 6import * as onEnter from './on_enter';
@@ -15,5 +16,6 @@ export {
15 parentModule, 16 parentModule,
16 runnables, 17 runnables,
17 syntaxTree, 18 syntaxTree,
18 onEnter 19 onEnter,
20 inlayHints
19}; 21};
diff --git a/editors/code/src/commands/inlay_hints.ts b/editors/code/src/commands/inlay_hints.ts
new file mode 100644
index 000000000..8154af8dc
--- /dev/null
+++ b/editors/code/src/commands/inlay_hints.ts
@@ -0,0 +1,104 @@
1import * as vscode from 'vscode';
2import { Range, TextDocumentChangeEvent, TextEditor } from 'vscode';
3import { TextDocumentIdentifier } from 'vscode-languageclient';
4import { Server } from '../server';
5
6interface InlayHintsParams {
7 textDocument: TextDocumentIdentifier;
8}
9
10interface InlayHint {
11 range: Range;
12 kind: string;
13 label: string;
14}
15
16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
17 after: {
18 color: new vscode.ThemeColor('ralsp.inlayHint')
19 }
20});
21
22export class HintsUpdater {
23 private displayHints = true;
24
25 public async loadHints(
26 editor: vscode.TextEditor | undefined
27 ): Promise<void> {
28 if (
29 this.displayHints &&
30 editor !== undefined &&
31 this.isRustDocument(editor.document)
32 ) {
33 await this.updateDecorationsFromServer(
34 editor.document.uri.toString(),
35 editor
36 );
37 }
38 }
39
40 public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
41 if (this.displayHints !== displayHints) {
42 this.displayHints = displayHints;
43
44 if (displayHints) {
45 return this.updateHints();
46 } else {
47 const editor = vscode.window.activeTextEditor;
48 if (editor != null) {
49 return editor.setDecorations(typeHintDecorationType, []);
50 }
51 }
52 }
53 }
54
55 public async updateHints(cause?: TextDocumentChangeEvent): Promise<void> {
56 if (!this.displayHints) {
57 return;
58 }
59 const editor = vscode.window.activeTextEditor;
60 if (editor == null) {
61 return;
62 }
63 const document = cause == null ? editor.document : cause.document;
64 if (!this.isRustDocument(document)) {
65 return;
66 }
67
68 return await this.updateDecorationsFromServer(
69 document.uri.toString(),
70 editor
71 );
72 }
73
74 private isRustDocument(document: vscode.TextDocument): boolean {
75 return document && document.languageId === 'rust';
76 }
77
78 private async updateDecorationsFromServer(
79 documentUri: string,
80 editor: TextEditor
81 ): Promise<void> {
82 const newHints = (await this.queryHints(documentUri)) || [];
83 const newDecorations = newHints.map(hint => ({
84 range: hint.range,
85 renderOptions: { after: { contentText: `: ${hint.label}` } }
86 }));
87 return editor.setDecorations(typeHintDecorationType, newDecorations);
88 }
89
90 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
91 const request: InlayHintsParams = {
92 textDocument: { uri: documentUri }
93 };
94 const client = Server.client;
95 return client
96 .onReady()
97 .then(() =>
98 client.sendRequest<InlayHint[] | null>(
99 'rust-analyzer/inlayHints',
100 request
101 )
102 );
103 }
104}
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 3f1b482e3..4d58a1a93 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -21,6 +21,7 @@ export class Config {
21 public raLspServerPath = RA_LSP_DEBUG || 'ra_lsp_server'; 21 public raLspServerPath = RA_LSP_DEBUG || 'ra_lsp_server';
22 public showWorkspaceLoadedNotification = true; 22 public showWorkspaceLoadedNotification = true;
23 public lruCapacity: null | number = null; 23 public lruCapacity: null | number = null;
24 public displayInlayHints = true;
24 public cargoWatchOptions: CargoWatchOptions = { 25 public cargoWatchOptions: CargoWatchOptions = {
25 enableOnStartup: 'ask', 26 enableOnStartup: 'ask',
26 trace: 'off', 27 trace: 'off',
@@ -123,5 +124,9 @@ export class Config {
123 if (config.has('lruCapacity')) { 124 if (config.has('lruCapacity')) {
124 this.lruCapacity = config.get('lruCapacity') as number; 125 this.lruCapacity = config.get('lruCapacity') as number;
125 } 126 }
127
128 if (config.has('displayInlayHints')) {
129 this.displayInlayHints = config.get('displayInlayHints') as boolean;
130 }
126 } 131 }
127} 132}
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index c8c3004a7..c6efc2e7e 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient';
3 3
4import * as commands from './commands'; 4import * as commands from './commands';
5import { CargoWatchProvider } from './commands/cargo_watch'; 5import { CargoWatchProvider } from './commands/cargo_watch';
6import { HintsUpdater } from './commands/inlay_hints';
6import { 7import {
7 interactivelyStartCargoWatch, 8 interactivelyStartCargoWatch,
8 startCargoWatch 9 startCargoWatch
@@ -147,6 +148,29 @@ export function activate(context: vscode.ExtensionContext) {
147 148
148 // Start the language server, finally! 149 // Start the language server, finally!
149 startServer(); 150 startServer();
151
152 if (Server.config.displayInlayHints) {
153 const hintsUpdater = new HintsUpdater();
154 hintsUpdater.loadHints(vscode.window.activeTextEditor).then(() => {
155 disposeOnDeactivation(
156 vscode.window.onDidChangeActiveTextEditor(editor =>
157 hintsUpdater.loadHints(editor)
158 )
159 );
160 disposeOnDeactivation(
161 vscode.workspace.onDidChangeTextDocument(e =>
162 hintsUpdater.updateHints(e)
163 )
164 );
165 disposeOnDeactivation(
166 vscode.workspace.onDidChangeConfiguration(_ =>
167 hintsUpdater.toggleHintsDisplay(
168 Server.config.displayInlayHints
169 )
170 )
171 );
172 });
173 }
150} 174}
151 175
152export function deactivate(): Thenable<void> { 176export function deactivate(): Thenable<void> {