From 6b4f88991b144b0748fd4642891977f73d26d559 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 4 May 2018 18:15:24 +0200 Subject: [PATCH] experiment with internal hierarchical model, #34968 --- src/vs/editor/common/modes.ts | 10 ++ src/vs/editor/contrib/quickOpen/quickOpen.ts | 20 ++-- src/vs/monaco.d.ts | 9 ++ .../workbench/api/node/extHostApiCommands.ts | 4 +- .../api/node/extHostLanguageFeatures.ts | 96 +++++++++---------- .../api/node/extHostTypeConverters.ts | 59 +++++++++--- 6 files changed, 125 insertions(+), 73 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index e9caa888ae202..ee5ac00ee25fa 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -647,6 +647,10 @@ export interface SymbolInformation { * The name of this symbol. */ name: string; + /** + * The detail of this symbol. + */ + detail?: string; /** * The name of the symbol containing this symbol. */ @@ -659,6 +663,12 @@ export interface SymbolInformation { * The location of this symbol. */ location: Location; + /** + * The defining range of this symbol. + */ + definingRange: IRange; + + children?: SymbolInformation[]; } /** * The document symbol provider interface defines the contract between extensions and diff --git a/src/vs/editor/contrib/quickOpen/quickOpen.ts b/src/vs/editor/contrib/quickOpen/quickOpen.ts index 485540588f68a..05c2680d57cec 100644 --- a/src/vs/editor/contrib/quickOpen/quickOpen.ts +++ b/src/vs/editor/contrib/quickOpen/quickOpen.ts @@ -17,15 +17,13 @@ import { asWinJsPromise } from 'vs/base/common/async'; export function getDocumentSymbols(model: ITextModel): TPromise { - let entries: SymbolInformation[] = []; + let roots: SymbolInformation[] = []; let promises = DocumentSymbolProviderRegistry.all(model).map(support => { - return asWinJsPromise((token) => { - return support.provideDocumentSymbols(model, token); - }).then(result => { + return asWinJsPromise(token => support.provideDocumentSymbols(model, token)).then(result => { if (Array.isArray(result)) { - entries.push(...result); + roots.push(...result); } }, err => { onUnexpectedExternalError(err); @@ -34,7 +32,7 @@ export function getDocumentSymbols(model: ITextModel): TPromise { return TPromise.join(promises).then(() => { let flatEntries: SymbolInformation[] = []; - flatten(flatEntries, entries, ''); + flatten(flatEntries, roots, ''); flatEntries.sort(compareEntriesUsingStart); return { @@ -51,10 +49,16 @@ function flatten(bucket: SymbolInformation[], entries: SymbolInformation[], over for (let entry of entries) { bucket.push({ kind: entry.kind, - location: entry.location, name: entry.name, - containerName: entry.containerName || overrideContainerLabel + detail: entry.detail, + containerName: entry.containerName || overrideContainerLabel, + location: entry.location, + definingRange: entry.definingRange, + children: undefined, // we flatten it... }); + if (entry.children) { + flatten(bucket, entry.children, entry.name); + } } } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 17a205c0f2d8c..241cb9ba3af64 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4861,6 +4861,10 @@ declare namespace monaco.languages { * The name of this symbol. */ name: string; + /** + * The detail of this symbol. + */ + detail?: string; /** * The name of the symbol containing this symbol. */ @@ -4873,6 +4877,11 @@ declare namespace monaco.languages { * The location of this symbol. */ location: Location; + /** + * The defining range of this symbol. + */ + definingRange: IRange; + children?: SymbolInformation[]; } /** diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index ec3b858344ba4..ca3ec915fde83 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -278,7 +278,7 @@ export class ExtHostApiCommands { const result: types.SymbolInformation[] = []; if (Array.isArray(value)) { for (let tuple of value) { - result.push(...tuple[1].map(typeConverters.toSymbolInformation)); + result.push(...tuple[1].map(typeConverters.SymbolInformation.to)); } } return result; @@ -418,7 +418,7 @@ export class ExtHostApiCommands { }; return this._commands.executeCommand('_executeDocumentSymbolProvider', args).then(value => { if (value && Array.isArray(value.entries)) { - return value.entries.map(typeConverters.toSymbolInformation); + return value.entries.map(typeConverters.SymbolInformation.to); } return undefined; }); diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 4c22a34d548bd..82ddd43759c7a 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -8,7 +8,7 @@ import URI, { UriComponents } from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { mixin } from 'vs/base/common/objects'; import * as vscode from 'vscode'; -import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters'; +import * as typeConvert from 'vs/workbench/api/node/extHostTypeConverters'; import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, HierarchicalSymbolInformation } from 'vs/workbench/api/node/extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; @@ -40,10 +40,10 @@ class OutlineAdapter { let doc = this._documents.getDocumentData(resource).document; return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => { if (value instanceof HierarchicalSymbolInformation) { - value = HierarchicalSymbolInformation.toFlatSymbolInformation(value); + return [typeConvert.HierarchicalSymbolInformation.from(value)]; } if (Array.isArray(value)) { - return value.map(symbol => IdObject.mixin(TypeConverters.fromSymbolInformation(symbol))); + return value.map(typeConvert.SymbolInformation.from); } return undefined; }); @@ -74,7 +74,7 @@ class CodeLensAdapter { return lenses.map(lens => { const id = this._heapService.keep(lens); return ObjectIdentifier.mixin({ - range: TypeConverters.fromRange(lens.range), + range: typeConvert.fromRange(lens.range), command: this._commands.toInternal(lens.command) }, id); }); @@ -116,12 +116,12 @@ class DefinitionAdapter { provideDefinition(resource: URI, position: IPosition): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.location.from); + return value.map(typeConvert.location.from); } else if (value) { - return TypeConverters.location.from(value); + return typeConvert.location.from(value); } return undefined; }); @@ -139,12 +139,12 @@ class ImplementationAdapter { provideImplementation(resource: URI, position: IPosition): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideImplementation(doc, pos, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.location.from); + return value.map(typeConvert.location.from); } else if (value) { - return TypeConverters.location.from(value); + return typeConvert.location.from(value); } return undefined; }); @@ -162,12 +162,12 @@ class TypeDefinitionAdapter { provideTypeDefinition(resource: URI, position: IPosition): TPromise { const doc = this._documents.getDocumentData(resource).document; - const pos = TypeConverters.toPosition(position); + const pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideTypeDefinition(doc, pos, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.location.from); + return value.map(typeConvert.location.from); } else if (value) { - return TypeConverters.location.from(value); + return typeConvert.location.from(value); } return undefined; }); @@ -187,7 +187,7 @@ class HoverAdapter { public provideHover(resource: URI, position: IPosition): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => { if (!value || isFalsyOrEmpty(value.contents)) { @@ -200,7 +200,7 @@ class HoverAdapter { value.range = new Range(pos, pos); } - return TypeConverters.fromHover(value); + return typeConvert.fromHover(value); }); } } @@ -218,7 +218,7 @@ class DocumentHighlightAdapter { provideDocumentHighlights(resource: URI, position: IPosition): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => { if (Array.isArray(value)) { @@ -230,7 +230,7 @@ class DocumentHighlightAdapter { private static _convertDocumentHighlight(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight { return { - range: TypeConverters.fromRange(documentHighlight.range), + range: typeConvert.fromRange(documentHighlight.range), kind: documentHighlight.kind }; } @@ -248,11 +248,11 @@ class ReferenceAdapter { provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideReferences(doc, pos, context, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.location.from); + return value.map(typeConvert.location.from); } return undefined; }); @@ -275,7 +275,7 @@ class CodeActionAdapter { provideCodeActions(resource: URI, range: IRange, context: modes.CodeActionContext): TPromise { const doc = this._documents.getDocumentData(resource).document; - const ran = TypeConverters.toRange(range); + const ran = typeConvert.toRange(range); const allDiagnostics: vscode.Diagnostic[] = []; for (const diagnostic of this._diagnostics.getDiagnostics(resource)) { @@ -311,8 +311,8 @@ class CodeActionAdapter { result.push({ title: candidate.title, command: candidate.command && this._commands.toInternal(candidate.command), - diagnostics: candidate.diagnostics && candidate.diagnostics.map(TypeConverters.fromDiagnostic), - edit: candidate.edit && TypeConverters.WorkspaceEdit.from(candidate.edit), + diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.fromDiagnostic), + edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit), kind: candidate.kind && candidate.kind.value }); } @@ -343,7 +343,7 @@ class DocumentFormattingAdapter { return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(document, options, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.TextEdit.from); + return value.map(typeConvert.TextEdit.from); } return undefined; }); @@ -363,11 +363,11 @@ class RangeFormattingAdapter { provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions): TPromise { const { document } = this._documents.getDocumentData(resource); - const ran = TypeConverters.toRange(range); + const ran = typeConvert.toRange(range); return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(document, ran, options, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.TextEdit.from); + return value.map(typeConvert.TextEdit.from); } return undefined; }); @@ -389,11 +389,11 @@ class OnTypeFormattingAdapter { provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise { const { document } = this._documents.getDocumentData(resource); - const pos = TypeConverters.toPosition(position); + const pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(document, pos, ch, options, token)).then(value => { if (Array.isArray(value)) { - return value.map(TypeConverters.TextEdit.from); + return value.map(typeConvert.TextEdit.from); } return undefined; }); @@ -423,7 +423,7 @@ class NavigateTypeAdapter { console.warn('INVALID SymbolInformation, lacks name', item); continue; } - const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item)); + const symbol = IdObject.mixin(typeConvert.SymbolInformation.from(item)); this._symbolCache[symbol._id] = item; result.symbols.push(symbol); } @@ -445,7 +445,7 @@ class NavigateTypeAdapter { 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 value && mixin(symbol, typeConvert.SymbolInformation.from(value), true); }); } return undefined; @@ -479,13 +479,13 @@ class RenameAdapter { provideRenameEdits(resource: URI, position: IPosition, newName: string): TPromise { let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => { if (!value) { return undefined; } - return TypeConverters.WorkspaceEdit.from(value); + return typeConvert.WorkspaceEdit.from(value); }, err => { if (typeof err === 'string') { return { @@ -510,7 +510,7 @@ class RenameAdapter { } let doc = this._documents.getDocumentData(resource).document; - let pos = TypeConverters.toPosition(position); + let pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => { @@ -533,7 +533,7 @@ class RenameAdapter { console.warn('INVALID rename location: range must contain position'); return undefined; } - return { range: TypeConverters.fromRange(range), text }; + return { range: typeConvert.fromRange(range), text }; }); } } @@ -560,10 +560,10 @@ class SuggestAdapter { provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise { const doc = this._documents.getDocumentData(resource).document; - const pos = TypeConverters.toPosition(position); + const pos = typeConvert.toPosition(position); return asWinJsPromise(token => { - return this._provider.provideCompletionItems(doc, pos, token, TypeConverters.CompletionContext.from(context)); + return this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.from(context)); }).then(value => { const _id = this._idPool++; @@ -623,7 +623,7 @@ class SuggestAdapter { } const doc = this._documents.getDocumentData(resource).document; - const pos = TypeConverters.toPosition(position); + const pos = typeConvert.toPosition(position); const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)).with({ end: pos }); const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId); if (newSuggestion) { @@ -650,14 +650,14 @@ class SuggestAdapter { _parentId, // label: item.label, - type: TypeConverters.CompletionItemKind.from(item.kind), + type: typeConvert.CompletionItemKind.from(item.kind), detail: item.detail, documentation: item.documentation, filterText: item.filterText, sortText: item.sortText, // insertText: undefined, - additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(TypeConverters.TextEdit.from), + additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), command: this._commands.toInternal(item.command), commitCharacters: item.commitCharacters }; @@ -714,11 +714,11 @@ class SignatureHelpAdapter { provideSignatureHelp(resource: URI, position: IPosition): TPromise { const doc = this._documents.getDocumentData(resource).document; - const pos = TypeConverters.toPosition(position); + const pos = typeConvert.toPosition(position); return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => { if (value) { - return TypeConverters.SignatureHelp.from(value); + return typeConvert.SignatureHelp.from(value); } return undefined; }); @@ -746,7 +746,7 @@ class LinkProviderAdapter { } const result: modes.ILink[] = []; for (const link of links) { - let data = TypeConverters.DocumentLink.from(link); + let data = typeConvert.DocumentLink.from(link); let id = this._heapService.keep(link); ObjectIdentifier.mixin(data, id); result.push(data); @@ -768,7 +768,7 @@ class LinkProviderAdapter { return asWinJsPromise(token => this._provider.resolveDocumentLink(item, token)).then(value => { if (value) { - return TypeConverters.DocumentLink.from(value); + return typeConvert.DocumentLink.from(value); } return undefined; }); @@ -791,8 +791,8 @@ class ColorProviderAdapter { const colorInfos: IRawColorInfo[] = colors.map(ci => { return { - color: TypeConverters.Color.from(ci.color), - range: TypeConverters.fromRange(ci.range) + color: typeConvert.Color.from(ci.color), + range: typeConvert.fromRange(ci.range) }; }); @@ -802,10 +802,10 @@ class ColorProviderAdapter { provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise { const document = this._documents.getDocumentData(resource).document; - const range = TypeConverters.toRange(raw.range); - const color = TypeConverters.Color.to(raw.color); + const range = typeConvert.toRange(raw.range); + const color = typeConvert.Color.to(raw.color); return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => { - return value.map(TypeConverters.ColorPresentation.from); + return value.map(typeConvert.ColorPresentation.from); }); } } @@ -823,7 +823,7 @@ class FoldingProviderAdapter { if (!Array.isArray(ranges)) { return void 0; } - return ranges.map(TypeConverters.FoldingRange.from); + return ranges.map(typeConvert.FoldingRange.from); }); } } diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index c8aec09c9dee2..78116fe3a5a8b 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -333,25 +333,54 @@ export namespace SymbolKind { } } -export function fromSymbolInformation(info: vscode.SymbolInformation): modes.SymbolInformation { - return { - name: info.name, - kind: SymbolKind.from(info.kind), - containerName: info.containerName, - location: location.from(info.location) - }; +export namespace SymbolInformation { + export function from(info: vscode.SymbolInformation): modes.SymbolInformation { + return { + name: info.name, + kind: SymbolKind.from(info.kind), + containerName: info.containerName, + location: location.from(info.location) + }; + } + export function to(info: modes.SymbolInformation): types.SymbolInformation { + return new types.SymbolInformation( + info.name, + SymbolKind.to(info.kind), + info.containerName, + location.to(info.location) + ); + } } -export function toSymbolInformation(bearing: modes.SymbolInformation): types.SymbolInformation { - return new types.SymbolInformation( - bearing.name, - SymbolKind.to(bearing.kind), - bearing.containerName, - location.to(bearing.location) - ); +export namespace HierarchicalSymbolInformation { + export function from(info: vscode.HierarchicalSymbolInformation): modes.SymbolInformation { + let result: modes.SymbolInformation = { + name: info.name, + detail: info.detail, + location: location.from(info.location), + definingRange: fromRange(info.range), + kind: SymbolKind.from(info.kind) + }; + if (info.children) { + result.children = info.children.map(from); + } + return result; + } + export function to(info: modes.SymbolInformation): types.HierarchicalSymbolInformation { + let result = new types.HierarchicalSymbolInformation( + info.name, + SymbolKind.to(info.kind), + info.detail, + location.to(info.location), + toRange(info.definingRange) + ); + if (info.children) { + result.children = info.children.map(to); + } + return result; + } } - export const location = { from(value: vscode.Location): modes.Location { return {