From f996098ad43bc8dc940fc51d74429b2e5ab3a973 Mon Sep 17 00:00:00 2001 From: Vladimir Piskarev Date: Thu, 27 Jun 2024 16:21:48 +0300 Subject: [PATCH] Improve implementation around widget management (#13818) Mainly, ensures that any widget promises returned by the `WidgetManager` will only resolve when the entire widget creation process has completed successfully, including the 'onWillCreateWidget` part. --- packages/core/src/browser/widget-manager.ts | 30 ++++++++++++------- .../core/src/browser/widget-open-handler.ts | 6 ++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/core/src/browser/widget-manager.ts b/packages/core/src/browser/widget-manager.ts index 77a4a2bb2e265..960131b2c1379 100644 --- a/packages/core/src/browser/widget-manager.ts +++ b/packages/core/src/browser/widget-manager.ts @@ -114,7 +114,7 @@ export class WidgetManager { protected _cachedFactories: Map; protected readonly widgets = new Map(); - protected readonly pendingWidgetPromises = new Map>(); + protected readonly pendingWidgetPromises = new Map>(); @inject(ContributionProvider) @named(WidgetFactory) protected readonly factoryProvider: ContributionProvider; @@ -207,9 +207,9 @@ export class WidgetManager { return widget as T; } } - for (const [key, widget] of this.pendingWidgetPromises.entries()) { + for (const [key, widgetPromise] of this.pendingWidgetPromises.entries()) { if (this.testPredicate(key, factoryId, predicate)) { - return widget as T; + return widgetPromise as Promise; } } } @@ -244,18 +244,26 @@ export class WidgetManager { if (!factory) { throw Error("No widget factory '" + factoryId + "' has been registered."); } - try { - const widgetPromise = factory.createWidget(options); - this.pendingWidgetPromises.set(key, widgetPromise); - const widget = await widgetPromise; - await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId, widget }); + const widgetPromise = this.doCreateWidget(factory, options).then(widget => { this.widgets.set(key, widget); widget.disposed.connect(() => this.widgets.delete(key)); this.onDidCreateWidgetEmitter.fire({ factoryId, widget }); - return widget as T; - } finally { - this.pendingWidgetPromises.delete(key); + return widget; + }).finally(() => this.pendingWidgetPromises.delete(key)); + this.pendingWidgetPromises.set(key, widgetPromise); + return widgetPromise; + } + + protected async doCreateWidget(factory: WidgetFactory, options?: any): Promise { + const widget = await factory.createWidget(options); + // Note: the widget creation process also includes the 'onWillCreateWidget' part, which can potentially fail + try { + await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId: factory.id, widget }); + } catch (e) { + widget.dispose(); + throw e; } + return widget as T; } /** diff --git a/packages/core/src/browser/widget-open-handler.ts b/packages/core/src/browser/widget-open-handler.ts index 7c08ca1d02845..7e3e4c37fab07 100644 --- a/packages/core/src/browser/widget-open-handler.ts +++ b/packages/core/src/browser/widget-open-handler.ts @@ -96,7 +96,7 @@ export abstract class WidgetOpenHandler implements OpenHan ...options }; if (!widget.isAttached) { - this.shell.addWidget(widget, op.widgetOptions || { area: 'main' }); + await this.shell.addWidget(widget, op.widgetOptions || { area: 'main' }); } if (op.mode === 'activate') { await this.shell.activateWidget(widget.id); @@ -143,12 +143,12 @@ export abstract class WidgetOpenHandler implements OpenHan protected getWidget(uri: URI, options?: WidgetOpenerOptions): Promise { const widgetOptions = this.createWidgetOptions(uri, options); - return this.widgetManager.getWidget(this.id, widgetOptions); + return this.widgetManager.getWidget(this.id, widgetOptions); } protected getOrCreateWidget(uri: URI, options?: WidgetOpenerOptions): Promise { const widgetOptions = this.createWidgetOptions(uri, options); - return this.widgetManager.getOrCreateWidget(this.id, widgetOptions); + return this.widgetManager.getOrCreateWidget(this.id, widgetOptions); } protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object;