From ac8a142dddc697d26d5aa8c878df933300163e09 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 30 Dec 2019 21:28:38 +0100 Subject: [PATCH] Refactor inlay hints --- editors/code/src/inlay_hints.ts | 170 +++++++++++++------------------- 1 file changed, 67 insertions(+), 103 deletions(-) diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index fb8f135c382..aae9de69c2e 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -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 { - 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 { - 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> = []; - - 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 { + private async refreshEditor(editor: vscode.TextEditor): Promise { 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 { const request: InlayHintsParams = { textDocument: { uri: documentUri }, }; - const client = Server.client; - return client - .onReady() - .then(() => - client.sendRequest( - 'rust-analyzer/inlayHints', - request, - ), - ); + await this.ctx.client.onReady(); + + return this.ctx.client.sendRequest( + 'rust-analyzer/inlayHints', + request, + ); } } -- 2.44.0