Skip to content

Commit c5598d9

Browse files
Avoid shared mutable state
1 parent 777552b commit c5598d9

File tree

2 files changed

+55
-71
lines changed

2 files changed

+55
-71
lines changed

editors/code/src/commands/inlay_hints.ts

Lines changed: 39 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -21,91 +21,72 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
2121

2222
export class HintsUpdater {
2323
private displayHints = true;
24-
private decorationsSinceLastChange = new Map<
25-
string,
26-
vscode.DecorationOptions[]
27-
>();
28-
29-
public async loadHints(editor?: vscode.TextEditor): Promise<void> {
30-
if (this.displayHints) {
31-
const documentUri = this.getEditorDocumentUri(editor);
32-
if (documentUri !== null) {
33-
const latestDecorations = this.decorationsSinceLastChange.get(
34-
documentUri.toString()
35-
);
36-
if (latestDecorations === undefined) {
37-
await this.updateDecorationsFromServer(
38-
documentUri,
39-
editor!
40-
);
41-
} else {
42-
await editor!.setDecorations(
43-
typeHintDecorationType,
44-
latestDecorations
45-
);
46-
}
47-
}
48-
}
49-
}
5024

5125
public async toggleHintsDisplay(displayHints: boolean): Promise<void> {
5226
if (this.displayHints !== displayHints) {
5327
this.displayHints = displayHints;
54-
this.decorationsSinceLastChange.clear();
55-
56-
if (displayHints) {
57-
return this.updateHints();
58-
} else {
59-
const currentEditor = vscode.window.activeTextEditor;
60-
if (this.getEditorDocumentUri(currentEditor) !== null) {
61-
return currentEditor!.setDecorations(
62-
typeHintDecorationType,
63-
[]
64-
);
65-
}
66-
}
28+
return this.refreshVisibleEditorsHints(
29+
displayHints ? undefined : []
30+
);
6731
}
6832
}
6933

70-
public async updateHints(cause?: TextDocumentChangeEvent): Promise<void> {
34+
public async refreshHintsForVisibleEditors(
35+
cause?: TextDocumentChangeEvent
36+
): Promise<void> {
7137
if (!this.displayHints) {
7238
return;
7339
}
74-
const editor = vscode.window.activeTextEditor;
75-
if (editor === undefined) {
40+
if (
41+
cause !== undefined &&
42+
(cause.contentChanges.length === 0 ||
43+
!this.isRustDocument(cause.document))
44+
) {
7645
return;
7746
}
78-
const document = cause === undefined ? editor.document : cause.document;
79-
if (!this.isRustDocument(document)) {
80-
return;
47+
return this.refreshVisibleEditorsHints();
48+
}
49+
50+
private async refreshVisibleEditorsHints(
51+
newDecorations?: vscode.DecorationOptions[]
52+
) {
53+
const promises: Array<Promise<void>> = [];
54+
55+
for (const rustEditor of vscode.window.visibleTextEditors.filter(
56+
editor => this.isRustDocument(editor.document)
57+
)) {
58+
if (newDecorations !== undefined) {
59+
promises.push(
60+
Promise.resolve(
61+
rustEditor.setDecorations(
62+
typeHintDecorationType,
63+
newDecorations
64+
)
65+
)
66+
);
67+
} else {
68+
promises.push(this.updateDecorationsFromServer(rustEditor));
69+
}
8170
}
8271

83-
this.decorationsSinceLastChange.clear();
84-
return await this.updateDecorationsFromServer(document.uri, editor);
72+
for (const promise of promises) {
73+
await promise;
74+
}
8575
}
8676

8777
private isRustDocument(document: vscode.TextDocument): boolean {
8878
return document && document.languageId === 'rust';
8979
}
9080

9181
private async updateDecorationsFromServer(
92-
documentUri: vscode.Uri,
9382
editor: TextEditor
9483
): Promise<void> {
95-
const newHints = await this.queryHints(documentUri.toString());
96-
if (
97-
newHints !== null &&
98-
this.getEditorDocumentUri(vscode.window.activeTextEditor) ===
99-
documentUri
100-
) {
84+
const newHints = await this.queryHints(editor.document.uri.toString());
85+
if (newHints !== null) {
10186
const newDecorations = newHints.map(hint => ({
10287
range: hint.range,
10388
renderOptions: { after: { contentText: `: ${hint.label}` } }
10489
}));
105-
this.decorationsSinceLastChange.set(
106-
documentUri.toString(),
107-
newDecorations
108-
);
10990
return editor.setDecorations(
11091
typeHintDecorationType,
11192
newDecorations
@@ -127,13 +108,4 @@ export class HintsUpdater {
127108
)
128109
);
129110
}
130-
131-
private getEditorDocumentUri(
132-
editor?: vscode.TextEditor
133-
): vscode.Uri | null {
134-
if (editor && this.isRustDocument(editor.document)) {
135-
return editor.document.uri;
136-
}
137-
return null;
138-
}
139111
}

editors/code/src/extension.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,27 @@ export function activate(context: vscode.ExtensionContext) {
151151

152152
if (Server.config.displayInlayHints) {
153153
const hintsUpdater = new HintsUpdater();
154-
hintsUpdater.loadHints(vscode.window.activeTextEditor).then(() => {
154+
hintsUpdater.refreshHintsForVisibleEditors().then(() => {
155+
// vscode may ignore top level hintsUpdater.refreshHintsForVisibleEditors()
156+
// so update the hints once when the focus changes to guarantee their presence
157+
let editorChangeDisposable: vscode.Disposable | null = null;
158+
editorChangeDisposable = vscode.window.onDidChangeActiveTextEditor(
159+
_ => {
160+
if (editorChangeDisposable !== null) {
161+
editorChangeDisposable.dispose();
162+
}
163+
return hintsUpdater.refreshHintsForVisibleEditors();
164+
}
165+
);
166+
155167
disposeOnDeactivation(
156-
vscode.window.onDidChangeActiveTextEditor(editor =>
157-
hintsUpdater.loadHints(editor)
168+
vscode.window.onDidChangeVisibleTextEditors(_ =>
169+
hintsUpdater.refreshHintsForVisibleEditors()
158170
)
159171
);
160172
disposeOnDeactivation(
161173
vscode.workspace.onDidChangeTextDocument(e =>
162-
hintsUpdater.updateHints(e)
174+
hintsUpdater.refreshHintsForVisibleEditors(e)
163175
)
164176
);
165177
disposeOnDeactivation(

0 commit comments

Comments
 (0)