mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Convert IOutlineSupport to DocumentSymbolProvider
This commit is contained in:
parent
3ca51f6d23
commit
1dd6ea33eb
|
@ -427,21 +427,127 @@ export interface DefinitionProvider {
|
|||
provideDefinition(model:editorCommon.IReadOnlyModel, position:editorCommon.IEditorPosition, token:CancellationToken): Definition | Thenable<Definition>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface used to compute an outline
|
||||
*/
|
||||
export interface IOutlineEntry {
|
||||
label: string;
|
||||
containerLabel?: string;
|
||||
type: string;
|
||||
icon?: string; // icon class or null to use the default images based on the type
|
||||
range: editorCommon.IRange;
|
||||
children?: IOutlineEntry[];
|
||||
export enum SymbolKind {
|
||||
File,
|
||||
Module,
|
||||
Namespace,
|
||||
Package,
|
||||
Class,
|
||||
Method,
|
||||
Property,
|
||||
Field,
|
||||
Constructor,
|
||||
Enum,
|
||||
Interface,
|
||||
Function,
|
||||
Variable,
|
||||
Constant,
|
||||
String,
|
||||
Number,
|
||||
Boolean,
|
||||
Array,
|
||||
Object,
|
||||
Key,
|
||||
Null
|
||||
}
|
||||
export namespace SymbolKind {
|
||||
|
||||
export interface IOutlineSupport {
|
||||
getOutline(resource:URI):TPromise<IOutlineEntry[]>;
|
||||
export function from(kind: number | SymbolKind): string {
|
||||
switch (kind) {
|
||||
case SymbolKind.Method:
|
||||
return 'method';
|
||||
case SymbolKind.Function:
|
||||
return 'function';
|
||||
case SymbolKind.Constructor:
|
||||
return 'constructor';
|
||||
case SymbolKind.Variable:
|
||||
return 'variable';
|
||||
case SymbolKind.Class:
|
||||
return 'class';
|
||||
case SymbolKind.Interface:
|
||||
return 'interface';
|
||||
case SymbolKind.Namespace:
|
||||
return 'namespace';
|
||||
case SymbolKind.Package:
|
||||
return 'package';
|
||||
case SymbolKind.Module:
|
||||
return 'module';
|
||||
case SymbolKind.Property:
|
||||
return 'property';
|
||||
case SymbolKind.Enum:
|
||||
return 'enum';
|
||||
case SymbolKind.String:
|
||||
return 'string';
|
||||
case SymbolKind.File:
|
||||
return 'file';
|
||||
case SymbolKind.Array:
|
||||
return 'array';
|
||||
case SymbolKind.Number:
|
||||
return 'number';
|
||||
case SymbolKind.Boolean:
|
||||
return 'boolean';
|
||||
case SymbolKind.Object:
|
||||
return 'object';
|
||||
case SymbolKind.Key:
|
||||
return 'key';
|
||||
case SymbolKind.Null:
|
||||
return 'null';
|
||||
}
|
||||
return 'property';
|
||||
}
|
||||
|
||||
export function to(type: string): SymbolKind {
|
||||
switch (type) {
|
||||
case 'method':
|
||||
return SymbolKind.Method;
|
||||
case 'function':
|
||||
return SymbolKind.Function;
|
||||
case 'constructor':
|
||||
return SymbolKind.Constructor;
|
||||
case 'variable':
|
||||
return SymbolKind.Variable;
|
||||
case 'class':
|
||||
return SymbolKind.Class;
|
||||
case 'interface':
|
||||
return SymbolKind.Interface;
|
||||
case 'namespace':
|
||||
return SymbolKind.Namespace;
|
||||
case 'package':
|
||||
return SymbolKind.Package;
|
||||
case 'module':
|
||||
return SymbolKind.Module;
|
||||
case 'property':
|
||||
return SymbolKind.Property;
|
||||
case 'enum':
|
||||
return SymbolKind.Enum;
|
||||
case 'string':
|
||||
return SymbolKind.String;
|
||||
case 'file':
|
||||
return SymbolKind.File;
|
||||
case 'array':
|
||||
return SymbolKind.Array;
|
||||
case 'number':
|
||||
return SymbolKind.Number;
|
||||
case 'boolean':
|
||||
return SymbolKind.Boolean;
|
||||
case 'object':
|
||||
return SymbolKind.Object;
|
||||
case 'key':
|
||||
return SymbolKind.Key;
|
||||
case 'null':
|
||||
return SymbolKind.Null;
|
||||
}
|
||||
return SymbolKind.Property;
|
||||
}
|
||||
}
|
||||
export interface SymbolInformation {
|
||||
name: string;
|
||||
containerName?: string;
|
||||
kind: SymbolKind;
|
||||
location: Location;
|
||||
}
|
||||
export interface DocumentSymbolProvider {
|
||||
provideDocumentSymbols(model:editorCommon.IReadOnlyModel, token: CancellationToken): SymbolInformation[] | Thenable<SymbolInformation[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -691,7 +797,7 @@ export const SignatureHelpProviderRegistry = new LanguageFeatureRegistry<Signatu
|
|||
|
||||
export const HoverProviderRegistry = new LanguageFeatureRegistry<HoverProvider>();
|
||||
|
||||
export const OutlineRegistry = new LanguageFeatureRegistry<IOutlineSupport>();
|
||||
export const DocumentSymbolProviderRegistry = new LanguageFeatureRegistry<DocumentSymbolProvider>();
|
||||
|
||||
export const DocumentHighlightProviderRegistry = new LanguageFeatureRegistry<DocumentHighlightProvider>();
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ import {IDisposable, dispose} from 'vs/base/common/lifecycle';
|
|||
import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import {Range} from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import {IOutlineEntry, OutlineRegistry} from 'vs/editor/common/modes';
|
||||
import {SymbolInformation, SymbolKind, DocumentSymbolProviderRegistry} from 'vs/editor/common/modes';
|
||||
import {ICodeEditor, IViewZone, IViewZoneChangeAccessor} from 'vs/editor/browser/editorBrowser';
|
||||
import {EditorBrowserRegistry} from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import {getOutlineEntries, IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {getDocumentSymbols, IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
|
||||
class OutlineViewZone implements IViewZone {
|
||||
|
||||
|
@ -25,15 +25,14 @@ class OutlineViewZone implements IViewZone {
|
|||
|
||||
public domNode:HTMLElement;
|
||||
|
||||
constructor(range:editorCommon.IRange, outlineType:string)
|
||||
{
|
||||
constructor(range:editorCommon.IRange, outlineType:SymbolKind) {
|
||||
this.afterLineNumber = range.startLineNumber-1;
|
||||
this.heightInPx = 4;
|
||||
this.suppressMouseDown = true;
|
||||
|
||||
this.domNode = document.createElement('div');
|
||||
var hr = document.createElement('hr');
|
||||
hr.className = 'outlineRule ' + outlineType;
|
||||
hr.className = 'outlineRule ' + SymbolKind.from(outlineType);
|
||||
this.domNode.appendChild(hr);
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +77,7 @@ class OutlineMarker {
|
|||
private _editor:ICodeEditor;
|
||||
|
||||
|
||||
public constructor(range:editorCommon.IRange, outlineType:string, _editor:ICodeEditor, helper:OutlineMarkerHelper, viewZoneChangeAccessor:IViewZoneChangeAccessor)
|
||||
{
|
||||
public constructor(range:editorCommon.IRange, outlineType:SymbolKind, _editor:ICodeEditor, helper:OutlineMarkerHelper, viewZoneChangeAccessor:IViewZoneChangeAccessor) {
|
||||
this._editor = _editor;
|
||||
this._viewZone = new OutlineViewZone(range, outlineType);
|
||||
this._viewZoneId = viewZoneChangeAccessor.addZone(this._viewZone);
|
||||
|
@ -177,7 +175,7 @@ export class OutlineMarkerContribution implements editorCommon.IEditorContributi
|
|||
return;
|
||||
}
|
||||
|
||||
if (!OutlineRegistry.has(model)) {
|
||||
if (!DocumentSymbolProviderRegistry.has(model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -186,7 +184,7 @@ export class OutlineMarkerContribution implements editorCommon.IEditorContributi
|
|||
this._currentOutlinePromise.cancel();
|
||||
}
|
||||
|
||||
this._currentOutlinePromise = getOutlineEntries(model);
|
||||
this._currentOutlinePromise = getDocumentSymbols(model);
|
||||
|
||||
this._currentOutlinePromise.then((result) => {
|
||||
this.renderOutlines(result.entries);
|
||||
|
@ -224,7 +222,7 @@ export class OutlineMarkerContribution implements editorCommon.IEditorContributi
|
|||
scheduler.schedule();
|
||||
}
|
||||
|
||||
private renderOutlines(entries: IOutlineEntry[]): void {
|
||||
private renderOutlines(entries: SymbolInformation[]): void {
|
||||
var centeredRange = this._editor.getCenteredRangeInViewport();
|
||||
var oldMarkersCount = this._markers.length;
|
||||
this._editor.changeDecorations((decorationsAccessor) => {
|
||||
|
@ -244,18 +242,16 @@ export class OutlineMarkerContribution implements editorCommon.IEditorContributi
|
|||
}
|
||||
}
|
||||
|
||||
private renderOutlinesRecursive(entries: IOutlineEntry[], helper:OutlineMarkerHelper, viewZoneChangeAccessor:IViewZoneChangeAccessor): void {
|
||||
private renderOutlinesRecursive(entries: SymbolInformation[], helper:OutlineMarkerHelper, viewZoneChangeAccessor:IViewZoneChangeAccessor): void {
|
||||
if (entries) {
|
||||
entries.forEach((outline) => {
|
||||
if (outline.type === 'class' || outline.type === 'method' || outline.type === 'function') {
|
||||
var range = Range.lift(outline.range);
|
||||
if (outline.kind === SymbolKind.Class || outline.kind === SymbolKind.Method || outline.kind === SymbolKind.Function) {
|
||||
var range = Range.lift(outline.location.range);
|
||||
if (!this.alreadyHasMarkerAtRange(range)) {
|
||||
var marker = new OutlineMarker(range, outline.type, this._editor, helper, viewZoneChangeAccessor);
|
||||
var marker = new OutlineMarker(range, outline.kind, this._editor, helper, viewZoneChangeAccessor);
|
||||
this._markers.push(marker);
|
||||
}
|
||||
}
|
||||
|
||||
this.renderOutlinesRecursive(outline.children, helper, viewZoneChangeAccessor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import 'vs/css!./quickOutline';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import {onUnexpectedError} from 'vs/base/common/errors';
|
||||
import {matchesFuzzy} from 'vs/base/common/filters';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
@ -17,9 +16,9 @@ import {IContext, IHighlight, QuickOpenEntryGroup, QuickOpenModel} from 'vs/base
|
|||
import {IAutoFocus, Mode} from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import {Behaviour} from 'vs/editor/common/editorActionEnablement';
|
||||
import {ICommonCodeEditor, IEditorActionDescriptorData, IRange} from 'vs/editor/common/editorCommon';
|
||||
import {IOutlineEntry, OutlineRegistry} from 'vs/editor/common/modes';
|
||||
import {SymbolInformation, SymbolKind, DocumentSymbolProviderRegistry} from 'vs/editor/common/modes';
|
||||
import {BaseEditorQuickOpenAction, IDecorator} from './editorQuickOpen';
|
||||
import {getOutlineEntries, IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {getDocumentSymbols, IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
|
||||
let SCOPE_PREFIX = ':';
|
||||
|
||||
|
@ -108,19 +107,11 @@ class SymbolEntry extends QuickOpenEntryGroup {
|
|||
}
|
||||
}
|
||||
|
||||
interface OutlineNode {
|
||||
label: string;
|
||||
type: string;
|
||||
range: IRange;
|
||||
children?: OutlineNode[];
|
||||
parentScope?: string[];
|
||||
}
|
||||
|
||||
export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
||||
|
||||
public static ID = 'editor.action.quickOutline';
|
||||
|
||||
private cachedResult: IOutlineEntry[];
|
||||
private cachedResult: SymbolInformation[];
|
||||
|
||||
constructor(descriptor: IEditorActionDescriptorData, editor: ICommonCodeEditor) {
|
||||
super(descriptor, editor, nls.localize('QuickOutlineAction.label', "Go to Symbol..."), Behaviour.WidgetFocus | Behaviour.ShowInContextMenu);
|
||||
|
@ -131,18 +122,18 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
|||
}
|
||||
|
||||
public isSupported(): boolean {
|
||||
return (OutlineRegistry.has(this.editor.getModel()) && super.isSupported());
|
||||
return (DocumentSymbolProviderRegistry.has(this.editor.getModel()) && super.isSupported());
|
||||
}
|
||||
|
||||
public run(): TPromise<boolean> {
|
||||
let model = this.editor.getModel();
|
||||
|
||||
if (!OutlineRegistry.has(model)) {
|
||||
if (!DocumentSymbolProviderRegistry.has(model)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Resolve outline
|
||||
let promise = getOutlineEntries(model);
|
||||
let promise = getDocumentSymbols(model);
|
||||
return promise.then((result: IOutline) => {
|
||||
if (result.entries.length > 0) {
|
||||
|
||||
|
@ -180,15 +171,9 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
|||
return nls.localize('quickOutlineActionInput', "Type the name of an identifier you wish to navigate to");
|
||||
}
|
||||
|
||||
private toQuickOpenEntries(outline: OutlineNode[], searchValue: string): SymbolEntry[] {
|
||||
private toQuickOpenEntries(flattened: SymbolInformation[], searchValue: string): SymbolEntry[] {
|
||||
let results: SymbolEntry[] = [];
|
||||
|
||||
// Flatten
|
||||
let flattened: OutlineNode[] = [];
|
||||
if (outline) {
|
||||
this.flatten(outline, flattened);
|
||||
}
|
||||
|
||||
// Convert to Entries
|
||||
let normalizedSearchValue = searchValue;
|
||||
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
|
||||
|
@ -197,7 +182,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
|||
|
||||
for (let i = 0; i < flattened.length; i++) {
|
||||
let element = flattened[i];
|
||||
let label = strings.trim(element.label);
|
||||
let label = strings.trim(element.name);
|
||||
|
||||
// Check for meatch
|
||||
let highlights = matchesFuzzy(normalizedSearchValue, label);
|
||||
|
@ -205,12 +190,12 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
|||
|
||||
// Show parent scope as description
|
||||
let description: string = null;
|
||||
if (element.parentScope) {
|
||||
description = arrays.tail(element.parentScope);
|
||||
if (element.containerName) {
|
||||
description = element.containerName;
|
||||
}
|
||||
|
||||
// Add
|
||||
results.push(new SymbolEntry(label, element.type, description, element.range, highlights, this.editor, this));
|
||||
results.push(new SymbolEntry(label, SymbolKind.from(element.kind), description, element.location.range, highlights, this.editor, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,27 +269,6 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction {
|
|||
return type;
|
||||
}
|
||||
|
||||
private flatten(outline: OutlineNode[], flattened: OutlineNode[], parentScope?: string[]): void {
|
||||
for (let i = 0; i < outline.length; i++) {
|
||||
let element = outline[i];
|
||||
flattened.push(element);
|
||||
|
||||
if (parentScope) {
|
||||
element.parentScope = parentScope;
|
||||
}
|
||||
|
||||
if (element.children) {
|
||||
let elementScope: string[] = [];
|
||||
if (parentScope) {
|
||||
elementScope = parentScope.slice(0);
|
||||
}
|
||||
elementScope.push(element.label);
|
||||
|
||||
this.flatten(element.children, flattened, elementScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sortNormal(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number {
|
||||
let elementAName = elementA.getLabel().toLowerCase();
|
||||
let elementBName = elementB.getLabel().toLowerCase();
|
||||
|
|
|
@ -11,20 +11,23 @@ import {TPromise} from 'vs/base/common/winjs.base';
|
|||
import {Range} from 'vs/editor/common/core/range';
|
||||
import {IModel} from 'vs/editor/common/editorCommon';
|
||||
import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions';
|
||||
import {IOutlineEntry, OutlineRegistry} from 'vs/editor/common/modes';
|
||||
import {SymbolInformation, DocumentSymbolProviderRegistry} from 'vs/editor/common/modes';
|
||||
import {IModelService} from 'vs/editor/common/services/modelService';
|
||||
import {asWinJsPromise} from 'vs/base/common/async';
|
||||
|
||||
export interface IOutline {
|
||||
entries: IOutlineEntry[];
|
||||
entries: SymbolInformation[];
|
||||
}
|
||||
|
||||
export function getOutlineEntries(model: IModel): TPromise<IOutline> {
|
||||
export function getDocumentSymbols(model: IModel): TPromise<IOutline> {
|
||||
|
||||
let entries: IOutlineEntry[] = [];
|
||||
let entries: SymbolInformation[] = [];
|
||||
|
||||
let promises = OutlineRegistry.all(model).map(support => {
|
||||
let promises = DocumentSymbolProviderRegistry.all(model).map(support => {
|
||||
|
||||
return support.getOutline(model.getAssociatedResource()).then(result => {
|
||||
return asWinJsPromise((token) => {
|
||||
return support.provideDocumentSymbols(model, token);
|
||||
}).then(result => {
|
||||
if (Array.isArray(result)) {
|
||||
entries.push(...result);
|
||||
}
|
||||
|
@ -34,7 +37,7 @@ export function getOutlineEntries(model: IModel): TPromise<IOutline> {
|
|||
});
|
||||
|
||||
return TPromise.join(promises).then(() => {
|
||||
let flatEntries: IOutlineEntry[] = [];
|
||||
let flatEntries: SymbolInformation[] = [];
|
||||
flatten(flatEntries, entries, '');
|
||||
flatEntries.sort(compareEntriesUsingStart);
|
||||
|
||||
|
@ -44,22 +47,18 @@ export function getOutlineEntries(model: IModel): TPromise<IOutline> {
|
|||
});
|
||||
}
|
||||
|
||||
function compareEntriesUsingStart(a: IOutlineEntry, b: IOutlineEntry): number{
|
||||
return Range.compareRangesUsingStarts(Range.lift(a.range), Range.lift(b.range));
|
||||
function compareEntriesUsingStart(a: SymbolInformation, b: SymbolInformation): number{
|
||||
return Range.compareRangesUsingStarts(Range.lift(a.location.range), Range.lift(b.location.range));
|
||||
}
|
||||
|
||||
function flatten(bucket: IOutlineEntry[], entries: IOutlineEntry[], overrideContainerLabel: string): void {
|
||||
function flatten(bucket: SymbolInformation[], entries: SymbolInformation[], overrideContainerLabel: string): void {
|
||||
for (let entry of entries) {
|
||||
bucket.push({
|
||||
type: entry.type,
|
||||
range: entry.range,
|
||||
label: entry.label,
|
||||
icon: entry.icon,
|
||||
containerLabel: entry.containerLabel || overrideContainerLabel
|
||||
kind: entry.kind,
|
||||
location: entry.location,
|
||||
name: entry.name,
|
||||
containerName: entry.containerName || overrideContainerLabel
|
||||
});
|
||||
if (entry.children) {
|
||||
flatten(bucket, entry.children, entry.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,5 +72,5 @@ CommonEditorRegistry.registerLanguageCommand('_executeDocumentSymbolProvider', f
|
|||
if (!model) {
|
||||
throw illegalArgument('resource');
|
||||
}
|
||||
return getOutlineEntries(model);
|
||||
return getDocumentSymbols(model);
|
||||
});
|
|
@ -345,7 +345,11 @@ export class CSSMode extends AbstractMode {
|
|||
// }
|
||||
// });
|
||||
|
||||
modes.OutlineRegistry.register(this.getId(), this);
|
||||
modes.DocumentSymbolProviderRegistry.register(this.getId(), {
|
||||
provideDocumentSymbols: (model, token): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._provideDocumentSymbols(model.getAssociatedResource()));
|
||||
}
|
||||
});
|
||||
|
||||
// modes.DefinitionProviderRegistry.register(this.getId(), {
|
||||
// provideDefinition: (model, position, token): Thenable<modes.Definition> => {
|
||||
|
@ -423,9 +427,9 @@ export class CSSMode extends AbstractMode {
|
|||
return this._worker((w) => w.provideReferences(resource, position));
|
||||
}
|
||||
|
||||
static $getOutline = OneWorkerAttr(CSSMode, CSSMode.prototype.getOutline);
|
||||
public getOutline(resource:URI):WinJS.TPromise<modes.IOutlineEntry[]> {
|
||||
return this._worker((w) => w.getOutline(resource));
|
||||
static $_provideDocumentSymbols = OneWorkerAttr(CSSMode, CSSMode.prototype._provideDocumentSymbols);
|
||||
private _provideDocumentSymbols(resource:URI):WinJS.TPromise<modes.SymbolInformation[]> {
|
||||
return this._worker((w) => w.provideDocumentSymbols(resource));
|
||||
}
|
||||
|
||||
static $findColorDeclarations = OneWorkerAttr(CSSMode, CSSMode.prototype.findColorDeclarations);
|
||||
|
|
|
@ -211,42 +211,44 @@ export class CSSWorker {
|
|||
|
||||
}
|
||||
|
||||
public getOutline(resource:URI):winjs.TPromise<modes.IOutlineEntry[]> {
|
||||
public provideDocumentSymbols(resource:URI):winjs.TPromise<modes.SymbolInformation[]> {
|
||||
|
||||
return this.languageService.join().then(() => {
|
||||
|
||||
let model = this.resourceService.get(resource),
|
||||
stylesheet = this.languageService.getStylesheet(resource),
|
||||
result:modes.IOutlineEntry[] = [];
|
||||
result:modes.SymbolInformation[] = [];
|
||||
|
||||
stylesheet.accept((node) => {
|
||||
|
||||
let entry:modes.IOutlineEntry = {
|
||||
label: null,
|
||||
type: 'rule',
|
||||
range: null,
|
||||
children: []
|
||||
let entry:modes.SymbolInformation = {
|
||||
name: null,
|
||||
kind: modes.SymbolKind.Class, // TODO@Martin: find a good SymbolKind
|
||||
location: null
|
||||
};
|
||||
|
||||
if(node instanceof nodes.Selector) {
|
||||
entry.label = node.getText();
|
||||
entry.name = node.getText();
|
||||
} else if(node instanceof nodes.VariableDeclaration) {
|
||||
entry.label = (<nodes.VariableDeclaration> node).getName();
|
||||
entry.type = 'letiable';
|
||||
entry.name = (<nodes.VariableDeclaration> node).getName();
|
||||
entry.kind = modes.SymbolKind.Variable;
|
||||
} else if(node instanceof nodes.MixinDeclaration) {
|
||||
entry.label = (<nodes.MixinDeclaration> node).getName();
|
||||
entry.type = 'method';
|
||||
entry.name = (<nodes.MixinDeclaration> node).getName();
|
||||
entry.kind = modes.SymbolKind.Method;
|
||||
} else if(node instanceof nodes.FunctionDeclaration) {
|
||||
entry.label = (<nodes.FunctionDeclaration> node).getName();
|
||||
entry.type = 'function';
|
||||
entry.name = (<nodes.FunctionDeclaration> node).getName();
|
||||
entry.kind = modes.SymbolKind.Function;
|
||||
} else if(node instanceof nodes.Keyframe) {
|
||||
entry.label = nls.localize('literal.keyframes', "@keyframes {0}", (<nodes.Keyframe> node).getName());
|
||||
entry.name = nls.localize('literal.keyframes', "@keyframes {0}", (<nodes.Keyframe> node).getName());
|
||||
} else if(node instanceof nodes.FontFace) {
|
||||
entry.label = nls.localize('literal.fontface', "@font-face");
|
||||
entry.name = nls.localize('literal.fontface', "@font-face");
|
||||
}
|
||||
|
||||
if(entry.label) {
|
||||
entry.range = this._range(node, model, true);
|
||||
if(entry.name) {
|
||||
entry.location = {
|
||||
uri: resource,
|
||||
range: this._range(node, model, true)
|
||||
};
|
||||
result.push(entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiat
|
|||
import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport';
|
||||
import {wireCancellationToken} from 'vs/base/common/async';
|
||||
|
||||
export class JSONMode extends AbstractMode implements modes.IOutlineSupport {
|
||||
export class JSONMode extends AbstractMode {
|
||||
|
||||
public tokenizationSupport: modes.ITokenizationSupport;
|
||||
public richEditSupport: modes.IRichEditSupport;
|
||||
|
@ -74,7 +74,11 @@ export class JSONMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
this.configSupport = this;
|
||||
|
||||
// Initialize Outline support
|
||||
modes.OutlineRegistry.register(this.getId(), this);
|
||||
modes.DocumentSymbolProviderRegistry.register(this.getId(), {
|
||||
provideDocumentSymbols: (model, token): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._provideDocumentSymbols(model.getAssociatedResource()));
|
||||
}
|
||||
});
|
||||
|
||||
modes.FormatRegistry.register(this.getId(), this);
|
||||
|
||||
|
@ -150,9 +154,9 @@ export class JSONMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
return this._worker((w) => w.provideHover(resource, position));
|
||||
}
|
||||
|
||||
static $getOutline = OneWorkerAttr(JSONMode, JSONMode.prototype.getOutline);
|
||||
public getOutline(resource:URI):WinJS.TPromise<modes.IOutlineEntry[]> {
|
||||
return this._worker((w) => w.getOutline(resource));
|
||||
static $_provideDocumentSymbols = OneWorkerAttr(JSONMode, JSONMode.prototype._provideDocumentSymbols);
|
||||
private _provideDocumentSymbols(resource:URI):WinJS.TPromise<modes.SymbolInformation[]> {
|
||||
return this._worker((w) => w.provideDocumentSymbols(resource));
|
||||
}
|
||||
|
||||
static $formatDocument = OneWorkerAttr(JSONMode, JSONMode.prototype.formatDocument);
|
||||
|
|
|
@ -344,7 +344,7 @@ export class JSONWorker {
|
|||
}
|
||||
|
||||
|
||||
public getOutline(resource:URI):WinJS.TPromise<Modes.IOutlineEntry[]> {
|
||||
public provideDocumentSymbols(resource:URI):WinJS.TPromise<Modes.SymbolInformation[]> {
|
||||
var modelMirror = this.resourceService.get(resource);
|
||||
|
||||
var parser = new Parser.JSONParser();
|
||||
|
@ -358,13 +358,20 @@ export class JSONWorker {
|
|||
var resourceString = resource.toString();
|
||||
if ((resourceString === 'vscode://defaultsettings/keybindings.json') || Strings.endsWith(resourceString.toLowerCase(), '/user/keybindings.json')) {
|
||||
if (root.type === 'array') {
|
||||
var result : Modes.IOutlineEntry[] = [];
|
||||
var result : Modes.SymbolInformation[] = [];
|
||||
(<Parser.ArrayASTNode> root).items.forEach((item) => {
|
||||
if (item.type === 'object') {
|
||||
var property = (<Parser.ObjectASTNode> item).getFirstProperty('key');
|
||||
if (property && property.value) {
|
||||
var range = modelMirror.getRangeFromOffsetAndLength(item.start, item.end - item.start);
|
||||
result.push({ label: property.value.getValue(), icon: 'function', type: 'string', range: range, children: []});
|
||||
result.push({
|
||||
name: property.value.getValue(),
|
||||
kind: Modes.SymbolKind.String,
|
||||
location: {
|
||||
uri: resource,
|
||||
range: range
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -372,10 +379,10 @@ export class JSONWorker {
|
|||
}
|
||||
}
|
||||
|
||||
function collectOutlineEntries(result: Modes.IOutlineEntry[], node: Parser.ASTNode): Modes.IOutlineEntry[] {
|
||||
function collectOutlineEntries(result: Modes.SymbolInformation[], node: Parser.ASTNode, containerName: string): Modes.SymbolInformation[] {
|
||||
if (node.type === 'array') {
|
||||
(<Parser.ArrayASTNode>node).items.forEach((node:Parser.ASTNode) => {
|
||||
collectOutlineEntries(result, node);
|
||||
collectOutlineEntries(result, node, containerName);
|
||||
});
|
||||
} else if (node.type === 'object') {
|
||||
var objectNode = <Parser.ObjectASTNode>node;
|
||||
|
@ -384,15 +391,23 @@ export class JSONWorker {
|
|||
var range = modelMirror.getRangeFromOffsetAndLength(property.start, property.end - property.start);
|
||||
var valueNode = property.value;
|
||||
if (valueNode) {
|
||||
var children = collectOutlineEntries([], valueNode);
|
||||
var icon = valueNode.type === 'object' ? 'module' : valueNode.type;
|
||||
result.push({ label: property.key.getValue(), icon: icon, type: valueNode.type, range: range, children: children});
|
||||
let childContainerName = containerName ? containerName + '.' + property.key.name : property.key.name;
|
||||
result.push({
|
||||
name: property.key.getValue(),
|
||||
kind: getSymbolKind(valueNode.type),
|
||||
location: {
|
||||
uri: resource,
|
||||
range: range,
|
||||
},
|
||||
containerName: containerName
|
||||
});
|
||||
collectOutlineEntries(result, valueNode, childContainerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
var result = collectOutlineEntries([], root);
|
||||
var result = collectOutlineEntries([], root, void 0);
|
||||
return WinJS.TPromise.as(result);
|
||||
}
|
||||
|
||||
|
@ -401,3 +416,20 @@ export class JSONWorker {
|
|||
return WinJS.TPromise.as(JSONFormatter.format(model, range, options));
|
||||
}
|
||||
}
|
||||
|
||||
function getSymbolKind(nodeType: string): Modes.SymbolKind {
|
||||
switch (nodeType) {
|
||||
case 'object':
|
||||
return Modes.SymbolKind.Module;
|
||||
case 'string':
|
||||
return Modes.SymbolKind.String;
|
||||
case 'number':
|
||||
return Modes.SymbolKind.Number;
|
||||
case 'array':
|
||||
return Modes.SymbolKind.Array;
|
||||
case 'boolean':
|
||||
return Modes.SymbolKind.Boolean;
|
||||
default: // 'null'
|
||||
return Modes.SymbolKind.Variable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,18 +18,24 @@ import EditorCommon = require('vs/editor/common/editorCommon');
|
|||
import Modes = require('vs/editor/common/modes');
|
||||
import WinJS = require('vs/base/common/winjs.base');
|
||||
|
||||
interface RelaxedSymbolInformation {
|
||||
name: string;
|
||||
containerName?: string;
|
||||
kind: Modes.SymbolKind;
|
||||
}
|
||||
|
||||
suite('JSON - Worker', () => {
|
||||
|
||||
var assertOutline:any = function(actual: Modes.IOutlineEntry[], expected: any[], message: string) {
|
||||
assert.equal(actual.length, expected.length, message);
|
||||
for (var i = 0; i < expected.length; i++) {
|
||||
assert.equal(actual[i].label, expected[i].label, message);
|
||||
assert.equal(actual[i].type, expected[i].type, message);
|
||||
var childrenExpected = expected[i].children || [];
|
||||
var childrenActual = actual[i].children || [];
|
||||
assertOutline(childrenExpected, childrenActual, message);
|
||||
}
|
||||
function toRelaxedSymbolInformation(a: RelaxedSymbolInformation): RelaxedSymbolInformation {
|
||||
return {
|
||||
name: a.name,
|
||||
containerName: a.containerName,
|
||||
kind: a.kind
|
||||
};
|
||||
}
|
||||
|
||||
var assertOutline = function(actual: Modes.SymbolInformation[], expected: RelaxedSymbolInformation[], message?: string) {
|
||||
assert.deepEqual(actual.map(toRelaxedSymbolInformation), expected.map(toRelaxedSymbolInformation), message);
|
||||
};
|
||||
|
||||
function mockWorkerEnv(url: URI, content: string): { worker: jsonworker.JSONWorker; model: EditorCommon.IMirrorModel; } {
|
||||
|
@ -80,10 +86,10 @@ suite('JSON - Worker', () => {
|
|||
return env.worker.navigateValueSet(url, range, up);
|
||||
};
|
||||
|
||||
function getOutline(content: string):WinJS.TPromise<Modes.IOutlineEntry[]> {
|
||||
function getOutline(content: string):WinJS.TPromise<Modes.SymbolInformation[]> {
|
||||
var url = URI.parse('test');
|
||||
var workerEnv = mockWorkerEnv(url, content);
|
||||
return workerEnv.worker.getOutline(url);
|
||||
return workerEnv.worker.provideDocumentSymbols(url);
|
||||
};
|
||||
|
||||
var assertSuggestion= function(completion:Modes.ISuggestResult, label:string, documentationLabel?: string) {
|
||||
|
@ -96,13 +102,13 @@ suite('JSON - Worker', () => {
|
|||
test('JSON outline - base types', function(testDone) {
|
||||
var content= '{ "key1": 1, "key2": "foo", "key3" : true }';
|
||||
|
||||
var expected= [
|
||||
{ label: 'key1', type: 'number'},
|
||||
{ label: 'key2', type: 'string'},
|
||||
{ label: 'key3', type: 'boolean'},
|
||||
var expected = [
|
||||
{ name: 'key1', kind: Modes.SymbolKind.Number},
|
||||
{ name: 'key2', kind: Modes.SymbolKind.String},
|
||||
{ name: 'key3', kind: Modes.SymbolKind.Boolean},
|
||||
];
|
||||
|
||||
getOutline(content).then((entries: Modes.IOutlineEntry[]) => {
|
||||
getOutline(content).then((entries: Modes.SymbolInformation[]) => {
|
||||
assertOutline(entries, expected);
|
||||
}).done(() => testDone(), (error) => {
|
||||
testDone(error);
|
||||
|
@ -113,12 +119,14 @@ suite('JSON - Worker', () => {
|
|||
var content= '{ "key1": 1, "key2": [ 1, 2, 3 ], "key3" : [ { "k1": 1 }, {"k2": 2 } ] }';
|
||||
|
||||
var expected= [
|
||||
{ label: 'key1', type: 'number'},
|
||||
{ label: 'key2', type: 'array'},
|
||||
{ label: 'key3', type: 'array', children : [ { label: 'k1', type: 'number'}, { label: 'k2', type: 'number'} ]},
|
||||
{ name: 'key1', kind: Modes.SymbolKind.Number},
|
||||
{ name: 'key2', kind: Modes.SymbolKind.Array},
|
||||
{ name: 'key3', kind: Modes.SymbolKind.Array},
|
||||
{ name: 'k1', kind: Modes.SymbolKind.Number, containerName: 'key3'},
|
||||
{ name: 'k2', kind: Modes.SymbolKind.Number, containerName: 'key3'},
|
||||
];
|
||||
|
||||
getOutline(content).then((entries: Modes.IOutlineEntry[]) => {
|
||||
getOutline(content).then((entries: Modes.SymbolInformation[]) => {
|
||||
assertOutline(entries, expected);
|
||||
}).done(() => testDone(), (error) => {
|
||||
testDone(error);
|
||||
|
@ -129,11 +137,13 @@ suite('JSON - Worker', () => {
|
|||
var content= '{ "key1": { "key2": true }, "key3" : { "k1": { } }';
|
||||
|
||||
var expected= [
|
||||
{ label: 'key1', type: 'object', children : [ { label: 'key2', type: 'boolean'} ] },
|
||||
{ label: 'key3', type: 'object', children : [ { label: 'k1', type: 'object'} ] }
|
||||
{ name: 'key1', kind: Modes.SymbolKind.Module},
|
||||
{ name: 'key2', kind: Modes.SymbolKind.Boolean, containerName: 'key1' },
|
||||
{ name: 'key3', kind: Modes.SymbolKind.Module},
|
||||
{ name: 'k1', kind: Modes.SymbolKind.Module, containerName: 'key3'}
|
||||
];
|
||||
|
||||
getOutline(content).then((entries: Modes.IOutlineEntry[]) => {
|
||||
getOutline(content).then((entries: Modes.SymbolInformation[]) => {
|
||||
assertOutline(entries, expected);
|
||||
}).done(() => testDone(), (error) => {
|
||||
testDone(error);
|
||||
|
@ -144,10 +154,12 @@ suite('JSON - Worker', () => {
|
|||
var content= '{ "key1": { "key2": true, "key3":, "key4": false } }';
|
||||
|
||||
var expected= [
|
||||
{ label: 'key1', type: 'object', children : [ { label: 'key2', type: 'boolean'}, { label: 'key4', type: 'boolean'} ] },
|
||||
{ name: 'key1', kind: Modes.SymbolKind.Module },
|
||||
{ name: 'key2', kind: Modes.SymbolKind.Boolean, containerName: 'key1'},
|
||||
{ name: 'key4', kind: Modes.SymbolKind.Boolean, containerName: 'key1'},
|
||||
];
|
||||
|
||||
getOutline(content).then((entries: Modes.IOutlineEntry[]) => {
|
||||
getOutline(content).then((entries: Modes.SymbolInformation[]) => {
|
||||
assertOutline(entries, expected);
|
||||
}).done(() => testDone(), (error) => {
|
||||
testDone(error);
|
||||
|
|
|
@ -176,7 +176,7 @@ export var language: Types.ILanguage = <Types.ILanguage> {
|
|||
}
|
||||
};
|
||||
|
||||
export class LESSMode extends AbstractMode implements modes.IOutlineSupport {
|
||||
export class LESSMode extends AbstractMode {
|
||||
|
||||
public inplaceReplaceSupport:modes.IInplaceReplaceSupport;
|
||||
public configSupport:modes.IConfigurationSupport;
|
||||
|
@ -225,7 +225,11 @@ export class LESSMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
}
|
||||
});
|
||||
|
||||
modes.OutlineRegistry.register(this.getId(), this);
|
||||
modes.DocumentSymbolProviderRegistry.register(this.getId(), {
|
||||
provideDocumentSymbols: (model, token): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._provideDocumentSymbols(model.getAssociatedResource()));
|
||||
}
|
||||
});
|
||||
|
||||
modes.SuggestRegistry.register(this.getId(), {
|
||||
triggerCharacters: [],
|
||||
|
@ -289,9 +293,9 @@ export class LESSMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
return this._worker((w) => w.provideHover(resource, position));
|
||||
}
|
||||
|
||||
static $getOutline = OneWorkerAttr(LESSMode, LESSMode.prototype.getOutline);
|
||||
public getOutline(resource:URI):winjs.TPromise<modes.IOutlineEntry[]> {
|
||||
return this._worker((w) => w.getOutline(resource));
|
||||
static $_provideDocumentSymbols = OneWorkerAttr(LESSMode, LESSMode.prototype._provideDocumentSymbols);
|
||||
private _provideDocumentSymbols(resource:URI):winjs.TPromise<modes.SymbolInformation[]> {
|
||||
return this._worker((w) => w.provideDocumentSymbols(resource));
|
||||
}
|
||||
|
||||
static $_provideDefinition = OneWorkerAttr(LESSMode, LESSMode.prototype._provideDefinition);
|
||||
|
|
|
@ -278,7 +278,7 @@ export var language = <Types.ILanguage>{
|
|||
}
|
||||
};
|
||||
|
||||
export class SASSMode extends AbstractMode implements modes.IOutlineSupport {
|
||||
export class SASSMode extends AbstractMode {
|
||||
|
||||
public inplaceReplaceSupport:modes.IInplaceReplaceSupport;
|
||||
public configSupport:modes.IConfigurationSupport;
|
||||
|
@ -326,14 +326,19 @@ export class SASSMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
}
|
||||
});
|
||||
|
||||
modes.OutlineRegistry.register(this.getId(), this);
|
||||
modes.DocumentSymbolProviderRegistry.register(this.getId(), {
|
||||
provideDocumentSymbols: (model, token): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._provideDocumentSymbols(model.getAssociatedResource()));
|
||||
}
|
||||
});
|
||||
|
||||
modes.SuggestRegistry.register(this.getId(), {
|
||||
triggerCharacters: [],
|
||||
shouldAutotriggerSuggest: true,
|
||||
provideCompletionItems: (model, position, token): Thenable<modes.ISuggestResult[]> => {
|
||||
return wireCancellationToken(token, this._provideCompletionItems(model.getAssociatedResource(), position));
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
this.tokenizationSupport = createTokenizationSupport(modeService, this, lexer);
|
||||
|
||||
|
@ -389,9 +394,9 @@ export class SASSMode extends AbstractMode implements modes.IOutlineSupport {
|
|||
return this._worker((w) => w.provideHover(resource, position));
|
||||
}
|
||||
|
||||
static $getOutline = OneWorkerAttr(SASSMode, SASSMode.prototype.getOutline);
|
||||
public getOutline(resource:URI):winjs.TPromise<modes.IOutlineEntry[]> {
|
||||
return this._worker((w) => w.getOutline(resource));
|
||||
static $_provideDocumentSymbols = OneWorkerAttr(SASSMode, SASSMode.prototype._provideDocumentSymbols);
|
||||
private _provideDocumentSymbols(resource:URI):winjs.TPromise<modes.SymbolInformation[]> {
|
||||
return this._worker((w) => w.provideDocumentSymbols(resource));
|
||||
}
|
||||
|
||||
static $_provideDefinition = OneWorkerAttr(SASSMode, SASSMode.prototype._provideDefinition);
|
||||
|
|
|
@ -28,7 +28,7 @@ export function register(modelService: IModelService, markerService: IMarkerServ
|
|||
disposables.push(modes.DocumentHighlightProviderRegistry.register(selector, new OccurrencesAdapter(modelService, worker)));
|
||||
disposables.push(modes.DefinitionProviderRegistry.register(selector, new DefinitionAdapter(modelService, worker)));
|
||||
disposables.push(modes.ReferenceProviderRegistry.register(selector, new ReferenceAdapter(modelService, worker)));
|
||||
disposables.push(modes.OutlineRegistry.register(selector, new OutlineAdapter(modelService, worker)));
|
||||
disposables.push(modes.DocumentSymbolProviderRegistry.register(selector, new OutlineAdapter(modelService, worker)));
|
||||
disposables.push(modes.FormatRegistry.register(selector, new FormatAdapter(modelService, worker)));
|
||||
disposables.push(modes.FormatOnTypeRegistry.register(selector, new FormatAdapter(modelService, worker)));
|
||||
disposables.push(new DiagnostcsAdapter(defaults, selector, markerService, modelService, worker));
|
||||
|
@ -394,28 +394,90 @@ class ReferenceAdapter extends Adapter implements modes.ReferenceProvider {
|
|||
|
||||
// --- outline ------
|
||||
|
||||
class OutlineAdapter extends Adapter implements modes.IOutlineSupport {
|
||||
class OutlineAdapter extends Adapter implements modes.DocumentSymbolProvider {
|
||||
|
||||
getOutline(resource: URI): TPromise<modes.IOutlineEntry[]> {
|
||||
return this._worker(resource).then(worker => worker.getNavigationBarItems(resource.toString())).then(items => {
|
||||
public provideDocumentSymbols(model:editorCommon.IReadOnlyModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> {
|
||||
const resource = model.getAssociatedResource();
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => worker.getNavigationBarItems(resource.toString())).then(items => {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
const convert = (item: ts.NavigationBarItem): modes.IOutlineEntry => {
|
||||
return {
|
||||
label: item.text,
|
||||
type: item.kind,
|
||||
range: this._textSpanToRange(resource, item.spans[0]),
|
||||
children: item.childItems && item.childItems.map(convert)
|
||||
function convert(bucket: modes.SymbolInformation[], item: ts.NavigationBarItem, containerLabel?: string): void {
|
||||
let result: modes.SymbolInformation = {
|
||||
name: item.text,
|
||||
kind: outlineTypeTable[item.kind] || modes.SymbolKind.Variable,
|
||||
location: {
|
||||
uri: resource,
|
||||
range: this._textSpanToRange(resource, item.spans[0])
|
||||
},
|
||||
containerName: containerLabel
|
||||
};
|
||||
};
|
||||
|
||||
return items.map(convert);
|
||||
});
|
||||
if (item.childItems && item.childItems.length > 0) {
|
||||
for (let child of item.childItems) {
|
||||
convert(bucket, child, result.name);
|
||||
}
|
||||
}
|
||||
|
||||
bucket.push(result);
|
||||
}
|
||||
|
||||
let result: modes.SymbolInformation[] = [];
|
||||
items.forEach(item => convert(result, item));
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class Kind {
|
||||
public static unknown:string = '';
|
||||
public static keyword:string = 'keyword';
|
||||
public static script:string = 'script';
|
||||
public static module:string = 'module';
|
||||
public static class:string = 'class';
|
||||
public static interface:string = 'interface';
|
||||
public static type:string = 'type';
|
||||
public static enum:string = 'enum';
|
||||
public static variable:string = 'var';
|
||||
public static localVariable:string = 'local var';
|
||||
public static function:string = 'function';
|
||||
public static localFunction:string = 'local function';
|
||||
public static memberFunction:string = 'method';
|
||||
public static memberGetAccessor:string = 'getter';
|
||||
public static memberSetAccessor:string = 'setter';
|
||||
public static memberVariable:string = 'property';
|
||||
public static constructorImplementation:string = 'constructor';
|
||||
public static callSignature:string = 'call';
|
||||
public static indexSignature:string = 'index';
|
||||
public static constructSignature:string = 'construct';
|
||||
public static parameter:string = 'parameter';
|
||||
public static typeParameter:string = 'type parameter';
|
||||
public static primitiveType:string = 'primitive type';
|
||||
public static label:string = 'label';
|
||||
public static alias:string = 'alias';
|
||||
public static const:string = 'const';
|
||||
public static let:string = 'let';
|
||||
public static warning:string = 'warning';
|
||||
}
|
||||
|
||||
let outlineTypeTable: { [kind: string]: modes.SymbolKind } = Object.create(null);
|
||||
outlineTypeTable[Kind.module] = modes.SymbolKind.Module;
|
||||
outlineTypeTable[Kind.class] = modes.SymbolKind.Class;
|
||||
outlineTypeTable[Kind.enum] = modes.SymbolKind.Enum;
|
||||
outlineTypeTable[Kind.interface] = modes.SymbolKind.Interface;
|
||||
outlineTypeTable[Kind.memberFunction] = modes.SymbolKind.Method;
|
||||
outlineTypeTable[Kind.memberVariable] = modes.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.memberGetAccessor] = modes.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.memberSetAccessor] = modes.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.variable] = modes.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.const] = modes.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.localVariable] = modes.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.variable] = modes.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.function] = modes.SymbolKind.Function;
|
||||
outlineTypeTable[Kind.localFunction] = modes.SymbolKind.Function;
|
||||
|
||||
// --- formatting ----
|
||||
|
||||
class FormatAdapter extends Adapter implements modes.IFormattingSupport {
|
||||
|
|
|
@ -22,7 +22,7 @@ import {CancellationToken} from 'vs/base/common/cancellation';
|
|||
|
||||
// --- adapter
|
||||
|
||||
class OutlineAdapter implements modes.IOutlineSupport {
|
||||
class OutlineAdapter {
|
||||
|
||||
private _documents: ExtHostModelService;
|
||||
private _provider: vscode.DocumentSymbolProvider;
|
||||
|
@ -32,7 +32,7 @@ class OutlineAdapter implements modes.IOutlineSupport {
|
|||
this._provider = provider;
|
||||
}
|
||||
|
||||
getOutline(resource: URI): TPromise<modes.IOutlineEntry[]> {
|
||||
provideDocumentSymbols(resource: URI): TPromise<modes.SymbolInformation[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
|
@ -643,8 +643,8 @@ export class ExtHostLanguageFeatures {
|
|||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$getOutline(handle: number, resource: URI): TPromise<modes.IOutlineEntry[]> {
|
||||
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.getOutline(resource));
|
||||
$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]> {
|
||||
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(resource));
|
||||
}
|
||||
|
||||
// --- code lens
|
||||
|
@ -847,9 +847,9 @@ export class MainThreadLanguageFeatures {
|
|||
// --- outline
|
||||
|
||||
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
this._registrations[handle] = modes.OutlineRegistry.register(selector, <modes.IOutlineSupport>{
|
||||
getOutline: (resource: URI): TPromise<modes.IOutlineEntry[]> => {
|
||||
return this._proxy.$getOutline(handle, resource);
|
||||
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
|
||||
provideDocumentSymbols: (model:IReadOnlyModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.getAssociatedResource()));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
|
|
|
@ -15,6 +15,7 @@ import {IPosition, ISelection, IRange, IRangeWithMessage, ISingleEditOperation}
|
|||
import {IHTMLContentElement} from 'vs/base/common/htmlContent';
|
||||
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';
|
||||
import * as vscode from 'vscode';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
export interface PositionLike {
|
||||
line: number;
|
||||
|
@ -194,114 +195,27 @@ export const TextEdit = {
|
|||
}
|
||||
};
|
||||
|
||||
export namespace SymbolKind {
|
||||
|
||||
export function from(kind: number | types.SymbolKind): string {
|
||||
switch (kind) {
|
||||
case types.SymbolKind.Method:
|
||||
return 'method';
|
||||
case types.SymbolKind.Function:
|
||||
return 'function';
|
||||
case types.SymbolKind.Constructor:
|
||||
return 'constructor';
|
||||
case types.SymbolKind.Variable:
|
||||
return 'variable';
|
||||
case types.SymbolKind.Class:
|
||||
return 'class';
|
||||
case types.SymbolKind.Interface:
|
||||
return 'interface';
|
||||
case types.SymbolKind.Namespace:
|
||||
return 'namespace';
|
||||
case types.SymbolKind.Package:
|
||||
return 'package';
|
||||
case types.SymbolKind.Module:
|
||||
return 'module';
|
||||
case types.SymbolKind.Property:
|
||||
return 'property';
|
||||
case types.SymbolKind.Enum:
|
||||
return 'enum';
|
||||
case types.SymbolKind.String:
|
||||
return 'string';
|
||||
case types.SymbolKind.File:
|
||||
return 'file';
|
||||
case types.SymbolKind.Array:
|
||||
return 'array';
|
||||
case types.SymbolKind.Number:
|
||||
return 'number';
|
||||
case types.SymbolKind.Boolean:
|
||||
return 'boolean';
|
||||
case types.SymbolKind.Object:
|
||||
return 'object';
|
||||
case types.SymbolKind.Key:
|
||||
return 'key';
|
||||
case types.SymbolKind.Null:
|
||||
return 'null';
|
||||
}
|
||||
return 'property';
|
||||
}
|
||||
|
||||
export function to(type: string): types.SymbolKind {
|
||||
switch (type) {
|
||||
case 'method':
|
||||
return types.SymbolKind.Method;
|
||||
case 'function':
|
||||
return types.SymbolKind.Function;
|
||||
case 'constructor':
|
||||
return types.SymbolKind.Constructor;
|
||||
case 'variable':
|
||||
return types.SymbolKind.Variable;
|
||||
case 'class':
|
||||
return types.SymbolKind.Class;
|
||||
case 'interface':
|
||||
return types.SymbolKind.Interface;
|
||||
case 'namespace':
|
||||
return types.SymbolKind.Namespace;
|
||||
case 'package':
|
||||
return types.SymbolKind.Package;
|
||||
case 'module':
|
||||
return types.SymbolKind.Module;
|
||||
case 'property':
|
||||
return types.SymbolKind.Property;
|
||||
case 'enum':
|
||||
return types.SymbolKind.Enum;
|
||||
case 'string':
|
||||
return types.SymbolKind.String;
|
||||
case 'file':
|
||||
return types.SymbolKind.File;
|
||||
case 'array':
|
||||
return types.SymbolKind.Array;
|
||||
case 'number':
|
||||
return types.SymbolKind.Number;
|
||||
case 'boolean':
|
||||
return types.SymbolKind.Boolean;
|
||||
case 'object':
|
||||
return types.SymbolKind.Object;
|
||||
case 'key':
|
||||
return types.SymbolKind.Key;
|
||||
case 'null':
|
||||
return types.SymbolKind.Null;
|
||||
}
|
||||
return types.SymbolKind.Property;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace SymbolInformation {
|
||||
|
||||
export function fromOutlineEntry(entry: modes.IOutlineEntry): types.SymbolInformation {
|
||||
return new types.SymbolInformation(entry.label,
|
||||
SymbolKind.to(entry.type),
|
||||
toRange(entry.range),
|
||||
undefined,
|
||||
entry.containerLabel);
|
||||
export function fromOutlineEntry(entry: modes.SymbolInformation): types.SymbolInformation {
|
||||
return new types.SymbolInformation(
|
||||
entry.name,
|
||||
entry.kind,
|
||||
toRange(entry.location.range),
|
||||
entry.location.uri,
|
||||
entry.containerName
|
||||
);
|
||||
}
|
||||
|
||||
export function toOutlineEntry(symbol: vscode.SymbolInformation): modes.IOutlineEntry {
|
||||
return <modes.IOutlineEntry>{
|
||||
type: SymbolKind.from(symbol.kind),
|
||||
range: fromRange(symbol.location.range),
|
||||
containerLabel: symbol.containerName,
|
||||
label: symbol.name,
|
||||
icon: undefined,
|
||||
export function toOutlineEntry(symbol: vscode.SymbolInformation): modes.SymbolInformation {
|
||||
return <modes.SymbolInformation>{
|
||||
name: symbol.name,
|
||||
kind: symbol.kind,
|
||||
containerName: symbol.containerName,
|
||||
location: {
|
||||
uri: <URI>symbol.location.uri,
|
||||
range: fromRange(symbol.location.range)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import 'vs/css!./media/gotoSymbolHandler';
|
||||
import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import nls = require('vs/nls');
|
||||
import arrays = require('vs/base/common/arrays');
|
||||
import errors = require('vs/base/common/errors');
|
||||
import types = require('vs/base/common/types');
|
||||
import strings = require('vs/base/common/strings');
|
||||
|
@ -24,8 +23,8 @@ import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/edito
|
|||
import {IQuickOpenService} from 'vs/workbench/services/quickopen/common/quickOpenService';
|
||||
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
|
||||
import {Position} from 'vs/platform/editor/common/editor';
|
||||
import {getOutlineEntries} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {OutlineRegistry} from 'vs/editor/common/modes';
|
||||
import {getDocumentSymbols} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {DocumentSymbolProviderRegistry, SymbolInformation, SymbolKind} from 'vs/editor/common/modes';
|
||||
|
||||
export const GOTO_SYMBOL_PREFIX = '@';
|
||||
export const SCOPE_PREFIX = ':';
|
||||
|
@ -205,7 +204,7 @@ class OutlineModel extends QuickOpenModel {
|
|||
|
||||
private renderGroupLabel(type: string, count: number, outline: Outline): string {
|
||||
|
||||
let pattern = outline.outlineGroupLabel[type] || OutlineModel.getDefaultGroupLabelPatterns()[type];
|
||||
let pattern = OutlineModel.getDefaultGroupLabelPatterns()[type];
|
||||
if (pattern) {
|
||||
return strings.format(pattern, count);
|
||||
}
|
||||
|
@ -361,18 +360,7 @@ class SymbolEntry extends EditorQuickOpenEntryGroup {
|
|||
}
|
||||
|
||||
interface Outline {
|
||||
entries: OutlineNode[];
|
||||
outlineGroupLabel?: { [name: string]: string; };
|
||||
}
|
||||
|
||||
interface OutlineNode {
|
||||
label: string;
|
||||
containerLabel?: string;
|
||||
type: string;
|
||||
icon?: string;
|
||||
range: IRange;
|
||||
children?: OutlineNode[];
|
||||
parentScope?: string[];
|
||||
entries: SymbolInformation[];
|
||||
}
|
||||
|
||||
interface IEditorLineDecoration {
|
||||
|
@ -439,7 +427,7 @@ export class GotoSymbolHandler extends QuickOpenHandler {
|
|||
}
|
||||
|
||||
if (model && types.isFunction((<ITokenizedModel>model).getMode)) {
|
||||
canRun = OutlineRegistry.has(<IModel>model);
|
||||
canRun = DocumentSymbolProviderRegistry.has(<IModel>model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,54 +448,24 @@ export class GotoSymbolHandler extends QuickOpenHandler {
|
|||
};
|
||||
}
|
||||
|
||||
private toQuickOpenEntries(outline: Outline): SymbolEntry[] {
|
||||
private toQuickOpenEntries(flattened: SymbolInformation[]): SymbolEntry[] {
|
||||
let results: SymbolEntry[] = [];
|
||||
|
||||
// Flatten
|
||||
let flattened: OutlineNode[] = [];
|
||||
if (outline) {
|
||||
this.flatten(outline.entries, flattened);
|
||||
}
|
||||
|
||||
for (let i = 0; i < flattened.length; i++) {
|
||||
let element = flattened[i];
|
||||
let label = strings.trim(element.label);
|
||||
let label = strings.trim(element.name);
|
||||
|
||||
// Show parent scope as description
|
||||
let description: string = element.containerLabel;
|
||||
if (element.parentScope) {
|
||||
description = arrays.tail(element.parentScope);
|
||||
}
|
||||
let description: string = element.containerName;
|
||||
|
||||
// Add
|
||||
let icon = element.icon || element.type;
|
||||
results.push(new SymbolEntry(i, label, element.type, description, icon, element.range, null, this.editorService, this));
|
||||
let icon = SymbolKind.from(element.kind);
|
||||
results.push(new SymbolEntry(i, label, SymbolKind.from(element.kind), description, icon, element.location.range, null, this.editorService, this));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private flatten(outline: OutlineNode[], flattened: OutlineNode[], parentScope?: string[]): void {
|
||||
for (let i = 0; i < outline.length; i++) {
|
||||
let element = outline[i];
|
||||
flattened.push(element);
|
||||
|
||||
if (parentScope) {
|
||||
element.parentScope = parentScope;
|
||||
}
|
||||
|
||||
if (element.children) {
|
||||
let elementScope: string[] = [];
|
||||
if (parentScope) {
|
||||
elementScope = parentScope.slice(0);
|
||||
}
|
||||
elementScope.push(element.label);
|
||||
|
||||
this.flatten(element.children, flattened, elementScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getActiveOutline(): TPromise<OutlineModel> {
|
||||
if (!this.activeOutlineRequest) {
|
||||
this.activeOutlineRequest = this.doGetActiveOutline();
|
||||
|
@ -533,9 +491,9 @@ export class GotoSymbolHandler extends QuickOpenHandler {
|
|||
return TPromise.as(this.outlineToModelCache[modelId]);
|
||||
}
|
||||
|
||||
return getOutlineEntries(<IModel>model).then(outline => {
|
||||
return getDocumentSymbols(<IModel>model).then(outline => {
|
||||
|
||||
let model = new OutlineModel(outline, this.toQuickOpenEntries(outline));
|
||||
let model = new OutlineModel(outline, this.toQuickOpenEntries(outline.entries));
|
||||
|
||||
this.outlineToModelCache = {}; // Clear cache, only keep 1 outline
|
||||
this.outlineToModelCache[modelId] = model;
|
||||
|
|
|
@ -21,8 +21,8 @@ import {IThreadService} from 'vs/platform/thread/common/thread';
|
|||
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/node/extHostCommands';
|
||||
import {ExtHostModelService} from 'vs/workbench/api/node/extHostDocuments';
|
||||
import {getOutlineEntries} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {OutlineRegistry, DocumentHighlightKind} from 'vs/editor/common/modes';
|
||||
import {getDocumentSymbols} from 'vs/editor/contrib/quickOpen/common/quickOpen';
|
||||
import {DocumentSymbolProviderRegistry, DocumentHighlightKind} from 'vs/editor/common/modes';
|
||||
import {getCodeLensData} from 'vs/editor/contrib/codelens/common/codelens';
|
||||
import {getDeclarationsAtPosition} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
|
||||
import {provideHover} from 'vs/editor/contrib/hover/common/hover';
|
||||
|
@ -105,7 +105,7 @@ suite('ExtHostLanguageFeatures', function() {
|
|||
// --- outline
|
||||
|
||||
test('DocumentSymbols, register/deregister', function() {
|
||||
assert.equal(OutlineRegistry.all(model).length, 0);
|
||||
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 0);
|
||||
let d1 = extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
|
||||
provideDocumentSymbols() {
|
||||
return [];
|
||||
|
@ -113,7 +113,7 @@ suite('ExtHostLanguageFeatures', function() {
|
|||
});
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
assert.equal(OutlineRegistry.all(model).length, 1);
|
||||
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 1);
|
||||
d1.dispose();
|
||||
return threadService.sync();
|
||||
});
|
||||
|
@ -134,7 +134,7 @@ suite('ExtHostLanguageFeatures', function() {
|
|||
|
||||
return threadService.sync().then(() => {
|
||||
|
||||
return getOutlineEntries(model).then(value => {
|
||||
return getDocumentSymbols(model).then(value => {
|
||||
assert.equal(value.entries.length, 1);
|
||||
});
|
||||
});
|
||||
|
@ -149,12 +149,12 @@ suite('ExtHostLanguageFeatures', function() {
|
|||
|
||||
return threadService.sync().then(() => {
|
||||
|
||||
return getOutlineEntries(model).then(value => {
|
||||
return getDocumentSymbols(model).then(value => {
|
||||
assert.equal(value.entries.length, 1);
|
||||
|
||||
let entry = value.entries[0];
|
||||
assert.equal(entry.label, 'test');
|
||||
assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });
|
||||
assert.equal(entry.name, 'test');
|
||||
assert.deepEqual(entry.location.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue