UNPKG

@codingame/monaco-vscode-extensions-service-override

Version:

VSCode public API plugged on the monaco editor - extensions service-override

375 lines (371 loc) 17.8 kB
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6'; import { Schemas } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network'; import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service'; import { ExtensionIdentifierMap } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensions/common/extensions'; import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service'; import { IWorkbenchEnvironmentService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/environment/common/environmentService.service'; import { determineExtensionHostKinds, ExtensionHostKind, ExtensionRunningPreference } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionHostKind'; import { IExtensionManifestPropertiesService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionManifestPropertiesService.service'; import { RemoteRunningLocation, LocalProcessRunningLocation, LocalWebWorkerRunningLocation } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionRunningLocation'; import { isProposedApiEnabled } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions'; let ExtensionRunningLocationTracker = class ExtensionRunningLocationTracker { get maxLocalProcessAffinity() { return this._maxLocalProcessAffinity; } get maxLocalWebWorkerAffinity() { return this._maxLocalWebWorkerAffinity; } constructor( _registry, _extensionHostKindPicker, _environmentService, _configurationService, _logService, _extensionManifestPropertiesService ) { this._registry = _registry; this._extensionHostKindPicker = _extensionHostKindPicker; this._environmentService = _environmentService; this._configurationService = _configurationService; this._logService = _logService; this._extensionManifestPropertiesService = _extensionManifestPropertiesService; this._runningLocation = ( new ExtensionIdentifierMap()); this._maxLocalProcessAffinity = 0; this._maxLocalWebWorkerAffinity = 0; } set(extensionId, runningLocation) { this._runningLocation.set(extensionId, runningLocation); } readExtensionKinds(extensionDescription) { if (extensionDescription.isUnderDevelopment && this._environmentService.extensionDevelopmentKind) { return this._environmentService.extensionDevelopmentKind; } return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription); } getRunningLocation(extensionId) { return this._runningLocation.get(extensionId) || null; } filterByRunningLocation(extensions, desiredRunningLocation) { return filterExtensionDescriptions( extensions, this._runningLocation, extRunningLocation => desiredRunningLocation.equals(extRunningLocation) ); } filterByExtensionHostKind(extensions, desiredExtensionHostKind) { return filterExtensionDescriptions( extensions, this._runningLocation, extRunningLocation => extRunningLocation.kind === desiredExtensionHostKind ); } filterByExtensionHostManager(extensions, extensionHostManager) { return filterExtensionDescriptions( extensions, this._runningLocation, extRunningLocation => extensionHostManager.representsRunningLocation(extRunningLocation) ); } _computeAffinity(inputExtensions, extensionHostKind, isInitialAllocation) { const extensions = ( new ExtensionIdentifierMap()); for (const extension of inputExtensions) { if (extension.main || extension.browser) { extensions.set(extension.identifier, extension); } } for (const extension of this._registry.getAllExtensionDescriptions()) { if (extension.main || extension.browser) { const runningLocation = this._runningLocation.get(extension.identifier); if (runningLocation && runningLocation.kind === extensionHostKind) { extensions.set(extension.identifier, extension); } } } const groups = ( new ExtensionIdentifierMap()); let groupNumber = 0; for (const [_, extension] of extensions) { groups.set(extension.identifier, ++groupNumber); } const changeGroup = (from, to) => { for (const [key, group] of groups) { if (group === from) { groups.set(key, to); } } }; for (const [_, extension] of extensions) { if (!extension.extensionDependencies) { continue; } const myGroup = groups.get(extension.identifier); for (const depId of extension.extensionDependencies) { const depGroup = groups.get(depId); if (!depGroup) { continue; } if (depGroup === myGroup) { continue; } changeGroup(depGroup, myGroup); } } for (const [_, extension] of extensions) { if (!extension.extensionAffinity) { continue; } if (!isProposedApiEnabled(extension)) { this._logService.warn( `Extension '${extension.identifier.value}' declares 'extensionAffinity' in its package.json but does not enable the 'extensionAffinity' API proposal. Add '"enabledApiProposals": ["extensionAffinity"]' to the extension's package.json to use this feature.` ); continue; } const myGroup = groups.get(extension.identifier); for (const colocateId of extension.extensionAffinity) { const colocateGroup = groups.get(colocateId); if (!colocateGroup) { continue; } if (colocateGroup === myGroup) { continue; } changeGroup(colocateGroup, myGroup); } } const resultingAffinities = ( new Map()); let lastAffinity = 0; for (const [_, extension] of extensions) { const runningLocation = this._runningLocation.get(extension.identifier); if (runningLocation) { const group = groups.get(extension.identifier); resultingAffinities.set(group, runningLocation.affinity); lastAffinity = Math.max(lastAffinity, runningLocation.affinity); } } if (!this._environmentService.isExtensionDevelopment) { const configuredAffinities = this._configurationService.getValue("extensions.experimental.affinity") || {}; const configuredExtensionIds = ( Object.keys(configuredAffinities)); const configuredAffinityToResultingAffinity = ( new Map()); for (const extensionId of configuredExtensionIds) { const configuredAffinity = configuredAffinities[extensionId]; if (typeof configuredAffinity !== "number" || configuredAffinity <= 0 || Math.floor(configuredAffinity) !== configuredAffinity) { this._logService.info( `Ignoring configured affinity for '${extensionId}' because the value is not a positive integer.` ); continue; } const group = groups.get(extensionId); if (!group) { continue; } const affinity1 = resultingAffinities.get(group); if (affinity1) { configuredAffinityToResultingAffinity.set(configuredAffinity, affinity1); continue; } const affinity2 = configuredAffinityToResultingAffinity.get(configuredAffinity); if (affinity2) { resultingAffinities.set(group, affinity2); continue; } if (!isInitialAllocation) { this._logService.info( `Ignoring configured affinity for '${extensionId}' because extension host(s) are already running. Reload window.` ); continue; } const affinity3 = ++lastAffinity; configuredAffinityToResultingAffinity.set(configuredAffinity, affinity3); resultingAffinities.set(group, affinity3); } } const result = ( new ExtensionIdentifierMap()); for (const extension of inputExtensions) { const group = groups.get(extension.identifier) || 0; const affinity = resultingAffinities.get(group) || 0; result.set(extension.identifier, affinity); } if (lastAffinity > 0 && isInitialAllocation) { for (let affinity = 1; affinity <= lastAffinity; affinity++) { const extensionIds = []; for (const extension of inputExtensions) { if (result.get(extension.identifier) === affinity) { extensionIds.push(extension.identifier); } } this._logService.info(`Placing extension(s) ${( extensionIds.map(e => e.value)).join(", ")} on a separate extension host.`); } } return { affinities: result, maxAffinity: lastAffinity }; } computeRunningLocation(localExtensions, remoteExtensions, isInitialAllocation) { return this._doComputeRunningLocation( this._runningLocation, localExtensions, remoteExtensions, isInitialAllocation ).runningLocation; } _doComputeRunningLocation( existingRunningLocation, localExtensions, remoteExtensions, isInitialAllocation ) { localExtensions = localExtensions.filter(extension => !( existingRunningLocation.has(extension.identifier))); remoteExtensions = remoteExtensions.filter(extension => !( existingRunningLocation.has(extension.identifier))); const extensionHostKinds = determineExtensionHostKinds( localExtensions, remoteExtensions, extension => this.readExtensionKinds(extension), ( extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference ) => this._extensionHostKindPicker.pickExtensionHostKind( extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference ) ); const extensions = ( new ExtensionIdentifierMap()); for (const extension of localExtensions) { extensions.set(extension.identifier, extension); } for (const extension of remoteExtensions) { extensions.set(extension.identifier, extension); } const result = ( new ExtensionIdentifierMap()); const localProcessExtensions = []; const localWebWorkerExtensions = []; for (const [extensionIdKey, extensionHostKind] of extensionHostKinds) { let runningLocation = null; if (extensionHostKind === ExtensionHostKind.LocalProcess) { const extensionDescription = extensions.get(extensionIdKey); if (extensionDescription) { localProcessExtensions.push(extensionDescription); } } else if (extensionHostKind === ExtensionHostKind.LocalWebWorker) { const extensionDescription = extensions.get(extensionIdKey); if (extensionDescription) { localWebWorkerExtensions.push(extensionDescription); } } else if (extensionHostKind === ExtensionHostKind.Remote) { runningLocation = ( new RemoteRunningLocation()); } result.set(extensionIdKey, runningLocation); } const { affinities, maxAffinity } = this._computeAffinity( localProcessExtensions, ExtensionHostKind.LocalProcess, isInitialAllocation ); for (const extension of localProcessExtensions) { const affinity = affinities.get(extension.identifier) || 0; result.set(extension.identifier, ( new LocalProcessRunningLocation(affinity))); } const { affinities: localWebWorkerAffinities, maxAffinity: maxLocalWebWorkerAffinity } = this._computeAffinity( localWebWorkerExtensions, ExtensionHostKind.LocalWebWorker, isInitialAllocation ); for (const extension of localWebWorkerExtensions) { const affinity = localWebWorkerAffinities.get(extension.identifier) || 0; result.set(extension.identifier, ( new LocalWebWorkerRunningLocation(affinity))); } for (const [extensionIdKey, runningLocation] of existingRunningLocation) { if (runningLocation) { result.set(extensionIdKey, runningLocation); } } return { runningLocation: result, maxLocalProcessAffinity: maxAffinity, maxLocalWebWorkerAffinity: maxLocalWebWorkerAffinity }; } initializeRunningLocation(localExtensions, remoteExtensions) { const { runningLocation, maxLocalProcessAffinity, maxLocalWebWorkerAffinity } = this._doComputeRunningLocation(this._runningLocation, localExtensions, remoteExtensions, true); this._runningLocation = runningLocation; this._maxLocalProcessAffinity = maxLocalProcessAffinity; this._maxLocalWebWorkerAffinity = maxLocalWebWorkerAffinity; } deltaExtensions(toAdd, toRemove) { const removedRunningLocation = ( new ExtensionIdentifierMap()); for (const extensionId of toRemove) { const extensionKey = extensionId; removedRunningLocation.set(extensionKey, this._runningLocation.get(extensionKey) || null); this._runningLocation.delete(extensionKey); } this._updateRunningLocationForAddedExtensions(toAdd); return removedRunningLocation; } _updateRunningLocationForAddedExtensions(toAdd) { const localProcessExtensions = []; const localWebWorkerExtensions = []; for (const extension of toAdd) { const extensionKind = this.readExtensionKinds(extension); const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote; const extensionHostKind = this._extensionHostKindPicker.pickExtensionHostKind( extension.identifier, extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None ); let runningLocation = null; if (extensionHostKind === ExtensionHostKind.LocalProcess) { localProcessExtensions.push(extension); } else if (extensionHostKind === ExtensionHostKind.LocalWebWorker) { localWebWorkerExtensions.push(extension); } else if (extensionHostKind === ExtensionHostKind.Remote) { runningLocation = ( new RemoteRunningLocation()); } this._runningLocation.set(extension.identifier, runningLocation); } const { affinities } = this._computeAffinity(localProcessExtensions, ExtensionHostKind.LocalProcess, false); for (const extension of localProcessExtensions) { const affinity = affinities.get(extension.identifier) || 0; this._runningLocation.set(extension.identifier, ( new LocalProcessRunningLocation(affinity))); } const { affinities: webWorkerExtensionsAffinities } = this._computeAffinity(localWebWorkerExtensions, ExtensionHostKind.LocalWebWorker, false); for (const extension of localWebWorkerExtensions) { const affinity = webWorkerExtensionsAffinities.get(extension.identifier) || 0; this._runningLocation.set(extension.identifier, ( new LocalWebWorkerRunningLocation(affinity))); } } }; ExtensionRunningLocationTracker = ( __decorate([( __param(2, IWorkbenchEnvironmentService)), ( __param(3, IConfigurationService)), ( __param(4, ILogService)), ( __param(5, IExtensionManifestPropertiesService))], ExtensionRunningLocationTracker)); function filterExtensionDescriptions(extensions, runningLocation, predicate) { return extensions.filter(ext => { const extRunningLocation = runningLocation.get(ext.identifier); return extRunningLocation && predicate(extRunningLocation); }); } function filterExtensionIdentifiers(extensions, runningLocation, predicate) { return extensions.filter(ext => { const extRunningLocation = runningLocation.get(ext); return extRunningLocation && predicate(extRunningLocation); }); } export { ExtensionRunningLocationTracker, filterExtensionDescriptions, filterExtensionIdentifiers };