-
Notifications
You must be signed in to change notification settings - Fork 884
Expand file tree
/
Copy pathAppHostFilePresenceWatcher.ts
More file actions
90 lines (80 loc) · 3.25 KB
/
AppHostFilePresenceWatcher.ts
File metadata and controls
90 lines (80 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import * as vscode from 'vscode';
import { getParserForDocument } from './parsers/AppHostResourceParser';
import { AppHostDataRepository } from '../views/AppHostDataRepository';
/**
* Watches the set of visible text editors and reports to {@link AppHostDataRepository}
* whether at least one of them is an AppHost file.
*
* This is what makes code-lens decorations on a freshly-created AppHost file see live
* resource state without the user first opening the Aspire side panel.
*
* The watcher reacts to:
* - editor visibility changes (`onDidChangeVisibleTextEditors`),
* - text edits to a visible document (`onDidChangeTextDocument`, debounced),
* so that toggling AppHost-ness by editing the file (e.g. adding the
* `DistributedApplication.CreateBuilder` call or the `#:sdk Aspire.AppHost.Sdk`
* directive) is picked up without requiring a save or focus change.
*/
export class AppHostFilePresenceWatcher implements vscode.Disposable {
private static readonly _changeDebounceMs = 250;
private readonly _disposables: vscode.Disposable[] = [];
private _lastValue = false;
private _changeTimer: NodeJS.Timeout | undefined;
private _updateVersion = 0;
private _updateTask: Promise<void> = Promise.resolve();
constructor(private readonly _repository: AppHostDataRepository) {
this._disposables.push(
vscode.window.onDidChangeVisibleTextEditors(() => this._queueUpdate()),
vscode.workspace.onDidChangeTextDocument(e => this._onTextDocumentChanged(e)),
);
this._queueUpdate();
}
private _onTextDocumentChanged(event: vscode.TextDocumentChangeEvent): void {
// Only re-evaluate when the changed document is currently visible — edits to
// background documents cannot change the visible-AppHost state.
const isVisible = vscode.window.visibleTextEditors.some(editor => editor.document === event.document);
if (!isVisible) {
return;
}
this._scheduleUpdate();
}
private _scheduleUpdate(): void {
if (this._changeTimer) {
clearTimeout(this._changeTimer);
}
this._changeTimer = setTimeout(() => {
this._changeTimer = undefined;
this._queueUpdate();
}, AppHostFilePresenceWatcher._changeDebounceMs);
}
private _queueUpdate(): void {
const version = ++this._updateVersion;
this._updateTask = this._update(version);
}
private async _update(version: number): Promise<void> {
const value = await this._anyVisibleEditorIsAppHost();
if (version !== this._updateVersion) {
return;
}
if (value === this._lastValue) {
return;
}
this._lastValue = value;
this._repository.setAppHostFileOpen(value);
}
private async _anyVisibleEditorIsAppHost(): Promise<boolean> {
for (const editor of vscode.window.visibleTextEditors) {
if (await getParserForDocument(editor.document)) {
return true;
}
}
return false;
}
dispose(): void {
if (this._changeTimer) {
clearTimeout(this._changeTimer);
this._changeTimer = undefined;
}
this._disposables.forEach(d => d.dispose());
}
}