VS Code merge to df8fe74bd55313de0dd2303bc47a4aab0ca56b0e (#17979)

* Merge from vscode 504f934659740e9d41501cad9f162b54d7745ad9

* delete unused folders

* distro

* Bump build node version

* update chokidar

* FIx hygiene errors

* distro

* Fix extension lint issues

* Remove strict-vscode

* Add copyright header exemptions

* Bump vscode-extension-telemetry to fix webpacking issue with zone.js

* distro

* Fix failing tests (revert marked.js back to current one until we decide to update)

* Skip searchmodel test

* Fix mac build

* temp debug script loading

* Try disabling coverage

* log error too

* Revert "log error too"

This reverts commit af0183e5d4ab458fdf44b88fbfab9908d090526f.

* Revert "temp debug script loading"

This reverts commit 3d687d541c76db2c5b55626c78ae448d3c25089c.

* Add comments explaining coverage disabling

* Fix ansi_up loading issue

* Merge latest from ads

* Use newer option

* Fix compile

* add debug logging warn

* Always log stack

* log more

* undo debug

* Update to use correct base path (+cleanup)

* distro

* fix compile errors

* Remove strict-vscode

* Fix sql editors not showing

* Show db dropdown input & fix styling

* Fix more info in gallery

* Fix gallery asset requests

* Delete unused workflow

* Fix tapable resolutions for smoke test compile error

* Fix smoke compile

* Disable crash reporting

* Disable interactive

Co-authored-by: ADS Merger <karlb@microsoft.com>
This commit is contained in:
Charles Gagnon
2022-01-06 09:06:56 -08:00
committed by GitHub
parent fd2736b6a6
commit 2bc6a0cd01
2099 changed files with 79520 additions and 43813 deletions

View File

@@ -9,11 +9,11 @@ import { IWorkbenchExtensionEnablementService, IWebExtensionsScannerService } fr
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionService, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionService, IExtensionHost, toExtensionDescription, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/productService';
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { AbstractExtensionService, ExtensionRunningLocationClassifier, ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { RemoteExtensionHost, IRemoteExtensionHostDataProvider, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
@@ -28,6 +28,7 @@ import { IExtensionManagementService } from 'vs/platform/extensionManagement/com
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
import { IAutomatedWindow } from 'vs/platform/log/browser/log';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
@@ -47,7 +48,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IConfigurationService configurationService: IConfigurationService,
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
@IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService,
@@ -67,7 +68,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
extensionManagementService,
contextService,
configurationService,
extensionManifestPropertiesService
extensionManifestPropertiesService,
webExtensionsScannerService
);
this._runningLocation = new Map<string, ExtensionRunningLocation>();
@@ -91,9 +93,9 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
}
const scannedExtension = await this._webExtensionsScannerService.scanAndTranslateSingleExtension(extension.location, extension.type);
const scannedExtension = await this._webExtensionsScannerService.scanExistingExtension(extension.location, extension.type);
if (scannedExtension) {
return parseScannedExtension(scannedExtension);
return toExtensionDescription(scannedExtension);
}
return null;
@@ -166,7 +168,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
const result: IExtensionHost[] = [];
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider());
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, false, this._createLocalExtensionHostDataProvider());
result.push(webWorkerExtHost);
const remoteAgentConnection = this._remoteAgentService.getConnection();
@@ -181,7 +183,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
protected async _scanAndHandleExtensions(): Promise<void> {
// fetch the remote environment
let [localExtensions, remoteEnv, remoteExtensions] = await Promise.all([
this._webExtensionsScannerService.scanAndTranslateExtensions().then(extensions => extensions.map(parseScannedExtension)),
this._scanWebExtensions(),
this._remoteAgentService.getEnvironment(),
this._remoteAgentService.scanExtensions()
]);
@@ -220,10 +222,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
// Dispose everything associated with the extension host
this.stopExtensionHosts();
// We log the exit code to the console. Do NOT remove this
// code as the automated integration tests in browser rely
// on this message to exit properly.
console.log(`vscode:exit ${code}`);
const automatedWindow = window as unknown as IAutomatedWindow;
if (typeof automatedWindow.codeAutomationExit === 'function') {
automatedWindow.codeAutomationExit(code);
}
}
}

View File

@@ -244,7 +244,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
}
// Extension is disabled. Enable the extension and reload the window to handle.
else {
else if (this.extensionEnablementService.canChangeEnablement(extension)) {
const result = await this.dialogService.confirm({
message: localize('enableAndHandle', "Extension '{0}' is disabled. Would you like to enable the extension and reload the window to open the URL?", extension.manifest.displayName || extension.manifest.name),
detail: `${extension.manifest.displayName || extension.manifest.name} (${extensionIdentifier.id}) wants to open a URL:\n\n${uri.toString()}`,
@@ -335,7 +335,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
}
private getConfirmedTrustedExtensionIdsFromConfiguration(): Array<string> {
const trustedExtensionIds = this.configurationService.getValue<Array<string>>(USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY);
const trustedExtensionIds = this.configurationService.getValue(USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY);
if (!Array.isArray(trustedExtensionIds)) {
return [];

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getWorkerBootstrapUrl } from 'vs/base/worker/defaultWorkerFactory';
import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';
import { Emitter, Event } from 'vs/base/common/event';
import { toDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
@@ -28,7 +28,6 @@ import { localize } from 'vs/nls';
import { generateUuid } from 'vs/base/common/uuid';
import { canceled, onUnexpectedError } from 'vs/base/common/errors';
import { Barrier } from 'vs/base/common/async';
import { FileAccess } from 'vs/base/common/network';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { NewWorkerMessage, TerminateWorkerMessage } from 'vs/workbench/services/extensions/common/polyfillNestedWorker.protocol';
@@ -41,8 +40,6 @@ export interface IWebWorkerExtensionHostDataProvider {
getInitData(): Promise<IWebWorkerExtensionHostInitData>;
}
const ttPolicy = window.trustedTypes?.createPolicy('webWorkerExtensionHost', { createScriptURL: value => value });
const ttPolicyNestedWorker = window.trustedTypes?.createPolicy('webNestedWorkerExtensionHost', {
createScriptURL(value) {
if (value.startsWith('blob:')) {
@@ -56,6 +53,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
public readonly kind = ExtensionHostKind.LocalWebWorker;
public readonly remoteAuthority = null;
public readonly lazyStart: boolean;
private readonly _onDidExit = this._register(new Emitter<[number, string | null]>());
public readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
@@ -68,6 +66,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
private readonly _extensionHostLogFile: URI;
constructor(
lazyStart: boolean,
private readonly _initDataProvider: IWebWorkerExtensionHostDataProvider,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@@ -78,6 +77,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
@ILayoutService private readonly _layoutService: ILayoutService,
) {
super();
this.lazyStart = lazyStart;
this._isTerminating = false;
this._protocolPromise = null;
this._protocol = null;
@@ -86,11 +86,35 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
}
private _webWorkerExtensionHostIframeSrc(): string | null {
const suffix = this._environmentService.debugExtensionHost && this._environmentService.debugRenderer ? '?debugged=1' : '?';
if (this._environmentService.options && this._environmentService.options.webWorkerExtensionHostIframeSrc) {
return this._environmentService.options.webWorkerExtensionHostIframeSrc;
return this._environmentService.options.webWorkerExtensionHostIframeSrc + suffix;
}
const forceHTTPS = (location.protocol === 'https:');
if (this._environmentService.options && this._environmentService.options.__uniqueWebWorkerExtensionHostOrigin) {
const webEndpointUrlTemplate = this._productService.webEndpointUrlTemplate;
const commit = this._productService.commit;
const quality = this._productService.quality;
if (webEndpointUrlTemplate && commit && quality) {
const baseUrl = (
webEndpointUrlTemplate
.replace('{{uuid}}', generateUuid())
.replace('{{commit}}', commit)
.replace('{{quality}}', quality)
);
const base = (
forceHTTPS
? `${baseUrl}/out/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html`
: `${baseUrl}/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
);
return base + suffix;
}
}
if (this._productService.webEndpointUrl) {
const forceHTTPS = (location.protocol === 'https:');
let baseUrl = this._productService.webEndpointUrl;
if (this._productService.quality) {
baseUrl += `/${this._productService.quality}`;
@@ -98,11 +122,13 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
if (this._productService.commit) {
baseUrl += `/${this._productService.commit}`;
}
return (
const base = (
forceHTTPS
? `${baseUrl}/out/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html`
: `${baseUrl}/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
);
return base + suffix;
}
return null;
}
@@ -134,7 +160,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
iframe.style.display = 'none';
const vscodeWebWorkerExtHostId = generateUuid();
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}?vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}&vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
const barrier = new Barrier();
let port!: MessagePort;
@@ -219,51 +245,58 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
private async _startOutsideIframe(): Promise<IMessagePassingProtocol> {
const emitter = new Emitter<VSBuffer>();
const url = getWorkerBootstrapUrl(FileAccess.asBrowserUri('../worker/extensionHostWorkerMain.js', require).toString(true), 'WorkerExtensionHost');
const worker = new Worker(ttPolicy?.createScriptURL(url) as unknown as string ?? url, { name: 'WorkerExtensionHost' });
const barrier = new Barrier();
let port!: MessagePort;
const nestedWorker = new Map<string, Worker>();
worker.onmessage = (event) => {
const name = this._environmentService.debugRenderer && this._environmentService.debugExtensionHost ? 'DebugWorkerExtensionHost' : 'WorkerExtensionHost';
const worker = new DefaultWorkerFactory(name).create(
'vs/workbench/services/extensions/worker/extensionHostWorker',
(data: MessagePort | NewWorkerMessage | TerminateWorkerMessage | any) => {
const data: MessagePort | NewWorkerMessage | TerminateWorkerMessage = event.data;
if (data instanceof MessagePort) {
// receiving a message port which is used to communicate
// with the web worker extension host
if (barrier.isOpen()) {
console.warn('UNEXPECTED message', data);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'received a message port AFTER opening the barrier']);
return;
}
port = data;
barrier.open();
if (data instanceof MessagePort) {
// receiving a message port which is used to communicate
// with the web worker extension host
if (barrier.isOpen()) {
console.warn('UNEXPECTED message', event);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'received a message port AFTER opening the barrier']);
return;
} else if (data?.type === '_newWorker') {
// receiving a message to create a new nested/child worker
const worker = new Worker((ttPolicyNestedWorker?.createScriptURL(data.url) ?? data.url) as string, data.options);
worker.postMessage(data.port, [data.port]);
worker.onerror = console.error.bind(console);
nestedWorker.set(data.id, worker);
} else if (data?.type === '_terminateWorker') {
// receiving a message to terminate nested/child worker
if (nestedWorker.has(data.id)) {
nestedWorker.get(data.id)!.terminate();
nestedWorker.delete(data.id);
}
} else {
// all other messages are an error
console.warn('UNEXPECTED message', data);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'UNEXPECTED message']);
}
port = data;
barrier.open();
},
(event: any) => {
console.error(event.message, event.error);
} else if (data?.type === '_newWorker') {
// receiving a message to create a new nested/child worker
const worker = new Worker((ttPolicyNestedWorker?.createScriptURL(data.url) ?? data.url) as string, data.options);
worker.postMessage(data.port, [data.port]);
worker.onerror = console.error.bind(console);
nestedWorker.set(data.id, worker);
} else if (data?.type === '_terminateWorker') {
// receiving a message to terminate nested/child worker
if (nestedWorker.has(data.id)) {
nestedWorker.get(data.id)!.terminate();
nestedWorker.delete(data.id);
if (!barrier.isOpen()) {
// Only terminate the web worker extension host when an error occurs during handshake
// and setup. All other errors can be normal uncaught exceptions
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, event.message || event.error]);
}
} else {
// all other messages are an error
console.warn('UNEXPECTED message', event);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'UNEXPECTED message']);
}
};
);
// await MessagePort and use it to directly communicate
// with the worker extension host
@@ -280,14 +313,10 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
};
worker.onerror = (event) => {
console.error(event.message, event.error);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, event.message || event.error]);
};
// keep for cleanup
this._register(emitter);
this._register(toDisposable(() => worker.terminate()));
this._register(worker);
const protocol: IMessagePassingProtocol = {
onMessage: emitter.event,
@@ -355,6 +384,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
environment: {
isExtensionDevelopmentDebug: this._environmentService.debugRenderer,
appName: this._productService.nameLong,
embedderIdentifier: this._productService.embedderIdentifier || 'web',
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,

View File

@@ -11,17 +11,16 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
import * as perf from 'vs/base/common/performance';
import { isEqualOrParent } from 'vs/base/common/resources';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWebExtensionsScannerService, IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind, toExtensionDescription, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind, IExtensionContributions } from 'vs/platform/extensions/common/extensions';
import { createExtensionHostManager, IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtensionDescription, IExtension, ExtensionKind, IExtensionContributions } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IProductService } from 'vs/platform/product/common/productService';
@@ -33,21 +32,12 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil';
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
export function parseScannedExtension(extension: ITranslatedScannedExtension): IExtensionDescription {
return {
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
isBuiltin: extension.type === ExtensionType.System,
isUserBuiltin: false,
isUnderDevelopment: extension.isUnderDevelopment,
extensionLocation: extension.location,
...extension.packageJSON,
};
}
class DeltaExtensionsQueueItem {
constructor(
public readonly toAdd: IExtension[],
@@ -55,13 +45,6 @@ class DeltaExtensionsQueueItem {
) { }
}
export const enum ExtensionRunningLocation {
None,
LocalProcess,
LocalWebWorker,
Remote
}
export const enum ExtensionRunningPreference {
None,
Local,
@@ -167,7 +150,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
protected _runningLocation: Map<string, ExtensionRunningLocation>;
// --- Members used per extension host process
protected _extensionHostManagers: ExtensionHostManager[];
protected _extensionHostManagers: IExtensionHostManager[];
protected _extensionHostActiveExtensions: Map<string, ExtensionIdentifier>;
private _extensionHostActivationTimes: Map<string, ActivationTimes>;
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
@@ -185,6 +168,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@IConfigurationService protected readonly _configurationService: IConfigurationService,
@IExtensionManifestPropertiesService protected readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@IWebExtensionsScannerService protected readonly _webExtensionsScannerService: IWebExtensionsScannerService,
) {
super();
@@ -230,13 +214,16 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
}));
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
if (event.local) {
if (this._safeInvokeIsEnabled(event.local)) {
// an extension has been installed
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
this._register(this._extensionManagementService.onDidInstallExtensions((result) => {
const extensions: IExtension[] = [];
for (const { local } of result) {
if (local && this._safeInvokeIsEnabled(local)) {
extensions.push(local);
}
}
if (extensions.length) {
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(extensions, []));
}
}));
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
@@ -255,7 +242,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription);
}
protected _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
protected _getExtensionHostManager(kind: ExtensionHostKind): IExtensionHostManager | null {
for (const extensionHostManager of this._extensionHostManagers) {
if (extensionHostManager.kind === kind) {
return extensionHostManager;
@@ -535,7 +522,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._onExtensionHostExit(exitCode);
}
private findTestExtensionHost(testLocation: URI): ExtensionHostManager | undefined | null {
private findTestExtensionHost(testLocation: URI): IExtensionHostManager | undefined | null {
let extensionHostKind: ExtensionHostKind | undefined;
for (const extension of this._registry.getAllExtensionDescriptions()) {
@@ -599,14 +586,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
const extensionHosts = this._createExtensionHosts(isInitialStart);
extensionHosts.forEach((extensionHost) => {
const processManager = this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
const processManager: IExtensionHostManager = createExtensionHostManager(this._instantiationService, extensionHost, isInitialStart, initialActivationEvents);
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
this._extensionHostManagers.push(processManager);
});
}
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
private _onExtensionHostCrashOrExit(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
// Unexpected termination
if (!this._isExtensionDevHost) {
@@ -617,7 +604,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._onExtensionHostExit(code);
}
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
protected _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal);
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
this.stopExtensionHosts();
@@ -737,6 +724,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
messages: this._extensionsMessages.get(extensionKey) || [],
activationTimes: this._extensionHostActivationTimes.get(extensionKey),
runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [],
runningLocation: this._runningLocation.get(extensionKey) || ExtensionRunningLocation.None,
};
}
}
@@ -771,7 +759,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._checkEnableProposedApi(extensions);
// keep only enabled extensions
return extensions.filter(extension => this._isEnabled(extension, ignoreWorkspaceTrust));
return this._filterEnabledExtensions(extensions, ignoreWorkspaceTrust);
}
/**
@@ -779,30 +767,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
* @argument ignoreWorkspaceTrust Do not take workspace trust into account.
*/
protected _isEnabled(extension: IExtensionDescription, ignoreWorkspaceTrust: boolean): boolean {
if (extension.isUnderDevelopment) {
// Never disable extensions under development
return true;
}
if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) {
// Check if this is the better merge extension which was migrated to a built-in extension
return false;
}
const ext = toExtension(extension);
const isEnabled = this._safeInvokeIsEnabled(ext);
if (isEnabled) {
return true;
}
if (ignoreWorkspaceTrust && this._safeInvokeIsDisabledByWorkspaceTrust(ext)) {
// This extension is disabled, but the reason for it being disabled
// is workspace trust, so we will consider it enabled
return true;
}
return false;
return this._filterEnabledExtensions([extension], ignoreWorkspaceTrust).includes(extension);
}
protected _safeInvokeIsEnabled(extension: IExtension): boolean {
@@ -813,12 +778,27 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
}
}
protected _safeInvokeIsDisabledByWorkspaceTrust(extension: IExtension): boolean {
try {
return this._extensionEnablementService.isDisabledByWorkspaceTrust(extension);
} catch (err) {
return false;
private _filterEnabledExtensions(extensions: IExtensionDescription[], ignoreWorkspaceTrust: boolean): IExtensionDescription[] {
const enabledExtensions: IExtensionDescription[] = [], extensionsToCheck: IExtensionDescription[] = [], mappedExtensions: IExtension[] = [];
for (const extension of extensions) {
if (extension.isUnderDevelopment) {
// Never disable extensions under development
enabledExtensions.push(extension);
}
else {
extensionsToCheck.push(extension);
mappedExtensions.push(toExtension(extension));
}
}
const enablementStates = this._extensionEnablementService.getEnablementStates(mappedExtensions, ignoreWorkspaceTrust ? { trusted: true } : undefined);
for (let index = 0; index < enablementStates.length; index++) {
if (this._extensionEnablementService.isEnabledEnablementState(enablementStates[index])) {
enabledExtensions.push(extensionsToCheck[index]);
}
}
return enabledExtensions;
}
protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void {
@@ -916,6 +896,16 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
//#region Called by extension host
protected createLogger(): Logger {
return new Logger((severity, source, message) => {
if (this._isDev && source) {
this._logOrShowMessage(severity, `[${source}]: ${message}`);
} else {
this._logOrShowMessage(severity, message);
}
});
}
protected _logOrShowMessage(severity: Severity, msg: string): void {
if (this._isDev) {
this._showMessageToUser(severity, msg);
@@ -946,7 +936,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
public _onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void {
type ExtensionActivationErrorClassification = {
extensionId: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
error: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
error: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
};
type ExtensionActivationErrorEvent = {
extensionId: string;
@@ -967,6 +957,21 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
this._onDidChangeExtensionsStatus.fire([extensionId]);
}
protected async _scanWebExtensions(): Promise<IExtensionDescription[]> {
const log = this.createLogger();
const system: IExtensionDescription[] = [], user: IExtensionDescription[] = [], development: IExtensionDescription[] = [];
try {
await Promise.all([
this._webExtensionsScannerService.scanSystemExtensions().then(extensions => system.push(...extensions.map(e => toExtensionDescription(e)))),
this._webExtensionsScannerService.scanUserExtensions().then(extensions => user.push(...extensions.map(e => toExtensionDescription(e)))),
this._webExtensionsScannerService.scanExtensionsUnderDevelopment().then(extensions => development.push(...extensions.map(e => toExtensionDescription(e, true))))
]);
} catch (error) {
log.error('', error);
}
return dedupExtensions(system, user, development, log);
}
//#endregion
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];

View File

@@ -23,14 +23,40 @@ import { VSBuffer } from 'vs/base/common/buffer';
import { IExtensionHost, ExtensionHostKind, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { timeout } from 'vs/base/common/async';
import { Barrier, timeout } from 'vs/base/common/async';
import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
// Enable to see detailed message communication between window and extension host
const LOG_EXTENSION_HOST_COMMUNICATION = false;
const LOG_USE_COLORS = true;
export class ExtensionHostManager extends Disposable {
export interface IExtensionHostManager {
readonly kind: ExtensionHostKind;
readonly onDidExit: Event<[number, string | null]>;
readonly onDidChangeResponsiveState: Event<ResponsiveState>;
dispose(): void;
ready(): Promise<void>;
deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
getInspectPort(tryEnableInspector: boolean): Promise<number>;
resolveAuthority(remoteAuthority: string): Promise<ResolverResult>;
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI>;
start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
extensionTestsExecute(): Promise<number>;
extensionTestsSendExit(exitCode: number): Promise<void>;
setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
}
export function createExtensionHostManager(instantiationService: IInstantiationService, extensionHost: IExtensionHost, isInitialStart: boolean, initialActivationEvents: string[]): IExtensionHostManager {
if (extensionHost.lazyStart && isInitialStart && initialActivationEvents.length === 0) {
return instantiationService.createInstance(LazyStartExtensionHostManager, extensionHost);
}
return instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
}
class ExtensionHostManager extends Disposable implements IExtensionHostManager {
public readonly kind: ExtensionHostKind;
public readonly onDidExit: Event<[number, string | null]>;
@@ -219,7 +245,8 @@ export class ExtensionHostManager extends Disposable {
MainContext.MainThreadNotebookDocuments,
MainContext.MainThreadNotebookEditors,
MainContext.MainThreadNotebookKernels,
MainContext.MainThreadNotebookRenderers
MainContext.MainThreadNotebookRenderers,
MainContext.MainThreadInteractive
];
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => (<any>MainContext)[key]).filter(v => !filtered.some(x => x === v));
this._rpcProtocol.assertRegistered(expected);
@@ -356,6 +383,127 @@ export class ExtensionHostManager extends Disposable {
}
}
/**
* Waits until `start()` and only if it has extensions proceeds to really start.
*/
class LazyStartExtensionHostManager extends Disposable implements IExtensionHostManager {
public readonly kind: ExtensionHostKind;
public readonly onDidExit: Event<[number, string | null]>;
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
public readonly onDidChangeResponsiveState: Event<ResponsiveState> = this._onDidChangeResponsiveState.event;
private readonly _extensionHost: IExtensionHost;
private _startCalled: Barrier;
private _actual: ExtensionHostManager | null;
constructor(
extensionHost: IExtensionHost,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILogService private readonly _logService: ILogService,
) {
super();
this._extensionHost = extensionHost;
this.kind = extensionHost.kind;
this.onDidExit = extensionHost.onExit;
this._startCalled = new Barrier();
this._actual = null;
}
private _createActual(reason: string): ExtensionHostManager {
this._logService.info(`Creating lazy extension host: ${reason}`);
this._actual = this._register(this._instantiationService.createInstance(ExtensionHostManager, this._extensionHost, []));
this._register(this._actual.onDidChangeResponsiveState((e) => this._onDidChangeResponsiveState.fire(e)));
return this._actual;
}
private async _getOrCreateActualAndStart(reason: string): Promise<ExtensionHostManager> {
if (this._actual) {
// already created/started
return this._actual;
}
const actual = this._createActual(reason);
await actual.start([]);
return actual;
}
public async ready(): Promise<void> {
await this._startCalled.wait();
if (this._actual) {
await this._actual.ready();
}
}
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
await this._startCalled.wait();
const extensionHostAlreadyStarted = Boolean(this._actual);
const shouldStartExtensionHost = (toAdd.length > 0);
if (extensionHostAlreadyStarted || shouldStartExtensionHost) {
const actual = await this._getOrCreateActualAndStart(`contains ${toAdd.length} new extension(s) (installed or enabled)`);
return actual.deltaExtensions(toAdd, toRemove);
}
}
public async activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.activate(extension, reason);
}
return false;
}
public async activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.activateByEvent(activationEvent, activationKind);
}
}
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.getInspectPort(tryEnableInspector);
}
return 0;
}
public async resolveAuthority(remoteAuthority: string): Promise<ResolverResult> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.resolveAuthority(remoteAuthority);
}
throw new Error(`Cannot resolve authority`);
}
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.getCanonicalURI(remoteAuthority, uri);
}
throw new Error(`Cannot resolve canonical URI`);
}
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
if (enabledExtensionIds.length > 0) {
// there are actual extensions, so let's launch the extension host
const actual = this._createActual(`contains ${enabledExtensionIds.length} extension(s).`);
const result = actual.start(enabledExtensionIds);
this._startCalled.open();
return result;
}
// there are no actual extensions
this._startCalled.open();
}
public async extensionTestsExecute(): Promise<number> {
await this._startCalled.wait();
const actual = await this._getOrCreateActualAndStart(`execute tests.`);
return actual.extensionTestsExecute();
}
public async extensionTestsSendExit(exitCode: number): Promise<void> {
await this._startCalled.wait();
const actual = await this._getOrCreateActualAndStart(`execute tests.`);
return actual.extensionTestsSendExit(exitCode);
}
public async setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void> {
await this._startCalled.wait();
if (this._actual) {
return this._actual.setRemoteEnvironment(env);
}
}
}
const colorTables = [
['#2977B1', '#FC802D', '#34A13A', '#D3282F', '#9366BA'],
['#8B564C', '#E177C0', '#7F7F7F', '#BBBE3D', '#2EBECD']
@@ -461,7 +609,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 {
const editorService = accessor.get(IEditorService);
const measurements = await Promise.all(getLatencyTestProviders().map(provider => provider.measure()));
editorService.openEditor({ contents: measurements.map(MeasureExtHostLatencyAction._print).join('\n\n'), options: { pinned: true } });
editorService.openEditor({ resource: undefined, contents: measurements.map(MeasureExtHostLatencyAction._print).join('\n\n'), options: { pinned: true } });
}
private static _print(m: ExtHostLatencyResult | null): string {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType, ExtensionVirtualWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkspaceSupportType, ExtensionVirtualWorkspaceSupportType, IExtensionIdentifier, ALL_EXTENSION_KINDS } 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';
@@ -15,7 +15,8 @@ import { ExtensionUntrustedWorkspaceSupport } from 'vs/base/common/product';
import { Disposable } from 'vs/base/common/lifecycle';
import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust';
import { isBoolean } from 'vs/base/common/types';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust';
import { ILogService } from 'vs/platform/log/common/log';
export const IExtensionManifestPropertiesService = createDecorator<IExtensionManifestPropertiesService>('extensionManifestPropertiesService');
@@ -31,39 +32,41 @@ export interface IExtensionManifestPropertiesService {
canExecuteOnWeb(manifest: IExtensionManifest): boolean;
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[];
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType;
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType;
getUserConfiguredExtensionKind(extensionIdentifier: IExtensionIdentifier): ExtensionKind[] | undefined;
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType;
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkspaceSupportType;
}
export class ExtensionManifestPropertiesService extends Disposable implements IExtensionManifestPropertiesService {
readonly _serviceBrand: undefined;
private _uiExtensionPoints: Set<string> | null = null;
private _extensionPointExtensionKindsMap: Map<string, ExtensionKind[]> | null = null;
private _productExtensionKindsMap: Map<string, ExtensionKind[]> | null = null;
private _configuredExtensionKindsMap: Map<string, ExtensionKind | ExtensionKind[]> | null = null;
private _productVirtualWorkspaceSupportMap: Map<string, { default?: boolean, override?: boolean }> | null = null;
private _configuredVirtualWorkspaceSupportMap: Map<string, boolean> | null = null;
private readonly _configuredExtensionWorkspaceTrustRequestMap: Map<string, { supported: ExtensionUntrustedWorkpaceSupportType, version?: string }>;
private readonly _configuredExtensionWorkspaceTrustRequestMap: Map<string, { supported: ExtensionUntrustedWorkspaceSupportType, version?: string }>;
private readonly _productExtensionWorkspaceTrustRequestMap: Map<string, ExtensionUntrustedWorkspaceSupport>;
constructor(
@IProductService private readonly productService: IProductService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService
@IWorkspaceTrustEnablementService private readonly workspaceTrustEnablementService: IWorkspaceTrustEnablementService,
@ILogService private readonly logService: ILogService,
) {
super();
// Workspace trust request type (settings.json)
this._configuredExtensionWorkspaceTrustRequestMap = new Map<string, { supported: ExtensionUntrustedWorkpaceSupportType, version?: string }>();
const configuredExtensionWorkspaceTrustRequests = configurationService.inspect<{ [key: string]: { supported: ExtensionUntrustedWorkpaceSupportType, version?: string } }>(WORKSPACE_TRUST_EXTENSION_SUPPORT).userValue || {};
this._configuredExtensionWorkspaceTrustRequestMap = new Map<string, { supported: ExtensionUntrustedWorkspaceSupportType, version?: string }>();
const configuredExtensionWorkspaceTrustRequests = configurationService.inspect<{ [key: string]: { supported: ExtensionUntrustedWorkspaceSupportType, version?: string } }>(WORKSPACE_TRUST_EXTENSION_SUPPORT).userValue || {};
for (const id of Object.keys(configuredExtensionWorkspaceTrustRequests)) {
this._configuredExtensionWorkspaceTrustRequestMap.set(ExtensionIdentifier.toKey(id), configuredExtensionWorkspaceTrustRequests[id]);
}
// Workpace trust request type (products.json)
// Workspace trust request type (products.json)
this._productExtensionWorkspaceTrustRequestMap = new Map<string, ExtensionUntrustedWorkspaceSupport>();
if (productService.extensionUntrustedWorkspaceSupport) {
for (const id of Object.keys(productService.extensionUntrustedWorkspaceSupport)) {
@@ -103,30 +106,51 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
}
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
// check in config
let result = this.getConfiguredExtensionKind(manifest);
if (typeof result !== 'undefined') {
return this.toArray(result);
}
const deducedExtensionKind = this.deduceExtensionKind(manifest);
const configuredExtensionKind = this.getConfiguredExtensionKind(manifest);
if (configuredExtensionKind) {
const result: ExtensionKind[] = [];
for (const extensionKind of configuredExtensionKind) {
if (extensionKind !== '-web') {
result.push(extensionKind);
}
}
// If opted out from web without specifying other extension kinds then default to ui, workspace
if (configuredExtensionKind.includes('-web') && !result.length) {
result.push('ui');
result.push('workspace');
}
// Add web kind if not opted out from web and can run in web
if (!configuredExtensionKind.includes('-web') && !configuredExtensionKind.includes('web') && deducedExtensionKind.includes('web')) {
result.push('web');
}
// 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);
return deducedExtensionKind;
}
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType {
getUserConfiguredExtensionKind(extensionIdentifier: IExtensionIdentifier): ExtensionKind[] | undefined {
if (this._configuredExtensionKindsMap === null) {
const configuredExtensionKindsMap = new Map<string, ExtensionKind | ExtensionKind[]>();
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 userConfiguredExtensionKind = this._configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionIdentifier.id));
return userConfiguredExtensionKind ? this.toArray(userConfiguredExtensionKind) : undefined;
}
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType {
// Workspace trust feature is disabled, or extension has no entry point
if (!this.workspaceTrustManagementService.workspaceTrustEnabled || !manifest.main) {
if (!this.workspaceTrustEnablementService.isWorkspaceTrustEnabled() || !manifest.main) {
return true;
}
@@ -137,12 +161,12 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
const productWorkspaceTrustRequest = this.getProductExtensionWorkspaceTrustRequest(manifest);
// Use settings.json override value if it exists
if (configuredWorkspaceTrustRequest) {
if (configuredWorkspaceTrustRequest !== undefined) {
return configuredWorkspaceTrustRequest;
}
// Use product.json override value if it exists
if (productWorkspaceTrustRequest?.override) {
if (productWorkspaceTrustRequest?.override !== undefined) {
return productWorkspaceTrustRequest.override;
}
@@ -152,14 +176,14 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
}
// Use product.json default value if it exists
if (productWorkspaceTrustRequest?.default) {
if (productWorkspaceTrustRequest?.default !== undefined) {
return productWorkspaceTrustRequest.default;
}
return false;
}
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType {
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkspaceSupportType {
// check user configured
const userConfiguredVirtualWorkspaceSupport = this.getConfiguredVirtualWorkspaceSupport(manifest);
if (userConfiguredVirtualWorkspaceSupport !== undefined) {
@@ -193,7 +217,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
return true;
}
deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
private deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
// Not an UI extension if it has main
if (manifest.main) {
if (manifest.browser) {
@@ -206,32 +230,72 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
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'];
let result = [...ALL_EXTENSION_KINDS];
// Extension pack defaults to workspace extensionKind
if (isNonEmptyArray(manifest.extensionPack) || isNonEmptyArray(manifest.extensionDependencies)) {
result = ['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'];
const supportedExtensionKinds = this.getSupportedExtensionKindsForExtensionPoint(contribution);
if (supportedExtensionKinds.length) {
result = result.filter(extensionKind => supportedExtensionKinds.includes(extensionKind));
}
}
}
return ['ui', 'workspace', 'web'];
if (!result.length) {
this.logService.warn('Cannot deduce extensionKind for extension', getGalleryExtensionId(manifest.publisher, manifest.name));
}
return result;
}
private isUIExtensionPoint(extensionPoint: string): boolean {
if (this._uiExtensionPoints === null) {
const uiExtensionPoints = new Set<string>();
ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => {
uiExtensionPoints.add(e.name);
});
this._uiExtensionPoints = uiExtensionPoints;
private getSupportedExtensionKindsForExtensionPoint(extensionPoint: string): ExtensionKind[] {
if (this._extensionPointExtensionKindsMap === null) {
const extensionPointExtensionKindsMap = new Map<string, ExtensionKind[]>();
ExtensionsRegistry.getExtensionPoints().forEach(e => extensionPointExtensionKindsMap.set(e.name, e.defaultExtensionKind || [] /* supports all */));
this._extensionPointExtensionKindsMap = extensionPointExtensionKindsMap;
}
return this._uiExtensionPoints.has(extensionPoint);
let extensionPointExtensionKind = this._extensionPointExtensionKindsMap.get(extensionPoint);
if (extensionPointExtensionKind) {
return extensionPointExtensionKind;
}
extensionPointExtensionKind = this.productService.extensionPointExtensionKind ? this.productService.extensionPointExtensionKind[extensionPoint] : undefined;
if (extensionPointExtensionKind) {
return extensionPointExtensionKind;
}
return ['workspace', 'web'] /* Unknown extension point => workspace, web */;
}
private getConfiguredExtensionKind(manifest: IExtensionManifest): (ExtensionKind | '-web')[] | null {
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
// check in config
let result: ExtensionKind | ExtensionKind[] | undefined = this.getUserConfiguredExtensionKind(extensionIdentifier);
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') {
result = this.toArray(result);
return result.filter(r => ALL_EXTENSION_KINDS.includes(r));
}
return null;
}
private getProductExtensionKind(manifest: IExtensionManifest): ExtensionKind[] | undefined {
@@ -249,20 +313,6 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
return this._productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
}
private getConfiguredExtensionKind(manifest: IExtensionManifest): ExtensionKind | ExtensionKind[] | undefined {
if (this._configuredExtensionKindsMap === null) {
const configuredExtensionKindsMap = new Map<string, ExtensionKind | ExtensionKind[]>();
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 getProductVirtualWorkspaceSupport(manifest: IExtensionManifest): { default?: boolean, override?: boolean } | undefined {
if (this._productVirtualWorkspaceSupportMap === null) {
const productWorkspaceSchemesMap = new Map<string, { default?: boolean, override?: boolean }>();
@@ -294,7 +344,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
return this._configuredVirtualWorkspaceSupportMap.get(ExtensionIdentifier.toKey(extensionId));
}
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType | undefined {
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType | undefined {
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
const extensionWorkspaceTrustRequest = this._configuredExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));

View File

@@ -24,6 +24,7 @@ export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
isBuiltin: false,
});
export type WebWorkerExtHostConfigValue = boolean | 'auto';
export const webWorkerExtHostConfig = 'extensions.webWorker';
export const IExtensionService = createDecorator<IExtensionService>('extensionService');
@@ -35,10 +36,18 @@ export interface IMessage {
extensionPointId: string;
}
export const enum ExtensionRunningLocation {
None,
LocalProcess,
LocalWebWorker,
Remote
}
export interface IExtensionsStatus {
messages: IMessage[];
activationTimes: ActivationTimes | undefined;
runtimeErrors: Error[];
runningLocation: ExtensionRunningLocation;
}
export class MissingExtensionDependency {
@@ -94,6 +103,7 @@ export const enum ExtensionHostKind {
export interface IExtensionHost {
readonly kind: ExtensionHostKind;
readonly remoteAuthority: string | null;
readonly lazyStart: boolean;
readonly onExit: Event<[number, string | null]>;
start(): Promise<IMessagePassingProtocol> | null;
@@ -288,12 +298,12 @@ export function toExtension(extensionDescription: IExtensionDescription): IExten
};
}
export function toExtensionDescription(extension: IExtension): IExtensionDescription {
export function toExtensionDescription(extension: IExtension, isUnderDevelopment?: boolean): IExtensionDescription {
return {
identifier: new ExtensionIdentifier(extension.identifier.id),
isBuiltin: extension.type === ExtensionType.System,
isUserBuiltin: extension.type === ExtensionType.User && extension.isBuiltin,
isUnderDevelopment: false,
isUnderDevelopment: !!isUnderDevelopment,
extensionLocation: extension.location,
...extension.manifest,
uuid: extension.identifier.uuid

View File

@@ -11,10 +11,9 @@ import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/co
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES, ExtensionKind } from 'vs/platform/extensions/common/extensions';
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
export type ExtensionKind = 'workspace' | 'ui' | undefined;
export class ExtensionMessageCollector {
@@ -63,9 +62,9 @@ export interface IExtensionPointUser<T> {
export type IExtensionPointHandler<T> = (extensions: readonly IExtensionPointUser<T>[], delta: ExtensionPointUserDelta<T>) => void;
export interface IExtensionPoint<T> {
name: string;
readonly name: string;
setHandler(handler: IExtensionPointHandler<T>): void;
defaultExtensionKind: ExtensionKind;
readonly defaultExtensionKind: ExtensionKind[] | undefined;
}
export class ExtensionPointUserDelta<T> {
@@ -104,13 +103,13 @@ export class ExtensionPointUserDelta<T> {
export class ExtensionPoint<T> implements IExtensionPoint<T> {
public readonly name: string;
public readonly defaultExtensionKind: ExtensionKind;
public readonly defaultExtensionKind: ExtensionKind[] | undefined;
private _handler: IExtensionPointHandler<T> | null;
private _users: IExtensionPointUser<T>[] | null;
private _delta: ExtensionPointUserDelta<T> | null;
constructor(name: string, defaultExtensionKind: ExtensionKind) {
constructor(name: string, defaultExtensionKind: ExtensionKind[] | undefined) {
this.name = name;
this.defaultExtensionKind = defaultExtensionKind;
this._handler = null;
@@ -312,7 +311,7 @@ export const schema: IJSONSchema = {
},
{
label: 'onNotebook',
body: 'onNotebook:${10:viewType}',
body: 'onNotebook:${1:type}',
description: nls.localize('vscode.extension.activationEvents.onNotebook', 'An activation event emitted whenever the specified notebook document is opened.'),
},
{
@@ -327,9 +326,14 @@ export const schema: IJSONSchema = {
},
{
label: 'onTerminalProfile',
body: 'onTerminalProfile:${1:terminalType}',
body: 'onTerminalProfile:${1:terminalId}',
description: nls.localize('vscode.extension.activationEvents.onTerminalProfile', 'An activation event emitted when a specific terminal profile is launched.'),
},
{
label: 'onWalkthrough',
body: 'onWalkthrough:${1:walkthroughID}',
description: nls.localize('vscode.extension.activationEvents.onWalkthrough', 'An activation event emitted when a specified walkthrough is opened.'),
},
{
label: '*',
description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'),
@@ -511,7 +515,7 @@ export interface IExtensionPointDescriptor {
extensionPoint: string;
deps?: IExtensionPoint<any>[];
jsonSchema: IJSONSchema;
defaultExtensionKind?: ExtensionKind;
defaultExtensionKind?: ExtensionKind[];
}
export class ExtensionsRegistryImpl {

View File

@@ -3,149 +3,34 @@
* Licensed under the Source EULA. 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 { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILog } from 'vs/workbench/services/extensions/common/extensionPoints';
import { localize } from 'vs/nls';
export class ExtensionKindController2 {
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 = getConfiguredExtensionKind(manifest, this.configurationService);
if (typeof result !== 'undefined') {
return toArray(result);
export function dedupExtensions(system: IExtensionDescription[], user: IExtensionDescription[], development: IExtensionDescription[], log: ILog): IExtensionDescription[] {
let result = new Map<string, IExtensionDescription>();
system.forEach((systemExtension) => {
const extensionKey = ExtensionIdentifier.toKey(systemExtension.identifier);
const extension = result.get(extensionKey);
if (extension) {
log.warn(systemExtension.extensionLocation.fsPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, systemExtension.extensionLocation.fsPath));
}
// check product.json
result = getProductExtensionKind(manifest, this.productService);
if (typeof result !== 'undefined') {
return result;
result.set(extensionKey, systemExtension);
});
user.forEach((userExtension) => {
const extensionKey = ExtensionIdentifier.toKey(userExtension.identifier);
const extension = result.get(extensionKey);
if (extension) {
log.warn(userExtension.extensionLocation.fsPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, userExtension.extensionLocation.fsPath));
}
// check the manifest itself
result = manifest.extensionKind;
if (typeof result !== 'undefined') {
return toArray(result);
}
return deduceExtensionKind(manifest);
}
result.set(extensionKey, userExtension);
});
development.forEach(developedExtension => {
log.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
result.set(extensionKey, developedExtension);
});
let r: IExtensionDescription[] = [];
result.forEach((value) => r.push(value));
return r;
}
export function 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 (!isUIExtensionPoint(contribution)) {
return ['workspace'];
}
}
}
return ['ui', 'workspace', 'web'];
}
let _uiExtensionPoints: Set<string> | null = null;
function isUIExtensionPoint(extensionPoint: string): boolean {
if (_uiExtensionPoints === null) {
const uiExtensionPoints = new Set<string>();
ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => {
uiExtensionPoints.add(e.name);
});
_uiExtensionPoints = uiExtensionPoints;
}
return _uiExtensionPoints.has(extensionPoint);
}
let _productExtensionKindsMap: Map<string, ExtensionKind[]> | null = null;
function getProductExtensionKind(manifest: IExtensionManifest, productService: IProductService): ExtensionKind[] | undefined {
if (_productExtensionKindsMap === null) {
const productExtensionKindsMap = new Map<string, ExtensionKind[]>();
if (productService.extensionKind) {
for (const id of Object.keys(productService.extensionKind)) {
productExtensionKindsMap.set(ExtensionIdentifier.toKey(id), productService.extensionKind[id]);
}
}
_productExtensionKindsMap = productExtensionKindsMap;
}
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
return _productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
}
let _configuredExtensionKindsMap: Map<string, ExtensionKind | ExtensionKind[]> | null = null;
function getConfiguredExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): ExtensionKind | ExtensionKind[] | undefined {
if (_configuredExtensionKindsMap === null) {
const configuredExtensionKindsMap = new Map<string, ExtensionKind | ExtensionKind[]>();
const configuredExtensionKinds = configurationService.getValue<{ [key: string]: ExtensionKind | ExtensionKind[] }>('remote.extensionKind') || {};
for (const id of Object.keys(configuredExtensionKinds)) {
configuredExtensionKindsMap.set(ExtensionIdentifier.toKey(id), configuredExtensionKinds[id]);
}
_configuredExtensionKindsMap = configuredExtensionKindsMap;
}
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
return _configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
}
function toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[] {
if (Array.isArray(extensionKind)) {
return extensionKind;
}
return extensionKind === 'ui' ? ['ui', 'workspace'] : [extensionKind];
}

View File

@@ -27,7 +27,7 @@ export interface IRPCProtocol {
export class ProxyIdentifier<T> {
public static count = 0;
_proxyIdentifierBrand: void;
_proxyIdentifierBrand: void = undefined;
public readonly isMain: boolean;
public readonly sid: string;
@@ -57,3 +57,12 @@ export function createExtHostContextProxyIdentifier<T>(identifier: string): Prox
export function getStringIdentifierForProxy(nid: number): string {
return identifiers[nid].sid;
}
/**
* Marks the object as containing buffers that should be serialized more efficently.
*/
export class SerializableObjectWithBuffers<T> {
constructor(
public readonly value: T
) { }
}

View File

@@ -52,6 +52,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
public readonly kind = ExtensionHostKind.Remote;
public readonly remoteAuthority: string;
public readonly lazyStart = false;
private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>());
public readonly onExit: Event<[number, string | null]> = this._onExit.event;
@@ -231,6 +232,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
isExtensionDevelopmentDebug,
appRoot: remoteInitData.appRoot,
appName: this._productService.nameLong,
embedderIdentifier: this._productService.embedderIdentifier || 'desktop',
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,

View File

@@ -4,16 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import { RunOnceScheduler } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CharCode } from 'vs/base/common/charCode';
import * as errors from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { MarshalledId, MarshalledObject } from 'vs/base/common/marshalling';
import { IURITransformer, transformIncomingURIs } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { LazyPromise } from 'vs/workbench/services/extensions/common/lazyPromise';
import { IRPCProtocol, ProxyIdentifier, getStringIdentifierForProxy } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { VSBuffer } from 'vs/base/common/buffer';
import { getStringIdentifierForProxy, IRPCProtocol, ProxyIdentifier, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
export interface JSONStringifyReplacer {
(key: string, value: any): any;
@@ -27,6 +28,55 @@ function safeStringify(obj: any, replacer: JSONStringifyReplacer | null): string
}
}
const refSymbolName = '$$ref$$';
const undefinedRef = { [refSymbolName]: -1 } as const;
class StringifiedJsonWithBufferRefs {
constructor(
public readonly jsonString: string,
public readonly referencedBuffers: readonly VSBuffer[],
) { }
}
export function stringifyJsonWithBufferRefs<T>(obj: T, replacer: JSONStringifyReplacer | null = null, useSafeStringify = false): StringifiedJsonWithBufferRefs {
const foundBuffers: VSBuffer[] = [];
const serialized = (useSafeStringify ? safeStringify : JSON.stringify)(obj, (key, value) => {
if (typeof value === 'undefined') {
return undefinedRef; // JSON.stringify normally converts 'undefined' to 'null'
} else if (typeof value === 'object') {
if (value instanceof VSBuffer) {
const bufferIndex = foundBuffers.push(value) - 1;
return { [refSymbolName]: bufferIndex };
}
if (replacer) {
return replacer(key, value);
}
}
return value;
});
return {
jsonString: serialized,
referencedBuffers: foundBuffers
};
}
export function parseJsonAndRestoreBufferRefs(jsonString: string, buffers: readonly VSBuffer[], uriTransformer: IURITransformer | null): any {
return JSON.parse(jsonString, (_key, value) => {
if (value) {
const ref = value[refSymbolName];
if (typeof ref === 'number') {
return buffers[ref];
}
if (uriTransformer && (<MarshalledObject>value).$mid === MarshalledId.Uri) {
return uriTransformer.transformIncoming(value);
}
}
return value;
});
}
function stringify(obj: any, replacer: JSONStringifyReplacer | null): string {
return JSON.stringify(obj, <(key: string, value: any) => any>replacer);
}
@@ -36,7 +86,7 @@ function createURIReplacer(transformer: IURITransformer | null): JSONStringifyRe
return null;
}
return (key: string, value: any): any => {
if (value && value.$mid === 1) {
if (value && value.$mid === MarshalledId.Uri) {
return transformer.transformOutgoing(value);
}
return value;
@@ -277,6 +327,11 @@ export class RPCProtocol extends Disposable implements IRPCProtocol {
this._receiveReply(msgLength, req, value);
break;
}
case MessageType.ReplyOKJSONWithBuffers: {
const value = MessageIO.deserializeReplyOKJSONWithBuffers(buff, this._uriTransformer);
this._receiveReply(msgLength, req, value);
break;
}
case MessageType.ReplyOKVSBuffer: {
let value = MessageIO.deserializeReplyOKVSBuffer(buff);
this._receiveReply(msgLength, req, value);
@@ -557,19 +612,25 @@ class MessageBuffer {
return buff;
}
public static sizeMixedArray(arr: VSBuffer[], arrType: ArgType[]): number {
public static sizeMixedArray(arr: readonly MixedArg[]): number {
let size = 0;
size += 1; // arr length
for (let i = 0, len = arr.length; i < len; i++) {
const el = arr[i];
const elType = arrType[i];
size += 1; // arg type
switch (elType) {
switch (el.type) {
case ArgType.String:
size += this.sizeLongString(el);
size += this.sizeLongString(el.value);
break;
case ArgType.VSBuffer:
size += this.sizeVSBuffer(el);
size += this.sizeVSBuffer(el.value);
break;
case ArgType.SerializedObjectWithBuffers:
size += this.sizeUInt8(); // buffer count
size += this.sizeLongString(el.value);
for (let i = 0; i < el.buffers.length; ++i) {
size += this.sizeVSBuffer(el.buffers[i]);
}
break;
case ArgType.Undefined:
// empty...
@@ -579,19 +640,26 @@ class MessageBuffer {
return size;
}
public writeMixedArray(arr: VSBuffer[], arrType: ArgType[]): void {
public writeMixedArray(arr: readonly MixedArg[]): void {
this._buff.writeUInt8(arr.length, this._offset); this._offset += 1;
for (let i = 0, len = arr.length; i < len; i++) {
const el = arr[i];
const elType = arrType[i];
switch (elType) {
switch (el.type) {
case ArgType.String:
this.writeUInt8(ArgType.String);
this.writeLongString(el);
this.writeLongString(el.value);
break;
case ArgType.VSBuffer:
this.writeUInt8(ArgType.VSBuffer);
this.writeVSBuffer(el);
this.writeVSBuffer(el.value);
break;
case ArgType.SerializedObjectWithBuffers:
this.writeUInt8(ArgType.SerializedObjectWithBuffers);
this.writeUInt8(el.buffers.length);
this.writeLongString(el.value);
for (let i = 0; i < el.buffers.length; ++i) {
this.writeBuffer(el.buffers[i]);
}
break;
case ArgType.Undefined:
this.writeUInt8(ArgType.Undefined);
@@ -600,9 +668,9 @@ class MessageBuffer {
}
}
public readMixedArray(): Array<string | VSBuffer | undefined> {
public readMixedArray(): Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> {
const arrLen = this._buff.readUInt8(this._offset); this._offset += 1;
let arr: Array<string | VSBuffer | undefined> = new Array(arrLen);
let arr: Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> = new Array(arrLen);
for (let i = 0; i < arrLen; i++) {
const argType = <ArgType>this.readUInt8();
switch (argType) {
@@ -612,6 +680,15 @@ class MessageBuffer {
case ArgType.VSBuffer:
arr[i] = this.readVSBuffer();
break;
case ArgType.SerializedObjectWithBuffers:
const bufferCount = this.readUInt8();
const jsonString = this.readLongString();
const buffers: VSBuffer[] = [];
for (let i = 0; i < bufferCount; ++i) {
buffers.push(this.readVSBuffer());
}
arr[i] = new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(jsonString, buffers, null));
break;
case ArgType.Undefined:
arr[i] = undefined;
break;
@@ -621,15 +698,26 @@ class MessageBuffer {
}
}
type SerializedRequestArguments = { type: 'mixed'; args: VSBuffer[]; argsType: ArgType[]; } | { type: 'simple'; args: string; };
const enum SerializedRequestArgumentType {
Simple,
Mixed,
}
type SerializedRequestArguments =
| { readonly type: SerializedRequestArgumentType.Simple; args: string; }
| { readonly type: SerializedRequestArgumentType.Mixed; args: MixedArg[] };
class MessageIO {
private static _arrayContainsBufferOrUndefined(arr: any[]): boolean {
private static _useMixedArgSerialization(arr: any[]): boolean {
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i] instanceof VSBuffer) {
return true;
}
if (arr[i] instanceof SerializableObjectWithBuffers) {
return true;
}
if (typeof arr[i] === 'undefined') {
return true;
}
@@ -638,39 +726,39 @@ class MessageIO {
}
public static serializeRequestArguments(args: any[], replacer: JSONStringifyReplacer | null): SerializedRequestArguments {
if (this._arrayContainsBufferOrUndefined(args)) {
let massagedArgs: VSBuffer[] = [];
let massagedArgsType: ArgType[] = [];
if (this._useMixedArgSerialization(args)) {
const massagedArgs: MixedArg[] = [];
for (let i = 0, len = args.length; i < len; i++) {
const arg = args[i];
if (arg instanceof VSBuffer) {
massagedArgs[i] = arg;
massagedArgsType[i] = ArgType.VSBuffer;
massagedArgs[i] = { type: ArgType.VSBuffer, value: arg };
} else if (typeof arg === 'undefined') {
massagedArgs[i] = VSBuffer.alloc(0);
massagedArgsType[i] = ArgType.Undefined;
massagedArgs[i] = { type: ArgType.Undefined };
} else if (arg instanceof SerializableObjectWithBuffers) {
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(arg.value, replacer);
massagedArgs[i] = { type: ArgType.SerializedObjectWithBuffers, value: VSBuffer.fromString(jsonString), buffers: referencedBuffers };
} else {
massagedArgs[i] = VSBuffer.fromString(stringify(arg, replacer));
massagedArgsType[i] = ArgType.String;
massagedArgs[i] = { type: ArgType.String, value: VSBuffer.fromString(stringify(arg, replacer)) };
}
}
return {
type: 'mixed',
type: SerializedRequestArgumentType.Mixed,
args: massagedArgs,
argsType: massagedArgsType
};
}
return {
type: 'simple',
type: SerializedRequestArgumentType.Simple,
args: stringify(args, replacer)
};
}
public static serializeRequest(req: number, rpcId: number, method: string, serializedArgs: SerializedRequestArguments, usesCancellationToken: boolean): VSBuffer {
if (serializedArgs.type === 'mixed') {
return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, serializedArgs.argsType, usesCancellationToken);
switch (serializedArgs.type) {
case SerializedRequestArgumentType.Simple:
return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
case SerializedRequestArgumentType.Mixed:
return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
}
return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
}
private static _requestJSONArgs(req: number, rpcId: number, method: string, args: string, usesCancellationToken: boolean): VSBuffer {
@@ -700,18 +788,18 @@ class MessageIO {
};
}
private static _requestMixedArgs(req: number, rpcId: number, method: string, args: VSBuffer[], argsType: ArgType[], usesCancellationToken: boolean): VSBuffer {
private static _requestMixedArgs(req: number, rpcId: number, method: string, args: readonly MixedArg[], usesCancellationToken: boolean): VSBuffer {
const methodBuff = VSBuffer.fromString(method);
let len = 0;
len += MessageBuffer.sizeUInt8();
len += MessageBuffer.sizeShortString(methodBuff);
len += MessageBuffer.sizeMixedArray(args, argsType);
len += MessageBuffer.sizeMixedArray(args);
let result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestMixedArgsWithCancellation : MessageType.RequestMixedArgs, req, len);
result.writeUInt8(rpcId);
result.writeShortString(methodBuff);
result.writeMixedArray(args, argsType);
result.writeMixedArray(args);
return result.buffer;
}
@@ -746,11 +834,14 @@ class MessageIO {
public static serializeReplyOK(req: number, res: any, replacer: JSONStringifyReplacer | null): VSBuffer {
if (typeof res === 'undefined') {
return this._serializeReplyOKEmpty(req);
}
if (res instanceof VSBuffer) {
} else if (res instanceof VSBuffer) {
return this._serializeReplyOKVSBuffer(req, res);
} else if (res instanceof SerializableObjectWithBuffers) {
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(res.value, replacer, true);
return this._serializeReplyOKJSONWithBuffers(req, jsonString, referencedBuffers);
} else {
return this._serializeReplyOKJSON(req, safeStringify(res, replacer));
}
return this._serializeReplyOKJSON(req, safeStringify(res, replacer));
}
private static _serializeReplyOKEmpty(req: number): VSBuffer {
@@ -781,11 +872,43 @@ class MessageIO {
return result.buffer;
}
private static _serializeReplyOKJSONWithBuffers(req: number, res: string, buffers: readonly VSBuffer[]): VSBuffer {
const resBuff = VSBuffer.fromString(res);
let len = 0;
len += MessageBuffer.sizeUInt8(); // buffer count
len += MessageBuffer.sizeLongString(resBuff);
for (const buffer of buffers) {
len += MessageBuffer.sizeVSBuffer(buffer);
}
let result = MessageBuffer.alloc(MessageType.ReplyOKJSONWithBuffers, req, len);
result.writeUInt8(buffers.length);
result.writeLongString(resBuff);
for (const buffer of buffers) {
result.writeBuffer(buffer);
}
return result.buffer;
}
public static deserializeReplyOKJSON(buff: MessageBuffer): any {
const res = buff.readLongString();
return JSON.parse(res);
}
public static deserializeReplyOKJSONWithBuffers(buff: MessageBuffer, uriTransformer: IURITransformer | null): SerializableObjectWithBuffers<any> {
const bufferCount = buff.readUInt8();
const res = buff.readLongString();
const buffers: VSBuffer[] = [];
for (let i = 0; i < bufferCount; ++i) {
buffers.push(buff.readVSBuffer());
}
return new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(res, buffers, uriTransformer));
}
public static serializeReplyErr(req: number, err: any): VSBuffer {
if (err) {
return this._serializeReplyErrEror(req, err);
@@ -824,12 +947,22 @@ const enum MessageType {
ReplyOKEmpty = 7,
ReplyOKVSBuffer = 8,
ReplyOKJSON = 9,
ReplyErrError = 10,
ReplyErrEmpty = 11,
ReplyOKJSONWithBuffers = 10,
ReplyErrError = 11,
ReplyErrEmpty = 12,
}
const enum ArgType {
String = 1,
VSBuffer = 2,
Undefined = 3
SerializedObjectWithBuffers = 3,
Undefined = 4,
}
type MixedArg =
| { readonly type: ArgType.String, readonly value: VSBuffer }
| { readonly type: ArgType.VSBuffer, readonly value: VSBuffer }
| { readonly type: ArgType.SerializedObjectWithBuffers, readonly value: VSBuffer, readonly buffers: readonly VSBuffer[] }
| { readonly type: ArgType.Undefined }
;

View File

@@ -14,12 +14,13 @@ import { URI } from 'vs/base/common/uri';
import * as pfs from 'vs/base/node/pfs';
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/productService';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, IRelaxedExtensionDescription } from 'vs/workbench/services/extensions/node/extensionPoints';
import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints';
import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil';
interface IExtensionCacheData {
input: ExtensionScannerInput;
@@ -79,32 +80,7 @@ export class CachedExtensionScanner {
try {
const translations = await this.translationConfig;
const { system, user, development } = await CachedExtensionScanner._scanInstalledExtensions(this._hostService, this._notificationService, this._environmentService, this._extensionEnablementService, this._productService, log, translations);
let result = new Map<string, IExtensionDescription>();
system.forEach((systemExtension) => {
const extensionKey = ExtensionIdentifier.toKey(systemExtension.identifier);
const extension = result.get(extensionKey);
if (extension) {
log.warn(systemExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, systemExtension.extensionLocation.fsPath));
}
result.set(extensionKey, systemExtension);
});
user.forEach((userExtension) => {
const extensionKey = ExtensionIdentifier.toKey(userExtension.identifier);
const extension = result.get(extensionKey);
if (extension) {
log.warn(userExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, userExtension.extensionLocation.fsPath));
}
result.set(extensionKey, userExtension);
});
development.forEach(developedExtension => {
log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
result.set(extensionKey, developedExtension);
});
let r: IExtensionDescription[] = [];
result.forEach((value) => r.push(value));
const r = dedupExtensions(system, user, development, log);
this._scannedExtensionsResolve(r);
} catch (err) {
this._scannedExtensionsReject(err);

View File

@@ -6,7 +6,7 @@
import { LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { AbstractExtensionService, ExtensionRunningLocationClassifier, ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import * as nls from 'vs/nls';
import { runWhenIdle } from 'vs/base/common/async';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -21,13 +21,12 @@ import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecyc
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig, ExtensionRunningLocation, WebWorkerExtHostConfigValue } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
import { IProductService } from 'vs/platform/product/common/productService';
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
import { flatten } from 'vs/base/common/arrays';
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
@@ -48,6 +47,7 @@ import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/w
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
private readonly _enableLocalWebWorker: boolean;
private readonly _lazyLocalWebWorker: boolean;
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
private readonly _extensionScanner: CachedExtensionScanner;
@@ -65,7 +65,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
@IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService,
@INativeHostService private readonly _nativeHostService: INativeHostService,
@IHostService private readonly _hostService: IHostService,
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
@@ -89,10 +89,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
extensionManagementService,
contextService,
configurationService,
extensionManifestPropertiesService
extensionManifestPropertiesService,
webExtensionsScannerService
);
this._enableLocalWebWorker = this._isLocalWebWorkerEnabled();
[this._enableLocalWebWorker, this._lazyLocalWebWorker] = this._isLocalWebWorkerEnabled();
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
@@ -110,14 +111,26 @@ export class ExtensionService extends AbstractExtensionService implements IExten
});
}
private _isLocalWebWorkerEnabled() {
if (this._configurationService.getValue<boolean>(webWorkerExtHostConfig)) {
return true;
}
private _isLocalWebWorkerEnabled(): [boolean, boolean] {
let isEnabled: boolean;
let isLazy: boolean;
if (this._environmentService.isExtensionDevelopment && this._environmentService.extensionDevelopmentKind?.some(k => k === 'web')) {
return true;
isEnabled = true;
isLazy = false;
} else {
const config = this._configurationService.getValue<WebWorkerExtHostConfigValue>(webWorkerExtHostConfig);
if (config === true) {
isEnabled = true;
isLazy = false;
} else if (config === 'auto') {
isEnabled = true;
isLazy = true;
} else {
isEnabled = false;
isLazy = false;
}
}
return false;
return [isEnabled, isLazy];
}
protected _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
@@ -131,7 +144,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
return flatten(await Promise.all([
this._extensionScanner.scannedExtensions,
this._webExtensionsScannerService.scanAndTranslateExtensions().then(extensions => extensions.map(parseScannedExtension))
this._scanWebExtensions(),
]));
}
@@ -220,7 +233,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
result.push(localProcessExtHost);
if (this._enableLocalWebWorker) {
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._lazyLocalWebWorker, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
result.push(webWorkerExtHost);
}
@@ -233,7 +246,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return result;
}
protected override _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
protected override _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
const activatedExtensions = Array.from(this._extensionHostActiveExtensions.values());
super._onExtensionHostCrashed(extensionHost, code, signal);
@@ -307,16 +320,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
// --- impl
private createLogger(): Logger {
return new Logger((severity, source, message) => {
if (this._isDev && source) {
this._logOrShowMessage(severity, `[${source}]: ${message}`);
} else {
this._logOrShowMessage(severity, message);
}
});
}
private async _resolveAuthorityAgain(): Promise<void> {
const remoteAuthority = this._environmentService.remoteAuthority;
if (!remoteAuthority) {

View File

@@ -67,6 +67,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
public readonly kind = ExtensionHostKind.LocalProcess;
public readonly remoteAuthority = null;
public readonly lazyStart = false;
private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>();
public readonly onExit: Event<[number, string]> = this._onExit.event;
@@ -238,7 +239,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
}
// Run Extension Host as fork of current process
this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost'], opts);
this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost', '--skipWorkspaceStorageLock'], opts);
// Catch all output coming from the extension host process
type Output = { data: string, format: string[] };
@@ -471,6 +472,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
appName: this._productService.nameLong,
embedderIdentifier: this._productService.embedderIdentifier || 'desktop',
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,

View File

@@ -7,7 +7,7 @@ import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'minimist';
import * as performance from 'vs/base/common/performance';
import { onUnexpectedError } from 'vs/base/common/errors';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
import { Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants, BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net';
@@ -22,12 +22,14 @@ import { Promises } from 'vs/base/node/pfs';
import { realpath } from 'vs/base/node/extpath';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import { RunOnceScheduler } from 'vs/base/common/async';
import { boolean } from 'vs/editor/common/config/editorOptions';
import 'vs/workbench/api/common/extHost.common.services';
import 'vs/workbench/api/node/extHost.node.services';
interface ParsedExtHostArgs {
uriTransformerPath?: string;
skipWorkspaceStorageLock?: boolean;
useHostProxy?: string;
}
@@ -46,6 +48,9 @@ const args = minimist(process.argv.slice(2), {
string: [
'uriTransformerPath',
'useHostProxy'
],
boolean: [
'skipWorkspaceStorageLock'
]
}) as ParsedExtHostArgs;
@@ -245,11 +250,13 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
if (idx >= 0) {
promise.catch(e => {
unhandledPromises.splice(idx, 1);
console.warn(`rejected promise not handled within 1 second: ${e}`);
if (e && e.stack) {
console.warn(`stack trace: ${e.stack}`);
if (!isPromiseCanceledError(e)) {
console.warn(`rejected promise not handled within 1 second: ${e}`);
if (e && e.stack) {
console.warn(`stack trace: ${e.stack}`);
}
onUnexpectedError(reason);
}
onUnexpectedError(reason);
});
}
}, 1000);
@@ -321,6 +328,7 @@ export async function startExtensionHostProcess(): Promise<void> {
// setup things
patchProcess(!!initData.environment.extensionTestsLocationURI); // to support other test frameworks like Jasmin that use process.exit (https://github.com/microsoft/vscode/issues/37708)
initData.environment.useHostProxy = args.useHostProxy !== undefined ? args.useHostProxy !== 'false' : undefined;
initData.environment.skipWorkspaceStorageLock = boolean(args.skipWorkspaceStorageLock, false);
// host abstraction
const hostUtils = new class NodeHost implements IHostUtils {

View File

@@ -91,6 +91,21 @@ class ExtensionManifestParser extends ExtensionManifestHandler {
}
}
interface MessageBag {
[key: string]: string | { message: string; comment: string[] };
}
interface TranslationBundle {
contents: {
package: MessageBag;
};
}
interface LocalizedMessages {
values: MessageBag | undefined;
default: string | null;
}
class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
private readonly _nlsConfig: NlsConfiguration;
@@ -101,21 +116,6 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
}
public replaceNLS(extensionDescription: IExtensionDescription): Promise<IExtensionDescription> {
interface MessageBag {
[key: string]: string;
}
interface TranslationBundle {
contents: {
package: MessageBag;
};
}
interface LocalizedMessages {
values: MessageBag | undefined;
default: string | null;
}
const reportErrors = (localized: string | null, errors: json.ParseError[]): void => {
errors.forEach((error) => {
this._log.error(this._absoluteFolderPath, nls.localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized, getParseErrorMessage(error.error)));
@@ -250,21 +250,22 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
* This routine makes the following assumptions:
* The root element is an object literal
*/
private static _replaceNLStrings<T extends object>(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void {
private static _replaceNLStrings<T extends object>(nlsConfig: NlsConfiguration, literal: T, messages: MessageBag, originalMessages: MessageBag | null, log: ILog, messageScope: string): void {
function processEntry(obj: any, key: string | number, command?: boolean) {
let value = obj[key];
const value = obj[key];
if (types.isString(value)) {
let str = <string>value;
let length = str.length;
const str = <string>value;
const length = str.length;
if (length > 1 && str[0] === '%' && str[length - 1] === '%') {
let messageKey = str.substr(1, length - 2);
let message = messages[messageKey];
const messageKey = str.substr(1, length - 2);
let translated = messages[messageKey];
// If the messages come from a language pack they might miss some keys
// Fill them from the original messages.
if (message === undefined && originalMessages) {
message = originalMessages[messageKey];
if (translated === undefined && originalMessages) {
translated = originalMessages[messageKey];
}
if (message) {
let message: string | undefined = typeof translated === 'string' ? translated : (typeof translated?.message === 'string' ? translated.message : undefined);
if (message !== undefined) {
if (nlsConfig.pseudo) {
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';

View File

@@ -4,11 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
import { ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
suite('BrowserExtensionService', () => {
test('pickRunningLocation', () => {
assert(true); // {{SQL CARBON EDIT}} Workaround for error loading test modules when there's no imports in the file
/* {{SQL CARBON EDIT}} Disable broken tests for unused service
test.skip('pickRunningLocation', () => { // {{SQL CARBON EDIT}} Disable broken tests for unused service
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
@@ -84,6 +85,5 @@ suite('BrowserExtensionService', () => {
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
*/
});
});

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IExtensionManifest, ExtensionKind, ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
import { IExtensionManifest, ExtensionUntrustedWorkspaceSupportType } 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';
@@ -12,49 +12,77 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IProductService } from 'vs/platform/product/common/productService';
import { isWeb } from 'vs/base/common/platform';
import { TestWorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustEnablementService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust';
import { NullLogService } from 'vs/platform/log/common/log';
suite('ExtensionManifestPropertiesService - ExtensionKind', () => {
function check(manifest: Partial<IExtensionManifest>, expected: ExtensionKind[]): void {
const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustManagementService());
assert.deepStrictEqual(extensionManifestPropertiesService.deduceExtensionKind(<IExtensionManifest>manifest), expected);
}
let testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustEnablementService(), new NullLogService());
test('declarative with extension dependencies => workspace', () => {
check({ extensionDependencies: ['ext1'] }, ['workspace']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionDependencies: ['ext1'] }), ['workspace']);
});
test('declarative extension pack => workspace', () => {
check({ extensionPack: ['ext1', 'ext2'] }, ['workspace']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'] }), ['workspace']);
});
test('declarative with unknown contribution point => workspace', () => {
check({ contributes: <any>{ 'unknownPoint': { something: true } } }, ['workspace']);
test('declarative extension pack and extension dependencies => workspace', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'], extensionDependencies: ['ext1', 'ext2'] }), ['workspace']);
});
test('declarative with unknown contribution point => workspace, web', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ contributes: <any>{ 'unknownPoint': { something: true } } }), ['workspace', 'web']);
});
test('declarative extension pack with unknown contribution point => workspace', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'], contributes: <any>{ 'unknownPoint': { something: true } } }), ['workspace']);
});
test('simple declarative => ui, workspace, web', () => {
check({}, ['ui', 'workspace', 'web']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{}), ['ui', 'workspace', 'web']);
});
test('only browser => web', () => {
check({ browser: 'main.browser.js' }, ['web']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js' }), ['web']);
});
test('only main => workspace', () => {
check({ main: 'main.js' }, ['workspace']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js' }), ['workspace']);
});
test('main and browser => workspace, web', () => {
check({ main: 'main.js', browser: 'main.browser.js' }, ['workspace', 'web']);
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js', browser: 'main.browser.js' }), ['workspace', 'web']);
});
test('browser entry point with workspace extensionKind => workspace, web', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js', browser: 'main.browser.js', extensionKind: ['workspace'] }), ['workspace', 'web']);
});
test('simple descriptive with workspace, ui extensionKind => workspace, ui, web', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionKind: ['workspace', 'ui'] }), ['workspace', 'ui', 'web']);
});
test('opt out from web through settings even if it can run in web', () => {
testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService());
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['ui', 'workspace']);
});
test('opt out from web and include only workspace through settings even if it can run in web', () => {
testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web', 'workspace'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService());
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['workspace']);
});
test('extension cannot opt out from web', () => {
assert.deepStrictEqual(testObject.getExtensionKind(<any>{ browser: 'main.browser.js', extensionKind: ['-web'] }), ['web']);
});
});
// Workspace Trust is disabled in web at the moment
if (!isWeb) {
suite('ExtensionManifestPropertiesService - ExtensionUntrustedWorkpaceSupportType', () => {
suite('ExtensionManifestPropertiesService - ExtensionUntrustedWorkspaceSupportType', () => {
let testObject: ExtensionManifestPropertiesService;
let instantiationService: TestInstantiationService;
let testConfigurationService: TestConfigurationService;
@@ -64,12 +92,11 @@ if (!isWeb) {
testConfigurationService = new TestConfigurationService();
instantiationService.stub(IConfigurationService, testConfigurationService);
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { enabled: true } } });
});
teardown(() => testObject.dispose());
function assertUntrustedWorkspaceSupport(extensionMaifest: IExtensionManifest, expected: ExtensionUntrustedWorkpaceSupportType): void {
function assertUntrustedWorkspaceSupport(extensionMaifest: IExtensionManifest, expected: ExtensionUntrustedWorkspaceSupportType): void {
testObject = instantiationService.createInstance(ExtensionManifestPropertiesService);
const untrustedWorkspaceSupport = testObject.getExtensionUntrustedWorkspaceSupportType(extensionMaifest);
@@ -82,7 +109,7 @@ if (!isWeb) {
test('test extension workspace trust request when main entry point is missing', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest();
assertUntrustedWorkspaceSupport(extensionMaifest, true);
@@ -90,58 +117,92 @@ if (!isWeb) {
test('test extension workspace trust request when workspace trust is disabled', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService(false));
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService(false));
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
assertUntrustedWorkspaceSupport(extensionMaifest, true);
});
test('test extension workspace trust request when override exists in settings.json', async () => {
test('test extension workspace trust request when "true" override exists in settings.json', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true } } });
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, true);
});
test('test extension workspace trust request when override for the version exists in settings.json', async () => {
test('test extension workspace trust request when override (false) exists in settings.json', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: false } } });
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, false);
});
test('test extension workspace trust request when override (true) for the version exists in settings.json', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true, version: '1.0.0' } } });
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, true);
});
test('test extension workspace trust request when override (false) for the version exists in settings.json', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: false, version: '1.0.0' } } });
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, false);
});
test('test extension workspace trust request when override for a different version exists in settings.json', async () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true, version: '2.0.0' } } });
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
});
test('test extension workspace trust request when default exists in product.json', () => {
test('test extension workspace trust request when default (true) exists in product.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: true } } });
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
assertUntrustedWorkspaceSupport(extensionMaifest, true);
});
test('test extension workspace trust request when override exists in product.json', () => {
test('test extension workspace trust request when default (false) exists in product.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: false } } });
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
assertUntrustedWorkspaceSupport(extensionMaifest, false);
});
test('test extension workspace trust request when override (limited) exists in product.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: 'limited' } } });
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } });
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
});
test('test extension workspace trust request when override (false) exists in product.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: false } } });
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } });
assertUntrustedWorkspaceSupport(extensionMaifest, false);
});
test('test extension workspace trust request when value exists in package.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
@@ -149,7 +210,7 @@ if (!isWeb) {
test('test extension workspace trust request when no value exists in package.json', () => {
instantiationService.stub(IProductService, <Partial<IProductService>>{});
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
assertUntrustedWorkspaceSupport(extensionMaifest, false);

View File

@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ProxyIdentifier, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -211,4 +211,31 @@ suite('RPCProtocol', () => {
bProxy.$m(badObject, '2');
});
});
test('SerializableObjectWithBuffers is correctly transfered', function (done) {
delegate = (a1: SerializableObjectWithBuffers<{ string: string, buff: VSBuffer }>, a2: number) => {
return new SerializableObjectWithBuffers({ string: a1.value.string + ' world', buff: a1.value.buff });
};
const b = VSBuffer.alloc(4);
b.buffer[0] = 1;
b.buffer[1] = 2;
b.buffer[2] = 3;
b.buffer[3] = 4;
bProxy.$m(new SerializableObjectWithBuffers({ string: 'hello', buff: b }), undefined).then((res: SerializableObjectWithBuffers<any>) => {
assert.ok(res instanceof SerializableObjectWithBuffers);
assert.strictEqual(res.value.string, 'hello world');
assert.ok(res.value.buff instanceof VSBuffer);
const bufferValues = Array.from(res.value.buff.buffer);
assert.strictEqual(bufferValues[0], 1);
assert.strictEqual(bufferValues[1], 2);
assert.strictEqual(bufferValues[2], 3);
assert.strictEqual(bufferValues[3], 4);
done(null);
}, done);
});
});

View File

@@ -16,6 +16,8 @@ import * as performance from 'vs/base/common/performance';
import 'vs/workbench/api/common/extHost.common.services';
import 'vs/workbench/api/worker/extHost.worker.services';
import { FileAccess } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
//#region --- Define, capture, and override some globals
@@ -29,6 +31,7 @@ declare namespace self {
let dispatchEvent: any;
let indexedDB: { open: any, [k: string]: any };
let caches: { open: any, [k: string]: any };
let importScripts: any;
}
const nativeClose = self.close.bind(self);
@@ -37,6 +40,8 @@ self.close = () => console.trace(`'close' has been blocked`);
const nativePostMessage = postMessage.bind(self);
self.postMessage = () => console.trace(`'postMessage' has been blocked`);
self.importScripts = () => { throw new Error(`'importScripts' has been blocked`); };
// const nativeAddEventListener = addEventListener.bind(self);
self.addEventListener = () => console.trace(`'addEventListener' has been blocked`);
@@ -55,7 +60,15 @@ if ((<any>self).Worker) {
// make sure new Worker(...) always uses blob: (to maintain current origin)
const _Worker = (<any>self).Worker;
Worker = <any>function (stringUrl: string | URL, options?: WorkerOptions) {
const js = `importScripts('${stringUrl}');`;
if (/^file:/i.test(stringUrl.toString())) {
stringUrl = FileAccess.asBrowserUri(URI.parse(stringUrl.toString())).toString(true);
}
const js = `(function() {
const ttPolicy = self.trustedTypes ? self.trustedTypes.createPolicy('extensionHostWorker', { createScriptURL: (value) => value }) : undefined;
const stringUrl = '${stringUrl}';
importScripts(ttPolicy ? ttPolicy.createScriptURL(stringUrl) : stringUrl);
})();
`;
options = options || {};
options.name = options.name || path.basename(stringUrl.toString());
const blob = new Blob([js], { type: 'application/javascript' });
@@ -150,7 +163,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
let onTerminate = (reason: string) => nativeClose();
(function create(): void {
export function create(): void {
const res = new ExtensionWorker();
performance.mark(`code/extHost/willConnectToRenderer`);
connectToRenderer(res.protocol).then(data => {
@@ -164,4 +177,4 @@ let onTerminate = (reason: string) => nativeClose();
onTerminate = (reason: string) => extHostMain.terminate(reason);
});
})();
}

View File

@@ -1,73 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
(function () {
const MonacoEnvironment = (<any>self).MonacoEnvironment;
const monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../../../';
const trustedTypesPolicy = (
typeof self.trustedTypes?.createPolicy === 'function'
? self.trustedTypes?.createPolicy('amdLoader', {
createScriptURL: value => value,
createScript: (_, ...args: string[]) => {
// workaround a chrome issue not allowing to create new functions
// see https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
const fnArgs = args.slice(0, -1).join(',');
const fnBody = args.pop()!.toString();
const body = `(function anonymous(${fnArgs}) {\n${fnBody}\n})`;
return body;
}
})
: undefined
);
function loadAMDLoader() {
return new Promise<void>((resolve, reject) => {
if (typeof (<any>self).define === 'function' && (<any>self).define.amd) {
return resolve();
}
const loaderSrc: string | TrustedScriptURL = monacoBaseUrl + 'vs/loader.js';
const isCrossOrigin = (/^((http:)|(https:)|(file:))/.test(loaderSrc) && loaderSrc.substring(0, self.origin.length) !== self.origin);
if (!isCrossOrigin) {
// use `fetch` if possible because `importScripts`
// is synchronous and can lead to deadlocks on Safari
fetch(loaderSrc).then((response) => {
if (response.status !== 200) {
throw new Error(response.statusText);
}
return response.text();
}).then((text) => {
text = `${text}\n//# sourceURL=${loaderSrc}`;
const func = (
trustedTypesPolicy
? self.eval(trustedTypesPolicy.createScript('', text) as unknown as string)
: new Function(text)
);
func.call(self);
resolve();
}).then(undefined, reject);
return;
}
if (trustedTypesPolicy) {
importScripts(trustedTypesPolicy.createScriptURL(loaderSrc) as unknown as string);
} else {
importScripts(loaderSrc as string);
}
resolve();
});
}
loadAMDLoader().then(() => {
require.config({
baseUrl: monacoBaseUrl,
catchError: true,
trustedTypesPolicy
});
require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
}).then(undefined, (err) => console.error(err));
})();

View File

@@ -1,13 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-LU+tuagpyx5mKuYgHsSvz9593ZGS6yeLPRvzq1lKXlY=' http: https:; connect-src http: https: ws: wss:" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=' http: https:; connect-src http: https: ws: wss:" />
</head>
<body>
<script>
(function() {
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
const searchParams = new URL(document.location).searchParams;
const vscodeWebWorkerExtHostId = searchParams.get('vscodeWebWorkerExtHostId') || '';
const name = searchParams.get('debugged') ? 'WorkerExtensionHost' : 'DebugWorkerExtensionHost';
function sendError(error) {
window.parent.postMessage({
@@ -21,7 +22,8 @@
}
try {
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
const worker = new Worker('../../../../base/worker/workerMain.js', { name });
worker.postMessage('vs/workbench/services/extensions/worker/extensionHostWorker');
const nestedWorkers = new Map();
worker.onmessage = (event) => {

View File

@@ -1,13 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-LU+tuagpyx5mKuYgHsSvz9593ZGS6yeLPRvzq1lKXlY=' https:; connect-src https: wss:" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=' https:; connect-src https: wss:" />
</head>
<body>
<script>
(function() {
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
const searchParams = new URL(document.location).searchParams;
const vscodeWebWorkerExtHostId = searchParams.get('vscodeWebWorkerExtHostId') || '';
const name = searchParams.get('debugged') ? 'WorkerExtensionHost' : 'DebugWorkerExtensionHost';
function sendError(error) {
window.parent.postMessage({
@@ -21,7 +22,8 @@
}
try {
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
const worker = new Worker('../../../../base/worker/workerMain.js', { name });
worker.postMessage('vs/workbench/services/extensions/worker/extensionHostWorker');
const nestedWorkers = new Map();
worker.onmessage = (event) => {