extensions.ts 9.4 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

A
Alex Dima 已提交
6
import { Event } from 'vs/base/common/event';
7
import Severity from 'vs/base/common/severity';
A
Alex Dima 已提交
8
import { URI } from 'vs/base/common/uri';
9 10
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
11
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
12
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
13

J
Johannes Rieken 已提交
14
export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
15
	identifier: new ExtensionIdentifier('nullExtensionDescription'),
16
	name: 'Null Extension Description',
J
Johannes Rieken 已提交
17
	version: '0.0.0',
18 19
	publisher: 'vscode',
	enableProposedApi: false,
J
Johannes Rieken 已提交
20 21
	engines: { vscode: '' },
	extensionLocation: URI.parse('void:location'),
22 23 24
	isBuiltin: false,
});

25 26 27 28 29
export const IExtensionService = createDecorator<IExtensionService>('extensionService');

export interface IMessage {
	type: Severity;
	message: string;
30
	extensionId: ExtensionIdentifier;
31 32 33 34 35
	extensionPointId: string;
}

export interface IExtensionsStatus {
	messages: IMessage[];
A
Alex Dima 已提交
36
	activationTimes: ActivationTimes | undefined;
37 38 39
	runtimeErrors: Error[];
}

40 41 42
export type ExtensionActivationError = string | MissingDependencyError;
export class MissingDependencyError {
	constructor(readonly dependency: string) { }
43 44
}

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
/**
 * 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<ProfileSegmentId, number>;
}

/**
 * Extension id or one of the four known program states.
 */
M
Matt Bierner 已提交
88
export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self';
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

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<T> {
	readonly description: IExtensionDescription;
	readonly value: T;

	constructor(description: IExtensionDescription, value: T) {
		this.description = description;
		this.value = value;
	}
}

111 112
export const ExtensionHostLogFileName = 'exthost';

113 114
export interface IWillActivateEvent {
	readonly event: string;
J
Johannes Rieken 已提交
115
	readonly activation: Promise<void>;
116 117
}

118 119 120 121 122 123
export interface IResponsiveStateChangeEvent {
	target: ICpuProfilerTarget;
	isResponsive: boolean;
}

export interface IExtensionService extends ICpuProfilerTarget {
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	_serviceBrand: any;

	/**
	 * 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<void>;

	/**
	 * @event
	 * Fired when extensions status changes.
	 * The event contains the ids of the extensions that have changed.
	 */
140
	onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]>;
141

142 143 144 145 146
	/**
	 * Fired when the available extensions change (i.e. when extensions are added or removed).
	 */
	onDidChangeExtensions: Event<void>;

147 148 149 150 151
	/**
	 * An event that is fired when activation happens.
	 */
	onWillActivateByEvent: Event<IWillActivateEvent>;

152 153 154 155 156 157
	/**
	 * An event that is fired when an extension host changes its
	 * responsive-state.
	 */
	onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent>;

158 159 160
	/**
	 * Send an activation event and activate interested extensions.
	 */
J
Johannes Rieken 已提交
161
	activateByEvent(activationEvent: string): Promise<void>;
162 163 164 165 166

	/**
	 * An promise that resolves when the installed extensions are registered after
	 * their extension points got handled.
	 */
A
Alex Dima 已提交
167
	whenInstalledExtensionsRegistered(): Promise<boolean>;
168 169 170 171

	/**
	 * Return all registered extensions
	 */
A
Alex Dima 已提交
172
	getExtensions(): Promise<IExtensionDescription[]>;
173

174 175 176 177 178 179
	/**
	 * Return a specific extension
	 * @param id An extension id
	 */
	getExtension(id: string): Promise<IExtensionDescription | undefined>;

180 181 182 183 184 185 186 187 188 189 190 191
	/**
	 * 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;

192 193 194
	/**
	 * Read all contributions to an extension point.
	 */
A
Alex Dima 已提交
195
	readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
196 197 198 199 200 201

	/**
	 * Get information about extensions status.
	 */
	getExtensionsStatus(): { [id: string]: IExtensionsStatus };

202 203 204 205 206
	/**
	 * Return the inspect port or 0.
	 */
	getInspectPort(): number;

207 208 209 210 211 212 213 214 215 216 217 218 219 220
	/**
	 * Restarts the extension host.
	 */
	restartExtensionHost(): void;

	/**
	 * Starts the extension host.
	 */
	startExtensionHost(): void;

	/**
	 * Stops the extension host.
	 */
	stopExtensionHost(): void;
221 222 223 224 225 226

	_logOrShowMessage(severity: Severity, msg: string): void;
	_activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise<void>;
	_onWillActivateExtension(extensionId: ExtensionIdentifier): void;
	_onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void;
	_onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void;
A
Alex Dima 已提交
227
	_onExtensionHostExit(code: number): void;
228 229
}

230 231 232 233 234 235 236 237 238 239 240 241 242
export interface ICpuProfilerTarget {

	/**
	 * Check if the extension host can be profiled.
	 */
	canProfileExtensionHost(): boolean;

	/**
	 * Begin an extension host process profile session.
	 */
	startExtensionHostProfile(): Promise<ProfileSession>;
}

243
export interface ProfileSession {
J
Johannes Rieken 已提交
244
	stop(): Promise<IExtensionHostProfile>;
245
}
246 247 248 249 250 251 252 253

export function checkProposedApiEnabled(extension: IExtensionDescription): void {
	if (!extension.enableProposedApi) {
		throwProposedApiError(extension);
	}
}

export function throwProposedApiError(extension: IExtensionDescription): never {
254
	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}`);
255
}
256 257 258 259 260 261 262 263 264

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,
	};
}
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287


export class NullExtensionService implements IExtensionService {
	_serviceBrand: any;
	onDidRegisterExtensions: Event<void> = Event.None;
	onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]> = Event.None;
	onDidChangeExtensions: Event<void> = Event.None;
	onWillActivateByEvent: Event<IWillActivateEvent> = Event.None;
	onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent> = Event.None;
	activateByEvent(_activationEvent: string): Promise<void> { return Promise.resolve(undefined); }
	whenInstalledExtensionsRegistered(): Promise<boolean> { return Promise.resolve(true); }
	getExtensions(): Promise<IExtensionDescription[]> { return Promise.resolve([]); }
	getExtension() { return Promise.resolve(undefined); }
	readExtensionPointContributions<T>(_extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> { return Promise.resolve(Object.create(null)); }
	getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { return Object.create(null); }
	canProfileExtensionHost(): boolean { return false; }
	getInspectPort(): number { return 0; }
	startExtensionHostProfile(): Promise<ProfileSession> { return Promise.resolve(Object.create(null)); }
	restartExtensionHost(): void { }
	startExtensionHost(): void { }
	stopExtensionHost(): void { }
	canAddExtension(): boolean { return false; }
	canRemoveExtension(): boolean { return false; }
288 289 290 291 292
	_logOrShowMessage(_severity: Severity, _msg: string): void { }
	_activateById(_extensionId: ExtensionIdentifier, _activationEvent: string): Promise<void> { 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 { }
A
Alex Dima 已提交
293
	_onExtensionHostExit(code: number): void { }
294
}