aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/inlay_hints.ts
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-12-30 20:28:38 +0000
committerAleksey Kladov <[email protected]>2019-12-30 20:32:04 +0000
commitac8a142dddc697d26d5aa8c878df933300163e09 (patch)
tree5216d5c287a7cf761cf30c959f5500548c65836c /editors/code/src/inlay_hints.ts
parentefbbc903e68aaf32ee1fba5537769070cd2d01e8 (diff)
Refactor inlay hints
Diffstat (limited to 'editors/code/src/inlay_hints.ts')
-rw-r--r--editors/code/src/inlay_hints.ts170
1 files changed, 67 insertions, 103 deletions
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index fb8f135c3..aae9de69c 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -1,39 +1,29 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import { Server } from './server'; 3
4import { Ctx } from './ctx'; 4import { Ctx } from './ctx';
5 5
6export function activateInlayHints(ctx: Ctx) { 6export function activateInlayHints(ctx: Ctx) {
7 const hintsUpdater = new HintsUpdater(); 7 const hintsUpdater = new HintsUpdater(ctx);
8 hintsUpdater.refreshHintsForVisibleEditors().then(() => { 8 console.log('activateInlayHints');
9 // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
10 // so update the hints once when the focus changes to guarantee their presence
11 let editorChangeDisposable: vscode.Disposable | null = null;
12 editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
13 _ => {
14 if (editorChangeDisposable !== null) {
15 editorChangeDisposable.dispose();
16 }
17 return hintsUpdater.refreshHintsForVisibleEditors();
18 },
19 );
20 9
21 ctx.pushCleanup( 10 vscode.window.onDidChangeVisibleTextEditors(async _ => {
22 vscode.window.onDidChangeVisibleTextEditors(_ => 11 await hintsUpdater.refresh();
23 hintsUpdater.refreshHintsForVisibleEditors(), 12 }, ctx.subscriptions);
24 ), 13
25 ); 14 vscode.workspace.onDidChangeTextDocument(async e => {
26 ctx.pushCleanup( 15 if (e.contentChanges.length === 0) return;
27 vscode.workspace.onDidChangeTextDocument(e => 16 if (e.document.languageId !== 'rust') return;
28 hintsUpdater.refreshHintsForVisibleEditors(e), 17 await hintsUpdater.refresh();
29 ), 18 }, ctx.subscriptions);
30 ); 19
31 ctx.pushCleanup( 20 vscode.workspace.onDidChangeConfiguration(_ => {
32 vscode.workspace.onDidChangeConfiguration(_ => 21 hintsUpdater.setEnabled(ctx.config.displayInlayHints);
33 hintsUpdater.toggleHintsDisplay(ctx.config.displayInlayHints), 22 }, ctx.subscriptions);
34 ), 23
35 ); 24 // XXX: don't await here;
36 }); 25 // Who knows what happens if an exception is thrown here...
26 hintsUpdater.refresh();
37} 27}
38 28
39interface InlayHintsParams { 29interface InlayHintsParams {
@@ -53,95 +43,69 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
53}); 43});
54 44
55class HintsUpdater { 45class HintsUpdater {
56 private displayHints = true; 46 private ctx: Ctx;
57 47 private enabled = true;
58 public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
59 if (this.displayHints !== displayHints) {
60 this.displayHints = displayHints;
61 return this.refreshVisibleEditorsHints(
62 displayHints ? undefined : [],
63 );
64 }
65 }
66 48
67 public async refreshHintsForVisibleEditors( 49 constructor(ctx: Ctx) {
68 cause?: vscode.TextDocumentChangeEvent, 50 this.ctx = ctx;
69 ): Promise<void> {
70 if (!this.displayHints) return;
71
72 if (
73 cause !== undefined &&
74 (cause.contentChanges.length === 0 ||
75 !this.isRustDocument(cause.document))
76 ) {
77 return;
78 }
79 return this.refreshVisibleEditorsHints();
80 } 51 }
81 52
82 private async refreshVisibleEditorsHints( 53 async setEnabled(enabled: boolean) {
83 newDecorations?: vscode.DecorationOptions[], 54 if (this.enabled == enabled) return;
84 ) { 55 this.enabled = enabled;
85 const promises: Array<Promise<void>> = [];
86
87 for (const rustEditor of vscode.window.visibleTextEditors.filter(
88 editor => this.isRustDocument(editor.document),
89 )) {
90 if (newDecorations !== undefined) {
91 promises.push(
92 Promise.resolve(
93 rustEditor.setDecorations(
94 typeHintDecorationType,
95 newDecorations,
96 ),
97 ),
98 );
99 } else {
100 promises.push(this.updateDecorationsFromServer(rustEditor));
101 }
102 }
103 56
104 for (const promise of promises) { 57 if (this.enabled) {
105 await promise; 58 await this.refresh();
59 } else {
60 this.allEditors.forEach(it => this.setDecorations(it, []));
106 } 61 }
107 } 62 }
108 63
109 private isRustDocument(document: vscode.TextDocument): boolean { 64 async refresh() {
110 return document && document.languageId === 'rust'; 65 if (!this.enabled) return;
66 const promises = this.allEditors.map(it => this.refreshEditor(it));
67 await Promise.all(promises);
111 } 68 }
112 69
113 private async updateDecorationsFromServer( 70 private async refreshEditor(editor: vscode.TextEditor): Promise<void> {
114 editor: vscode.TextEditor,
115 ): Promise<void> {
116 const newHints = await this.queryHints(editor.document.uri.toString()); 71 const newHints = await this.queryHints(editor.document.uri.toString());
117 if (newHints !== null) { 72
118 const newDecorations = newHints.map(hint => ({ 73 const newDecorations = (newHints ? newHints : []).map(hint => ({
119 range: hint.range, 74 range: hint.range,
120 renderOptions: { 75 renderOptions: {
121 after: { 76 after: {
122 contentText: `: ${hint.label}`, 77 contentText: `: ${hint.label}`,
123 },
124 }, 78 },
125 })); 79 },
126 return editor.setDecorations( 80 }));
127 typeHintDecorationType, 81 this.setDecorations(editor, newDecorations);
128 newDecorations, 82 }
129 ); 83
130 } 84 private get allEditors(): vscode.TextEditor[] {
85 return vscode.window.visibleTextEditors.filter(
86 editor => editor.document.languageId === 'rust',
87 );
88 }
89
90 private setDecorations(
91 editor: vscode.TextEditor,
92 decorations: vscode.DecorationOptions[],
93 ) {
94 editor.setDecorations(
95 typeHintDecorationType,
96 this.enabled ? decorations : [],
97 );
131 } 98 }
132 99
133 private async queryHints(documentUri: string): Promise<InlayHint[] | null> { 100 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
134 const request: InlayHintsParams = { 101 const request: InlayHintsParams = {
135 textDocument: { uri: documentUri }, 102 textDocument: { uri: documentUri },
136 }; 103 };
137 const client = Server.client; 104 await this.ctx.client.onReady();
138 return client 105
139 .onReady() 106 return this.ctx.client.sendRequest<InlayHint[] | null>(
140 .then(() => 107 'rust-analyzer/inlayHints',
141 client.sendRequest<InlayHint[] | null>( 108 request,
142 'rust-analyzer/inlayHints', 109 );
143 request,
144 ),
145 );
146 } 110 }
147} 111}