diff --git a/src/vs/workbench/api/browser/pluginHost.api.impl.ts b/src/vs/workbench/api/browser/pluginHost.api.impl.ts index 3364186808d..a7556ab7512 100644 --- a/src/vs/workbench/api/browser/pluginHost.api.impl.ts +++ b/src/vs/workbench/api/browser/pluginHost.api.impl.ts @@ -22,6 +22,7 @@ import {PluginHostMessageService} from 'vs/workbench/api/common/pluginHostMessag import {PluginHostTelemetryService} from 'vs/workbench/api/common/pluginHostTelemetry'; import {PluginHostEditors} from 'vs/workbench/api/common/pluginHostEditors'; import {ExtHostLanguages} from 'vs/workbench/api/common/extHostLanguages'; +import {ExtHostLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures'; import * as extHostTypes from 'vs/workbench/api/common/pluginHostTypes'; import 'vs/workbench/api/common/pluginHostTypes.marshalling'; import {wrapAsWinJSPromise} from 'vs/base/common/async'; @@ -251,6 +252,7 @@ export class PluginHostAPIImplementation { const languages = new ExtHostLanguages(this._threadService); const pluginHostDiagnostics = new PluginHostDiagnostics(this._threadService); const features = LanguageFeatures.createExtensionHostInstances(this._threadService); + const languageFeatures = threadService.getRemotable(ExtHostLanguageFeatures); this.languages = { createDiagnosticCollection(name?: string): vscode.DiagnosticCollection { @@ -284,7 +286,7 @@ export class PluginHostAPIImplementation { return features.rename.register(selector, provider); }, registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable { - return features.documentSymbols.register(selector, provider); + return languageFeatures.registerDocumentSymbolProvider(selector, provider); }, registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { return features.workspaceSymbols.register(provider); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts new file mode 100644 index 00000000000..d99e870d0e5 --- /dev/null +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -0,0 +1,160 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import Event, {Emitter} from 'vs/base/common/event'; +import Severity from 'vs/base/common/severity'; +import {TPromise} from 'vs/base/common/winjs.base'; +import {sequence} from 'vs/base/common/async'; +import {Range as EditorRange} from 'vs/editor/common/core/range'; +import {IDisposable} from 'vs/base/common/lifecycle'; +import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService'; +import {Remotable, IThreadService} from 'vs/platform/thread/common/thread'; +import * as vscode from 'vscode'; +import * as TypeConverters from 'vs/workbench/api/common/pluginHostTypeConverters'; +import {Position, Range, SymbolKind, DocumentHighlightKind, Disposable, Diagnostic, DiagnosticSeverity, Location, SignatureHelp, CompletionItemKind} from 'vs/workbench/api/common/pluginHostTypes'; +import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon'; +import * as modes from 'vs/editor/common/modes'; +import {CancellationTokenSource} from 'vs/base/common/cancellation'; +import {PluginHostModelService} from 'vs/workbench/api/common/pluginHostDocuments'; +import {IMarkerService, IMarker} from 'vs/platform/markers/common/markers'; +import {PluginHostCommands, MainThreadCommands} from 'vs/workbench/api/common/pluginHostCommands'; +import DeclarationRegistry from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; +import ExtraInfoRegistry from 'vs/editor/contrib/hover/common/hover'; +import DocumentHighlighterRegistry from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; +import ReferenceSearchRegistry from 'vs/editor/contrib/referenceSearch/common/referenceSearch'; +import QuickFixRegistry from 'vs/editor/contrib/quickFix/common/quickFix'; +import {OutlineRegistry, IOutlineEntry, IOutlineSupport} from 'vs/editor/contrib/quickOpen/common/quickOpen'; +import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry'; +import {NavigateTypesSupportRegistry, INavigateTypesSupport, ITypeBearing} from 'vs/workbench/parts/search/common/search' +import {RenameRegistry} from 'vs/editor/contrib/rename/common/rename'; +import {FormatRegistry, FormatOnTypeRegistry} from 'vs/editor/contrib/format/common/format'; +import {CodeLensRegistry} from 'vs/editor/contrib/codelens/common/codelens'; +import {ParameterHintsRegistry} from 'vs/editor/contrib/parameterHints/common/parameterHints'; +import {SuggestRegistry} from 'vs/editor/contrib/suggest/common/suggest'; + +function isThenable(obj: any): obj is Thenable { + return obj && typeof obj['then'] === 'function'; +} + +function asWinJsPromise(callback: (token: vscode.CancellationToken) => T | Thenable): TPromise { + let source = new CancellationTokenSource(); + return new TPromise((resolve, reject) => { + let item = callback(source.token); + if (isThenable(item)) { + item.then(resolve, reject); + } else { + resolve(item); + } + }, () => { + source.cancel(); + }); +} + +// --- adapter + +class OutlineSupportAdapter implements IOutlineSupport { + + private _documents: PluginHostModelService; + private _provider: vscode.DocumentSymbolProvider; + + constructor(documents: PluginHostModelService, provider: vscode.DocumentSymbolProvider) { + this._documents = documents; + this._provider = provider; + } + + getOutline(resource: URI): TPromise { + let doc = this._documents.getDocument(resource); + return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => { + if (Array.isArray(value)) { + return value.map(OutlineSupportAdapter._convertSymbolInfo); + } + }); + } + + private static _convertSymbolInfo(symbol: vscode.SymbolInformation): IOutlineEntry { + return { + type: TypeConverters.fromSymbolKind(symbol.kind), + range: TypeConverters.fromRange(symbol.location.range), + containerLabel: symbol.containerName, + label: symbol.name, + icon: undefined, + }; + } +} + +type Adapter = OutlineSupportAdapter; + +@Remotable.PluginHostContext('ExtHostLanguageFeatures') +export class ExtHostLanguageFeatures { + + private static _handlePool = 0; + + private _proxy: MainThreadLanguageFeatures; + private _documents: PluginHostModelService; + private _adapter: { [handle: number]: Adapter } = Object.create(null); + + constructor( @IThreadService threadService: IThreadService) { + this._proxy = threadService.getRemotable(MainThreadLanguageFeatures); + this._documents = threadService.getRemotable(PluginHostModelService); + } + + private _createDisposable(handle: number): Disposable { + return new Disposable(() => { + delete this._adapter[handle]; + this._proxy.$unregister(handle); + }); + } + + // --- outline + + registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable { + const handle = ExtHostLanguageFeatures._handlePool++; + this._proxy.$registerOutlineSupport(handle, selector); + this._adapter[handle] = new OutlineSupportAdapter(this._documents, provider); + return this._createDisposable(handle); + } + + $getOutline(handle: number, resource: URI): TPromise{ + let adapter = this._adapter[handle]; + if (adapter instanceof OutlineSupportAdapter) { + return adapter.getOutline(resource); + } + return TPromise.wrapError(new Error('no adapter found')); + } +} + +@Remotable.MainContext('MainThreadLanguageFeatures') +export class MainThreadLanguageFeatures { + + private _proxy: ExtHostLanguageFeatures; + private _disposables: { [handle: number]: IDisposable; } = Object.create(null); + + constructor( @IThreadService threadService: IThreadService) { + this._proxy = threadService.getRemotable(ExtHostLanguageFeatures); + } + + $unregister(handle: number): TPromise { + let d = this._disposables[handle]; + if (d) { + d.dispose(); + delete this._disposables[handle]; + } + return undefined; + } + + // --- outline + + $registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise { + let disposable = OutlineRegistry.register(selector, { + getOutline: (resource: URI): TPromise => { + return this._proxy.$getOutline(handle, resource); + } + }); + this._disposables[handle] = disposable; + return undefined; + } +} \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index cd3566cd7d5..67d448b965c 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -68,6 +68,7 @@ import {MainThreadEditors} from 'vs/workbench/api/common/pluginHostEditors'; import {MainThreadWorkspace} from 'vs/workbench/api/browser/pluginHostWorkspace'; import {MainThreadConfiguration} from 'vs/workbench/api/common/pluginHostConfiguration'; import {LanguageFeatures} from 'vs/workbench/api/common/languageFeatures'; +import {MainThreadLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures'; import {EventService} from 'vs/platform/event/common/eventService'; import {IOptions} from 'vs/workbench/common/options'; import themes = require('vs/platform/theme/common/themes'); @@ -337,6 +338,7 @@ export class WorkbenchShell { this.threadServiceInstance.getRemotable(MainThreadWorkspace); this.threadServiceInstance.getRemotable(MainThreadEditors); this.threadServiceInstance.getRemotable(MainThreadStorage); + this.threadServiceInstance.getRemotable(MainThreadLanguageFeatures); LanguageFeatures.createMainThreadInstances(this.threadServiceInstance); }