extensions.ts 6.5 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 12
import { ExtensionIdentifier, IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
13

14
export interface IExtensionDescription extends IExtensionManifest {
15
	readonly identifier: ExtensionIdentifier;
16 17
	readonly uuid?: string;
	readonly isBuiltin: boolean;
18
	readonly isUnderDevelopment: boolean;
19
	readonly extensionLocation: URI;
20 21 22
	enableProposedApi?: boolean;
}

J
Johannes Rieken 已提交
23
export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
24
	identifier: new ExtensionIdentifier('nullExtensionDescription'),
25
	name: 'Null Extension Description',
J
Johannes Rieken 已提交
26
	version: '0.0.0',
27 28
	publisher: 'vscode',
	enableProposedApi: false,
J
Johannes Rieken 已提交
29 30
	engines: { vscode: '' },
	extensionLocation: URI.parse('void:location'),
31 32 33
	isBuiltin: false,
});

34 35 36 37 38
export const IExtensionService = createDecorator<IExtensionService>('extensionService');

export interface IMessage {
	type: Severity;
	message: string;
39
	extensionId: ExtensionIdentifier;
40 41 42 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 88 89 90 91
	extensionPointId: string;
}

export interface IExtensionsStatus {
	messages: IMessage[];
	activationTimes: ActivationTimes;
	runtimeErrors: Error[];
}

/**
 * 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.
 */
92
export type ProfileSegmentId = string | 'idle' | 'program' | 'gc' | 'self' | null;
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

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;
	}
}

115 116
export const ExtensionHostLogFileName = 'exthost';

117 118
export interface IWillActivateEvent {
	readonly event: string;
J
Johannes Rieken 已提交
119
	readonly activation: Promise<void>;
120 121
}

122 123 124 125 126 127
export interface IResponsiveStateChangeEvent {
	target: ICpuProfilerTarget;
	isResponsive: boolean;
}

export interface IExtensionService extends ICpuProfilerTarget {
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
	_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.
	 */
144
	onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]>;
145

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

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

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

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

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

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

179 180 181
	/**
	 * Read all contributions to an extension point.
	 */
A
Alex Dima 已提交
182
	readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
183 184 185 186 187 188

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

189 190 191 192 193
	/**
	 * Return the inspect port or 0.
	 */
	getInspectPort(): number;

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	/**
	 * Restarts the extension host.
	 */
	restartExtensionHost(): void;

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

	/**
	 * Stops the extension host.
	 */
	stopExtensionHost(): void;
}

210 211 212 213 214 215 216 217 218 219 220 221 222
export interface ICpuProfilerTarget {

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

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

223
export interface ProfileSession {
J
Johannes Rieken 已提交
224
	stop(): Promise<IExtensionHostProfile>;
225
}
226 227 228 229 230 231 232 233

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

export function throwProposedApiError(extension: IExtensionDescription): never {
234
	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}`);
235
}
236 237 238 239 240 241 242 243 244

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,
	};
}