From 2fbc328d86d40a738d1556e30b92df27b39ce0ab Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 8 May 2018 09:02:08 +0200 Subject: [PATCH] outline baby steps --- build/lib/i18n.resources.json | 4 + .../electron-browser/media/Constant_16x.svg | 1 + .../media/Constant_16x_inverse.svg | 1 + .../electron-browser/media/EnumItem_16x.svg | 1 + .../media/EnumItem_inverse_16x.svg | 1 + .../media/Event_16x_vscode.svg | 1 + .../media/Event_16x_vscode_inverse.svg | 1 + .../media/Operator_16x_vscode.svg | 1 + .../media/Operator_16x_vscode_inverse.svg | 1 + .../media/Structure_16x_vscode.svg | 1 + .../media/Structure_16x_vscode_inverse.svg | 1 + .../media/Template_16x_vscode.svg | 1 + .../media/Template_16x_vscode_inverse.svg | 1 + .../electron-browser/media/outline.css | 160 ++++++++++++++++++ .../electron-browser/media/symbol-sprite.svg | 1 + .../electron-browser/outline.contribution.ts | 21 +++ .../outline/electron-browser/outlineModel.ts | 64 +++++++ .../outline/electron-browser/outlinePanel.ts | 124 ++++++++++++++ .../outline/electron-browser/outlineTree.ts | 89 ++++++++++ src/vs/workbench/workbench.main.ts | 2 + 20 files changed, 477 insertions(+) create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Constant_16x.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Constant_16x_inverse.svg create mode 100755 src/vs/workbench/parts/outline/electron-browser/media/EnumItem_16x.svg create mode 100755 src/vs/workbench/parts/outline/electron-browser/media/EnumItem_inverse_16x.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode_inverse.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode_inverse.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode_inverse.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode_inverse.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/outline.css create mode 100644 src/vs/workbench/parts/outline/electron-browser/media/symbol-sprite.svg create mode 100644 src/vs/workbench/parts/outline/electron-browser/outline.contribution.ts create mode 100644 src/vs/workbench/parts/outline/electron-browser/outlineModel.ts create mode 100644 src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts create mode 100644 src/vs/workbench/parts/outline/electron-browser/outlineTree.ts diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 0c22b17f5ef..336995ff70b 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -146,6 +146,10 @@ "name": "vs/workbench/parts/welcome", "project": "vscode-workbench" }, + { + "name": "vs/workbench/parts/outline", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/actions", "project": "vscode-workbench" diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x.svg b/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x.svg new file mode 100644 index 00000000000..ed2a1751005 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x_inverse.svg b/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x_inverse.svg new file mode 100644 index 00000000000..173e427f964 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Constant_16x_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_16x.svg b/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_16x.svg new file mode 100755 index 00000000000..aa901ec1934 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_inverse_16x.svg b/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_inverse_16x.svg new file mode 100755 index 00000000000..791759092fc --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/EnumItem_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode.svg b/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode.svg new file mode 100644 index 00000000000..0e202ec10be --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode_inverse.svg b/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode_inverse.svg new file mode 100644 index 00000000000..a508edcd3d6 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Event_16x_vscode_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode.svg b/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode.svg new file mode 100644 index 00000000000..ba2f2d091cf --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode_inverse.svg b/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode_inverse.svg new file mode 100644 index 00000000000..21e1e814b2e --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Operator_16x_vscode_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode.svg b/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode.svg new file mode 100644 index 00000000000..e776cbc5651 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode_inverse.svg b/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode_inverse.svg new file mode 100644 index 00000000000..1b76b62be9a --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Structure_16x_vscode_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode.svg b/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode.svg new file mode 100644 index 00000000000..788cc8d6450 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode_inverse.svg b/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode_inverse.svg new file mode 100644 index 00000000000..6cec71cb033 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/Template_16x_vscode_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/media/outline.css b/src/vs/workbench/parts/outline/electron-browser/media/outline.css new file mode 100644 index 00000000000..e505caeea5a --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/outline.css @@ -0,0 +1,160 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .outline-item .icon { + display: inline-block; + height: 16px; + width: 16px; +} + +.monaco-workbench .outline-item .icon.constant { + background-image: url('Constant_16x.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.constant, +.hc-black .monaco-workbench .outline-item .icon.constant { + background-image: url('Constant_16x_inverse.svg'); +} + +.monaco-workbench .outline-item .icon.enum-member { + background-image: url('EnumItem_16x.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.enum-member, +.hc-black .monaco-workbench .outline-item .icon.enum-member { + background-image: url('EnumItem_inverse_16x.svg'); +} + +.monaco-workbench .outline-item .icon.struct { + background-image: url('Structure_16x_vscode.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.struct, +.hc-black .monaco-workbench .outline-item .icon.struct { + background-image: url('Structure_16x_vscode_inverse.svg'); +} + +.monaco-workbench .outline-item .icon.event { + background-image: url('Event_16x_vscode.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.event, +.hc-black .monaco-workbench .outline-item .icon.event { + background-image: url('Event_16x_vscode_inverse.svg'); +} + +.monaco-workbench .outline-item .icon.operator { + background-image: url('Operator_16x_vscode.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.operator, +.hc-black .monaco-workbench .outline-item .icon.operator { + background-image: url('Operator_16x_vscode_inverse.svg'); +} + +.monaco-workbench .outline-item .icon.type-parameter { + background-image: url('Template_16x_vscode.svg'); + background-repeat: no-repeat; + background-position: 0 -2px; +} +.vs-dark .monaco-workbench .outline-item .icon.type-parameter, +.hc-black .monaco-workbench .outline-item .icon.type-parameter { + background-image: url('Template_16x_vscode_inverse.svg'); +} + +.monaco-workbench .outline-item .icon.method, +.monaco-workbench .outline-item .icon.function, +.monaco-workbench .outline-item .icon.constructor, +.monaco-workbench .outline-item .icon.field, +.monaco-workbench .outline-item .icon.variable, +.monaco-workbench .outline-item .icon.class, +.monaco-workbench .outline-item .icon.interface, +.monaco-workbench .outline-item .icon.object, +.monaco-workbench .outline-item .icon.namespace, +.monaco-workbench .outline-item .icon.package, +.monaco-workbench .outline-item .icon.module, +.monaco-workbench .outline-item .icon.property, +.monaco-workbench .outline-item .icon.enum, +.monaco-workbench .outline-item .icon.key, +.monaco-workbench .outline-item .icon.string, +.monaco-workbench .outline-item .icon.rule, +.monaco-workbench .outline-item .icon.file, +.monaco-workbench .outline-item .icon.array, +.monaco-workbench .outline-item .icon.number, +.monaco-workbench .outline-item .icon.null, +.monaco-workbench .outline-item .icon.boolean { + background-image: url('symbol-sprite.svg'); + background-repeat: no-repeat; +} + +.vs .monaco-workbench .outline-item .icon.method, +.vs .monaco-workbench .outline-item .icon.function, +.vs .monaco-workbench .outline-item .icon.constructor { background-position: 0 -4px; } +.vs .monaco-workbench .outline-item .icon.field, +.vs .monaco-workbench .outline-item .icon.variable { background-position: -22px -4px; } +.vs .monaco-workbench .outline-item .icon.class { background-position: -43px -3px; } +.vs .monaco-workbench .outline-item .icon.interface { background-position: -63px -4px; } +.vs .monaco-workbench .outline-item .icon.object, +.vs .monaco-workbench .outline-item .icon.namespace, +.vs .monaco-workbench .outline-item .icon.package, +.vs .monaco-workbench .outline-item .icon.module { background-position: -82px -4px; } +.vs .monaco-workbench .outline-item .icon.property { background-position: -102px -3px; } +.vs .monaco-workbench .outline-item .icon.enum { background-position: -122px -3px; } +.vs .monaco-workbench .outline-item .icon.key, +.vs .monaco-workbench .outline-item .icon.string { background-position: -202px -3px; } +.vs .monaco-workbench .outline-item .icon.rule { background-position: -242px -4px; } +.vs .monaco-workbench .outline-item .icon.file { background-position: -262px -4px; } +.vs .monaco-workbench .outline-item .icon.array { background-position: -302px -4px; } +.vs .monaco-workbench .outline-item .icon.number { background-position: -322px -4px; } +.vs .monaco-workbench .outline-item .icon.null, +.vs .monaco-workbench .outline-item .icon.boolean { background-position: -343px -4px; } + +.vs-dark .monaco-workbench .outline-item .icon.method, +.vs-dark .monaco-workbench .outline-item .icon.function, +.vs-dark .monaco-workbench .outline-item .icon.constructor, +.hc-black .monaco-workbench .outline-item .icon.method, +.hc-black .monaco-workbench .outline-item .icon.function, +.hc-black .monaco-workbench .outline-item .icon.constructor { background-position: 0 -24px; } +.vs-dark .monaco-workbench .outline-item .icon.field, +.hc-black .monaco-workbench .outline-item .icon.field, +.vs-dark .monaco-workbench .outline-item .icon.variable, +.hc-black .monaco-workbench .outline-item .icon.variable { background-position: -22px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.class, +.hc-black .monaco-workbench .outline-item .icon.class { background-position: -43px -23px; } +.vs-dark .monaco-workbench .outline-item .icon.interface, +.hc-black .monaco-workbench .outline-item .icon.interface { background-position: -63px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.object, +.vs-dark .monaco-workbench .outline-item .icon.namespace, +.vs-dark .monaco-workbench .outline-item .icon.package, +.vs-dark .monaco-workbench .outline-item .icon.module, +.hc-black .monaco-workbench .outline-item .icon.object, +.hc-black .monaco-workbench .outline-item .icon.namespace, +.hc-black .monaco-workbench .outline-item .icon.package, +.hc-black .monaco-workbench .outline-item .icon.module { background-position: -82px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.property, +.hc-black .monaco-workbench .outline-item .icon.property { background-position: -102px -23px; } +.vs-dark .monaco-workbench .outline-item .icon.key, +.vs-dark .monaco-workbench .outline-item .icon.string, +.hc-black .monaco-workbench .outline-item .icon.key, +.hc-black .monaco-workbench .outline-item .icon.string { background-position: -202px -23px; } +.vs-dark .monaco-workbench .outline-item .icon.enum, +.hc-black .monaco-workbench .outline-item .icon.enum { background-position: -122px -23px; } +.vs-dark .monaco-workbench .outline-item .icon.rule, +.hc-black .monaco-workbench .outline-item .icon.rule { background-position: -242px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.file, +.hc-black .monaco-workbench .outline-item .icon.file { background-position: -262px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.array, +.hc-black .monaco-workbench .outline-item .icon.array { background-position: -302px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.number, +.hc-black .monaco-workbench .outline-item .icon.number { background-position: -322px -24px; } +.vs-dark .monaco-workbench .outline-item .icon.null, +.vs-dark .monaco-workbench .outline-item .icon.boolean, +.hc-black .monaco-workbench .outline-item .icon.null, +.hc-black .monaco-workbench .outline-item .icon.boolean { background-position: -342px -24px; } diff --git a/src/vs/workbench/parts/outline/electron-browser/media/symbol-sprite.svg b/src/vs/workbench/parts/outline/electron-browser/media/symbol-sprite.svg new file mode 100644 index 00000000000..ee9a63dcf6f --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/media/symbol-sprite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/outline/electron-browser/outline.contribution.ts b/src/vs/workbench/parts/outline/electron-browser/outline.contribution.ts new file mode 100644 index 00000000000..15cc238353f --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/outline.contribution.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { localize } from 'vs/nls'; +import { ViewsRegistry, ViewLocation } from 'vs/workbench/common/views'; +import { OutlinePanel } from './outlinePanel'; + +// get outline tree (per extension...) + +// sorting by range, name, type + +ViewsRegistry.registerViews([{ + id: 'code.outline', + name: localize('name', "Outline"), + ctor: OutlinePanel, + location: ViewLocation.Explorer, + canToggleVisibility: true +}]); diff --git a/src/vs/workbench/parts/outline/electron-browser/outlineModel.ts b/src/vs/workbench/parts/outline/electron-browser/outlineModel.ts new file mode 100644 index 00000000000..d656f58fc93 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/outlineModel.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { DocumentSymbolProviderRegistry, SymbolInformation } from 'vs/editor/common/modes'; +import { ITextModel } from '../../../../editor/common/model'; +import { asWinJsPromise } from '../../../../base/common/async'; +import { TPromise } from 'vs/base/common/winjs.base'; + +export function getOutline(model: ITextModel): TPromise { + let outlines = new Array(); + let promises = DocumentSymbolProviderRegistry.ordered(model).map((provider, i) => { + return asWinJsPromise(token => provider.provideDocumentSymbols(model, token)).then(result => { + let items = new Array(); + let source = `provider${i}`; + for (const item of result) { + OutlineItem.convert(items, item, undefined); + } + outlines.push(new OneOutline(source, items)); + }, err => { + // + }); + }); + return TPromise.join(promises).then(() => outlines); +} + +export class OutlineItem { + + static convert(bucket: OutlineItem[], info: SymbolInformation, parent: OutlineItem): void { + let res = new OutlineItem( + `${info.name}/${parent ? parent.id : ''}`, + info, + parent, + [] + ); + if (info.children) { + for (const child of info.children) { + OutlineItem.convert(res.children, child, res); + } + } + bucket.push(res); + } + + constructor( + readonly id: string, + readonly symbol: SymbolInformation, + readonly parent: OutlineItem, + readonly children: OutlineItem[], + ) { + // + } +} + +export class OneOutline { + + constructor( + readonly source: string, + readonly items: OutlineItem[] + ) { + // + } +} diff --git a/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts b/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts new file mode 100644 index 00000000000..943b3700769 --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts @@ -0,0 +1,124 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser'; +import { DocumentSymbolProviderRegistry } from 'vs/editor/common/modes'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { WorkbenchTree } from 'vs/platform/list/browser/listService'; +import { IViewOptions, ViewsViewletPanel } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { getOutline, OneOutline } from './outlineModel'; +import { OutlineDataSource, OutlineRenderer, OutlineSorter } from './outlineTree'; + +class OutlineRequestLogic { + + private readonly _disposables = new Array(); + private readonly _onDidChangeActiveEditor = new Emitter(); + + private _editorListener: IDisposable; + + readonly onDidChangeActiveEditor: Event = this._onDidChangeActiveEditor.event; + + constructor( + @IEditorGroupService editorGroupService: IEditorGroupService, + @IWorkbenchEditorService private readonly _workbenchEditorService: IWorkbenchEditorService, + ) { + editorGroupService.onEditorsChanged(this._update, this, this._disposables); + DocumentSymbolProviderRegistry.onDidChange(this._update, this, this._disposables); + } + + dispose(): void { + dispose(this._disposables); + } + + private _update(): void { + dispose(this._editorListener); + let editor = this._workbenchEditorService.getActiveEditor(); + let control = editor && editor.getControl(); + let codeEditor: ICodeEditor = undefined; + if (isCodeEditor(control)) { + codeEditor = control; + } else if (isDiffEditor(control)) { + codeEditor = control.getModifiedEditor(); + } + this._editorListener = codeEditor && codeEditor.onDidChangeModelContent(e => this._onDidChangeActiveEditor.fire(codeEditor)); + this._onDidChangeActiveEditor.fire(codeEditor); + } +} + +export class OutlinePanel extends ViewsViewletPanel { + + private readonly _disposables = new Array(); + private readonly _activeEditorOracle: OutlineRequestLogic; + + private _tree: Tree; + + constructor( + options: IViewOptions, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IKeybindingService keybindingService: IKeybindingService, + @IContextMenuService contextMenuService: IContextMenuService, + @IConfigurationService configurationService: IConfigurationService + ) { + super(options, keybindingService, contextMenuService, configurationService); + + this._activeEditorOracle = _instantiationService.createInstance(OutlineRequestLogic); + this._disposables.push(this._activeEditorOracle.onDidChangeActiveEditor(editor => { + if (editor) { + getOutline(editor.getModel()).then(outline => { + let model = this._tree.getInput(); + let [first] = outline; + if (first) { + if (model instanceof OneOutline && first.source === model.source) { + model.items.splice(0, model.items.length, ...first.items); + this._tree.refresh(undefined, true); + } else { + this._tree.setInput(first); + } + } + }, err => { + console.error(err); + }); + } + })); + this._disposables.push(this._activeEditorOracle); + } + + dispose(): void { + dispose(this._disposables); + super.dispose(); + } + + protected renderBody(container: HTMLElement): void { + const dataSource = new OutlineDataSource(); + const renderer = new OutlineRenderer(); + const sorter = new OutlineSorter(); + + this._tree = this._instantiationService.createInstance( + WorkbenchTree, + container, + { dataSource, renderer, sorter }, + {} + ); + this._disposables.push(this._tree); + } + + protected layoutBody(height: number): void { + this._tree.layout(height); + } + + setVisible(visible: boolean): TPromise { + return super.setVisible(visible); + } +} diff --git a/src/vs/workbench/parts/outline/electron-browser/outlineTree.ts b/src/vs/workbench/parts/outline/electron-browser/outlineTree.ts new file mode 100644 index 00000000000..b7cb94a113b --- /dev/null +++ b/src/vs/workbench/parts/outline/electron-browser/outlineTree.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import 'vs/css!./media/outline'; +import { TPromise } from 'vs/base/common/winjs.base'; +import * as dom from 'vs/base/browser/dom'; +import { symbolKindToCssClass } from 'vs/editor/common/modes'; +import { Range } from 'vs/editor/common/core/range'; +import { IDataSource, IRenderer, ITree, ISorter } from 'vs/base/parts/tree/browser/tree'; +import { OneOutline, OutlineItem } from './outlineModel'; + +export class OutlineSorter implements ISorter { + compare(tree: ITree, a: any, b: any): number { + return Range.compareRangesUsingStarts((a).symbol.location.range, (b).symbol.location.range); + } +} + +export class OutlineDataSource implements IDataSource { + + getId(tree: ITree, element: OneOutline | OutlineItem): string { + if (element instanceof OneOutline) { + return element.source; + } else { + return element.id; + } + } + + hasChildren(tree: ITree, element: OneOutline | OutlineItem): boolean { + if (element instanceof OneOutline) { + return element.items.length > 0; + } else { + return element.children.length > 0; + } + } + + async getChildren(tree: ITree, element: OneOutline | OutlineItem): TPromise { + if (element instanceof OneOutline) { + return element.items; + } else { + return element.children; + } + } + + getParent(tree: ITree, element: any): TPromise { + return null; + } +} + +export class OutlineItemTemplate { + + readonly icon: HTMLSpanElement; + readonly label: HTMLSpanElement; + readonly detail: HTMLSpanElement; + + constructor(container: HTMLElement) { + this.icon = document.createElement('span'); + this.label = document.createElement('span'); + this.detail = document.createElement('span'); + container.appendChild(this.icon); + container.appendChild(this.label); + container.appendChild(this.detail); + dom.addClass(this.icon, 'icon'); + dom.addClass(this.label, 'label'); + dom.addClass(this.detail, 'detail'); + dom.addClass(container, 'outline-item'); + } +} + +export class OutlineRenderer implements IRenderer { + getHeight(tree: ITree, element: any): number { + return 22; + } + getTemplateId(tree: ITree, element: any): string { + return 'outline.element'; + } + renderTemplate(tree: ITree, templateId: string, container: HTMLElement) { + return new OutlineItemTemplate(container); + } + renderElement(tree: ITree, element: any, templateId: string, template: OutlineItemTemplate): void { + template.icon.classList.add(symbolKindToCssClass((element).symbol.kind)); + template.label.innerText = (element).symbol.name; + } + disposeTemplate(tree: ITree, templateId: string, templateData: OutlineItemTemplate): void { + //todo@joh + } +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 78ae4f9f1ea..3348e0c8088 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -132,5 +132,7 @@ import 'vs/workbench/parts/watermark/electron-browser/watermark'; import 'vs/workbench/parts/welcome/overlay/browser/welcomeOverlay'; +import 'vs/workbench/parts/outline/electron-browser/outline.contribution'; + // services import 'vs/workbench/services/bulkEdit/electron-browser/bulkEditService';