diff --git a/src/vs/workbench/api/browser/pluginHost.api.impl.ts b/src/vs/workbench/api/browser/pluginHost.api.impl.ts index a87e5e38be4..e466e1dd0fa 100644 --- a/src/vs/workbench/api/browser/pluginHost.api.impl.ts +++ b/src/vs/workbench/api/browser/pluginHost.api.impl.ts @@ -289,7 +289,7 @@ export class PluginHostAPIImplementation { return languageFeatures.registerDocumentSymbolProvider(selector, provider); }, registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { - return features.workspaceSymbols.register(provider); + return languageFeatures.registerWorkspaceSymbolProvider(provider); }, registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable { return languageFeatures.registerDocumentFormattingEditProvider(selector, provider); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 046d93e0a3c..72618bb2842 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -426,8 +426,36 @@ class OnTypeFormattingAdapter implements modes.IFormattingSupport { } } +class NavigateTypeAdapter implements INavigateTypesSupport { + + private _provider: vscode.WorkspaceSymbolProvider; + + constructor(provider: vscode.WorkspaceSymbolProvider) { + this._provider = provider; + } + + getNavigateToItems(search: string): TPromise { + return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => { + if (Array.isArray(value)) { + return value.map(NavigateTypeAdapter._fromSymbolInformation); + } + }); + } + + private static _fromSymbolInformation(info: vscode.SymbolInformation): ITypeBearing { + return { + name: info.name, + type: SymbolKind[info.kind || SymbolKind.Property].toLowerCase(), + range: TypeConverters.fromRange(info.location.range), + resourceUri: info.location.uri, + containerName: info.containerName, + parameters: '', + }; + } +} + type Adapter = OutlineAdapter | CodeLensAdapter | DeclarationAdapter | ExtraInfoAdapter | OccurrencesAdapter | ReferenceAdapter | QuickFixAdapter - | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter; + | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter; @Remotable.PluginHostContext('ExtHostLanguageFeatures') export class ExtHostLanguageFeatures { @@ -598,6 +626,18 @@ export class ExtHostLanguageFeatures { return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.formatAfterKeystroke(resource, position, ch, options)); } + // --- navigate types + + registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { + const handle = this._nextHandle(); + this._adapter[handle] = new NavigateTypeAdapter(provider); + this._proxy.$registerNavigateTypeSupport(handle); + return this._createDisposable(handle); + } + + $getNavigateToItems(handle: number, search: string): TPromise { + return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.getNavigateToItems(search)); + } } @Remotable.MainContext('MainThreadLanguageFeatures') @@ -747,4 +787,15 @@ export class MainThreadLanguageFeatures { }); return undefined; } + + // --- navigate type + + $registerNavigateTypeSupport(handle: number): TPromise { + this._registrations[handle] = NavigateTypesSupportRegistry.register({ + getNavigateToItems: (search: string): TPromise => { + return this._proxy.$getNavigateToItems(handle, search); + } + }); + return undefined; + } } \ No newline at end of file diff --git a/src/vs/workbench/api/common/languageFeatures.ts b/src/vs/workbench/api/common/languageFeatures.ts index bd81407d0ec..0d4b5744de0 100644 --- a/src/vs/workbench/api/common/languageFeatures.ts +++ b/src/vs/workbench/api/common/languageFeatures.ts @@ -625,124 +625,17 @@ export class MainThreadCompletions extends AbstractMainThreadFeature { - let idx = this._provider.indexOf(provider); - if (idx >= 0) { - this._provider.splice(idx, 1); - if (this._provider.length === 0) { - this._proxy._enable(false); - } - } - }); - } - - private _runAsCommand(query: string): TPromise { - - if (typeof query !== 'string') { - return TPromise.wrapError('query is not string'); - } - - let symbols: vscode.SymbolInformation[] = []; - let promises = this._provider.map(provider => { - return asWinJsPromise(token => { - return provider.provideWorkspaceSymbols(query, token) - }).then(value => { - if (Array.isArray(value)) { - symbols.push(...value); - } - }, err => { - console.error(err); - }); - }); - - return TPromise.join(promises).then(() => { - return symbols.map(ExtensionHostWorkspaceSymbols._fromSymbolInformation); - }); - } - - private static _fromSymbolInformation(info: vscode.SymbolInformation): ITypeBearing { - return { - name: info.name, - type: SymbolKind[info.kind || SymbolKind.Property].toLowerCase(), - range: TypeConverters.fromRange(info.location.range), - resourceUri: info.location.uri, - containerName: info.containerName, - parameters: '', - }; - } -} - -@Remotable.MainContext('MainThreadWorkspaceSymbols') -export class MainThreadWorkspaceSymbols implements INavigateTypesSupport { - - static CommandId = 'vscode.executeWorkspaceSymbolProvider'; - - private _commands: PluginHostCommands; - private _disposable: IDisposable; - - constructor(@IThreadService threadService: IThreadService) { - this._commands = threadService.getRemotable(PluginHostCommands); - } - - _enable(value: boolean): void { - if (value) { - this._disposable = NavigateTypesSupportRegistry.register(this); - } else if (this._disposable) { - this._disposable.dispose(); - this._disposable = undefined; - } - } - - getNavigateToItems(search: string): TPromise { - let value = this._commands.executeCommand(MainThreadWorkspaceSymbols.CommandId, search); - return TPromise.as(value); - } -} - export namespace LanguageFeatures { export function createMainThreadInstances(threadService: IThreadService): void { - threadService.getRemotable(MainThreadWorkspaceSymbols); threadService.getRemotable(MainThreadRename); - threadService.getRemotable(MainThreadFormatDocument); - threadService.getRemotable(MainThreadFormatRange); - threadService.getRemotable(MainThreadFormatOnType); threadService.getRemotable(MainThreadSignatureHelp); threadService.getRemotable(MainThreadCompletions); } export function createExtensionHostInstances(threadService: IThreadService) { return { - workspaceSymbols: new ExtensionHostWorkspaceSymbols(threadService), rename: new ExtensionHostRename(threadService), - formatDocument: new ExtHostFormatDocument(threadService), - formatRange: new ExtHostFormatRange(threadService), - formatOnType: new ExtHostFormatOnType(threadService), signatureHelp: new ExtHostSignatureHelp(threadService), completions: threadService.getRemotable(ExtHostCompletions) }; diff --git a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts index 9ba6d686ae4..ce269924a21 100644 --- a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts @@ -23,7 +23,7 @@ import {IWorkbenchEditorService, IFileInput} from 'vs/workbench/services/editor/ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IModeService} from 'vs/editor/common/services/modeService'; -import {NavigateTypesSupportRegistry, ITypeBearing} from '../common/search'; +import {NavigateTypesSupportRegistry, ITypeBearing, getNavigateToItems} from '../common/search'; class SymbolEntry extends EditorQuickOpenEntry { private name: string; @@ -135,21 +135,7 @@ export class OpenSymbolHandler extends QuickOpenHandler { private doGetResults(searchValue: string): TPromise { - let registry = Registry.as(Extensions.EditorModes); - - // Find Types (and ignore error) - let bearings: ITypeBearing[] = []; - let promises = NavigateTypesSupportRegistry.getAll().map(support => { - return support.getNavigateToItems(searchValue).then(result => { - if (Array.isArray(result)) { - bearings.push(...result); - } - }, err => { - errors.onUnexpectedError(err); - }); - }); - - return TPromise.join(promises).then(() => { + return getNavigateToItems(searchValue).then(bearings => { return this.toQuickOpenEntries(bearings, searchValue); }); } diff --git a/src/vs/workbench/parts/search/common/search.ts b/src/vs/workbench/parts/search/common/search.ts index 92013490687..b62874ccf73 100644 --- a/src/vs/workbench/parts/search/common/search.ts +++ b/src/vs/workbench/parts/search/common/search.ts @@ -6,6 +6,7 @@ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; +import {onUnexpectedError} from 'vs/base/common/errors'; import {IDisposable} from 'vs/base/common/lifecycle'; import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry'; import {IRange} from 'vs/editor/common/editorCommon'; @@ -51,11 +52,24 @@ export namespace NavigateTypesSupportRegistry { } } - // export function has(): boolean { - // return _supports.length > 0; - // } - - export function getAll(): INavigateTypesSupport[] { + export function all(): INavigateTypesSupport[] { return _supports.slice(0); } } + +export function getNavigateToItems(query: string): TPromise { + + const promises = NavigateTypesSupportRegistry.all().map(support => { + return support.getNavigateToItems(query).then(value => value, onUnexpectedError); + }); + + return TPromise.join(promises).then(all => { + const result: ITypeBearing[] = []; + for (let bearings of all) { + if (Array.isArray(bearings)) { + result.push(...bearings); + } + } + return result; + }); +} \ No newline at end of file diff --git a/src/vs/workbench/test/common/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/common/api/extHostLanguageFeatures.test.ts index 997e30d7bfa..079bae46d01 100644 --- a/src/vs/workbench/test/common/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/common/api/extHostLanguageFeatures.test.ts @@ -33,6 +33,7 @@ import {ExtraInfoRegistry, getExtraInfoAtPosition} from 'vs/editor/contrib/hover import {OccurrencesRegistry, getOccurrencesAtPosition} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter'; import {ReferenceRegistry, findReferences} from 'vs/editor/contrib/referenceSearch/common/referenceSearch'; import {getQuickFixes} from 'vs/editor/contrib/quickFix/common/quickFix'; +import {getNavigateToItems} from 'vs/workbench/parts/search/common/search'; const defaultSelector = { scheme: 'far' }; const model: EditorCommon.IModel = new EditorModel( @@ -681,4 +682,29 @@ suite('ExtHostLanguageFeatures', function() { }); }); }); + + // --- navigate types + + test('Navigate types, evil provider', function(done) { + + disposables.push(extHost.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols(): any { + throw new Error('evil'); + } + })); + + disposables.push(extHost.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols(): any { + return [new types.SymbolInformation('testing', types.SymbolKind.Array, new types.Range(0, 0, 1, 1))] + } + })); + + threadService.sync().then(() => { + + getNavigateToItems('').then(value => { + assert.equal(value.length, 1); + done(); + }); + }); + }) }); \ No newline at end of file