Avoid shared mutable state

This commit is contained in:
Kirill Bulatov 2019-08-05 22:31:12 +03:00
parent 777552b6a8
commit c5598d9ade
2 changed files with 55 additions and 71 deletions

View file

@ -21,67 +21,57 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
export class HintsUpdater {
private displayHints = true;
private decorationsSinceLastChange = new Map<
string,
vscode.DecorationOptions[]
>();
public async loadHints(editor?: vscode.TextEditor): Promise<void> {
if (this.displayHints) {
const documentUri = this.getEditorDocumentUri(editor);
if (documentUri !== null) {
const latestDecorations = this.decorationsSinceLastChange.get(
documentUri.toString()
);
if (latestDecorations === undefined) {
await this.updateDecorationsFromServer(
documentUri,
editor!
);
} else {
await editor!.setDecorations(
typeHintDecorationType,
latestDecorations
);
}
}
}
}
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
if (this.displayHints !== displayHints) {
this.displayHints = displayHints;
this.decorationsSinceLastChange.clear();
if (displayHints) {
return this.updateHints();
} else {
const currentEditor = vscode.window.activeTextEditor;
if (this.getEditorDocumentUri(currentEditor) !== null) {
return currentEditor!.setDecorations(
typeHintDecorationType,
[]
);
}
}
return this.refreshVisibleEditorsHints(
displayHints ? undefined : []
);
}
}
public async updateHints(cause?: TextDocumentChangeEvent): Promise<void> {
public async refreshHintsForVisibleEditors(
cause?: TextDocumentChangeEvent
): Promise<void> {
if (!this.displayHints) {
return;
}
const editor = vscode.window.activeTextEditor;
if (editor === undefined) {
if (
cause !== undefined &&
(cause.contentChanges.length === 0 ||
!this.isRustDocument(cause.document))
) {
return;
}
const document = cause === undefined ? editor.document : cause.document;
if (!this.isRustDocument(document)) {
return;
return this.refreshVisibleEditorsHints();
}
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));
}
}
this.decorationsSinceLastChange.clear();
return await this.updateDecorationsFromServer(document.uri, editor);
for (const promise of promises) {
await promise;
}
}
private isRustDocument(document: vscode.TextDocument): boolean {
@ -89,23 +79,14 @@ export class HintsUpdater {
}
private async updateDecorationsFromServer(
documentUri: vscode.Uri,
editor: TextEditor
): Promise<void> {
const newHints = await this.queryHints(documentUri.toString());
if (
newHints !== null &&
this.getEditorDocumentUri(vscode.window.activeTextEditor) ===
documentUri
) {
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}` } }
}));
this.decorationsSinceLastChange.set(
documentUri.toString(),
newDecorations
);
return editor.setDecorations(
typeHintDecorationType,
newDecorations
@ -127,13 +108,4 @@ export class HintsUpdater {
)
);
}
private getEditorDocumentUri(
editor?: vscode.TextEditor
): vscode.Uri | null {
if (editor && this.isRustDocument(editor.document)) {
return editor.document.uri;
}
return null;
}
}

View file

@ -151,15 +151,27 @@ export function activate(context: vscode.ExtensionContext) {
if (Server.config.displayInlayHints) {
const hintsUpdater = new HintsUpdater();
hintsUpdater.loadHints(vscode.window.activeTextEditor).then(() => {
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();
}
);
disposeOnDeactivation(
vscode.window.onDidChangeActiveTextEditor(editor =>
hintsUpdater.loadHints(editor)
vscode.window.onDidChangeVisibleTextEditors(_ =>
hintsUpdater.refreshHintsForVisibleEditors()
)
);
disposeOnDeactivation(
vscode.workspace.onDidChangeTextDocument(e =>
hintsUpdater.updateHints(e)
hintsUpdater.refreshHintsForVisibleEditors(e)
)
);
disposeOnDeactivation(