diff --git a/src/vs/editor/contrib/quickOpen/quickOpen.ts b/src/vs/editor/contrib/quickOpen/quickOpen.ts index 3e940a4ca4a..e22c364bd98 100644 --- a/src/vs/editor/contrib/quickOpen/quickOpen.ts +++ b/src/vs/editor/contrib/quickOpen/quickOpen.ts @@ -14,7 +14,7 @@ import { DocumentSymbol, DocumentSymbolProviderRegistry } from 'vs/editor/common import { IModelService } from 'vs/editor/common/services/modelService'; import { CancellationToken } from 'vs/base/common/cancellation'; -export function getDocumentSymbols(model: ITextModel, token: CancellationToken): Thenable { +export function getDocumentSymbols(model: ITextModel, flat: boolean, token: CancellationToken): Thenable { let roots: DocumentSymbol[] = []; @@ -31,7 +31,11 @@ export function getDocumentSymbols(model: ITextModel, token: CancellationToken): return Promise.all(promises).then(() => { let flatEntries: DocumentSymbol[] = []; - flatten(flatEntries, roots, ''); + if (flat) { + flatten(flatEntries, roots, ''); + } else { + flatEntries = roots; + } flatEntries.sort(compareEntriesUsingStart); return flatEntries; }); @@ -68,5 +72,5 @@ registerLanguageCommand('_executeDocumentSymbolProvider', function (accessor, ar if (!model) { throw illegalArgument('resource'); } - return getDocumentSymbols(model, CancellationToken.None); + return getDocumentSymbols(model, false, CancellationToken.None); }); diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts index e8a19062033..83ec34ab012 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts @@ -141,7 +141,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { } // Resolve outline - return TPromise.wrap(getDocumentSymbols(model, CancellationToken.None).then((result: DocumentSymbol[]) => { + return TPromise.wrap(getDocumentSymbols(model, true, CancellationToken.None).then((result: DocumentSymbol[]) => { if (result.length === 0) { return; } diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index b2228a48908..caafafe8a78 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -112,7 +112,7 @@ export class ExtHostApiCommands { args: [ { name: 'uri', description: 'Uri of a text document', constraint: URI } ], - returns: 'A promise that resolves to an array of SymbolInformation-instances.' + returns: 'A promise that resolves to an array of SymbolInformation and DocumentSymbol instances.' }); this._register('vscode.executeCompletionItemProvider', this._executeCompletionItemProvider, { description: 'Execute completion item provider.', @@ -420,16 +420,27 @@ export class ExtHostApiCommands { if (isFalsyOrEmpty(value)) { return undefined; } - let result: vscode.SymbolInformation[] = []; - for (const symbol of value) { - result.push(new types.SymbolInformation( - symbol.name, - typeConverters.SymbolKind.to(symbol.kind), - symbol.containerName, - new types.Location(resource, typeConverters.Range.to(symbol.range)) - )); + class MergedInfo extends types.SymbolInformation implements vscode.DocumentSymbol { + static to(symbol: modes.DocumentSymbol): MergedInfo { + let res = new MergedInfo( + symbol.name, + typeConverters.SymbolKind.to(symbol.kind), + symbol.containerName, + new types.Location(resource, typeConverters.Range.to(symbol.range)) + ); + res.detail = symbol.detail; + res.range = res.location.range; + res.selectionRange = typeConverters.Range.to(symbol.selectionRange); + res.children = symbol.children && symbol.children.map(MergedInfo.to); + return res; + } + + detail: string; + range: vscode.Range; + selectionRange: vscode.Range; + children: vscode.DocumentSymbol[]; } - return result; + return value.map(MergedInfo.to); }); } diff --git a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts index b13a52e2bb1..75d56ed393e 100644 --- a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts @@ -476,7 +476,7 @@ export class GotoSymbolHandler extends QuickOpenHandler { return TPromise.as(this.outlineToModelCache[modelId]); } - return TPromise.wrap(asThenable(() => getDocumentSymbols(model, token)).then(entries => { + return TPromise.wrap(asThenable(() => getDocumentSymbols(model, true, token)).then(entries => { const model = new OutlineModel(this.toQuickOpenEntries(entries)); this.outlineToModelCache = {}; // Clear cache, only keep 1 outline diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index 26f198c254f..a1be3772424 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -340,6 +340,36 @@ suite('ExtHostLanguageFeatureCommands', function () { }); }); + test('vscode.executeDocumentSymbolProvider command only returns SymbolInformation[] rather than DocumentSymbol[] #57984', function () { + disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, { + provideDocumentSymbols(): any { + return [ + new types.SymbolInformation('SymbolInformation', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)) + ]; + } + })); + disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, { + provideDocumentSymbols(): any { + let root = new types.DocumentSymbol('DocumentSymbol', 'DocumentSymbol#detail', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0)); + root.children = [new types.DocumentSymbol('DocumentSymbol#child', 'DocumentSymbol#detail#child', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0))]; + return [root]; + } + })); + + return rpcProtocol.sync().then(() => { + return commands.executeCommand<(vscode.SymbolInformation & vscode.DocumentSymbol)[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => { + assert.equal(values.length, 2); + let [first, second] = values; + assert.ok(first instanceof types.SymbolInformation); + assert.ok(!(first instanceof types.DocumentSymbol)); + assert.ok(second instanceof types.SymbolInformation); + assert.equal(first.name, 'DocumentSymbol'); + assert.equal(first.children.length, 1); + assert.equal(second.name, 'SymbolInformation'); + }); + }); + }); + // --- suggest test('Suggest, back and forth', function () { diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index 9e475b315a0..c0936096f1e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -162,7 +162,7 @@ suite('ExtHostLanguageFeatures', function () { return rpcProtocol.sync().then(() => { - return getDocumentSymbols(model, CancellationToken.None).then(value => { + return getDocumentSymbols(model, true, CancellationToken.None).then(value => { assert.equal(value.length, 1); }); }); @@ -177,7 +177,7 @@ suite('ExtHostLanguageFeatures', function () { return rpcProtocol.sync().then(() => { - return getDocumentSymbols(model, CancellationToken.None).then(value => { + return getDocumentSymbols(model, true, CancellationToken.None).then(value => { assert.equal(value.length, 1); let entry = value[0];