/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; export const nullExtensionDescription = Object.freeze({ identifier: new ExtensionIdentifier('nullExtensionDescription'), name: 'Null Extension Description', version: '0.0.0', publisher: 'vscode', enableProposedApi: false, engines: { vscode: '' }, extensionLocation: URI.parse('void:location'), isBuiltin: false, }); export const IExtensionService = createDecorator('extensionService'); export interface IMessage { type: Severity; message: string; extensionId: ExtensionIdentifier; extensionPointId: string; } export interface IExtensionsStatus { messages: IMessage[]; activationTimes: ActivationTimes | undefined; runtimeErrors: Error[]; } export type ExtensionActivationError = string | MissingDependencyError; export class MissingDependencyError { constructor(readonly dependency: string) { } } /** * e.g. * ``` * { * startTime: 1511954813493000, * endTime: 1511954835590000, * deltas: [ 100, 1500, 123456, 1500, 100000 ], * ids: [ 'idle', 'self', 'extension1', 'self', 'idle' ] * } * ``` */ export interface IExtensionHostProfile { /** * Profiling start timestamp in microseconds. */ startTime: number; /** * Profiling end timestamp in microseconds. */ endTime: number; /** * Duration of segment in microseconds. */ deltas: number[]; /** * Segment identifier: extension id or one of the four known strings. */ ids: ProfileSegmentId[]; /** * Get the information as a .cpuprofile. */ data: object; /** * Get the aggregated time per segmentId */ getAggregatedTimes(): Map; } export interface IExtensionHostStarter { readonly onExit: Event<[number, string | null]>; start(): Promise | null; getInspectPort(): number | undefined; dispose(): void; } /** * Extension id or one of the four known program states. */ export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self'; export class ActivationTimes { constructor( public readonly startup: boolean, public readonly codeLoadingTime: number, public readonly activateCallTime: number, public readonly activateResolvedTime: number, public readonly activationEvent: string ) { } } export class ExtensionPointContribution { readonly description: IExtensionDescription; readonly value: T; constructor(description: IExtensionDescription, value: T) { this.description = description; this.value = value; } } export const ExtensionHostLogFileName = 'exthost'; export interface IWillActivateEvent { readonly event: string; readonly activation: Promise; } export interface IResponsiveStateChangeEvent { isResponsive: boolean; } export interface IExtensionService { _serviceBrand: undefined; /** * An event emitted when extensions are registered after their extension points got handled. * * This event will also fire on startup to signal the installed extensions. * * @returns the extensions that got registered */ onDidRegisterExtensions: Event; /** * @event * Fired when extensions status changes. * The event contains the ids of the extensions that have changed. */ onDidChangeExtensionsStatus: Event; /** * Fired when the available extensions change (i.e. when extensions are added or removed). */ onDidChangeExtensions: Event; /** * An event that is fired when activation happens. */ onWillActivateByEvent: Event; /** * An event that is fired when an extension host changes its * responsive-state. */ onDidChangeResponsiveChange: Event; /** * Send an activation event and activate interested extensions. */ activateByEvent(activationEvent: string): Promise; /** * An promise that resolves when the installed extensions are registered after * their extension points got handled. */ whenInstalledExtensionsRegistered(): Promise; /** * Return all registered extensions */ getExtensions(): Promise; /** * Return a specific extension * @param id An extension id */ getExtension(id: string): Promise; /** * Returns `true` if the given extension can be added. Otherwise `false`. * @param extension An extension */ canAddExtension(extension: IExtensionDescription): boolean; /** * Returns `true` if the given extension can be removed. Otherwise `false`. * @param extension An extension */ canRemoveExtension(extension: IExtensionDescription): boolean; /** * Read all contributions to an extension point. */ readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]>; /** * Get information about extensions status. */ getExtensionsStatus(): { [id: string]: IExtensionsStatus }; /** * Return the inspect port or `0`, the latter means inspection * is not possible. */ getInspectPort(): number; /** * Restarts the extension host. */ restartExtensionHost(): void; /** * Modify the environment of the remote extension host * @param env New properties for the remote extension host */ setRemoteEnvironment(env: { [key: string]: string | null }): Promise; _logOrShowMessage(severity: Severity, msg: string): void; _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise; _onWillActivateExtension(extensionId: ExtensionIdentifier): void; _onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void; _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void; _onExtensionHostExit(code: number): void; } export interface ProfileSession { stop(): Promise; } export function checkProposedApiEnabled(extension: IExtensionDescription): void { if (!extension.enableProposedApi) { throwProposedApiError(extension); } } export function throwProposedApiError(extension: IExtensionDescription): never { throw new Error(`[${extension.identifier.value}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.identifier.value}`); } export function toExtension(extensionDescription: IExtensionDescription): IExtension { return { type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User, identifier: { id: getGalleryExtensionId(extensionDescription.publisher, extensionDescription.name), uuid: extensionDescription.uuid }, manifest: extensionDescription, location: extensionDescription.extensionLocation, }; } export class NullExtensionService implements IExtensionService { _serviceBrand: undefined; onDidRegisterExtensions: Event = Event.None; onDidChangeExtensionsStatus: Event = Event.None; onDidChangeExtensions: Event = Event.None; onWillActivateByEvent: Event = Event.None; onDidChangeResponsiveChange: Event = Event.None; activateByEvent(_activationEvent: string): Promise { return Promise.resolve(undefined); } whenInstalledExtensionsRegistered(): Promise { return Promise.resolve(true); } getExtensions(): Promise { return Promise.resolve([]); } getExtension() { return Promise.resolve(undefined); } readExtensionPointContributions(_extPoint: IExtensionPoint): Promise[]> { return Promise.resolve(Object.create(null)); } getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { return Object.create(null); } getInspectPort(): number { return 0; } restartExtensionHost(): void { } async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise { } canAddExtension(): boolean { return false; } canRemoveExtension(): boolean { return false; } _logOrShowMessage(_severity: Severity, _msg: string): void { } _activateById(_extensionId: ExtensionIdentifier, _activationEvent: string): Promise { return Promise.resolve(); } _onWillActivateExtension(_extensionId: ExtensionIdentifier): void { } _onDidActivateExtension(_extensionId: ExtensionIdentifier, _startup: boolean, _codeLoadingTime: number, _activateCallTime: number, _activateResolvedTime: number, _activationEvent: string): void { } _onExtensionRuntimeError(_extensionId: ExtensionIdentifier, _err: Error): void { } _onExtensionHostExit(code: number): void { } }