VSCode
在 1.88
的更新日志中宣布了 Restart extensions
的功能:
在本地 VSCode
中,现在不需要 Reload Window
就可以重启插件了。这不禁让我好奇,他们到底做了些什么?
ToC
找找
让我们先用关键词 Reload Extensions
来找一找:
this.enabled = true; this.class = ExtensionRuntimeStateAction.EnabledClass; this.tooltip = runtimeState.reason; this.label = runtimeState.action === ExtensionRuntimeActionType.ReloadWindow ? localize('reload window', 'Reload Window') : runtimeState.action === ExtensionRuntimeActionType.RestartExtensions ? localize('restart extensions', 'Restart Extensions') : runtimeState.action === ExtensionRuntimeActionType.QuitAndInstall ? localize('restart product', 'Restart to Update') : runtimeState.action === ExtensionRuntimeActionType.ApplyUpdate || runtimeState.action === ExtensionRuntimeActionType.DownloadUpdate ? localize('update product', 'Update {0}', this.productService.nameShort) : ''; }
找到了 runtimeState.action
。它是怎么定义的呢?
export const enum ExtensionRuntimeActionType { ReloadWindow = "reloadWindow", RestartExtensions = "restartExtensions", DownloadUpdate = "downloadUpdate", ApplyUpdate = "applyUpdate", QuitAndInstall = "quitAndInstall",}
看来是加了个 ExtensionRuntimeActionType.RestartExtensions
。继续追引用:
override async run(): Promise<any> {21 collapsed lines
const runtimeState = this.extension?.runtimeState; if (!runtimeState?.action) { return; }
type ExtensionRuntimeStateActionClassification = { owner: 'sandy081'; comment: 'Extension runtime state action event'; action: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Executed action' }; }; type ExtensionRuntimeStateActionEvent = { action: string; }; this.telemetryService.publicLog2<ExtensionRuntimeStateActionEvent, ExtensionRuntimeStateActionClassification>('extensions:runtimestate:action', { action: runtimeState.action });
if (runtimeState?.action === ExtensionRuntimeActionType.ReloadWindow) { return this.hostService.reload(); }
else if (runtimeState?.action === ExtensionRuntimeActionType.RestartExtensions) { return this.extensionsWorkbenchService.updateRunningExtensions(); }13 collapsed lines
else if (runtimeState?.action === ExtensionRuntimeActionType.DownloadUpdate) { return this.updateService.downloadUpdate(); }
else if (runtimeState?.action === ExtensionRuntimeActionType.ApplyUpdate) { return this.updateService.applyUpdate(); }
else if (runtimeState?.action === ExtensionRuntimeActionType.QuitAndInstall) { return this.updateService.quitAndInstall(); }
}
看来核心逻辑都在 updateRunningExtensions
里了。
看看
看看 updateRunningExtensions
:
async updateRunningExtensions(): Promise<void> { const toAdd: ILocalExtension[] = []; const toRemove: string[] = [];
const extensionsToCheck = [...this.local];
const notExistingRunningExtensions = this.extensionService.extensions.filter(e => !this.local.some(local => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, local.identifier))); if (notExistingRunningExtensions.length) { const extensions = await this.getExtensions(notExistingRunningExtensions.map(e => ({ id: e.identifier.value })), CancellationToken.None); extensionsToCheck.push(...extensions); }
for (const extension of extensionsToCheck) { const runtimeState = extension.runtimeState; if (!runtimeState || runtimeState.action !== ExtensionRuntimeActionType.RestartExtensions) { continue; } if (extension.state === ExtensionState.Uninstalled) { toRemove.push(extension.identifier.id); continue; } if (!extension.local) { continue; } const isEnabled = this.extensionEnablementService.isEnabled(extension.local); if (isEnabled) { const runningExtension = this.extensionService.extensions.find(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier)); if (runningExtension) { toRemove.push(runningExtension.identifier.value); } toAdd.push(extension.local); } else { toRemove.push(extension.identifier.id); } } if (toAdd.length || toRemove.length) { if (await this.extensionService.stopExtensionHosts(nls.localize('restart', "Enable or Disable extensions"))) { await this.extensionService.startExtensionHosts({ toAdd, toRemove }); } } }
还以为会有什么魔法,结果居然是先 Stop
再 Start
??
这里 startExtensionHosts()
的签名相比于之前的版本增加了 toAdd
和 toRemove
两个参数,传到内部之后是直接调用了 _handleDeltaExtensions
:
public async startExtensionHosts(updates?: { toAdd: IExtension[]; toRemove: string[] }): Promise<void> { this._doStopExtensionHosts();
if (updates) { await this._handleDeltaExtensions(new DeltaExtensionsQueueItem(updates.toAdd, updates.toRemove)); }
const lock = await this._registry.acquireLock('startExtensionHosts'); try { this._startExtensionHostsIfNecessary(false, Array.from(this._allRequestedActivateEvents.keys()));
const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess); await Promise.all(localProcessExtensionHosts.map(extHost => extHost.ready())); } finally { lock.dispose(); } }
没意思,还以为是做了什么好东西,这样实现居然还不支持 Remote
,软软没救了,散了散了)