Skip to content

Commit ed8831e

Browse files
Add async initialization to ChangeSetFileElement (#15761)
1 parent 72e894c commit ed8831e

File tree

1 file changed

+69
-9
lines changed

1 file changed

+69
-9
lines changed

packages/ai-chat/src/browser/change-set-file-element.ts

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ export class ChangeSetFileElement implements ChangeSetElement {
7676
protected readonly toDispose = new DisposableCollection();
7777
protected _state: ChangeSetElementState;
7878

79-
protected originalContent: string | undefined;
79+
private _originalContent: string | undefined;
80+
protected _initialized = false;
81+
protected _initializationPromise: Promise<void> | undefined;
8082

8183
protected readonly onDidChangeEmitter = new Emitter<void>();
8284
readonly onDidChange = this.onDidChangeEmitter.event;
@@ -85,12 +87,36 @@ export class ChangeSetFileElement implements ChangeSetElement {
8587

8688
@postConstruct()
8789
init(): void {
90+
this._initializationPromise = this.initializeAsync();
8891
this.toDispose.push(this.onDidChangeEmitter);
8992
}
9093

94+
protected async initializeAsync(): Promise<void> {
95+
await this.obtainOriginalContent();
96+
this.listenForOriginalFileChanges();
97+
this._initialized = true;
98+
}
99+
100+
/**
101+
* Ensures that the element is fully initialized before proceeding.
102+
* This includes loading the original content from the file system.
103+
*/
104+
async ensureInitialized(): Promise<void> {
105+
await this._initializationPromise;
106+
}
107+
108+
/**
109+
* Returns true if the element has been fully initialized.
110+
*/
111+
get isInitialized(): boolean {
112+
return this._initialized;
113+
}
114+
91115
protected async obtainOriginalContent(): Promise<void> {
92-
this.originalContent = await this.changeSetFileService.read(this.uri);
93-
this.readOnlyResource.update({ contents: this.originalContent ?? '' });
116+
this._originalContent = await this.changeSetFileService.read(this.uri);
117+
if (this._readOnlyResource) {
118+
this.readOnlyResource.update({ contents: this._originalContent ?? '' });
119+
}
94120
}
95121

96122
protected getInMemoryUri(uri: URI): ConfigurableMutableReferenceResource {
@@ -100,10 +126,14 @@ export class ChangeSetFileElement implements ChangeSetElement {
100126
protected listenForOriginalFileChanges(): void {
101127
this.toDispose.push(this.fileService.onDidFilesChange(async event => {
102128
if (!event.contains(this.uri)) { return; }
129+
if (!this._initialized && this._initializationPromise) {
130+
// make sure we are initialized
131+
await this._initializationPromise;
132+
}
103133
// If we are applied, the tricky thing becomes the question what to revert to; otherwise, what to apply.
104134
const newContent = await this.changeSetFileService.read(this.uri).catch(() => '');
105135
this.readOnlyResource.update({ contents: newContent });
106-
if (newContent === this.originalContent) {
136+
if (newContent === this._originalContent) {
107137
this.state = 'pending';
108138
} else if (newContent === this.targetState) {
109139
this.state = 'applied';
@@ -120,10 +150,19 @@ export class ChangeSetFileElement implements ChangeSetElement {
120150
protected get readOnlyResource(): ConfigurableMutableReferenceResource {
121151
if (!this._readOnlyResource) {
122152
this._readOnlyResource = this.getInMemoryUri(ChangeSetFileElement.toReadOnlyUri(this.uri, this.elementProps.chatSessionId));
123-
this._readOnlyResource.update({ autosaveable: false, readOnly: true });
153+
this._readOnlyResource.update({
154+
autosaveable: false,
155+
readOnly: true,
156+
contents: this._originalContent ?? ''
157+
});
124158
this.toDispose.push(this._readOnlyResource);
125-
this.obtainOriginalContent();
126-
this.listenForOriginalFileChanges();
159+
160+
// If not yet initialized, update the resource once initialization completes
161+
if (!this._initialized) {
162+
this._initializationPromise?.then(() => {
163+
this._readOnlyResource?.update({ contents: this._originalContent ?? '' });
164+
});
165+
}
127166
}
128167
return this._readOnlyResource;
129168
}
@@ -180,22 +219,41 @@ export class ChangeSetFileElement implements ChangeSetElement {
180219
return this.elementProps.data;
181220
};
182221

222+
get originalContent(): string | undefined {
223+
if (!this._initialized && this._initializationPromise) {
224+
console.warn('Accessing originalContent before initialization is complete. Consider using async methods.');
225+
}
226+
return this._originalContent;
227+
}
228+
229+
/**
230+
* Gets the original content of the file asynchronously.
231+
* Ensures initialization is complete before returning the content.
232+
*/
233+
async getOriginalContent(): Promise<string | undefined> {
234+
await this.ensureInitialized();
235+
return this._originalContent;
236+
}
237+
183238
get targetState(): string {
184239
return this.elementProps.targetState ?? '';
185240
}
186241

187242
async open(): Promise<void> {
243+
await this.ensureInitialized();
188244
this.changeSetFileService.open(this);
189245
}
190246

191247
async openChange(): Promise<void> {
248+
await this.ensureInitialized();
192249
this.changeSetFileService.openDiff(
193250
this.readOnlyUri,
194251
this.changedUri
195252
);
196253
}
197254

198255
async apply(contents?: string): Promise<void> {
256+
await this.ensureInitialized();
199257
if (!await this.confirm('Apply')) { return; }
200258
if (!(await this.changeSetFileService.trySave(this.changedUri))) {
201259
if (this.type === 'delete') {
@@ -214,16 +272,18 @@ export class ChangeSetFileElement implements ChangeSetElement {
214272
}
215273

216274
onShow(): void {
275+
// Ensure we have the latest state when showing
217276
this.changeResource.update({ contents: this.targetState, onSave: content => this.writeChanges(content) });
218277
}
219278

220279
async revert(): Promise<void> {
280+
await this.ensureInitialized();
221281
if (!await this.confirm('Revert')) { return; }
222282
this.state = 'pending';
223283
if (this.type === 'add') {
224284
await this.changeSetFileService.delete(this.uri);
225-
} else if (this.originalContent) {
226-
await this.changeSetFileService.write(this.uri, this.originalContent);
285+
} else if (this._originalContent) {
286+
await this.changeSetFileService.write(this.uri, this._originalContent);
227287
}
228288
}
229289

0 commit comments

Comments
 (0)