diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 757bab38cea..9578af3db6e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -205,9 +205,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- navigate type $registerNavigateTypeSupport(handle: number): TPromise { + let lastResultId: number; this._registrations[handle] = WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string): TPromise => { - return this._heapService.trackRecursive(this._proxy.$provideWorkspaceSymbols(handle, search)); + + return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => { + if (lastResultId !== undefined) { + this._proxy.$releaseWorkspaceSymbols(handle, lastResultId); + } + lastResultId = result._id; + return result.symbols; + }); }, resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise => { return this._proxy.$resolveWorkspaceSymbol(handle, item); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 9d95254ff6a..2346b9d7ebb 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -552,6 +552,21 @@ export interface IExtHostSuggestResult { incomplete?: boolean; } +export interface IdObject { + _id: number; +} + +export namespace IdObject { + let n = 0; + export function mixin(object: T): T & IdObject { + (object)._id = n++; + return object; + } +} + +export type IWorkspaceSymbol = IdObject & modes.SymbolInformation; +export interface IWorkspaceSymbols extends IdObject { symbols: IWorkspaceSymbol[]; }; + export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: URI): TPromise; $provideCodeLenses(handle: number, resource: URI): TPromise; @@ -566,8 +581,9 @@ export interface ExtHostLanguageFeaturesShape { $provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise; $provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise; $provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise; - $provideWorkspaceSymbols(handle: number, search: string): TPromise; - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $provideWorkspaceSymbols(handle: number, search: string): TPromise; + $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise; + $releaseWorkspaceSymbols(handle: number, id: number): void; $provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise; $provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise; $resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise; diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 7718b667dd4..3b5bb8f8b44 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -16,9 +16,8 @@ import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; -import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion } from './extHost.protocol'; +import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion, IWorkspaceSymbols, IWorkspaceSymbol, IdObject } from './extHost.protocol'; import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; @@ -368,45 +367,56 @@ class OnTypeFormattingAdapter { } } +class NavigateTypeAdapter { -class NavigateTypeAdapter implements IWorkspaceSymbolProvider { + private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null); + private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null); + private readonly _provider: vscode.WorkspaceSymbolProvider; - private _provider: vscode.WorkspaceSymbolProvider; - private _heapService: ExtHostHeapService; - - constructor(provider: vscode.WorkspaceSymbolProvider, heapService: ExtHostHeapService) { + constructor(provider: vscode.WorkspaceSymbolProvider) { this._provider = provider; - this._heapService = heapService; } - provideWorkspaceSymbols(search: string): TPromise { - + provideWorkspaceSymbols(search: string): TPromise { + const result: IWorkspaceSymbols = IdObject.mixin({ symbols: [] }); return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => { - if (Array.isArray(value)) { - return value.map(item => { - const id = this._heapService.keep(item); - const result = TypeConverters.fromSymbolInformation(item); - return ObjectIdentifier.mixin(result, id); - }); + if (!isFalsyOrEmpty(value)) { + for (const item of value) { + const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item)); + this._symbolCache[symbol._id] = item; + result.symbols.push(symbol); + } } - return undefined; + }).then(() => { + this._resultCache[result._id] = [result.symbols[0]._id, result.symbols[result.symbols.length - 1]._id]; + return result; }); } - resolveWorkspaceSymbol(item: modes.SymbolInformation): TPromise { + resolveWorkspaceSymbol(symbol: IWorkspaceSymbol): TPromise { if (typeof this._provider.resolveWorkspaceSymbol !== 'function') { - return TPromise.as(item); + return TPromise.as(symbol); } - const symbolInfo = this._heapService.get(ObjectIdentifier.of(item)); - if (symbolInfo) { - return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(symbolInfo, token)).then(value => { - return value && TypeConverters.fromSymbolInformation(value); + const item = this._symbolCache[symbol._id]; + if (item) { + return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => { + return value && mixin(symbol, TypeConverters.fromSymbolInformation(value), true); }); } return undefined; } + + releaseWorkspaceSymbols(id: number): any { + const range = this._resultCache[id]; + if (range) { + for (let [from, to] = range; from <= to; from++) { + delete this._symbolCache[from]; + } + delete this._resultCache[id]; + } + } } class RenameAdapter { @@ -946,19 +956,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new NavigateTypeAdapter(provider, this._heapService)); + this._adapter.set(handle, new NavigateTypeAdapter(provider)); this._proxy.$registerNavigateTypeSupport(handle); return this._createDisposable(handle); } - $provideWorkspaceSymbols(handle: number, search: string): TPromise { + $provideWorkspaceSymbols(handle: number, search: string): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search)); } - $resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise { + $resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise { return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol)); } + $releaseWorkspaceSymbols(handle: number, id: number) { + this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id)); + } + // --- rename registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {