]> git.lizzy.rs Git - rust.git/commitdiff
Refactor inlay hints
authorAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 30 Dec 2019 20:28:38 +0000 (21:28 +0100)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Mon, 30 Dec 2019 20:32:04 +0000 (21:32 +0100)
editors/code/src/inlay_hints.ts

index fb8f135c382a0962e1f7d3b4244fb9451f560847..aae9de69c2e9f2ed8b4e67c9050e927cab5afa33 100644 (file)
@@ -1,39 +1,29 @@
 import * as vscode from 'vscode';
 import * as lc from 'vscode-languageclient';
-import { Server } from './server';
+
 import { Ctx } from './ctx';
 
 export function activateInlayHints(ctx: Ctx) {
-    const hintsUpdater = new HintsUpdater();
-    hintsUpdater.refreshHintsForVisibleEditors().then(() => {
-        // vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
-        // so update the hints once when the focus changes to guarantee their presence
-        let editorChangeDisposable: vscode.Disposable | null = null;
-        editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
-            _ => {
-                if (editorChangeDisposable !== null) {
-                    editorChangeDisposable.dispose();
-                }
-                return hintsUpdater.refreshHintsForVisibleEditors();
-            },
-        );
+    const hintsUpdater = new HintsUpdater(ctx);
+    console.log('activateInlayHints');
 
-        ctx.pushCleanup(
-            vscode.window.onDidChangeVisibleTextEditors(_ =>
-                hintsUpdater.refreshHintsForVisibleEditors(),
-            ),
-        );
-        ctx.pushCleanup(
-            vscode.workspace.onDidChangeTextDocument(e =>
-                hintsUpdater.refreshHintsForVisibleEditors(e),
-            ),
-        );
-        ctx.pushCleanup(
-            vscode.workspace.onDidChangeConfiguration(_ =>
-                hintsUpdater.toggleHintsDisplay(ctx.config.displayInlayHints),
-            ),
-        );
-    });
+    vscode.window.onDidChangeVisibleTextEditors(async _ => {
+        await hintsUpdater.refresh();
+    }, ctx.subscriptions);
+
+    vscode.workspace.onDidChangeTextDocument(async e => {
+        if (e.contentChanges.length === 0) return;
+        if (e.document.languageId !== 'rust') return;
+        await hintsUpdater.refresh();
+    }, ctx.subscriptions);
+
+    vscode.workspace.onDidChangeConfiguration(_ => {
+        hintsUpdater.setEnabled(ctx.config.displayInlayHints);
+    }, ctx.subscriptions);
+
+    // XXX: don't await here;
+    // Who knows what happens if an exception is thrown here...
+    hintsUpdater.refresh();
 }
 
 interface InlayHintsParams {
@@ -53,95 +43,69 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
 });
 
 class HintsUpdater {
-    private displayHints = true;
-
-    public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
-        if (this.displayHints !== displayHints) {
-            this.displayHints = displayHints;
-            return this.refreshVisibleEditorsHints(
-                displayHints ? undefined : [],
-            );
-        }
-    }
+    private ctx: Ctx;
+    private enabled = true;
 
-    public async refreshHintsForVisibleEditors(
-        cause?: vscode.TextDocumentChangeEvent,
-    ): Promise<void> {
-        if (!this.displayHints) return;
-
-        if (
-            cause !== undefined &&
-            (cause.contentChanges.length === 0 ||
-                !this.isRustDocument(cause.document))
-        ) {
-            return;
-        }
-        return this.refreshVisibleEditorsHints();
+    constructor(ctx: Ctx) {
+        this.ctx = ctx;
     }
 
-    private async refreshVisibleEditorsHints(
-        newDecorations?: vscode.DecorationOptions[],
-    ) {
-        const promises: Array<Promise<void>> = [];
-
-        for (const rustEditor of vscode.window.visibleTextEditors.filter(
-            editor => this.isRustDocument(editor.document),
-        )) {
-            if (newDecorations !== undefined) {
-                promises.push(
-                    Promise.resolve(
-                        rustEditor.setDecorations(
-                            typeHintDecorationType,
-                            newDecorations,
-                        ),
-                    ),
-                );
-            } else {
-                promises.push(this.updateDecorationsFromServer(rustEditor));
-            }
-        }
+    async setEnabled(enabled: boolean) {
+        if (this.enabled == enabled) return;
+        this.enabled = enabled;
 
-        for (const promise of promises) {
-            await promise;
+        if (this.enabled) {
+            await this.refresh();
+        } else {
+            this.allEditors.forEach(it => this.setDecorations(it, []));
         }
     }
 
-    private isRustDocument(document: vscode.TextDocument): boolean {
-        return document && document.languageId === 'rust';
+    async refresh() {
+        if (!this.enabled) return;
+        const promises = this.allEditors.map(it => this.refreshEditor(it));
+        await Promise.all(promises);
     }
 
-    private async updateDecorationsFromServer(
-        editor: vscode.TextEditor,
-    ): Promise<void> {
+    private async refreshEditor(editor: vscode.TextEditor): Promise<void> {
         const newHints = await this.queryHints(editor.document.uri.toString());
-        if (newHints !== null) {
-            const newDecorations = newHints.map(hint => ({
-                range: hint.range,
-                renderOptions: {
-                    after: {
-                        contentText: `: ${hint.label}`,
-                    },
+
+        const newDecorations = (newHints ? newHints : []).map(hint => ({
+            range: hint.range,
+            renderOptions: {
+                after: {
+                    contentText: `: ${hint.label}`,
                 },
-            }));
-            return editor.setDecorations(
-                typeHintDecorationType,
-                newDecorations,
-            );
-        }
+            },
+        }));
+        this.setDecorations(editor, newDecorations);
+    }
+
+    private get allEditors(): vscode.TextEditor[] {
+        return vscode.window.visibleTextEditors.filter(
+            editor => editor.document.languageId === 'rust',
+        );
+    }
+
+    private setDecorations(
+        editor: vscode.TextEditor,
+        decorations: vscode.DecorationOptions[],
+    ) {
+        editor.setDecorations(
+            typeHintDecorationType,
+            this.enabled ? decorations : [],
+        );
     }
 
     private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
         const request: InlayHintsParams = {
             textDocument: { uri: documentUri },
         };
-        const client = Server.client;
-        return client
-            .onReady()
-            .then(() =>
-                client.sendRequest<InlayHint[] | null>(
-                    'rust-analyzer/inlayHints',
-                    request,
-                ),
-            );
+        await this.ctx.client.onReady();
+
+        return this.ctx.client.sendRequest<InlayHint[] | null>(
+            'rust-analyzer/inlayHints',
+            request,
+        );
     }
 }