diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index d03fd31da61..ff787b6ee67 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -42,15 +42,19 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as vscode from 'vscode'; import * as paths from 'vs/base/common/paths'; +import { realpathSync } from 'fs'; import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { MainContext, ExtHostContext, InstanceCollection } from './extHost.protocol'; + +export interface IExtensionApiFactory { + (extension: IExtensionDescription): typeof vscode; +} + /** * This method instantiates and returns the extension API surface */ -export function createApiImplementation(threadService: IThreadService, extensionService: ExtHostExtensionService, - contextService: IWorkspaceContextService, - telemetryService: ITelemetryService): typeof vscode { +export function createApiFactory(threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService, telemetryService: ITelemetryService): IExtensionApiFactory { // Addressable instances @@ -88,295 +92,301 @@ export function createApiImplementation(threadService: IThreadService, extension ExtHostTypeConverters.Command.initialize(extHostCommands); registerApiCommands(extHostCommands); - // namespace: commands - const commands: typeof vscode.commands = { - registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { - return extHostCommands.registerCommand(id, command, thisArgs); - }, - registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable { - return extHostCommands.registerCommand(id, (...args: any[]) => { - let activeTextEditor = extHostEditors.getActiveTextEditor(); - if (!activeTextEditor) { - console.warn('Cannot execute ' + id + ' because there is no active text editor.'); - return; - } - - 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) => { - console.warn('An error occured while running command ' + id, err); - }); - }); - }, - executeCommand(id: string, ...args: any[]): Thenable { - return extHostCommands.executeCommand(id, ...args); - }, - getCommands(filterInternal: boolean = false): Thenable { - return extHostCommands.getCommands(filterInternal); - } - }; - - // namespace: env + // TODO@joh,alex - this is lifecycle critical + // fetch and store telemetry info let telemetryInfo: ITelemetryInfo; telemetryService.getTelemetryInfo().then(info => telemetryInfo = info, errors.onUnexpectedError); - const env: typeof vscode.env = Object.freeze({ - get machineId() { return telemetryInfo.machineId; }, - get sessionId() { return telemetryInfo.sessionId; }, - get language() { return Platform.language; }, - get appName() { return product.nameLong; } - }); - // namespace: extensions - const extensions: typeof vscode.extensions = { - getExtension(extensionId: string): Extension { - let desc = ExtensionsRegistry.getExtensionDescription(extensionId); - if (desc) { - return new Extension(extensionService, desc); + return function (extension: IExtensionDescription): typeof vscode { + + // namespace: commands + const commands: typeof vscode.commands = { + registerCommand(id: string, command: (...args: any[]) => T | Thenable, thisArgs?: any): vscode.Disposable { + return extHostCommands.registerCommand(id, command, thisArgs); + }, + registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable { + return extHostCommands.registerCommand(id, (...args: any[]) => { + let activeTextEditor = extHostEditors.getActiveTextEditor(); + if (!activeTextEditor) { + console.warn('Cannot execute ' + id + ' because there is no active text editor.'); + return; + } + + 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) => { + console.warn('An error occured while running command ' + id, err); + }); + }); + }, + executeCommand(id: string, ...args: any[]): Thenable { + return extHostCommands.executeCommand(id, ...args); + }, + getCommands(filterInternal: boolean = false): Thenable { + return extHostCommands.getCommands(filterInternal); } - }, - get all(): Extension[] { - return ExtensionsRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc)); - } - }; + }; - // namespace: languages - const languages: typeof vscode.languages = { - createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { - return extHostDiagnostics.createDiagnosticCollection(name); - }, - getLanguages(): TPromise { - return extHostLanguages.getLanguages(); - }, - match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number { - return score(selector, 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); - }, - 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 { - return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters); - }, - 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); - } - }; + // namespace: env + const env: typeof vscode.env = Object.freeze({ + get machineId() { return telemetryInfo.machineId; }, + get sessionId() { return telemetryInfo.sessionId; }, + get language() { return Platform.language; }, + get appName() { return product.nameLong; } + }); - // namespace: window - const window: typeof vscode.window = { - get activeTextEditor() { - return extHostEditors.getActiveTextEditor(); - }, - get visibleTextEditors() { - return extHostEditors.getVisibleTextEditors(); - }, - showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean): TPromise { - return extHostEditors.showTextDocument(document, column, preserveFocus); - }, - createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType { - return extHostEditors.createTextEditorDecorationType(options); - }, - onDidChangeActiveTextEditor: extHostEditors.onDidChangeActiveTextEditor.bind(extHostEditors), - onDidChangeVisibleTextEditors(listener, thisArg, disposables) { - return extHostEditors.onDidChangeVisibleTextEditors(listener, thisArg, disposables); - }, - onDidChangeTextEditorSelection: (listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { - return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables); - }, - onDidChangeTextEditorOptions: (listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { - return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables); - }, - onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) { - return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables); - }, - onDidCloseTerminal: extHostTerminalService.onDidCloseTerminal.bind(extHostTerminalService), - showInformationMessage: (message, ...items) => { - return extHostMessageService.showMessage(Severity.Info, message, items); - }, - showWarningMessage: (message, ...items) => { - return extHostMessageService.showMessage(Severity.Warning, message, items); - }, - showErrorMessage: (message, ...items) => { - return extHostMessageService.showMessage(Severity.Error, message, items); - }, - showQuickPick: (items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) => { - 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 { - return extHostStatusBar.createStatusBarEntry(position, priority); - }, - setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): vscode.Disposable { - return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable); - }, - createOutputChannel(name: string): vscode.OutputChannel { - return extHostOutputService.createOutputChannel(name); - }, - createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal { - return extHostTerminalService.createTerminal(name, shellPath, shellArgs); - } - }; - - // namespace: workspace - const workspace: typeof vscode.workspace = { - get rootPath() { - return extHostWorkspace.getPath(); - }, - set rootPath(value) { - throw errors.readonly(); - }, - asRelativePath: (pathOrUri) => { - return extHostWorkspace.getRelativePath(pathOrUri); - }, - findFiles: (include, exclude, maxResults?, token?) => { - return extHostWorkspace.findFiles(include, exclude, maxResults, token); - }, - saveAll: (includeUntitled?) => { - return extHostWorkspace.saveAll(includeUntitled); - }, - applyEdit(edit: vscode.WorkspaceEdit): TPromise { - 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(); - }, - openTextDocument(uriOrFileName: vscode.Uri | string) { - let uri: URI; - if (typeof uriOrFileName === 'string') { - uri = URI.file(uriOrFileName); - } else if (uriOrFileName instanceof URI) { - uri = uriOrFileName; - } else { - throw new Error('illegal argument - uriOrFileName'); + // namespace: extensions + const extensions: typeof vscode.extensions = { + getExtension(extensionId: string): Extension { + let desc = ExtensionsRegistry.getExtensionDescription(extensionId); + if (desc) { + return new Extension(extensionService, desc); + } + }, + get all(): Extension[] { + return ExtensionsRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc)); } - return extHostDocuments.ensureDocumentData(uri).then(() => { - const data = extHostDocuments.getDocumentData(uri); - return data && data.document; - }); - }, - registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) { - return extHostDocuments.registerTextDocumentContentProvider(scheme, provider); - }, - 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); - }, - onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { - return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); - }, - getConfiguration: (section?: string): vscode.WorkspaceConfiguration => { - return extHostConfiguration.getConfiguration(section); - } - }; + }; - return { - version: pkg.version, - // namespaces - commands, - env, - extensions, - languages, - window, - workspace, - // types - Uri: URI, - Location: extHostTypes.Location, - Diagnostic: extHostTypes.Diagnostic, - DiagnosticSeverity: extHostTypes.DiagnosticSeverity, - EventEmitter: Emitter, - Disposable: extHostTypes.Disposable, - TextEdit: extHostTypes.TextEdit, - WorkspaceEdit: extHostTypes.WorkspaceEdit, - Position: extHostTypes.Position, - Range: extHostTypes.Range, - Selection: extHostTypes.Selection, - CancellationTokenSource: CancellationTokenSource, - Hover: extHostTypes.Hover, - SymbolKind: extHostTypes.SymbolKind, - SymbolInformation: extHostTypes.SymbolInformation, - DocumentHighlightKind: extHostTypes.DocumentHighlightKind, - DocumentHighlight: extHostTypes.DocumentHighlight, - CodeLens: extHostTypes.CodeLens, - ParameterInformation: extHostTypes.ParameterInformation, - SignatureInformation: extHostTypes.SignatureInformation, - SignatureHelp: extHostTypes.SignatureHelp, - CompletionItem: extHostTypes.CompletionItem, - CompletionItemKind: extHostTypes.CompletionItemKind, - CompletionList: extHostTypes.CompletionList, - DocumentLink: extHostTypes.DocumentLink, - ViewColumn: extHostTypes.ViewColumn, - StatusBarAlignment: extHostTypes.StatusBarAlignment, - IndentAction: Modes.IndentAction, - OverviewRulerLane: EditorCommon.OverviewRulerLane, - TextEditorRevealType: extHostTypes.TextEditorRevealType, - EndOfLine: extHostTypes.EndOfLine, - TextEditorCursorStyle: EditorCommon.TextEditorCursorStyle, - TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle, - TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind, - TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason, + // namespace: languages + const languages: typeof vscode.languages = { + createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { + return extHostDiagnostics.createDiagnosticCollection(name); + }, + getLanguages(): TPromise { + return extHostLanguages.getLanguages(); + }, + match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number { + return score(selector, 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); + }, + 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 { + return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters); + }, + 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); + } + }; + + // namespace: window + const window: typeof vscode.window = { + get activeTextEditor() { + return extHostEditors.getActiveTextEditor(); + }, + get visibleTextEditors() { + return extHostEditors.getVisibleTextEditors(); + }, + showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean): TPromise { + return extHostEditors.showTextDocument(document, column, preserveFocus); + }, + createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType { + return extHostEditors.createTextEditorDecorationType(options); + }, + onDidChangeActiveTextEditor: extHostEditors.onDidChangeActiveTextEditor.bind(extHostEditors), + onDidChangeVisibleTextEditors(listener, thisArg, disposables) { + return extHostEditors.onDidChangeVisibleTextEditors(listener, thisArg, disposables); + }, + onDidChangeTextEditorSelection: (listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { + return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables); + }, + onDidChangeTextEditorOptions: (listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { + return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables); + }, + onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) { + return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables); + }, + onDidCloseTerminal: extHostTerminalService.onDidCloseTerminal.bind(extHostTerminalService), + showInformationMessage: (message, ...items) => { + return extHostMessageService.showMessage(Severity.Info, message, items); + }, + showWarningMessage: (message, ...items) => { + return extHostMessageService.showMessage(Severity.Warning, message, items); + }, + showErrorMessage: (message, ...items) => { + return extHostMessageService.showMessage(Severity.Error, message, items); + }, + showQuickPick: (items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) => { + 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 { + return extHostStatusBar.createStatusBarEntry(position, priority); + }, + setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): vscode.Disposable { + return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable); + }, + createOutputChannel(name: string): vscode.OutputChannel { + return extHostOutputService.createOutputChannel(name); + }, + createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal { + return extHostTerminalService.createTerminal(name, shellPath, shellArgs); + } + }; + + // namespace: workspace + const workspace: typeof vscode.workspace = { + get rootPath() { + return extHostWorkspace.getPath(); + }, + set rootPath(value) { + throw errors.readonly(); + }, + asRelativePath: (pathOrUri) => { + return extHostWorkspace.getRelativePath(pathOrUri); + }, + findFiles: (include, exclude, maxResults?, token?) => { + return extHostWorkspace.findFiles(include, exclude, maxResults, token); + }, + saveAll: (includeUntitled?) => { + return extHostWorkspace.saveAll(includeUntitled); + }, + applyEdit(edit: vscode.WorkspaceEdit): TPromise { + 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(); + }, + openTextDocument(uriOrFileName: vscode.Uri | string) { + let uri: URI; + if (typeof uriOrFileName === 'string') { + uri = URI.file(uriOrFileName); + } else if (uriOrFileName instanceof URI) { + uri = uriOrFileName; + } else { + throw new Error('illegal argument - uriOrFileName'); + } + return extHostDocuments.ensureDocumentData(uri).then(() => { + const data = extHostDocuments.getDocumentData(uri); + return data && data.document; + }); + }, + registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) { + return extHostDocuments.registerTextDocumentContentProvider(scheme, provider); + }, + 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); + }, + onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { + return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); + }, + getConfiguration: (section?: string): vscode.WorkspaceConfiguration => { + return extHostConfiguration.getConfiguration(section); + } + }; + + return { + version: pkg.version, + // namespaces + commands, + env, + extensions, + languages, + window, + workspace, + // types + Uri: URI, + Location: extHostTypes.Location, + Diagnostic: extHostTypes.Diagnostic, + DiagnosticSeverity: extHostTypes.DiagnosticSeverity, + EventEmitter: Emitter, + Disposable: extHostTypes.Disposable, + TextEdit: extHostTypes.TextEdit, + WorkspaceEdit: extHostTypes.WorkspaceEdit, + Position: extHostTypes.Position, + Range: extHostTypes.Range, + Selection: extHostTypes.Selection, + CancellationTokenSource: CancellationTokenSource, + Hover: extHostTypes.Hover, + SymbolKind: extHostTypes.SymbolKind, + SymbolInformation: extHostTypes.SymbolInformation, + DocumentHighlightKind: extHostTypes.DocumentHighlightKind, + DocumentHighlight: extHostTypes.DocumentHighlight, + CodeLens: extHostTypes.CodeLens, + ParameterInformation: extHostTypes.ParameterInformation, + SignatureInformation: extHostTypes.SignatureInformation, + SignatureHelp: extHostTypes.SignatureHelp, + CompletionItem: extHostTypes.CompletionItem, + CompletionItemKind: extHostTypes.CompletionItemKind, + CompletionList: extHostTypes.CompletionList, + DocumentLink: extHostTypes.DocumentLink, + ViewColumn: extHostTypes.ViewColumn, + StatusBarAlignment: extHostTypes.StatusBarAlignment, + IndentAction: Modes.IndentAction, + OverviewRulerLane: EditorCommon.OverviewRulerLane, + TextEditorRevealType: extHostTypes.TextEditorRevealType, + EndOfLine: extHostTypes.EndOfLine, + TextEditorCursorStyle: EditorCommon.TextEditorCursorStyle, + TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle, + TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind, + TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason, + }; }; } @@ -408,14 +418,107 @@ class Extension implements vscode.Extension { } } -export function defineAPI(impl: typeof vscode) { - let node_module = require.__$__nodeRequire('module'); - let original = node_module._load; - node_module._load = function load(request, parent, isMain) { - if (request === 'vscode') { - return impl; +export function defineAPI(factory: IExtensionApiFactory, extensions: IExtensionDescription[]): void { + + // each extension is meant to get its own api implementation + const extApiImpl: { [id: string]: typeof vscode } = Object.create(null); + let defaultApiImpl: typeof vscode; + + // create trie to enable fast 'filename -> extension id' look up + const trie = new TrieMap(); + for (const ext of extensions) { + if (ext.name) { + const path = realpathSync(ext.extensionFolderPath); + trie.insert(path, ext); } - return original.apply(this, arguments); + } + + const node_module = require.__$__nodeRequire('module'); + const original = node_module._load; + node_module._load = function load(request, parent, isMain) { + if (request !== 'vscode') { + return original.apply(this, arguments); + } + + // get extension id from filename and api for extension + const ext = trie.findSubstr(parent.filename); + if (ext) { + let apiImpl = extApiImpl[ext.id]; + if (!apiImpl) { + apiImpl = extApiImpl[ext.id] = factory(ext); + } + return apiImpl; + } + + // fall back to a default implementation + if (!defaultApiImpl) { + defaultApiImpl = factory(undefined); + } + return defaultApiImpl; }; - define('vscode', [], impl); } + +// --- trie'ish datastructure + +interface Node { + element?: E; + children: { [key: string]: Node }; +} + +class TrieMap { + + private static _sep = /[\\/]/; + + private _root: Node = { + children: Object.create(null) + }; + + insert(path: string, element: E): void { + const parts = path.split(TrieMap._sep); + let i = 0; + + // find insertion node + let node = this._root; + for (; i < parts.length; i++) { + let child = node.children[parts[i]]; + if (child) { + node = child; + continue; + } + break; + } + + // create new nodes + let newNode: Node; + for (; i < parts.length; i++) { + newNode = { children: Object.create(null) }; + node.children[parts[i]] = newNode; + node = newNode; + } + + newNode.element = element; + } + + findSubstr(path: string): E { + const parts = path.split(TrieMap._sep); + + let lastNode: Node; + let {children} = this._root; + for (const part of parts) { + const node = children[part]; + if (!node) { + break; + } + if (node.element) { + lastNode = node; + } + children = node.children; + } + + // return the last matching node + // that had an element + if (lastNode) { + return lastNode.element; + } + } +} \ No newline at end of file diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index ea0c04fe6d6..a0044918522 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -13,7 +13,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import paths = require('vs/base/common/paths'); import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; -import { createApiImplementation, defineAPI } from 'vs/workbench/api/node/extHost.api.impl'; +import { createApiFactory, defineAPI } from 'vs/workbench/api/node/extHost.api.impl'; import { IMainProcessExtHostIPC } from 'vs/platform/extensions/common/ipcRemoteCom'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostThreadService } from 'vs/workbench/services/thread/common/extHostThreadService'; @@ -76,7 +76,8 @@ export class ExtensionHostMain { this._extensionService = new ExtHostExtensionService(threadService, telemetryService, { _serviceBrand: 'optionalArgs', workspaceStoragePath }); // Create the ext host API - defineAPI(createApiImplementation(threadService, this._extensionService, this._contextService, telemetryService)); + const factory = createApiFactory(threadService, this._extensionService, this._contextService, telemetryService); + defineAPI(factory, this._extensions); } private _getOrCreateWorkspaceStoragePath(): string {