diff --git a/src/vs/workbench/api/browser/mainThreadCLICommands.ts b/src/vs/workbench/api/browser/mainThreadCLICommands.ts index 43241ad99e2..62002c1f80e 100644 --- a/src/vs/workbench/api/browser/mainThreadCLICommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCLICommands.ts @@ -20,7 +20,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IExtensionManifest } from 'vs/workbench/workbench.web.api'; @@ -88,22 +88,19 @@ class RemoteExtensionCLIManagementService extends ExtensionManagementCLIService private _location: string | undefined; - private readonly _extensionKindController: ExtensionKindController; - constructor( @IExtensionManagementService extensionManagementService: IExtensionManagementService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, @ILabelService labelService: ILabelService, - @IWorkbenchEnvironmentService envService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService envService: IWorkbenchEnvironmentService, + @IExtensionManifestPropertiesService private readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(extensionManagementService, extensionGalleryService); const remoteAuthority = envService.remoteAuthority; this._location = remoteAuthority ? labelService.getHostLabel(Schemas.vscodeRemote, remoteAuthority) : undefined; - - this._extensionKindController = new ExtensionKindController(productService, configurationService); } protected override get location(): string | undefined { @@ -111,7 +108,7 @@ class RemoteExtensionCLIManagementService extends ExtensionManagementCLIService } protected override validateExtensionKind(manifest: IExtensionManifest, output: CLIOutput): boolean { - if (!this._extensionKindController.canExecuteOnWorkspace(manifest)) { + if (!this._extensionManifestPropertiesService.canExecuteOnWorkspace(manifest)) { output.log(localize('cannot be installed', "Cannot install the '{0}' extension because it is declared to not run in this setup.", getExtensionId(manifest.publisher, manifest.name))); return false; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 0f1116116fc..9c7ab008f47 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -45,7 +45,6 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; import { IWorkbenchThemeService, IWorkbenchTheme, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IWorkbenchProductIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProductService } from 'vs/platform/product/common/productService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -61,6 +60,7 @@ import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { infoIcon, manageExtensionIcon, syncEnabledIcon, syncIgnoredIcon, trustIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { isWeb } from 'vs/base/common/platform'; import { isWorkspaceTrustEnabled } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; function getRelativeDateLabel(date: Date): string { const delta = new Date().getTime() - date.getTime(); @@ -448,8 +448,6 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} prominent install`; private static readonly InstallingClass = `${ExtensionAction.LABEL_ACTION_CLASS} install installing`; - private _extensionKindController: ExtensionKindController; - updateWhenCounterExtensionChanges: boolean = true; constructor( @@ -460,11 +458,10 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false); this.update(); - - this._extensionKindController = new ExtensionKindController(productService, configurationService); } update(): void { @@ -506,28 +503,28 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { } // Prefers to run on UI - if (this.server === this.extensionManagementServerService.localExtensionManagementServer && this._extensionKindController.prefersExecuteOnUI(this.extension.local.manifest)) { + if (this.server === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local.manifest)) { return true; } // Prefers to run on Workspace - if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && this._extensionKindController.prefersExecuteOnWorkspace(this.extension.local.manifest)) { + if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local.manifest)) { return true; } // Prefers to run on Web - if (this.server === this.extensionManagementServerService.webExtensionManagementServer && this._extensionKindController.prefersExecuteOnWeb(this.extension.local.manifest)) { + if (this.server === this.extensionManagementServerService.webExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWeb(this.extension.local.manifest)) { return true; } if (this.canInstallAnyWhere) { // Can run on UI - if (this.server === this.extensionManagementServerService.localExtensionManagementServer && this._extensionKindController.canExecuteOnUI(this.extension.local.manifest)) { + if (this.server === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.canExecuteOnUI(this.extension.local.manifest)) { return true; } // Can run on Workspace - if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && this._extensionKindController.canExecuteOnWorkspace(this.extension.local.manifest)) { + if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.canExecuteOnWorkspace(this.extension.local.manifest)) { return true; } } @@ -562,8 +559,9 @@ export class RemoteInstallAction extends InstallInOtherServerAction { @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, canInstallAnyWhere, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService); + super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, canInstallAnyWhere, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService, extensionManifestPropertiesService); } protected getInstallLabel(): string { @@ -581,8 +579,9 @@ export class LocalInstallAction extends InstallInOtherServerAction { @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService); + super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService, extensionManifestPropertiesService); } protected getInstallLabel(): string { @@ -599,8 +598,9 @@ export class WebInstallAction extends InstallInOtherServerAction { @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, @IWebExtensionsScannerService private readonly webExtensionsScannerService: IWebExtensionsScannerService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(`extensions.webInstall`, extensionManagementServerService.webExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService); + super(`extensions.webInstall`, extensionManagementServerService.webExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService, extensionManifestPropertiesService); } protected getInstallLabel(): string { @@ -1210,22 +1210,19 @@ export class ReloadAction extends ExtensionAction { updateWhenCounterExtensionChanges: boolean = true; private _runningExtensions: IExtensionDescription[] | null = null; - private _extensionKindController: ExtensionKindController; - constructor( @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IHostService private readonly hostService: IHostService, @IExtensionService private readonly extensionService: IExtensionService, @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, ) { super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false); this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); this.updateRunningExtensions(); - - this._extensionKindController = new ExtensionKindController(productService, configurationService); } private updateRunningExtensions(): void { @@ -1293,7 +1290,7 @@ export class ReloadAction extends ExtensionAction { const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)[0]; if (extensionInOtherServer) { // This extension prefers to run on UI/Local side but is running in remote - if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this._extensionKindController.prefersExecuteOnUI(this.extension.local!.manifest)) { + if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local!.manifest)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('enable locally', "Please reload Visual Studio Code to enable this extension locally."); @@ -1301,7 +1298,7 @@ export class ReloadAction extends ExtensionAction { } // This extension prefers to run on Workspace/Remote side but is running in local - if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this._extensionKindController.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { + if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label); @@ -1313,7 +1310,7 @@ export class ReloadAction extends ExtensionAction { if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { // This extension prefers to run on UI/Local side but is running in remote - if (this._extensionKindController.prefersExecuteOnUI(this.extension.local!.manifest)) { + if (this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local!.manifest)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); @@ -1321,7 +1318,7 @@ export class ReloadAction extends ExtensionAction { } if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) { // This extension prefers to run on Workspace/Remote side but is running in local - if (this._extensionKindController.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { + if (this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('postEnableTooltip', "Please reload Visual Studio Code to enable this extension."); @@ -2085,23 +2082,19 @@ export class SystemDisabledWarningAction extends ExtensionAction { updateWhenCounterExtensionChanges: boolean = true; private _runningExtensions: IExtensionDescription[] | null = null; - private _extensionKindController: ExtensionKindController; - constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @ILabelService private readonly labelService: ILabelService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionService private readonly extensionService: IExtensionService, - @IProductService productService: IProductService, - @IConfigurationService private readonly configurationService: IConfigurationService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false); this._register(this.labelService.onDidChangeFormatters(() => this.update(), this)); this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); this.updateRunningExtensions(); this.update(); - - this._extensionKindController = new ExtensionKindController(productService, configurationService); } private updateRunningExtensions(): void { @@ -2147,14 +2140,14 @@ export class SystemDisabledWarningAction extends ExtensionAction { const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)) : null; if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { - if (this._extensionKindController.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { + if (this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(this.extension.local!.manifest)) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.extensionManagementServerService.remoteExtensionManagementServer.label); } return; } if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) { - if (this._extensionKindController.prefersExecuteOnUI(this.extension.local!.manifest)) { + if (this.extensionManifestPropertiesService.prefersExecuteOnUI(this.extension.local!.manifest)) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.extensionManagementServerService.remoteExtensionManagementServer.label); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index c114b95be95..02ec9138ccc 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -36,12 +36,12 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IProductService } from 'vs/platform/product/common/productService'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { FileAccess } from 'vs/base/common/network'; import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions'; import { IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { isBoolean } from 'vs/base/common/types'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; interface IExtensionStateProvider { (extension: Extension): T; @@ -518,8 +518,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private installing: IExtension[] = []; - private readonly extensionKindController: ExtensionKindController; - constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IEditorService private readonly editorService: IEditorService, @@ -538,7 +536,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IIgnoredExtensionsManagementService private readonly extensionsSyncManagementService: IIgnoredExtensionsManagementService, @IUserDataAutoSyncService private readonly userDataAutoSyncService: IUserDataAutoSyncService, @IProductService private readonly productService: IProductService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(); this.hasOutdatedExtensionsContextKey = HasOutdatedExtensionsContext.bindTo(contextKeyService); @@ -588,8 +587,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.updateContexts(); this.updateActivity(); })); - - this.extensionKindController = new ExtensionKindController(productService, configurationService); } get local(): IExtension[] { @@ -716,7 +713,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return extensionsToChoose[0]; } - const extensionKinds = this.extensionKindController.getExtensionKind(manifest); + const extensionKinds = this.extensionManifestPropertiesService.getExtensionKind(manifest); let extension = extensionsToChoose.find(extension => { for (const extensionKind of extensionKinds) { diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 60742700d05..8620ab7957a 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -14,7 +14,6 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtension, isAuthenticaionProviderExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IProductService } from 'vs/platform/product/common/productService'; import { StorageManager } from 'vs/platform/extensionManagement/common/extensionEnablementService'; @@ -28,6 +27,7 @@ import { IExtensionBisectService } from 'vs/workbench/services/extensionManageme import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { Promises } from 'vs/base/common/async'; import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; const SOURCE = 'IWorkbenchExtensionEnablementService'; @@ -39,7 +39,6 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench public readonly onEnablementChanged: Event = this._onEnablementChanged.event; private readonly storageManger: StorageManager; - private readonly extensionKindController: ExtensionKindController; constructor( @IStorageService storageService: IStorageService, @@ -58,7 +57,8 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench @IHostService readonly hostService: IHostService, @IExtensionBisectService private readonly extensionBisectService: IExtensionBisectService, @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(); this.storageManger = this._register(new StorageManager(storageService)); @@ -86,8 +86,6 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench }]); }); } - - this.extensionKindController = new ExtensionKindController(productService, configurationService); } private get hasWorkspace(): boolean { @@ -246,7 +244,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench private _isDisabledByExtensionKind(extension: IExtension): boolean { if (this.extensionManagementServerService.remoteExtensionManagementServer || this.extensionManagementServerService.webExtensionManagementServer) { const server = this.extensionManagementServerService.getExtensionManagementServer(extension); - for (const extensionKind of this.extensionKindController.getExtensionKind(extension.manifest)) { + for (const extensionKind of this.extensionManifestPropertiesService.getExtensionKind(extension.manifest)) { if (extensionKind === 'ui') { if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.localExtensionManagementServer === server) { return false; diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts index bd730af5360..d824f860b7d 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -18,6 +18,7 @@ import { WebRemoteExtensionManagementService } from 'vs/workbench/services/exten import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IProductService } from 'vs/platform/product/common/productService'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class ExtensionManagementServerService implements IExtensionManagementServerService { @@ -34,10 +35,11 @@ export class ExtensionManagementServerService implements IExtensionManagementSer @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, @IInstantiationService instantiationService: IInstantiationService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { - const extensionManagementService = new WebRemoteExtensionManagementService(remoteAgentConnection.getChannel('extensions'), galleryService, configurationService, productService); + const extensionManagementService = new WebRemoteExtensionManagementService(remoteAgentConnection.getChannel('extensions'), galleryService, configurationService, productService, extensionManifestPropertiesService); this.remoteExtensionManagementServer = { id: 'remote', extensionManagementService, diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index cc66e2789d5..8fab913ad8e 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -15,7 +15,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { CancellationToken } from 'vs/base/common/cancellation'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localize } from 'vs/nls'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IProductService } from 'vs/platform/product/common/productService'; import { Schemas } from 'vs/base/common/network'; import { IDownloadService } from 'vs/platform/download/common/download'; @@ -27,6 +26,7 @@ import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementServ import { Promises } from 'vs/base/common/async'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class ExtensionManagementService extends Disposable implements IWorkbenchExtensionManagementService { @@ -39,8 +39,6 @@ export class ExtensionManagementService extends Disposable implements IWorkbench protected readonly servers: IExtensionManagementServer[] = []; - protected readonly extensionKindController: ExtensionKindController; - constructor( @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @@ -51,7 +49,8 @@ export class ExtensionManagementService extends Disposable implements IWorkbench @IUserDataAutoSyncEnablementService private readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, @IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService, @IDialogService private readonly dialogService: IDialogService, - @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(); if (this.extensionManagementServerService.localExtensionManagementServer) { @@ -68,8 +67,6 @@ export class ExtensionManagementService extends Disposable implements IWorkbench this.onDidInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidInstallExtension); return emitter; }, new EventMultiplexer())).event; this.onUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onUninstallExtension); return emitter; }, new EventMultiplexer())).event; this.onDidUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidUninstallExtension); return emitter; }, new EventMultiplexer())).event; - - this.extensionKindController = new ExtensionKindController(productService, configurationService); } async getInstalled(type?: ExtensionType): Promise { @@ -113,7 +110,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench private async uninstallInServer(extension: ILocalExtension, server: IExtensionManagementServer, options?: UninstallOptions): Promise { if (server === this.extensionManagementServerService.localExtensionManagementServer) { const installedExtensions = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getInstalled(ExtensionType.User); - const dependentNonUIExtensions = installedExtensions.filter(i => !this.extensionKindController.prefersExecuteOnUI(i.manifest) + const dependentNonUIExtensions = installedExtensions.filter(i => !this.extensionManifestPropertiesService.prefersExecuteOnUI(i.manifest) && i.manifest.extensionDependencies && i.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier))); if (dependentNonUIExtensions.length) { return Promise.reject(new Error(this.getDependentsErrorMessage(extension, dependentNonUIExtensions))); @@ -184,7 +181,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench const [local] = await Promises.settled([this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer].map(server => this.installVSIX(vsix, server))); return local; } - if (this.extensionKindController.prefersExecuteOnUI(manifest)) { + if (this.extensionManifestPropertiesService.prefersExecuteOnUI(manifest)) { // Install only on local server return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer); } @@ -299,7 +296,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench return this.extensionManagementServerService.localExtensionManagementServer; } - const extensionKind = this.extensionKindController.getExtensionKind(manifest); + const extensionKind = this.extensionManifestPropertiesService.getExtensionKind(manifest); for (const kind of extensionKind) { if (kind === 'ui' && this.extensionManagementServerService.localExtensionManagementServer) { return this.extensionManagementServerService.localExtensionManagementServer; diff --git a/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts index 588bccce94e..1438be0c5f7 100644 --- a/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts @@ -5,30 +5,27 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IExtensionManagementService, IGalleryExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class WebRemoteExtensionManagementService extends ExtensionManagementChannelClient implements IExtensionManagementService { - protected readonly extensionKindController: ExtensionKindController; - constructor( channel: IChannel, @IExtensionGalleryService protected readonly galleryService: IExtensionGalleryService, @IConfigurationService protected readonly configurationService: IConfigurationService, - @IProductService protected readonly productService: IProductService + @IProductService protected readonly productService: IProductService, + @IExtensionManifestPropertiesService protected readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(channel); - - this.extensionKindController = new ExtensionKindController(productService, configurationService); } async override canInstall(extension: IGalleryExtension): Promise { const manifest = await this.galleryService.getManifest(extension, CancellationToken.None); - return !!manifest && this.extensionKindController.canExecuteOnWorkspace(manifest); + return !!manifest && this.extensionManifestPropertiesService.canExecuteOnWorkspace(manifest); } } diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts index f272cca128d..bbac4ba0e84 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts @@ -19,6 +19,7 @@ import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementServ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class ExtensionManagementService extends BaseExtensionManagementService { @@ -33,9 +34,10 @@ export class ExtensionManagementService extends BaseExtensionManagementService { @IUserDataAutoSyncEnablementService userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, @IUserDataSyncResourceEnablementService userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService, @IDialogService dialogService: IDialogService, - @IWorkspaceTrustRequestService workspaceTrustRequestService: IWorkspaceTrustRequestService + @IWorkspaceTrustRequestService workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(extensionManagementServerService, extensionGalleryService, extensionWorkspaceTrustRequestService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService); + super(extensionManagementServerService, extensionGalleryService, extensionWorkspaceTrustRequestService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService, extensionManifestPropertiesService); } protected async override installVSIX(vsix: URI, server: IExtensionManagementServer): Promise { diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index 2457ecfb80b..746049b0f8a 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -21,6 +21,7 @@ import { WebRemoteExtensionManagementService } from 'vs/workbench/services/exten import { IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { Promises } from 'vs/base/common/async'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class NativeRemoteExtensionManagementService extends WebRemoteExtensionManagementService implements IExtensionManagementService { @@ -33,9 +34,10 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa @IExtensionGalleryService galleryService: IExtensionGalleryService, @IConfigurationService configurationService: IConfigurationService, @IProductService productService: IProductService, - @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService + @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { - super(channel, galleryService, configurationService, productService); + super(channel, galleryService, configurationService, productService, extensionManifestPropertiesService); this.localExtensionManagementService = localExtensionManagementServer.extensionManagementService; } @@ -125,7 +127,7 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa for (let idx = 0; idx < extensions.length; idx++) { const extension = extensions[idx]; const manifest = manifests[idx]; - if (manifest && this.extensionKindController.prefersExecuteOnUI(manifest) === uiExtension) { + if (manifest && this.extensionManifestPropertiesService.prefersExecuteOnUI(manifest) === uiExtension) { result.set(extension.identifier.id.toLowerCase(), extension); extensionsManifests.push(manifest); } diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index c5e2c7fcf88..06853dd3c61 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -33,6 +33,8 @@ import { IExtensionBisectService } from 'vs/workbench/services/extensionManageme import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { TestWorkspaceTrustManagementService, TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; import { IExtensionWorkspaceTrustRequestService } from 'vs/workbench/services/extensions/common/extensionWorkspaceTrustRequest'; +import { ExtensionManifestPropertiesService, IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { TestProductService } from 'vs/workbench/test/common/workbenchTestServices'; function createStorageService(instantiationService: TestInstantiationService): IStorageService { let service = instantiationService.get(IStorageService); @@ -70,7 +72,8 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { instantiationService.get(IHostService), new class extends mock() { override isDisabledByBisect() { return false; } }, instantiationService.get(IWorkspaceTrustManagementService) || instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()), - instantiationService.get(IWorkspaceTrustRequestService) || instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService()) + instantiationService.get(IWorkspaceTrustRequestService) || instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService()), + instantiationService.get(IExtensionManifestPropertiesService) || instantiationService.stub(IExtensionManifestPropertiesService, new ExtensionManifestPropertiesService(TestProductService, instantiationService.get(IConfigurationService))) ); } diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index d957e9f96b5..a50a1aba3b4 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -26,6 +26,7 @@ import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remot import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; export class ExtensionService extends AbstractExtensionService implements IExtensionService { @@ -47,6 +48,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, @IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super( new ExtensionRunningLocationClassifier( @@ -63,6 +65,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten extensionManagementService, contextService, configurationService, + extensionManifestPropertiesService ); this._runningLocation = new Map(); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index a597c4f1a52..508e6b02da4 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -29,10 +29,10 @@ import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtens import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ExtensionKindController } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; const hasOwnProperty = Object.hasOwnProperty; const NO_OP_VOID_PROMISE = Promise.resolve(undefined); @@ -108,8 +108,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx private _extensionHostActivationTimes: Map; private _extensionHostExtensionRuntimeErrors: Map; - private readonly _extensionKindController: ExtensionKindController; - constructor( protected readonly _runningLocationClassifier: ExtensionRunningLocationClassifier, @IInstantiationService protected readonly _instantiationService: IInstantiationService, @@ -122,6 +120,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx @IExtensionManagementService protected readonly _extensionManagementService: IExtensionManagementService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IConfigurationService protected readonly _configurationService: IConfigurationService, + @IExtensionManifestPropertiesService protected readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super(); @@ -150,8 +149,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx this._runningLocation = new Map(); - this._extensionKindController = new ExtensionKindController(this._productService, this._configurationService); - this._register(this._extensionEnablementService.onEnablementChanged((extensions) => { let toAdd: IExtension[] = []; let toRemove: string[] = []; @@ -189,7 +186,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return this._environmentService.extensionDevelopmentKind; } - return this._extensionKindController.getExtensionKind(extensionDescription); + return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription); } protected _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null { diff --git a/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts new file mode 100644 index 00000000000..a04bfa8dfd9 --- /dev/null +++ b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts @@ -0,0 +1,174 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IExtensionManifest, ExtensionKind, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export const IExtensionManifestPropertiesService = createDecorator('extensionManifestPropertiesService'); + +export interface IExtensionManifestPropertiesService { + readonly _serviceBrand: undefined; + + prefersExecuteOnUI(manifest: IExtensionManifest): boolean; + prefersExecuteOnWorkspace(manifest: IExtensionManifest): boolean; + prefersExecuteOnWeb(manifest: IExtensionManifest): boolean; + + canExecuteOnUI(manifest: IExtensionManifest): boolean; + canExecuteOnWorkspace(manifest: IExtensionManifest): boolean; + canExecuteOnWeb(manifest: IExtensionManifest): boolean; + + getExtensionKind(manifest: IExtensionManifest): ExtensionKind[]; +} + +export class ExtensionManifestPropertiesService implements IExtensionManifestPropertiesService { + + readonly _serviceBrand: undefined; + + private _uiExtensionPoints: Set | null = null; + private _productExtensionKindsMap: Map | null = null; + private _configuredExtensionKindsMap: Map | null = null; + + constructor( + @IProductService private readonly productService: IProductService, + @IConfigurationService private readonly configurationService: IConfigurationService, + ) { } + + prefersExecuteOnUI(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return (extensionKind.length > 0 && extensionKind[0] === 'ui'); + } + + prefersExecuteOnWorkspace(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return (extensionKind.length > 0 && extensionKind[0] === 'workspace'); + } + + prefersExecuteOnWeb(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return (extensionKind.length > 0 && extensionKind[0] === 'web'); + } + + canExecuteOnUI(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return extensionKind.some(kind => kind === 'ui'); + } + + canExecuteOnWorkspace(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return extensionKind.some(kind => kind === 'workspace'); + } + + canExecuteOnWeb(manifest: IExtensionManifest): boolean { + const extensionKind = this.getExtensionKind(manifest); + return extensionKind.some(kind => kind === 'web'); + } + + getExtensionKind(manifest: IExtensionManifest): ExtensionKind[] { + // check in config + let result = this.getConfiguredExtensionKind(manifest); + if (typeof result !== 'undefined') { + return this.toArray(result); + } + + // check product.json + result = this.getProductExtensionKind(manifest); + if (typeof result !== 'undefined') { + return result; + } + + // check the manifest itself + result = manifest.extensionKind; + if (typeof result !== 'undefined') { + return this.toArray(result); + } + + return this.deduceExtensionKind(manifest); + } + + deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] { + // Not an UI extension if it has main + if (manifest.main) { + if (manifest.browser) { + return ['workspace', 'web']; + } + return ['workspace']; + } + + if (manifest.browser) { + return ['web']; + } + + // Not an UI nor web extension if it has dependencies or an extension pack + if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) { + return ['workspace']; + } + + if (manifest.contributes) { + // Not an UI nor web extension if it has no ui contributions + for (const contribution of Object.keys(manifest.contributes)) { + if (!this.isUIExtensionPoint(contribution)) { + return ['workspace']; + } + } + } + + return ['ui', 'workspace', 'web']; + } + + private isUIExtensionPoint(extensionPoint: string): boolean { + if (this._uiExtensionPoints === null) { + const uiExtensionPoints = new Set(); + ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => { + uiExtensionPoints.add(e.name); + }); + this._uiExtensionPoints = uiExtensionPoints; + } + return this._uiExtensionPoints.has(extensionPoint); + } + + private getProductExtensionKind(manifest: IExtensionManifest): ExtensionKind[] | undefined { + if (this._productExtensionKindsMap === null) { + const productExtensionKindsMap = new Map(); + if (this.productService.extensionKind) { + for (const id of Object.keys(this.productService.extensionKind)) { + productExtensionKindsMap.set(ExtensionIdentifier.toKey(id), this.productService.extensionKind[id]); + } + } + this._productExtensionKindsMap = productExtensionKindsMap; + } + + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + return this._productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId)); + } + + private getConfiguredExtensionKind(manifest: IExtensionManifest): ExtensionKind | ExtensionKind[] | undefined { + if (this._configuredExtensionKindsMap === null) { + const configuredExtensionKindsMap = new Map(); + const configuredExtensionKinds = this.configurationService.getValue<{ [key: string]: ExtensionKind | ExtensionKind[] }>('remote.extensionKind') || {}; + for (const id of Object.keys(configuredExtensionKinds)) { + configuredExtensionKindsMap.set(ExtensionIdentifier.toKey(id), configuredExtensionKinds[id]); + } + this._configuredExtensionKindsMap = configuredExtensionKindsMap; + } + + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + return this._configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId)); + } + + private toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[] { + if (Array.isArray(extensionKind)) { + return extensionKind; + } + return extensionKind === 'ui' ? ['ui', 'workspace'] : [extensionKind]; + } +} + +registerSingleton(IExtensionManifestPropertiesService, ExtensionManifestPropertiesService); diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts index ce539f48eea..93a114150af 100644 --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts @@ -10,8 +10,7 @@ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/ex import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IProductService } from 'vs/platform/product/common/productService'; - -export class ExtensionKindController { +export class ExtensionKindController2 { constructor( @IProductService private readonly productService: IProductService, @IConfigurationService private readonly configurationService: IConfigurationService, diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index a20ccff1632..f573b93115e 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -45,6 +45,7 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurati import { Codicon } from 'vs/base/common/codicons'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; const MACHINE_PROMPT = false; @@ -76,6 +77,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten @ILogService private readonly _logService: ILogService, @IDialogService private readonly _dialogService: IDialogService, @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { super( new ExtensionRunningLocationClassifier( @@ -92,6 +94,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten extensionManagementService, contextService, configurationService, + extensionManifestPropertiesService ); this._enableLocalWebWorker = this._isLocalWebWorkerEnabled(); diff --git a/src/vs/workbench/services/extensions/test/common/extensionsUtil.test.ts b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts similarity index 71% rename from src/vs/workbench/services/extensions/test/common/extensionsUtil.test.ts rename to src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts index 4ca1afc4eeb..c8a0a61747e 100644 --- a/src/vs/workbench/services/extensions/test/common/extensionsUtil.test.ts +++ b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts @@ -4,13 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { deduceExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IExtensionManifest, ExtensionKind } from 'vs/platform/extensions/common/extensions'; +import { ExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { TestProductService } from 'vs/workbench/test/common/workbenchTestServices'; suite('ExtensionKind', () => { function check(manifest: Partial, expected: ExtensionKind[]): void { - assert.deepStrictEqual(deduceExtensionKind(manifest), expected); + const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService()); + assert.deepStrictEqual(extensionManifestPropertiesService.deduceExtensionKind(manifest), expected); } test('declarative with extension dependencies => workspace', () => { diff --git a/src/vs/workbench/test/common/workbenchTestServices.ts b/src/vs/workbench/test/common/workbenchTestServices.ts index 258788de2c3..a18ab24b418 100644 --- a/src/vs/workbench/test/common/workbenchTestServices.ts +++ b/src/vs/workbench/test/common/workbenchTestServices.ts @@ -21,6 +21,7 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IFileStatWithMetadata } from 'vs/platform/files/common/files'; import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor'; import { CancellationToken } from 'vs/base/common/cancellation'; +import product from 'vs/platform/product/common/product'; export class TestTextResourcePropertiesService implements ITextResourcePropertiesService { @@ -213,3 +214,5 @@ export interface Ctor { } export class TestExtensionService extends NullExtensionService { } + +export const TestProductService = { _serviceBrand: undefined, ...product }; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 89f64a73eb8..c7872b65b09 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -74,6 +74,7 @@ import 'vs/workbench/services/mode/common/workbenchModeService'; import 'vs/workbench/services/commands/common/commandService'; import 'vs/workbench/services/themes/browser/workbenchThemeService'; import 'vs/workbench/services/label/common/labelService'; +import 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import 'vs/workbench/services/extensionManagement/common/webExtensionsScannerService'; import 'vs/workbench/services/extensionManagement/browser/extensionEnablementService'; import 'vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService';