add resolveWorkspaceSymbol method and wire it up, not yet exposed in the API

This commit is contained in:
Johannes Rieken 2016-08-02 16:15:15 +02:00
parent 36a2a04f86
commit e62cfe9734
8 changed files with 119 additions and 76 deletions

View file

@ -28,7 +28,7 @@ import * as modes from 'vs/editor/common/modes';
import {IResourceEdit} from 'vs/editor/common/services/bulkEdit';
import {IPickOpenEntry, IPickOptions} from 'vs/workbench/services/quickopen/common/quickOpenService';
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';
import {IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
import {TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent} from './mainThreadEditorsTracker';
import {EndOfLine} from './extHostTypes';
@ -263,7 +263,8 @@ export abstract class ExtHostLanguageFeaturesShape {
$provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]> { throw ni(); }
$provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: editorCommon.IRange, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]> { throw ni(); }
$provideOnTypeFormattingEdits(handle: number, resource: URI, position: editorCommon.IPosition, ch: string, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]> { throw ni(); }
$getNavigateToItems(handle: number, search: string): TPromise<ITypeBearing[]> { throw ni(); }
$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbol[]> { throw ni(); }
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> { throw ni(); }
$provideRenameEdits(handle: number, resource: URI, position: editorCommon.IPosition, newName: string): TPromise<modes.WorkspaceEdit> { throw ni(); }
$provideCompletionItems(handle: number, resource: URI, position: editorCommon.IPosition): TPromise<modes.ISuggestResult[]> { throw ni(); }
$resolveCompletionItem(handle: number, resource: URI, position: editorCommon.IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> { throw ni(); }

View file

@ -16,7 +16,7 @@ import {ICommandHandlerDescription} from 'vs/platform/commands/common/commands';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {IQuickFix2} from 'vs/editor/contrib/quickFix/common/quickFix';
import {IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';
import {IWorkspaceSymbolProvider, IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
import {ICodeLensData} from 'vs/editor/contrib/codelens/common/codelens';
export function registerApiCommands(commands:ExtHostCommands) {
@ -240,10 +240,14 @@ class ExtHostApiCommands {
* @return A promise that resolves to an array of symbol information.
*/
private _executeWorkspaceSymbolProvider(query: string): Thenable<types.SymbolInformation[]> {
return this._commands.executeCommand<ITypeBearing[]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
return this._commands.executeCommand<[IWorkspaceSymbolProvider, IWorkspaceSymbol[]][]>('_executeWorkspaceSymbolProvider', { query }).then(value => {
const result: types.SymbolInformation[] = [];
if (Array.isArray(value)) {
return value.map(typeConverters.toSymbolInformation);
for (const tuple of value) {
result.push(...tuple[1].map(typeConverters.toSymbolInformation));
}
}
return result;
});
}

View file

@ -16,7 +16,7 @@ import * as modes from 'vs/editor/common/modes';
import {ExtHostDocuments} from 'vs/workbench/api/node/extHostDocuments';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
import {INavigateTypesSupport, ITypeBearing} from 'vs/workbench/parts/search/common/search';
import {IWorkspaceSymbolProvider, IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
import {asWinJsPromise, ShallowCancelThenPromise} from 'vs/base/common/async';
import {MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape} from './extHost.protocol';
import {regExpLeadsToEndlessLoop} from 'vs/base/common/strings';
@ -394,7 +394,7 @@ class OnTypeFormattingAdapter {
}
}
class NavigateTypeAdapter implements INavigateTypesSupport {
class NavigateTypeAdapter implements IWorkspaceSymbolProvider {
private _provider: vscode.WorkspaceSymbolProvider;
@ -402,13 +402,17 @@ class NavigateTypeAdapter implements INavigateTypesSupport {
this._provider = provider;
}
getNavigateToItems(search: string): TPromise<ITypeBearing[]> {
provideWorkspaceSymbols(search: string): TPromise<IWorkspaceSymbol[]> {
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (Array.isArray(value)) {
return value.map(TypeConverters.fromSymbolInformation);
}
});
}
resolveWorkspaceSymbol(item: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
return TPromise.as(item);
}
}
class RenameAdapter {
@ -795,8 +799,12 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}
$getNavigateToItems(handle: number, search: string): TPromise<ITypeBearing[]> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.getNavigateToItems(search));
$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbol[]> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
}
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
}
// --- rename

View file

@ -12,7 +12,7 @@ import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import {Position as EditorPosition} from 'vs/platform/editor/common/editor';
import {IPosition, ISelection, IRange, IDecorationOptions, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';
import {IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
@ -190,22 +190,21 @@ export namespace SymbolInformation {
}
}
export function fromSymbolInformation(info: vscode.SymbolInformation): ITypeBearing {
return <ITypeBearing>{
export function fromSymbolInformation(info: vscode.SymbolInformation): IWorkspaceSymbol {
return <IWorkspaceSymbol>{
name: info.name,
type: types.SymbolKind[info.kind || types.SymbolKind.Property].toLowerCase(),
range: fromRange(info.location.range),
resourceUri: info.location.uri,
containerName: info.containerName,
parameters: '',
resource: info.location.uri,
containerName: info.containerName
};
}
export function toSymbolInformation(bearing: ITypeBearing): types.SymbolInformation {
export function toSymbolInformation(bearing: IWorkspaceSymbol): types.SymbolInformation {
return new types.SymbolInformation(bearing.name,
types.SymbolKind[bearing.type.charAt(0).toUpperCase() + bearing.type.substr(1)],
toRange(bearing.range),
bearing.resourceUri,
bearing.resource,
bearing.containerName);
}

View file

@ -10,7 +10,7 @@ import {IThreadService} from 'vs/workbench/services/thread/common/threadService'
import * as vscode from 'vscode';
import {IReadOnlyModel, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {NavigateTypesSupportRegistry, INavigateTypesSupport, ITypeBearing} from 'vs/workbench/parts/search/common/search';
import {WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider, IWorkspaceSymbol} from 'vs/workbench/parts/search/common/search';
import {wireCancellationToken} from 'vs/base/common/async';
import {CancellationToken} from 'vs/base/common/cancellation';
import {Position as EditorPosition} from 'vs/editor/common/core/position';
@ -152,9 +152,12 @@ export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape
// --- navigate type
$registerNavigateTypeSupport(handle: number): TPromise<any> {
this._registrations[handle] = NavigateTypesSupportRegistry.register(<INavigateTypesSupport>{
getNavigateToItems: (search: string): TPromise<ITypeBearing[]> => {
return this._proxy.$getNavigateToItems(handle, search);
this._registrations[handle] = WorkspaceSymbolProviderRegistry.register(<IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search);
},
resolveWorkspaceSymbol: (item: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item);
}
});
return undefined;

View file

@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TPromise} from 'vs/base/common/winjs.base';
import nls = require('vs/nls');
import URI from 'vs/base/common/uri';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {ThrottledDelayer} from 'vs/base/common/async';
import {QuickOpenHandler, EditorQuickOpenEntry} from 'vs/workbench/browser/quickopen';
import {QuickOpenModel, QuickOpenEntry} from 'vs/base/parts/quickopen/browser/quickOpenModel';
import {IAutoFocus/*, Mode, IEntryRunContext*/} from 'vs/base/parts/quickopen/common/quickOpen';
import {IAutoFocus, Mode, IEntryRunContext} from 'vs/base/parts/quickopen/common/quickOpen';
import filters = require('vs/base/common/filters');
import {Range} from 'vs/editor/common/core/range';
import {EditorInput, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor';
@ -18,18 +20,19 @@ import {IResourceInput} from 'vs/platform/editor/common/editor';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
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 {IConfigurationService} from 'vs/platform/configuration/common/configuration';
import {ITypeBearing, INavigateTypesSupport, getNavigateToItems} from 'vs/workbench/parts/search/common/search';
import {IWorkspaceSymbol, IWorkspaceSymbolProvider, getWorkspaceSymbols} from 'vs/workbench/parts/search/common/search';
class SymbolEntry extends EditorQuickOpenEntry {
private _bearingResolve: TPromise<this>;
constructor(
private _bearing: ITypeBearing,
private _provider: INavigateTypesSupport,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
private _bearing: IWorkspaceSymbol,
private _provider: IWorkspaceSymbolProvider,
@IConfigurationService private _configurationService: IConfigurationService,
@IWorkspaceContextService private _contextService: IWorkspaceContextService
@IWorkspaceContextService private _contextService: IWorkspaceContextService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService
) {
super(editorService);
}
@ -45,7 +48,7 @@ class SymbolEntry extends EditorQuickOpenEntry {
public getDescription(): string {
let result = this._bearing.containerName;
if (!result) {
result = labels.getPathLabel(this._bearing.resourceUri, this._contextService);
result = labels.getPathLabel(this._bearing.resource, this._contextService);
}
return result;
}
@ -54,9 +57,34 @@ class SymbolEntry extends EditorQuickOpenEntry {
return this._bearing.type;
}
public getResource(): URI {
return this._bearing.resource;
}
public run(mode: Mode, context: IEntryRunContext): boolean {
// resolve this type bearing if neccessary
if (!this._bearingResolve
&& typeof this._provider.resolveWorkspaceSymbol === 'function'
&& !this._bearing.range
) {
this._bearingResolve = this._provider.resolveWorkspaceSymbol(this._bearing).then(result => {
this._bearing = result || this._bearing;
return this;
}, onUnexpectedError);
}
TPromise.as(this._bearingResolve)
.then(_ => super.run(mode, context))
.done(undefined, onUnexpectedError);
return true;
}
public getInput(): IResourceInput | EditorInput {
let input: IResourceInput = {
resource: this._bearing.resourceUri,
resource: this._bearing.resource,
options: {
pinned: !this._configurationService.getConfiguration<IWorkbenchEditorConfiguration>().workbench.editor.enablePreviewFromQuickOpen
}
@ -97,12 +125,7 @@ export class OpenSymbolHandler extends QuickOpenHandler {
private delayer: ThrottledDelayer<QuickOpenEntry[]>;
private options: IOpenSymbolOptions;
constructor(
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IModeService private modeService: IModeService,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
) {
constructor(@IInstantiationService private instantiationService: IInstantiationService) {
super();
this.delayer = new ThrottledDelayer<QuickOpenEntry[]>(OpenSymbolHandler.SEARCH_DELAY);
@ -135,13 +158,24 @@ export class OpenSymbolHandler extends QuickOpenHandler {
}
private doGetResults(searchValue: string): TPromise<SymbolEntry[]> {
return getNavigateToItems(searchValue).then(bearings => {
return this.toQuickOpenEntries(bearings, searchValue);
return getWorkspaceSymbols(searchValue).then(tuples => {
const result: SymbolEntry[] = [];
for (const tuple of tuples) {
const [provider, bearings] = tuple;
this.fillInSymbolEntries(result, provider, bearings, searchValue);
}
// Sort (Standalone only)
if (!this.options.skipSorting) {
searchValue = searchValue.toLowerCase();
return result.sort((a, b) => SymbolEntry.compare(a, b, searchValue));
} else {
return result;
}
});
}
private toQuickOpenEntries(types: ITypeBearing[], searchValue: string): SymbolEntry[] {
const results: SymbolEntry[] = [];
private fillInSymbolEntries(bucket: SymbolEntry[], provider: IWorkspaceSymbolProvider, types: IWorkspaceSymbol[], searchValue: string): void {
// Convert to Entries
for (const element of types) {
@ -150,18 +184,10 @@ export class OpenSymbolHandler extends QuickOpenHandler {
continue; // ignore local symbols if we are told so
}
const entry = this.instantiationService.createInstance(SymbolEntry, element, undefined);
const entry = this.instantiationService.createInstance(SymbolEntry, element, provider);
entry.setHighlights(filters.matchesFuzzy(searchValue, entry.getLabel()));
results.push(entry);
bucket.push(entry);
}
// Sort (Standalone only)
if (!this.options.skipSorting) {
searchValue = searchValue.toLowerCase();
return results.sort((a, b) => SymbolEntry.compare(a, b, searchValue));
}
return results;
}
public getGroupLabel(): string {

View file

@ -15,24 +15,24 @@ import URI from 'vs/base/common/uri';
/**
* Interface used to navigate to types by value.
*/
export interface ITypeBearing {
containerName: string;
export interface IWorkspaceSymbol {
name: string;
parameters: string;
type: string;
containerName: string;
range: IRange;
resourceUri: URI;
resource: URI;
}
export interface INavigateTypesSupport {
getNavigateToItems: (search: string) => TPromise<ITypeBearing[]>;
export interface IWorkspaceSymbolProvider {
provideWorkspaceSymbols(search: string): TPromise<IWorkspaceSymbol[]>;
resolveWorkspaceSymbol?: (item: IWorkspaceSymbol) => TPromise<IWorkspaceSymbol>;
}
export namespace NavigateTypesSupportRegistry {
export namespace WorkspaceSymbolProviderRegistry {
const _supports: INavigateTypesSupport[] = [];
const _supports: IWorkspaceSymbolProvider[] = [];
export function register(support: INavigateTypesSupport): IDisposable {
export function register(support: IWorkspaceSymbolProvider): IDisposable {
if (support) {
_supports.push(support);
@ -51,26 +51,24 @@ export namespace NavigateTypesSupportRegistry {
};
}
export function all(): INavigateTypesSupport[] {
export function all(): IWorkspaceSymbolProvider[] {
return _supports.slice(0);
}
}
export function getNavigateToItems(query: string): TPromise<ITypeBearing[]> {
export function getWorkspaceSymbols(query: string): TPromise<[IWorkspaceSymbolProvider, IWorkspaceSymbol[]][]> {
const promises = NavigateTypesSupportRegistry.all().map(support => {
return support.getNavigateToItems(query).then(value => value, onUnexpectedError);
});
const result: [IWorkspaceSymbolProvider, IWorkspaceSymbol[]][] = [];
return TPromise.join(promises).then(all => {
const result: ITypeBearing[] = [];
for (let bearings of all) {
if (Array.isArray(bearings)) {
result.push(...bearings);
const promises = WorkspaceSymbolProviderRegistry.all().map(support => {
return support.provideWorkspaceSymbols(query).then(value => {
if (Array.isArray(value)) {
result.push([support, value]);
}
}
return result;
}, onUnexpectedError);
});
return TPromise.join(promises).then(_ => result);
}
CommonEditorRegistry.registerLanguageCommand('_executeWorkspaceSymbolProvider', function (accessor, args: { query: string; }) {
@ -78,5 +76,5 @@ CommonEditorRegistry.registerLanguageCommand('_executeWorkspaceSymbolProvider',
if (typeof query !== 'string') {
throw illegalArgument();
}
return getNavigateToItems(query);
return getWorkspaceSymbols(query);
});

View file

@ -30,7 +30,7 @@ import {getHover} from 'vs/editor/contrib/hover/common/hover';
import {getOccurrencesAtPosition} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import {provideReferences} from 'vs/editor/contrib/referenceSearch/common/referenceSearch';
import {getCodeActions} from 'vs/editor/contrib/quickFix/common/quickFix';
import {getNavigateToItems} from 'vs/workbench/parts/search/common/search';
import {getWorkspaceSymbols} from 'vs/workbench/parts/search/common/search';
import {rename} from 'vs/editor/contrib/rename/common/rename';
import {provideSignatureHelp} from 'vs/editor/contrib/parameterHints/common/parameterHints';
import {provideSuggestionItems} from 'vs/editor/contrib/suggest/common/suggest';
@ -649,8 +649,12 @@ suite('ExtHostLanguageFeatures', function() {
return threadService.sync().then(() => {
return getNavigateToItems('').then(value => {
return getWorkspaceSymbols('').then(value => {
assert.equal(value.length, 1);
const [first] = value;
const [, symbols] = first;
assert.equal(symbols.length, 1);
assert.equal(symbols[0].name, 'testing');
});
});
});