extHost.api.impl.ts 32.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

7
import { Emitter } from 'vs/base/common/event';
8
import { TrieMap } from 'vs/base/common/map';
J
Johannes Rieken 已提交
9
import { score } from 'vs/editor/common/modes/languageSelector';
10
import * as Platform from 'vs/base/common/platform';
E
Erich Gamma 已提交
11
import * as errors from 'vs/base/common/errors';
12 13
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
J
Johannes Rieken 已提交
14
import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService';
J
Johannes Rieken 已提交
15
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
J
Johannes Rieken 已提交
16
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
17
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/node/extHostDocumentContentProviders';
J
Johannes Rieken 已提交
18 19 20
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
S
Sandeep Somavarapu 已提交
21
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
J
Johannes Rieken 已提交
22 23
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
24
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
J
Joao Moreno 已提交
25
import { ExtHostSCM } from 'vs/workbench/api/node/extHostSCM';
J
Johannes Rieken 已提交
26 27 28 29 30 31
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { ExtHostStatusBar } from 'vs/workbench/api/node/extHostStatusBar';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostOutputService } from 'vs/workbench/api/node/extHostOutputService';
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
import { ExtHostMessageService } from 'vs/workbench/api/node/extHostMessageService';
J
Johannes Rieken 已提交
32
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
J
Johannes Rieken 已提交
33 34
import { ExtHostLanguages } from 'vs/workbench/api/node/extHostLanguages';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
35
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
36
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
37
import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
C
Christof Marti 已提交
38
import { ExtHostCredentials } from 'vs/workbench/api/node/extHostCredentials';
J
Johannes Rieken 已提交
39
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
E
Erich Gamma 已提交
40 41 42
import URI from 'vs/base/common/uri';
import Severity from 'vs/base/common/severity';
import EditorCommon = require('vs/editor/common/editorCommon');
J
Johannes Rieken 已提交
43 44 45
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { TPromise } from 'vs/base/common/winjs.base';
46
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
J
Johannes Rieken 已提交
47
import { CancellationTokenSource } from 'vs/base/common/cancellation';
48
import * as vscode from 'vscode';
E
Erich Gamma 已提交
49
import * as paths from 'vs/base/common/paths';
J
Johannes Rieken 已提交
50
import { realpath } from 'fs';
51
import { MainContext, ExtHostContext, IInitData } from './extHost.protocol';
52
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
53
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
54
import { ExtHostThreadService } from "vs/workbench/services/thread/node/extHostThreadService";
55
import { ProxyIdentifier } from "vs/workbench/services/thread/common/threadService";
E
Erich Gamma 已提交
56

57
export interface IExtensionApiFactory {
58
	(extension: IExtensionDescription): typeof vscode;
59 60
}

61
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
62
	if (extension.enableProposedApi) {
63 64 65
		return fn;
	} else {
		return <any>(() => {
66
			throw new Error(`[${extension.id}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.id}`);
67 68 69 70
		});
	}
}

E
Erich Gamma 已提交
71
/**
72
 * This method instantiates and returns the extension API surface
E
Erich Gamma 已提交
73
 */
74 75
export function createApiFactory(
	initData: IInitData,
76
	threadService: ExtHostThreadService,
77 78 79
	extensionService: ExtHostExtensionService,
	telemetryService: ITelemetryService
): IExtensionApiFactory {
80

81
	// Addressable instances
82 83 84 85 86 87 88 89 90
	const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
	const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService));
	const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors));
	const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors));
	const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace)));
	const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors));
	const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService));
	const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands));
	const extHostWorkspace = threadService.set(ExtHostContext.ExtHostWorkspace, new ExtHostWorkspace(threadService, initData.workspace));
91
	const extHostDebugService = threadService.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace));
92 93 94 95 96 97 98 99 100 101 102 103 104 105
	const extHostConfiguration = threadService.set(ExtHostContext.ExtHostConfiguration, new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration));
	const extHostDiagnostics = threadService.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(threadService));
	const languageFeatures = threadService.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
	const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
	const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService));
	const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService));
	const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands));
	const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService));
	const extHostCredentials = threadService.set(ExtHostContext.ExtHostCredentials, new ExtHostCredentials(threadService));
	threadService.set(ExtHostContext.ExtHostExtensionService, extensionService);

	// Check that no named customers are missing
	const expected: ProxyIdentifier<any>[] = Object.keys(ExtHostContext).map((key) => ExtHostContext[key]);
	threadService.assertRegistered(expected);
106

107 108 109
	// Other instances
	const extHostMessageService = new ExtHostMessageService(threadService);
	const extHostStatusBar = new ExtHostStatusBar(threadService);
110
	const extHostProgress = new ExtHostProgress(threadService.get(MainContext.MainThreadProgress));
111 112
	const extHostOutputService = new ExtHostOutputService(threadService);
	const extHostLanguages = new ExtHostLanguages(threadService);
113

114 115
	// Register API-ish commands
	ExtHostApiCommands.register(extHostCommands);
116

117
	return function (extension: IExtensionDescription): typeof vscode {
118

119
		if (extension.enableProposedApi && !extension.isBuiltin) {
120

121 122 123 124
			if (
				!initData.environment.enableProposedApiForAll &&
				initData.environment.enableProposedApiFor.indexOf(extension.id) < 0
			) {
125
				extension.enableProposedApi = false;
126
				console.error(`Extension '${extension.id} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`);
127 128

			} else {
129 130 131
				// proposed api is available when developing or when an extension was explicitly
				// spelled out via a command line argument
				console.warn(`Extension '${extension.id}' uses PROPOSED API which is subject to change and removal without notice.`);
132
			}
133 134
		}

135 136 137 138 139 140 141 142 143 144 145 146 147 148
		const apiUsage = new class {
			private _seen = new Set<string>();
			publicLog(apiName: string) {
				if (this._seen.has(apiName)) {
					return undefined;
				}
				this._seen.add(apiName);
				return telemetryService.publicLog('apiUsage', {
					name: apiName,
					extension: extension.id
				});
			}
		};

149 150
		// namespace: commands
		const commands: typeof vscode.commands = {
151 152
			registerCommand<T>(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
				return extHostCommands.registerCommand(id, command, thisArgs);
153
			},
154
			registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable {
155
				return extHostCommands.registerCommand(id, (...args: any[]): any => {
156 157 158
					let activeTextEditor = extHostEditors.getActiveTextEditor();
					if (!activeTextEditor) {
						console.warn('Cannot execute ' + id + ' because there is no active text editor.');
159
						return undefined;
160
					}
161 162 163 164 165 166 167 168 169 170

					return activeTextEditor.edit((edit: vscode.TextEditorEdit) => {
						args.unshift(activeTextEditor, edit);
						callback.apply(thisArg, args);

					}).then((result) => {
						if (!result) {
							console.warn('Edits from command ' + id + ' were not applied.');
						}
					}, (err) => {
171
						console.warn('An error occurred while running command ' + id, err);
172
					});
173
				});
174 175
			},
			registerDiffInformationCommand: proposedApiFunction(extension, (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => {
176 177 178 179 180 181 182 183 184 185
				return extHostCommands.registerCommand(id, async (...args: any[]) => {
					let activeTextEditor = extHostEditors.getActiveTextEditor();
					if (!activeTextEditor) {
						console.warn('Cannot execute ' + id + ' because there is no active text editor.');
						return undefined;
					}

					const diff = await extHostEditors.getDiffInformation(activeTextEditor.id);
					callback.apply(thisArg, [diff, ...args]);
				});
186
			}),
187
			executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
188
				return extHostCommands.executeCommand<T>(id, ...args);
189
			},
190 191 192
			getCommands(filterInternal: boolean = false): Thenable<string[]> {
				return extHostCommands.getCommands(filterInternal);
			}
193
		};
194

195 196
		// namespace: env
		const env: typeof vscode.env = Object.freeze({
197 198
			get machineId() { return initData.telemetryInfo.machineId; },
			get sessionId() { return initData.telemetryInfo.sessionId; },
199 200 201
			get language() { return Platform.language; },
			get appName() { return product.nameLong; }
		});
E
Erich Gamma 已提交
202

203 204 205
		// namespace: extensions
		const extensions: typeof vscode.extensions = {
			getExtension(extensionId: string): Extension<any> {
206
				let desc = extensionService.getExtensionDescription(extensionId);
207 208 209
				if (desc) {
					return new Extension(extensionService, desc);
				}
210
				return undefined;
211 212
			},
			get all(): Extension<any>[] {
213
				return extensionService.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
E
Erich Gamma 已提交
214
			}
215
		};
E
Erich Gamma 已提交
216

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
		// namespace: languages
		const languages: typeof vscode.languages = {
			createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
				return extHostDiagnostics.createDiagnosticCollection(name);
			},
			getLanguages(): TPromise<string[]> {
				return extHostLanguages.getLanguages();
			},
			match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number {
				return score(selector, <any>document.uri, document.languageId);
			},
			registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
				return languageFeatures.registerCodeActionProvider(selector, provider);
			},
			registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
				return languageFeatures.registerCodeLensProvider(selector, provider);
			},
			registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
				return languageFeatures.registerDefinitionProvider(selector, provider);
			},
M
Matt Bierner 已提交
237 238
			registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
				return languageFeatures.registerImplementationProvider(selector, provider);
239
			},
240 241 242
			registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
				return languageFeatures.registerTypeDefinitionProvider(selector, provider);
			},
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
			registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
				return languageFeatures.registerHoverProvider(selector, provider);
			},
			registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
				return languageFeatures.registerDocumentHighlightProvider(selector, provider);
			},
			registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
				return languageFeatures.registerReferenceProvider(selector, provider);
			},
			registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
				return languageFeatures.registerRenameProvider(selector, provider);
			},
			registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
				return languageFeatures.registerDocumentSymbolProvider(selector, provider);
			},
			registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
				return languageFeatures.registerWorkspaceSymbolProvider(provider);
			},
			registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
				return languageFeatures.registerDocumentFormattingEditProvider(selector, provider);
			},
			registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
				return languageFeatures.registerDocumentRangeFormattingEditProvider(selector, provider);
			},
			registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
				return languageFeatures.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
			},
			registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, ...triggerCharacters: string[]): vscode.Disposable {
				return languageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters);
			},
			registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
274
				return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters);
275 276 277 278 279 280
			},
			registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
				return languageFeatures.registerDocumentLinkProvider(selector, provider);
			},
			setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
				return languageFeatures.setLanguageConfiguration(language, configuration);
281 282 283 284 285
			},
			// proposed API
			registerColorProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider) => {
				return languageFeatures.registerColorProvider(selector, provider);
			})
286
		};
E
Erich Gamma 已提交
287

288 289 290 291 292 293 294 295
		// namespace: window
		const window: typeof vscode.window = {
			get activeTextEditor() {
				return extHostEditors.getActiveTextEditor();
			},
			get visibleTextEditors() {
				return extHostEditors.getVisibleTextEditors();
			},
J
Johannes Rieken 已提交
296
			showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): TPromise<vscode.TextEditor> {
B
Benjamin Pasero 已提交
297
				let documentPromise: TPromise<vscode.TextDocument>;
J
Johannes Rieken 已提交
298 299
				if (URI.isUri(documentOrUri)) {
					documentPromise = TPromise.wrap(workspace.openTextDocument(documentOrUri));
B
Benjamin Pasero 已提交
300
				} else {
J
Johannes Rieken 已提交
301
					documentPromise = TPromise.wrap(<vscode.TextDocument>documentOrUri);
B
Benjamin Pasero 已提交
302 303 304 305
				}
				return documentPromise.then(document => {
					return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
				});
306 307 308 309
			},
			createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
				return extHostEditors.createTextEditorDecorationType(options);
			},
310 311 312
			onDidChangeActiveTextEditor(listener, thisArg?, disposables?) {
				return extHostEditors.onDidChangeActiveTextEditor(listener, thisArg, disposables);
			},
313 314 315
			onDidChangeVisibleTextEditors(listener, thisArg, disposables) {
				return extHostEditors.onDidChangeVisibleTextEditors(listener, thisArg, disposables);
			},
316
			onDidChangeTextEditorSelection(listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
317 318
				return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables);
			},
319
			onDidChangeTextEditorOptions(listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
320 321 322 323 324
				return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables);
			},
			onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) {
				return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables);
			},
325 326 327
			onDidCloseTerminal(listener, thisArg?, disposables?) {
				return extHostTerminalService.onDidCloseTerminal(listener, thisArg, disposables);
			},
J
Joao Moreno 已提交
328 329
			showInformationMessage(message, first, ...rest) {
				return extHostMessageService.showMessage(Severity.Info, message, first, rest);
330
			},
J
Joao Moreno 已提交
331 332
			showWarningMessage(message, first, ...rest) {
				return extHostMessageService.showMessage(Severity.Warning, message, first, rest);
333
			},
J
Joao Moreno 已提交
334 335
			showErrorMessage(message, first, ...rest) {
				return extHostMessageService.showMessage(Severity.Error, message, first, rest);
336
			},
337
			showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) {
338 339 340 341 342 343
				return extHostQuickOpen.showQuickPick(items, options, token);
			},
			showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
				return extHostQuickOpen.showInput(options, token);
			},
			createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem {
344
				return extHostStatusBar.createStatusBarEntry(extension.id, <number>position, priority);
345 346 347 348
			},
			setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
				return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
			},
349
			withScmProgress<R>(task: (progress: vscode.Progress<number>) => Thenable<R>) {
350
				console.warn(`[Deprecation Warning] function 'withScmProgress' is deprecated and should no longer be used. Use 'withProgress' instead.`);
351
				return extHostProgress.withProgress(extension, { location: extHostTypes.ProgressLocation.SourceControl }, (progress, token) => task({ report(n: number) { /*noop*/ } }));
J
Johannes Rieken 已提交
352 353 354
			},
			withProgress<R>(options: vscode.ProgressOptions, task: (progress: vscode.Progress<{ message?: string; percentage?: number }>) => Thenable<R>) {
				return extHostProgress.withProgress(extension, options, task);
355
			},
356 357 358
			createOutputChannel(name: string): vscode.OutputChannel {
				return extHostOutputService.createOutputChannel(name);
			},
359 360 361 362
			createTerminal(nameOrOptions: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
				if (typeof nameOrOptions === 'object') {
					return extHostTerminalService.createTerminalFromOptions(<vscode.TerminalOptions>nameOrOptions);
				}
D
Daniel Imms 已提交
363
				return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
364
			},
S
Sandeep Somavarapu 已提交
365 366 367
			registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
				return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider);
			},
368 369
			// proposed API
			sampleFunction: proposedApiFunction(extension, () => {
J
Joao Moreno 已提交
370
				return extHostMessageService.showMessage(Severity.Info, 'Hello Proposed Api!', {}, []);
371
			}),
372
		};
E
Erich Gamma 已提交
373

374 375 376
		// namespace: workspace
		const workspace: typeof vscode.workspace = {
			get rootPath() {
377
				apiUsage.publicLog('workspace#rootPath');
378 379 380 381 382
				return extHostWorkspace.getPath();
			},
			set rootPath(value) {
				throw errors.readonly();
			},
383 384
			getWorkspaceFolder(resource) {
				return extHostWorkspace.getWorkspaceFolder(resource);
385
			},
386
			get workspaceFolders() {
387
				apiUsage.publicLog('workspace#workspaceFolders');
388
				return extHostWorkspace.getWorkspaceFolders();
389
			},
390
			onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
391
				apiUsage.publicLog('workspace#onDidChangeWorkspaceFolders');
392
				return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
393
			},
J
Johannes Rieken 已提交
394 395
			asRelativePath: (pathOrUri, includeWorkspace) => {
				return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
			},
			findFiles: (include, exclude, maxResults?, token?) => {
				return extHostWorkspace.findFiles(include, exclude, maxResults, token);
			},
			saveAll: (includeUntitled?) => {
				return extHostWorkspace.saveAll(includeUntitled);
			},
			applyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
				return extHostWorkspace.appyEdit(edit);
			},
			createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
				return extHostFileSystemEvent.createFileSystemWatcher(pattern, ignoreCreate, ignoreChange, ignoreDelete);
			},
			get textDocuments() {
				return extHostDocuments.getAllDocumentData().map(data => data.document);
			},
			set textDocuments(value) {
				throw errors.readonly();
			},
415
			openTextDocument(uriOrFileNameOrOptions?: vscode.Uri | string | { language?: string; content?: string; }) {
B
Benjamin Pasero 已提交
416 417
				let uriPromise: TPromise<URI>;

418
				let options = uriOrFileNameOrOptions as { language?: string; content?: string; };
B
Benjamin Pasero 已提交
419 420 421 422 423 424
				if (!options || typeof options.language === 'string') {
					uriPromise = extHostDocuments.createDocumentData(options);
				} else if (typeof uriOrFileNameOrOptions === 'string') {
					uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions));
				} else if (uriOrFileNameOrOptions instanceof URI) {
					uriPromise = TPromise.as(<URI>uriOrFileNameOrOptions);
425
				} else {
B
Benjamin Pasero 已提交
426
					throw new Error('illegal argument - uriOrFileNameOrOptions');
427
				}
B
Benjamin Pasero 已提交
428 429 430 431 432 433

				return uriPromise.then(uri => {
					return extHostDocuments.ensureDocumentData(uri).then(() => {
						const data = extHostDocuments.getDocumentData(uri);
						return data && data.document;
					});
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
				});
			},
			onDidOpenTextDocument: (listener, thisArgs?, disposables?) => {
				return extHostDocuments.onDidAddDocument(listener, thisArgs, disposables);
			},
			onDidCloseTextDocument: (listener, thisArgs?, disposables?) => {
				return extHostDocuments.onDidRemoveDocument(listener, thisArgs, disposables);
			},
			onDidChangeTextDocument: (listener, thisArgs?, disposables?) => {
				return extHostDocuments.onDidChangeDocument(listener, thisArgs, disposables);
			},
			onDidSaveTextDocument: (listener, thisArgs?, disposables?) => {
				return extHostDocuments.onDidSaveDocument(listener, thisArgs, disposables);
			},
			onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
				return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables);
450
			},
451
			onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
452 453
				return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables);
			},
S
Sandeep Somavarapu 已提交
454 455
			getConfiguration: (section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration => {
				return extHostConfiguration.getConfiguration(section, <URI>resource);
456
			},
457 458 459
			registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) {
				return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider);
			},
460
			registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
461
				return extHostTask.registerTaskProvider(extension, provider);
J
Johannes Rieken 已提交
462 463 464 465
			},
			registerFileSystemProvider: proposedApiFunction(extension, (authority, provider) => {
				return extHostWorkspace.registerFileSystemProvider(authority, provider);
			})
466
		};
467

468 469
		// namespace: scm
		const scm: typeof vscode.scm = {
470 471
			get inputBox() {
				return extHostSCM.inputBox;
472
			},
J
Joao Moreno 已提交
473
			createSourceControl(id: string, label: string) {
474 475
				telemetryService.publicLog('registerSCMProvider', {
					extensionId: extension.id,
J
Joao Moreno 已提交
476 477
					providerId: id,
					providerLabel: label
478 479
				});

J
Joao Moreno 已提交
480
				return extHostSCM.createSourceControl(id, label);
J
Joao Moreno 已提交
481
			}
482
		};
J
Joao Moreno 已提交
483

484 485
		// namespace: debug
		const debug: typeof vscode.debug = {
486 487 488
			get activeDebugSession() {
				return extHostDebugService.activeDebugSession;
			},
489
			startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration) {
490
				return extHostDebugService.startDebugging(folder, nameOrConfig);
491
			},
492 493
			onDidStartDebugSession(listener, thisArg?, disposables?) {
				return extHostDebugService.onDidStartDebugSession(listener, thisArg, disposables);
494 495
			},
			onDidTerminateDebugSession(listener, thisArg?, disposables?) {
496
				return extHostDebugService.onDidTerminateDebugSession(listener, thisArg, disposables);
497
			},
A
Andre Weinand 已提交
498
			onDidChangeActiveDebugSession(listener, thisArg?, disposables?) {
499
				return extHostDebugService.onDidChangeActiveDebugSession(listener, thisArg, disposables);
A
Andre Weinand 已提交
500 501
			},
			onDidReceiveDebugSessionCustomEvent(listener, thisArg?, disposables?) {
A
Andre Weinand 已提交
502
				return extHostDebugService.onDidReceiveDebugSessionCustomEvent(listener, thisArg, disposables);
503 504 505 506
			},
			registerDebugConfigurationProvider: proposedApiFunction(extension, (debugType: string, provider: vscode.DebugConfigurationProvider) => {
				return extHostDebugService.registerDebugConfigurationProvider(debugType, provider);
			}),
507 508
		};

C
Christof Marti 已提交
509 510 511 512 513 514 515 516 517 518 519
		// namespace: credentials
		const credentials: typeof vscode.credentials = {
			readSecret(service: string, account: string): Thenable<string | undefined> {
				return extHostCredentials.readSecret(service, account);
			},
			writeSecret(service: string, account: string, secret: string): Thenable<void> {
				return extHostCredentials.writeSecret(service, account, secret);
			},
			deleteSecret(service: string, account: string): Thenable<boolean> {
				return extHostCredentials.deleteSecret(service, account);
			}
520 521 522
		};


523
		const api: typeof vscode = {
524 525 526 527 528 529 530 531
			version: pkg.version,
			// namespaces
			commands,
			env,
			extensions,
			languages,
			window,
			workspace,
J
Joao Moreno 已提交
532
			scm,
533
			debug,
534
			credentials,
535 536 537
			// types
			CancellationTokenSource: CancellationTokenSource,
			CodeLens: extHostTypes.CodeLens,
538
			Color: extHostTypes.Color,
J
Joao Moreno 已提交
539
			ColorRange: extHostTypes.ColorRange,
540
			EndOfLine: extHostTypes.EndOfLine,
541 542 543
			CompletionItem: extHostTypes.CompletionItem,
			CompletionItemKind: extHostTypes.CompletionItemKind,
			CompletionList: extHostTypes.CompletionList,
544 545 546 547 548
			Diagnostic: extHostTypes.Diagnostic,
			DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
			Disposable: extHostTypes.Disposable,
			DocumentHighlight: extHostTypes.DocumentHighlight,
			DocumentHighlightKind: extHostTypes.DocumentHighlightKind,
549
			DocumentLink: extHostTypes.DocumentLink,
550 551
			EventEmitter: Emitter,
			Hover: extHostTypes.Hover,
552
			IndentAction: languageConfiguration.IndentAction,
553
			Location: extHostTypes.Location,
554
			OverviewRulerLane: EditorCommon.OverviewRulerLane,
555 556 557 558 559 560 561 562 563 564 565 566
			ParameterInformation: extHostTypes.ParameterInformation,
			Position: extHostTypes.Position,
			Range: extHostTypes.Range,
			Selection: extHostTypes.Selection,
			SignatureHelp: extHostTypes.SignatureHelp,
			SignatureInformation: extHostTypes.SignatureInformation,
			SnippetString: extHostTypes.SnippetString,
			StatusBarAlignment: extHostTypes.StatusBarAlignment,
			SymbolInformation: extHostTypes.SymbolInformation,
			SymbolKind: extHostTypes.SymbolKind,
			TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
			TextEdit: extHostTypes.TextEdit,
567
			TextEditorCursorStyle: TextEditorCursorStyle,
568
			TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle,
569
			TextEditorRevealType: extHostTypes.TextEditorRevealType,
570
			TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind,
571
			DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
572
			Uri: <any>URI,
573 574
			ViewColumn: extHostTypes.ViewColumn,
			WorkspaceEdit: extHostTypes.WorkspaceEdit,
J
Johannes Rieken 已提交
575
			ProgressLocation: extHostTypes.ProgressLocation,
S
Sandeep Somavarapu 已提交
576
			TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
S
Sandeep Somavarapu 已提交
577
			TreeItem: extHostTypes.TreeItem,
578
			ThemeColor: extHostTypes.ThemeColor,
J
Joao Moreno 已提交
579
			// functions
580
			TaskRevealKind: extHostTypes.TaskRevealKind,
581
			TaskPanelKind: extHostTypes.TaskPanelKind,
582
			TaskGroup: extHostTypes.TaskGroup,
D
Dirk Baeumer 已提交
583 584
			ProcessExecution: extHostTypes.ProcessExecution,
			ShellExecution: extHostTypes.ShellExecution,
S
Sandeep Somavarapu 已提交
585 586
			Task: extHostTypes.Task,
			ConfigurationTarget: extHostTypes.ConfigurationTarget
587
		};
588 589 590 591
		if (!extension.enableProposedApi) {
			delete api.credentials; // Instead of error to avoid #31854
		}
		return api;
592
	};
E
Erich Gamma 已提交
593 594 595 596
}

class Extension<T> implements vscode.Extension<T> {

A
Alex Dima 已提交
597
	private _extensionService: ExtHostExtensionService;
E
Erich Gamma 已提交
598 599 600 601 602

	public id: string;
	public extensionPath: string;
	public packageJSON: any;

J
Johannes Rieken 已提交
603
	constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription) {
A
Alex Dima 已提交
604
		this._extensionService = extensionService;
E
Erich Gamma 已提交
605 606 607 608 609 610
		this.id = description.id;
		this.extensionPath = paths.normalize(description.extensionFolderPath, true);
		this.packageJSON = description;
	}

	get isActive(): boolean {
A
Alex Dima 已提交
611
		return this._extensionService.isActivated(this.id);
E
Erich Gamma 已提交
612 613 614
	}

	get exports(): T {
A
Alex Dima 已提交
615
		return <T>this._extensionService.getExtensionExports(this.id);
E
Erich Gamma 已提交
616 617 618
	}

	activate(): Thenable<T> {
A
Alex Dima 已提交
619
		return this._extensionService.activateById(this.id).then(() => this.exports);
E
Erich Gamma 已提交
620 621 622
	}
}

J
Johannes Rieken 已提交
623 624 625
export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory): TPromise<void> {
	return createExtensionPathIndex(extensionService).then(trie => defineAPI(apiFactory, trie));
}
626

J
Johannes Rieken 已提交
627
function createExtensionPathIndex(extensionService: ExtHostExtensionService): TPromise<TrieMap<IExtensionDescription>> {
628 629

	// create trie to enable fast 'filename -> extension id' look up
630
	const trie = new TrieMap<IExtensionDescription>();
J
Johannes Rieken 已提交
631 632
	const extensions = extensionService.getAllExtensionDescriptions().map(ext => {
		if (!ext.main) {
633
			return undefined;
634
		}
J
Johannes Rieken 已提交
635 636 637 638 639
		return new TPromise((resolve, reject) => {
			realpath(ext.extensionFolderPath, (err, path) => {
				if (err) {
					reject(err);
				} else {
J
Johannes Rieken 已提交
640
					trie.insert(path, ext);
J
Johannes Rieken 已提交
641 642 643 644 645 646 647 648 649 650 651 652
					resolve(void 0);
				}
			});
		});
	});

	return TPromise.join(extensions).then(() => trie);
}

function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap<IExtensionDescription>): void {

	// each extension is meant to get its own api implementation
J
Johannes Rieken 已提交
653
	const extApiImpl = new Map<string, typeof vscode>();
J
Johannes Rieken 已提交
654
	let defaultApiImpl: typeof vscode;
655 656 657

	const node_module = <any>require.__$__nodeRequire('module');
	const original = node_module._load;
E
Erich Gamma 已提交
658
	node_module._load = function load(request, parent, isMain) {
659 660 661 662 663
		if (request !== 'vscode') {
			return original.apply(this, arguments);
		}

		// get extension id from filename and api for extension
J
Johannes Rieken 已提交
664
		const ext = extensionPaths.findSubstr(parent.filename);
665
		if (ext) {
J
Johannes Rieken 已提交
666
			let apiImpl = extApiImpl.get(ext.id);
667
			if (!apiImpl) {
J
Johannes Rieken 已提交
668 669
				apiImpl = factory(ext);
				extApiImpl.set(ext.id, apiImpl);
670 671 672 673 674 675
			}
			return apiImpl;
		}

		// fall back to a default implementation
		if (!defaultApiImpl) {
676
			defaultApiImpl = factory(nullExtensionDescription);
E
Erich Gamma 已提交
677
		}
678
		return defaultApiImpl;
E
Erich Gamma 已提交
679 680
	};
}
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695

const nullExtensionDescription: IExtensionDescription = {
	id: 'nullExtensionDescription',
	name: 'Null Extension Description',
	publisher: 'vscode',
	activationEvents: undefined,
	contributes: undefined,
	enableProposedApi: false,
	engines: undefined,
	extensionDependencies: undefined,
	extensionFolderPath: undefined,
	isBuiltin: false,
	main: undefined,
	version: undefined
};