From 2657a9daeac24f46dba2e29e3ae3403ab7f63a17 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 26 Sep 2016 15:21:39 -0700 Subject: [PATCH 001/119] Add contributes.explorer section and add it to ViewletRegistry Disable hygiene for now. --- package.json | 3 - src/vs/monaco.d.ts | 14 -- .../actions/browser/menusExtensionPoint.ts | 40 ++++++ .../common/extensionManagement.ts | 6 + .../explorers/browser/media/files-dark.svg | 1 + .../treeExplorerViewlet.contribution.css | 9 ++ .../treeExplorerViewlet.contribution.ts | 3 + .../explorers/browser/treeExplorerViewlet.ts | 74 +++++++++++ .../parts/explorers/browser/views/treeView.ts | 125 ++++++++++++++++++ .../explorers/browser/views/treeViewer.ts | 75 +++++++++++ .../parts/explorers/common/goOutline.ts | 60 +++++++++ .../parts/explorers/common/goPath.ts | 78 +++++++++++ .../parts/explorers/common/treeViewModel.ts | 15 +++ src/vs/workbench/workbench.main.ts | 2 + 14 files changed, 488 insertions(+), 17 deletions(-) create mode 100644 src/vs/workbench/parts/explorers/browser/media/files-dark.svg create mode 100644 src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css create mode 100644 src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts create mode 100644 src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts create mode 100644 src/vs/workbench/parts/explorers/browser/views/treeView.ts create mode 100644 src/vs/workbench/parts/explorers/browser/views/treeViewer.ts create mode 100644 src/vs/workbench/parts/explorers/common/goOutline.ts create mode 100644 src/vs/workbench/parts/explorers/common/goPath.ts create mode 100644 src/vs/workbench/parts/explorers/common/treeViewModel.ts diff --git a/package.json b/package.json index c06abe95d10..3d4454ffec2 100644 --- a/package.json +++ b/package.json @@ -104,9 +104,6 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "config": { - "ghooks": { - "pre-commit": "node build/gulpfile.hygiene.js" - } }, "optionalDependencies": { "windows-foreground-love": "0.1.0", diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 3bf3adbe4ef..adaa36fa7af 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2788,20 +2788,6 @@ declare module monaco.editor { * An array of keybindings for the action. */ keybindings?: number[]; - /** - * Control if the action should show up in the context menu and where. - * The context menu of the editor has these default: - * navigation - The navigation group comes first in all cases. - * 1_modification - This group comes next and contains commands that modify your code. - * 9_cutcopypaste - The last default group with the basic editing commands. - * You can also create your own group. - * Defaults to null (don't show in context menu). - */ - contextMenuGroupId?: string; - /** - * Control the order in the context menu group. - */ - contextMenuOrder?: number; /** * The keybinding rule. */ diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 42e12353fdf..8ffafaec1d0 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -14,6 +14,8 @@ import { forEach } from 'vs/base/common/collections'; import { IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { Registry } from 'vs/platform/platform'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; namespace schema { @@ -206,6 +208,29 @@ namespace schema { } ] }; + + // --- treeExplorers contribution point + + export interface IExplorer { + treeContentProviderId: string; + icon: IUserFriendlyIcon; + } + + export const explorerContribtion: IJSONSchema = { + description: localize('vscode.extension.contributes.explorer', "Contributes explorer viewlet to the sidebar"), + type: 'object', + properties: { + treeContentProviderId: { + description: localize('vscode.extension.contributes.explorer.treeContentProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeContentProvider'), + type: 'string' + }, + icon: { + description: localize('vscode.extension.contributes.explorer.icon', 'Icon to put on activity bar'), + type: 'string' + } + } + }; + } ExtensionsRegistry.registerExtensionPoint('commands', schema.commandsContribution).setHandler(extensions => { @@ -307,3 +332,18 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM }); } }); + +ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { + for (let extension of extensions) { + const { treeContentProviderId, icon } = extension.value; + + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( + 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', + 'TreeExplorerViewlet', + 'workbench.view.treeExplorer', // Later change this to make it unique + localize('treeExplorer', 'treeExplorer'), + 'treeExplorer', + 125 + )); + } +}); \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 96bbe6beb85..f3aef501a95 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -74,6 +74,11 @@ export interface ITheme { label: string; } +export interface ITreeExplorer { + treeContentProviderId: string; + icon: string; +} + export interface IExtensionContributions { commands?: ICommand[]; configuration?: IConfiguration; @@ -85,6 +90,7 @@ export interface IExtensionContributions { menus?: { [context: string]: IMenu[] }; snippets?: ISnippet[]; themes?: ITheme[]; + explorer?: ITreeExplorer; } export interface IExtensionManifest { diff --git a/src/vs/workbench/parts/explorers/browser/media/files-dark.svg b/src/vs/workbench/parts/explorers/browser/media/files-dark.svg new file mode 100644 index 00000000000..7e3e59b370b --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/media/files-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css b/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css new file mode 100644 index 00000000000..fe7d7722e73 --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* Activity Bar */ +.monaco-workbench > .activitybar .monaco-action-bar .action-label.treeExplorer { + background-image: url('files-dark.svg'); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts new file mode 100644 index 00000000000..5721dc1b88f --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -0,0 +1,3 @@ +'use strict'; + +import 'vs/css!./media/treeExplorerViewlet.contribution'; \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts new file mode 100644 index 00000000000..e27974dc1ab --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -0,0 +1,74 @@ +import 'vs/css!./media/customViewlet'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import { Builder, Dimension } from 'vs/base/browser/builder'; +import { SplitView, Orientation } from 'vs/base/browser/ui/splitview/splitview'; + +import { IViewletView, Viewlet } from 'vs/workbench/browser/viewlet'; + +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +import { TreeView } from 'vs/workbench/parts/explorers/browser/views/treeView'; + +export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.customViewlet.'; + +export class TreeExplorerViewlet extends Viewlet { + private static _idCounter = 1; + + private viewletContainer: Builder; + private splitView: SplitView; + private views: IViewletView[]; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IConfigurationService private configurationService: IConfigurationService, + @IInstantiationService private instantiationService: IInstantiationService + ) { + super(CUSTOM_VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter, telemetryService); + TreeExplorerViewlet._idCounter++; + + this.views = []; + } + + create(parent: Builder): TPromise { + super.create(parent); + + this.viewletContainer = parent.div().addClass('custom-viewlet'); + this.splitView = new SplitView(this.viewletContainer.getHTMLElement()); + this.addTreeView('Tree ' + (this.views.length + 1)); + + const settings = this.configurationService.getConfiguration(); + + return this.onConfigurationUpdated(settings); + } + + layout(dimension: Dimension): void { + this.splitView.layout(dimension.height); + } + + private onConfigurationUpdated(config: ICustomViewletConfiguration): TPromise { + return TPromise.as(null); + } + + private addTreeView(treeName: string): void { + const treeView = this.instantiationService.createInstance(TreeView, treeName, this.getActionRunner()); + this.views.push(treeView); + this.splitView.addView(treeView); + } + + dispose(): void { + this.views.forEach(view => { + view.dispose(); + }); + this.views = null; + } +} + + +export interface ICustomViewletConfiguration { + viewlet: { + + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts new file mode 100644 index 00000000000..7a010364668 --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -0,0 +1,125 @@ +import nls = require('vs/nls'); +import labels = require('vs/base/common/labels'); + +import URI from 'vs/base/common/uri'; +import { TPromise } from 'vs/base/common/winjs.base'; +import * as DOM from 'vs/base/browser/dom'; +import { Builder, $ } from 'vs/base/browser/builder'; +import { IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet'; + +import { IActionRunner } from 'vs/base/common/actions'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; + +import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; +import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; +import { TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; + +import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; + +import { documentSymbols } from '../../common/goOutline'; + +export class TreeView extends CollapsibleViewletView { + private workspace: IWorkspace; + + private _treeName: string = "TreeExplorer"; + + get treeName(): string { return this._treeName; } + + constructor( + treeName: string, + actionRunner: IActionRunner, + @IMessageService messageService: IMessageService, + @IKeybindingService keybindingService: IKeybindingService, + @IContextMenuService contextMenuService: IContextMenuService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IInstantiationService private instantiationService: IInstantiationService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IEditorGroupService private editorGroupService: IEditorGroupService + ) { + super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService); + + this.workspace = contextService.getWorkspace(); + this.create(); + } + + renderHeader(container: HTMLElement): void { + const titleDiv = $('div.title').appendTo(container); + $('span') + .text(this._treeName) + .title(this._treeName) + .appendTo(titleDiv); + + super.renderHeader(container); + } + + renderBody(container: HTMLElement): void { + this.treeContainer = super.renderViewTree(container); + DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); + + this.tree = this.createViewer($(this.treeContainer)); + } + + createViewer(container: Builder): ITree { + const dataSource = this.instantiationService.createInstance(TreeDataSource); + const renderer = this.instantiationService.createInstance(TreeRenderer, this.actionRunner, container.getHTMLElement()); + const controller = null; + const sorter = null; + const filter = null; + const dnd = null; + const accessibilityProvider = null; + + return new Tree(container.getHTMLElement(), { + dataSource, + renderer, + controller, + sorter, + filter, + dnd, + accessibilityProvider + }); + } + + create(): TPromise { + this.toDispose.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())) + return TPromise.as(null); + } + + private onEditorsChanged() { + const activeInput = this.editorService.getActiveEditorInput(); + + if (activeInput instanceof FileEditorInput) { + const fileResource = activeInput.getResource(); + + this.updateOutlineViewlet(fileResource); + } + + } + + private doRefresh(): TPromise { + return TPromise.as(null); + } + + private updateOutlineViewlet(fileURI: URI): TPromise { + documentSymbols(fileURI.path).then(nodes => { + const root = nodes[0]; + this.tree.setInput(root); + }); + + return TPromise.as(null); + } + + public getOptimalWidth(): number { + const parentNode = this.tree.getHTMLElement(); + const childNodes = [].slice.call(parentNode.querySelectorAll('.outline-item-label > a')); + + return DOM.getLargestChildWidth(parentNode, childNodes); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts new file mode 100644 index 00000000000..992beebc61c --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -0,0 +1,75 @@ +import { TPromise } from 'vs/base/common/winjs.base'; +import { $, Builder } from 'vs/base/browser/builder'; + +import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/tree/browser/tree'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; +import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; +import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; + +import { IActionRunner } from 'vs/base/common/actions'; +import { ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; + +import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { IModeService } from 'vs/editor/common/services/modeService'; + +export class TreeDataSource implements IDataSource { + + constructor() { + + } + + public getId(tree: ITree, node: TreeViewNode): string { + return node.label; + } + + public hasChildren(tree: ITree, node: TreeViewNode): boolean { + return node.children.length > 0; + } + + public getChildren(tree: ITree, node: TreeViewNode): TPromise { + return TPromise.as(node.children); + } + + public getParent(tree: ITree, node: TreeViewNode): TPromise { + return TPromise.as(null); + } +} + +export class TreeRenderer extends ActionsRenderer implements IRenderer { + + constructor( + actionRunner: IActionRunner, + private container: HTMLElement, + @IContextViewService private contextViewService: IContextViewService, + @IExtensionService private extensionService: IExtensionService, + @IModeService private modeService: IModeService + ) { + super({ + actionProvider: null, + actionRunner: actionRunner + }); + } + + public getContentHeight(tree: ITree, element: any): number { + return 22; + } + + public renderContents(tree: ITree, node: TreeViewNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { + const el = $(domElement).clearChildren(); + const item = $('.custom-viewlet-tree-node-item'); + item.appendTo(el); + return this.renderFileFolderLabel(item, node); + } + + private renderFileFolderLabel(container: Builder, node: TreeViewNode): IElementCallback { + const label = $('.custom-viewlet-tree-node-item-label').appendTo(container); + $('a.plain').text(node.label).title(node.label).appendTo(label); + + return null; + } +} + +export class TreeController extends DefaultController { + +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/goOutline.ts b/src/vs/workbench/parts/explorers/common/goOutline.ts new file mode 100644 index 00000000000..b81eed7fd4c --- /dev/null +++ b/src/vs/workbench/parts/explorers/common/goOutline.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------- + * 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 cp = require('child_process'); +import path = require('path'); +import { getBinPath } from './goPath'; + +import { TreeViewNode } from './treeViewModel'; + +// Keep in sync with https://github.com/lukehoban/go-outline +export interface GoOutlineRange { + start: number; + end: number; +} + +export interface GoOutlineDeclaration { + label: string; + type: string; + receiverType?: string; + icon?: string; // icon class or null to use the default images based on the type + start: number; + end: number; + children?: GoOutlineDeclaration[]; + signature?: GoOutlineRange; + comment?: GoOutlineRange; +} + +function documentSymbolToSymbolStat(decl: GoOutlineDeclaration): TreeViewNode { + const children = decl.children && decl.children.length > 0 + ? decl.children.map(documentSymbolToSymbolStat) + : []; + + return new TreeViewNode(decl.label, decl.type, decl.start, decl.end, children); +} + +export function documentSymbols(filename: string): Promise { + return new Promise((resolve, reject) => { + let gooutline = getBinPath('go-outline'); + // Spawn `go-outline` process + let p = cp.execFile(gooutline, ['-f', filename], {}, (err, stdout, stderr) => { + try { + if (err && (err).code === 'ENOENT') { + console.log('Go-outline not installed'); + // promptForMissingTool('go-outline'); + } + if (err) return resolve(null); + let result = stdout.toString(); + let decls = JSON.parse(result); + let symbols = decls.map(documentSymbolToSymbolStat); + return resolve(symbols); + } catch (e) { + reject(e); + } + }); + }); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/goPath.ts b/src/vs/workbench/parts/explorers/common/goPath.ts new file mode 100644 index 00000000000..07e51376aa0 --- /dev/null +++ b/src/vs/workbench/parts/explorers/common/goPath.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------- + * 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 fs = require('fs'); +import path = require('path'); +import os = require('os'); + +let binPathCache: { [bin: string]: string; } = {}; +let runtimePathCache: string = null; + +export function getBinPath(binname: string) { + binname = correctBinname(binname); + if (binPathCache[binname]) return binPathCache[binname]; + + // First search each GOPATH workspace's bin folder + if (process.env['GOPATH']) { + let workspaces = process.env['GOPATH'].split(path.delimiter); + for (let i = 0; i < workspaces.length; i++) { + let binpath = path.join(workspaces[i], 'bin', binname); + if (fs.existsSync(binpath)) { + binPathCache[binname] = binpath; + return binpath; + } + } + } + + // Then search PATH parts + if (process.env['PATH']) { + let pathparts = process.env['PATH'].split(path.delimiter); + for (let i = 0; i < pathparts.length; i++) { + let binpath = path.join(pathparts[i], binname); + if (fs.existsSync(binpath)) { + binPathCache[binname] = binpath; + return binpath; + } + } + } + + // Finally check GOROOT just in case + if (process.env['GOROOT']) { + let binpath = path.join(process.env['GOROOT'], 'bin', binname); + if (fs.existsSync(binpath)) { + binPathCache[binname] = binpath; + return binpath; + } + } + + // Else return the binary name directly (this will likely always fail downstream) + binPathCache[binname] = binname; + return binname; +} + +function correctBinname(binname: string) { + if (process.platform === 'win32') + return binname + '.exe'; + else + return binname; +} + +/** + * Returns Go runtime binary path. + * + * @return the path to the Go binary. + */ +export function getGoRuntimePath(): string { + if (runtimePathCache) return runtimePathCache; + if (process.env['GOROOT']) { + runtimePathCache = path.join(process.env['GOROOT'], 'bin', correctBinname('go')); + } else if (process.env['PATH']) { + let pathparts = (process.env.PATH).split(path.delimiter); + runtimePathCache = pathparts.map(dir => path.join(dir, correctBinname('go'))).filter(candidate => fs.existsSync(candidate))[0]; + } + return runtimePathCache; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts new file mode 100644 index 00000000000..fae5b6d90e0 --- /dev/null +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -0,0 +1,15 @@ +export class TreeViewNode { + public label: string; + public type: string; + public start: number; + public end: number; + public children: TreeViewNode[]; + + constructor(label: string, type: string, start: number, end: number, children: TreeViewNode[]) { + this.label = label; + this.type = type; + this.start = start; + this.end = end; + this.children = children; + } +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 44e08cbac2e..ea66c2ef039 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -57,6 +57,8 @@ import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution'; import 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen'; import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately +import 'vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution'; + import 'vs/workbench/parts/output/browser/output.contribution'; import 'vs/workbench/parts/output/browser/outputPanel'; // can be packaged separately From aa1ffcd8fb907ce56aae758f6d665b4d05e9cb37 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 26 Sep 2016 16:24:02 -0700 Subject: [PATCH 002/119] Add icon to activity bar (loaded separately than stock Viewlets) --- .../browser/parts/activitybar/activitybarPart.ts | 9 +++++++++ src/vs/workbench/browser/viewlet.ts | 5 +++++ .../parts/explorers/browser/treeExplorerViewlet.ts | 4 +--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 293ccb4d87c..b8c7ab81294 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -51,6 +51,15 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); + + // Update activity bar on registering an external viewlet + this.toUnbind.push( + (Registry.as(ViewletExtensions.Viewlets)).onDidViewletRegister(viewletDescriptor => this.onViewletRegistryUpdated(viewletDescriptor)) + ); + } + + private onViewletRegistryUpdated(viewletDescriptor: ViewletDescriptor) { + this.viewletSwitcherBar.push(this.toAction(viewletDescriptor), { label: true, icon: true }); } private onActiveCompositeChanged(composite: IComposite): void { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 52b0d77f53d..4bd63e7f8c5 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -7,6 +7,7 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); +import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/platform'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; @@ -164,12 +165,16 @@ export const Extensions = { export class ViewletRegistry extends CompositeRegistry { private defaultViewletId: string; + private _onDidViewletRegister = new Emitter(); + + public get onDidViewletRegister() { return this._onDidViewletRegister.event; } /** * Registers a viewlet to the platform. */ public registerViewlet(descriptor: ViewletDescriptor): void { super.registerComposite(descriptor); + this._onDidViewletRegister.fire(descriptor); } /** diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index e27974dc1ab..0bfa1600f36 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -1,5 +1,3 @@ -import 'vs/css!./media/customViewlet'; - import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { SplitView, Orientation } from 'vs/base/browser/ui/splitview/splitview'; @@ -12,7 +10,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { TreeView } from 'vs/workbench/parts/explorers/browser/views/treeView'; -export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.customViewlet.'; +export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.treeExplorerViewlet.'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; From c2bdd6a853480e213d0ac042ec29e1c21e5bbf87 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 28 Sep 2016 11:11:22 -0700 Subject: [PATCH 003/119] Refactor and put id as property of TreeContentProvider --- .../actions/browser/menusExtensionPoint.ts | 6 +-- src/vs/vscode.d.ts | 18 +++++++ src/vs/workbench/api/node/extHost.api.impl.ts | 3 ++ .../api/node/extHost.contribution.ts | 2 + src/vs/workbench/api/node/extHost.protocol.ts | 11 ++++ src/vs/workbench/api/node/extHostExplorers.ts | 51 +++++++++++++++++++ .../workbench/api/node/mainThreadDocuments.ts | 1 + .../workbench/api/node/mainThreadExplorers.ts | 22 ++++++++ .../treeExplorerViewlet.contribution.css | 2 +- 9 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/vs/workbench/api/node/extHostExplorers.ts create mode 100644 src/vs/workbench/api/node/mainThreadExplorers.ts diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 8ffafaec1d0..bb2e096b51b 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -340,9 +340,9 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - 'workbench.view.treeExplorer', // Later change this to make it unique - localize('treeExplorer', 'treeExplorer'), - 'treeExplorer', + 'workbench.view.customViewlet.' + treeContentProviderId, + treeContentProviderId, + treeContentProviderId, 125 )); } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index e37e0d0f218..9c867df6750 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,6 +1348,22 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } + export interface TreeContentProvider { + id: string; + provideTreeContent(): ITree; + } + + export interface ITree { + root: ITreeNode; + } + + export interface ITreeNode { + label: string; + isExpanded: boolean; + parent: ITreeNode; + children: ITreeNode[] + } + /** * Represents an item that can be selected from * a list of items. @@ -3803,6 +3819,8 @@ declare module 'vscode' { */ export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; + export function registerTreeContentProvider(provider: TreeContentProvider): Disposable; + /** * An event that is emitted when a [text document](#TextDocument) is opened. */ diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 060ac66a02f..565b3dccdb8 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -12,11 +12,13 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import * as errors from 'vs/base/common/errors'; import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; + import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; +import { ExtHostExplorers } from 'vs/workbench/api/node/extHostExplorers'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen'; import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; @@ -64,6 +66,7 @@ export function createApiFactory(threadService: IThreadService, extensionService const extHostDocuments = col.define(ExtHostContext.ExtHostDocuments).set(new ExtHostDocuments(threadService)); const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocuments)); + const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostExplorers(threadService)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostEditors, extHostHeapService)); const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration))); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); diff --git a/src/vs/workbench/api/node/extHost.contribution.ts b/src/vs/workbench/api/node/extHost.contribution.ts index 0c08d17a796..040b1453475 100644 --- a/src/vs/workbench/api/node/extHost.contribution.ts +++ b/src/vs/workbench/api/node/extHost.contribution.ts @@ -20,6 +20,7 @@ import { MainThreadDiagnostics } from './mainThreadDiagnostics'; import { MainThreadDocuments } from './mainThreadDocuments'; import { MainThreadEditors } from './mainThreadEditors'; import { MainThreadErrors } from './mainThreadErrors'; +import { MainThreadExplorers } from './mainThreadExplorers'; import { MainThreadLanguageFeatures } from './mainThreadLanguageFeatures'; import { MainThreadLanguages } from './mainThreadLanguages'; import { MainThreadMessageService } from './mainThreadMessageService'; @@ -70,6 +71,7 @@ export class ExtHostContribution implements IWorkbenchContribution { col.define(MainContext.MainThreadDocuments).set(create(MainThreadDocuments)); col.define(MainContext.MainThreadEditors).set(create(MainThreadEditors)); col.define(MainContext.MainThreadErrors).set(create(MainThreadErrors)); + col.define(MainContext.MainThreadExplorers).set(create(MainThreadExplorers)); col.define(MainContext.MainThreadLanguageFeatures).set(create(MainThreadLanguageFeatures)); col.define(MainContext.MainThreadLanguages).set(create(MainThreadLanguages)); col.define(MainContext.MainThreadMessageService).set(create(MainThreadMessageService)); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8813c2da060..1f52b3d8cb5 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -115,6 +115,11 @@ export abstract class MainThreadEditorsShape { $tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise { throw ni(); } } +export abstract class MainThreadExplorersShape { + $registerTreeContentProvider(treeContentProviderId: string): void { throw ni(); } + $unregisterTreeContentProvider(treeContentProviderId: string): void { throw ni(); } +} + export abstract class MainThreadErrorsShape { onUnexpectedExtHostError(err: any): void { throw ni(); } } @@ -257,6 +262,10 @@ export abstract class ExtHostEditorsShape { $acceptTextEditorRemove(id: string): void { throw ni(); } } +export abstract class ExtHostExplorersShape { + $provideTextDocumentContent(treeContentProviderId: string): vscode.ITree { throw ni(); }; +} + export abstract class ExtHostExtensionServiceShape { $localShowMessage(severity: Severity, msg: string): void { throw ni(); } $activateExtension(extensionDescription: IExtensionDescription): TPromise { throw ni(); } @@ -331,6 +340,7 @@ export const MainContext = { MainThreadDocuments: createMainId('MainThreadDocuments', MainThreadDocumentsShape), MainThreadEditors: createMainId('MainThreadEditors', MainThreadEditorsShape), MainThreadErrors: createMainId('MainThreadErrors', MainThreadErrorsShape), + MainThreadExplorers: createMainId('MainThreadExplorers', MainThreadExplorersShape), MainThreadLanguageFeatures: createMainId('MainThreadLanguageFeatures', MainThreadLanguageFeaturesShape), MainThreadLanguages: createMainId('MainThreadLanguages', MainThreadLanguagesShape), MainThreadMessageService: createMainId('MainThreadMessageService', MainThreadMessageServiceShape), @@ -351,6 +361,7 @@ export const ExtHostContext = { ExtHostDocuments: createExtId('ExtHostDocuments', ExtHostDocumentsShape), ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant', ExtHostDocumentSaveParticipantShape), ExtHostEditors: createExtId('ExtHostEditors', ExtHostEditorsShape), + ExtHostExplorers: createExtId('ExtHostExplorers',ExtHostExplorersShape), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService', ExtHostFileSystemEventServiceShape), ExtHostHeapService: createExtId('ExtHostHeapMonitor', ExtHostHeapServiceShape), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures', ExtHostLanguageFeaturesShape), diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts new file mode 100644 index 00000000000..7c9cbce1a77 --- /dev/null +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as vscode from 'vscode'; +import {TPromise} from 'vs/base/common/winjs.base'; +import {Disposable} from 'vs/workbench/api/node/extHostTypes'; +import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; +import {MainContext, ExtHostExplorersShape, MainThreadExplorersShape} from './extHost.protocol'; + +export class ExtHostExplorers extends ExtHostExplorersShape { + private _proxy: MainThreadExplorersShape; + + private _treeContentProviders: { [treeContentProviderId: string]: vscode.TreeContentProvider; }; + + constructor(threadService: IThreadService) { + super(); + + this._proxy = threadService.get(MainContext.MainThreadExplorers); + + this._treeContentProviders = Object.create(null); + } + + public registerTreeContentProvider(provider: vscode.TreeContentProvider): vscode.Disposable { + const treeContentProviderId = provider.id; + + if (this._treeContentProviders[treeContentProviderId]) { + throw new Error(`TreeContentProvider with id '${provider.id} already registered`); + } + + this._treeContentProviders[treeContentProviderId] = provider; + this._proxy.$registerTreeContentProvider(treeContentProviderId); + + return new Disposable(() => { + if (delete this._treeContentProviders[treeContentProviderId]) { + this._proxy.$unregisterTreeContentProvider(treeContentProviderId); + } + }); + } + + $provideTextDocumentContent(treeContentProviderId: string): vscode.ITree { + const provider = this._treeContentProviders[treeContentProviderId]; + if (!provider) { + throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); + } + + return provider.provideTreeContent(); + } +} diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index b39faff7845..2f5c1ff3583 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -264,4 +264,5 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { } }, onUnexpectedError); } + } diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts new file mode 100644 index 00000000000..42f68184b19 --- /dev/null +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -0,0 +1,22 @@ +import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; +import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from './extHost.protocol'; + +export class MainThreadExplorers extends MainThreadExplorersShape { + private _proxy: ExtHostExplorersShape; + + constructor( + @IThreadService threadService: IThreadService + ) { + super(); + + this._proxy = threadService.get(ExtHostContext.ExtHostExplorers); + } + + $registerTreeContentProvider(treeContentProviderId: string): void { + const tree = this._proxy.$provideTextDocumentContent(treeContentProviderId); + } + + $unregisterTreeContentProvider(treeContentProviderId: string): void { + + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css b/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css index fe7d7722e73..255fb5a7d8b 100644 --- a/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css +++ b/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css @@ -4,6 +4,6 @@ *--------------------------------------------------------------------------------------------*/ /* Activity Bar */ -.monaco-workbench > .activitybar .monaco-action-bar .action-label.treeExplorer { +.monaco-workbench > .activitybar .monaco-action-bar .action-label.pineTree { background-image: url('files-dark.svg'); } \ No newline at end of file From d03ea815b6647f34a051b1717dd66b87ed336c70 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 30 Sep 2016 09:22:31 -0700 Subject: [PATCH 004/119] Make TreeViewlet render correctly --- .../explorers/browser/treeExplorerViewlet.ts | 35 ++++++------ .../parts/explorers/browser/views/treeView.ts | 53 ++++++++++++++---- .../explorers/browser/views/treeViewer.ts | 30 ++++++++++- .../parts/explorers/common/goOutline.ts | 54 +++++++++---------- .../parts/explorers/common/treeViewModel.ts | 37 ++++++++----- 5 files changed, 140 insertions(+), 69 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 0bfa1600f36..f7fd583e3d5 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -9,41 +9,45 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TreeView } from 'vs/workbench/parts/explorers/browser/views/treeView'; +import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.treeExplorerViewlet.'; +const ID = 'workbench.view.customViewlet.' + 'pineTree'; // for now export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; private viewletContainer: Builder; - private splitView: SplitView; - private views: IViewletView[]; + private view: IViewletView; + + private viewletState: TreeExplorerViewletState; constructor( @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService ) { - super(CUSTOM_VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter, telemetryService); - TreeExplorerViewlet._idCounter++; + super(ID, telemetryService); - this.views = []; + this.viewletState = new TreeExplorerViewletState(); + + TreeExplorerViewlet._idCounter++; } create(parent: Builder): TPromise { super.create(parent); this.viewletContainer = parent.div().addClass('custom-viewlet'); - this.splitView = new SplitView(this.viewletContainer.getHTMLElement()); - this.addTreeView('Tree ' + (this.views.length + 1)); + this.addTreeView('Tree1'); + + this.setVisible(true).then(() => this.focus()); const settings = this.configurationService.getConfiguration(); - return this.onConfigurationUpdated(settings); } layout(dimension: Dimension): void { - this.splitView.layout(dimension.height); + this.view.layout(dimension.height, Orientation.VERTICAL); } private onConfigurationUpdated(config: ICustomViewletConfiguration): TPromise { @@ -51,16 +55,15 @@ export class TreeExplorerViewlet extends Viewlet { } private addTreeView(treeName: string): void { - const treeView = this.instantiationService.createInstance(TreeView, treeName, this.getActionRunner()); - this.views.push(treeView); - this.splitView.addView(treeView); + // 0 for now, add back header later if needed + const headerSize = 0; + + this.view = this.instantiationService.createInstance(TreeView, this.viewletState, treeName, this.getActionRunner(), headerSize); + this.view.render(this.viewletContainer.getHTMLElement(), Orientation.VERTICAL); } dispose(): void { - this.views.forEach(view => { - view.dispose(); - }); - this.views = null; + this.view = null; } } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts index 7a010364668..186a95ae222 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -8,7 +8,7 @@ import { Builder, $ } from 'vs/base/browser/builder'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet'; -import { IActionRunner } from 'vs/base/common/actions'; +import { IActionRunner, IAction } from 'vs/base/common/actions'; import { IMessageService } from 'vs/platform/message/common/message'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -20,22 +20,41 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; -import { TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; +import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import { documentSymbols } from '../../common/goOutline'; +// import { documentSymbols } from '../../common/goOutline'; +import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; + +function getTree(): TreeViewNode { + const root = new TreeViewNode(1, "foo"); + const node1 = new TreeViewNode(2, "bar"); + const node2 = new TreeViewNode(3, "baz"); + const node11 = new TreeViewNode(4, "qux"); + + root.addChild(node1); + root.addChild(node2); + node1.addChild(node11); + + return root; +} export class TreeView extends CollapsibleViewletView { private workspace: IWorkspace; + private treeViewer: ITree; + + private viewletState: TreeExplorerViewletState; private _treeName: string = "TreeExplorer"; get treeName(): string { return this._treeName; } constructor( + viewletState: TreeExplorerViewletState, treeName: string, actionRunner: IActionRunner, + headerSize: number, @IMessageService messageService: IMessageService, @IKeybindingService keybindingService: IKeybindingService, @IContextMenuService contextMenuService: IContextMenuService, @@ -44,20 +63,16 @@ export class TreeView extends CollapsibleViewletView { @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService ) { - super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService); + super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService, headerSize); this.workspace = contextService.getWorkspace(); + + this.viewletState = viewletState; this.create(); } renderHeader(container: HTMLElement): void { - const titleDiv = $('div.title').appendTo(container); - $('span') - .text(this._treeName) - .title(this._treeName) - .appendTo(titleDiv); - super.renderHeader(container); } renderBody(container: HTMLElement): void { @@ -65,11 +80,16 @@ export class TreeView extends CollapsibleViewletView { DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); this.tree = this.createViewer($(this.treeContainer)); + this.tree.setInput(getTree()); + } + + getActions(): IAction[] { + return []; } createViewer(container: Builder): ITree { const dataSource = this.instantiationService.createInstance(TreeDataSource); - const renderer = this.instantiationService.createInstance(TreeRenderer, this.actionRunner, container.getHTMLElement()); + const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); const controller = null; const sorter = null; const filter = null; @@ -100,7 +120,11 @@ export class TreeView extends CollapsibleViewletView { this.updateOutlineViewlet(fileResource); } + } + refresh(): TPromise { + const input = this.tree.getInput(); + return this.doRefresh(); } private doRefresh(): TPromise { @@ -108,14 +132,21 @@ export class TreeView extends CollapsibleViewletView { } private updateOutlineViewlet(fileURI: URI): TPromise { + this.tree.setInput(getTree()); + /* documentSymbols(fileURI.path).then(nodes => { const root = nodes[0]; this.tree.setInput(root); }); + */ return TPromise.as(null); } + focus(): void { + + } + public getOptimalWidth(): number { const parentNode = this.tree.getHTMLElement(); const childNodes = [].slice.call(parentNode.querySelectorAll('.outline-item-label > a')); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index 992beebc61c..b6b52f6328e 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -7,7 +7,8 @@ import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel' import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IActionRunner } from 'vs/base/common/actions'; -import { ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; +import { IActionProvider, ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; +import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -39,6 +40,7 @@ export class TreeDataSource implements IDataSource { export class TreeRenderer extends ActionsRenderer implements IRenderer { constructor( + state: TreeExplorerViewletState, actionRunner: IActionRunner, private container: HTMLElement, @IContextViewService private contextViewService: IContextViewService, @@ -46,7 +48,7 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { @IModeService private modeService: IModeService ) { super({ - actionProvider: null, + actionProvider: state.actionProvider, actionRunner: actionRunner }); } @@ -72,4 +74,28 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { +} + +export interface ITreeExplorerViewletState { + actionProvider: IActionProvider; +} + +export class TreeExplorerActionProvider extends ContributableActionProvider { + private state: TreeExplorerViewletState; + + constructor(state: TreeExplorerViewletState) { + super(); + + this.state = state; + } +} + +export class TreeExplorerViewletState implements ITreeExplorerViewletState { + private _actionProvider: TreeExplorerActionProvider; + + constructor() { + this._actionProvider = new TreeExplorerActionProvider(this); + } + + get actionProvider() { return this._actionProvider; } } \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/goOutline.ts b/src/vs/workbench/parts/explorers/common/goOutline.ts index b81eed7fd4c..88bde4d2969 100644 --- a/src/vs/workbench/parts/explorers/common/goOutline.ts +++ b/src/vs/workbench/parts/explorers/common/goOutline.ts @@ -29,32 +29,32 @@ export interface GoOutlineDeclaration { comment?: GoOutlineRange; } -function documentSymbolToSymbolStat(decl: GoOutlineDeclaration): TreeViewNode { - const children = decl.children && decl.children.length > 0 - ? decl.children.map(documentSymbolToSymbolStat) - : []; +// function documentSymbolToSymbolStat(decl: GoOutlineDeclaration): TreeViewNode { +// const children = decl.children && decl.children.length > 0 +// ? decl.children.map(documentSymbolToSymbolStat) +// : []; - return new TreeViewNode(decl.label, decl.type, decl.start, decl.end, children); -} +// return new TreeViewNode(decl.label, decl.type, decl.start, decl.end, children); +// } -export function documentSymbols(filename: string): Promise { - return new Promise((resolve, reject) => { - let gooutline = getBinPath('go-outline'); - // Spawn `go-outline` process - let p = cp.execFile(gooutline, ['-f', filename], {}, (err, stdout, stderr) => { - try { - if (err && (err).code === 'ENOENT') { - console.log('Go-outline not installed'); - // promptForMissingTool('go-outline'); - } - if (err) return resolve(null); - let result = stdout.toString(); - let decls = JSON.parse(result); - let symbols = decls.map(documentSymbolToSymbolStat); - return resolve(symbols); - } catch (e) { - reject(e); - } - }); - }); -} \ No newline at end of file +// export function documentSymbols(filename: string): Promise { +// return new Promise((resolve, reject) => { +// let gooutline = getBinPath('go-outline'); +// // Spawn `go-outline` process +// let p = cp.execFile(gooutline, ['-f', filename], {}, (err, stdout, stderr) => { +// try { +// if (err && (err).code === 'ENOENT') { +// console.log('Go-outline not installed'); +// // promptForMissingTool('go-outline'); +// } +// if (err) return resolve(null); +// let result = stdout.toString(); +// let decls = JSON.parse(result); +// let symbols = decls.map(documentSymbolToSymbolStat); +// return resolve(symbols); +// } catch (e) { +// reject(e); +// } +// }); +// }); +// } \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index fae5b6d90e0..8d0cd3cdfe6 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -1,15 +1,26 @@ -export class TreeViewNode { - public label: string; - public type: string; - public start: number; - public end: number; - public children: TreeViewNode[]; - constructor(label: string, type: string, start: number, end: number, children: TreeViewNode[]) { - this.label = label; - this.type = type; - this.start = start; - this.end = end; - this.children = children; - } +export class TreeViewNode implements vscode.ITreeNode { + id: number; + label: string; + isExpanded: boolean; + parent: vscode.ITreeNode; + children: vscode.ITreeNode[]; + + constructor( + id: number, + label: string, + isExpanded: boolean = true, + parent: vscode.ITreeNode = null, + children: vscode.ITreeNode[] = []) { + this.id = id; + this.label = label; + this.isExpanded = isExpanded; + this.parent = parent; + this.children = children; + } + + addChild(child: vscode.ITreeNode) { + this.children.push(child); + child.parent = this; + } } From d8c0af7f6d390cc1c3e5e11d95dc54dbf4e23b9a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 30 Sep 2016 16:38:56 -0700 Subject: [PATCH 005/119] Hook up provider mechanism and add onClick --- src/vs/vscode.d.ts | 10 +--- src/vs/workbench/api/node/extHost.api.impl.ts | 3 ++ src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostExplorers.ts | 26 +++++----- .../workbench/api/node/mainThreadExplorers.ts | 22 ++++++-- .../treeExplorerViewlet.contribution.ts | 7 ++- .../explorers/browser/treeExplorerViewlet.ts | 6 +++ .../browser/treeExplorerViewletService.ts | 36 +++++++++++++ .../parts/explorers/browser/views/treeView.ts | 50 ++++++------------- .../explorers/browser/views/treeViewer.ts | 8 ++- .../parts/explorers/common/treeViewModel.ts | 11 ++-- 11 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 9c867df6750..97e1ac32a48 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1349,18 +1349,12 @@ declare module 'vscode' { } export interface TreeContentProvider { - id: string; - provideTreeContent(): ITree; - } - - export interface ITree { - root: ITreeNode; + provideTreeContent(): Thenable; } export interface ITreeNode { label: string; isExpanded: boolean; - parent: ITreeNode; children: ITreeNode[] } @@ -3819,7 +3813,7 @@ declare module 'vscode' { */ export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; - export function registerTreeContentProvider(provider: TreeContentProvider): Disposable; + export function registerTreeContentProvider(providerId: string, provider: TreeContentProvider): Disposable; /** * An event that is emitted when a [text document](#TextDocument) is opened. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 565b3dccdb8..e04975b4841 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -335,6 +335,9 @@ export function createApiFactory(threadService: IThreadService, extensionService onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables); }, + registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider) { + return extHostExplorers.registerTreeContentProvider(providerId, provider); + }, onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); }, diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 1f52b3d8cb5..43ab9e5fbd2 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -263,7 +263,7 @@ export abstract class ExtHostEditorsShape { } export abstract class ExtHostExplorersShape { - $provideTextDocumentContent(treeContentProviderId: string): vscode.ITree { throw ni(); }; + $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index 7c9cbce1a77..f0be05d4693 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -15,7 +15,9 @@ export class ExtHostExplorers extends ExtHostExplorersShape { private _treeContentProviders: { [treeContentProviderId: string]: vscode.TreeContentProvider; }; - constructor(threadService: IThreadService) { + constructor( + threadService: IThreadService + ) { super(); this._proxy = threadService.get(MainContext.MainThreadExplorers); @@ -23,29 +25,25 @@ export class ExtHostExplorers extends ExtHostExplorersShape { this._treeContentProviders = Object.create(null); } - public registerTreeContentProvider(provider: vscode.TreeContentProvider): vscode.Disposable { - const treeContentProviderId = provider.id; - - if (this._treeContentProviders[treeContentProviderId]) { - throw new Error(`TreeContentProvider with id '${provider.id} already registered`); - } - - this._treeContentProviders[treeContentProviderId] = provider; - this._proxy.$registerTreeContentProvider(treeContentProviderId); + public registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider): vscode.Disposable { + this._proxy.$registerTreeContentProvider(providerId); + this._treeContentProviders[providerId] = provider; return new Disposable(() => { - if (delete this._treeContentProviders[treeContentProviderId]) { - this._proxy.$unregisterTreeContentProvider(treeContentProviderId); + if (delete this._treeContentProviders[providerId]) { + this._proxy.$unregisterTreeContentProvider(providerId); } }); } - $provideTextDocumentContent(treeContentProviderId: string): vscode.ITree { + $provideTreeContent(treeContentProviderId: string): TPromise { const provider = this._treeContentProviders[treeContentProviderId]; if (!provider) { throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); } - return provider.provideTreeContent(); + return TPromise.wrap(provider.provideTreeContent().then(treeContent => { + return JSON.stringify(treeContent); + })); } } diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 42f68184b19..3e31c82261e 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -1,19 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ITreeNode } from 'vscode'; +import {TPromise} from 'vs/base/common/winjs.base'; import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from './extHost.protocol'; +import {ITreeExplorerViewletService} from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; export class MainThreadExplorers extends MainThreadExplorersShape { private _proxy: ExtHostExplorersShape; constructor( - @IThreadService threadService: IThreadService + @IThreadService threadService: IThreadService, + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { super(); this._proxy = threadService.get(ExtHostContext.ExtHostExplorers); } - $registerTreeContentProvider(treeContentProviderId: string): void { - const tree = this._proxy.$provideTextDocumentContent(treeContentProviderId); + $registerTreeContentProvider(providerId: string): void { + this.treeExplorerViewletService.registerTreeContentProvider(providerId, { + provideTreeContent: (): TPromise => { + return this._proxy.$provideTreeContent(providerId).then(jsonTree => { + return JSON.parse(jsonTree); + }) + } + }); } $unregisterTreeContentProvider(treeContentProviderId: string): void { diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 5721dc1b88f..758d1f57b3e 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -1,3 +1,8 @@ 'use strict'; -import 'vs/css!./media/treeExplorerViewlet.contribution'; \ No newline at end of file +import 'vs/css!./media/treeExplorerViewlet.contribution'; + +import {ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index f7fd583e3d5..a1c991eb346 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -50,6 +50,12 @@ export class TreeExplorerViewlet extends Viewlet { this.view.layout(dimension.height, Orientation.VERTICAL); } + setVisible(visible: boolean): TPromise { + return super.setVisible(visible).then(() => { + this.view.setVisible(visible).done(); + }) + } + private onConfigurationUpdated(config: ICustomViewletConfiguration): TPromise { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts new file mode 100644 index 00000000000..f899fc22680 --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -0,0 +1,36 @@ +'use strict'; + +import { ITreeNode, TreeContentProvider } from 'vscode'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, {Emitter} from 'vs/base/common/event'; +import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; + +export const ITreeExplorerViewletService = createDecorator('customViewletService'); + +export interface ITreeExplorerViewletService { + _serviceBrand: any; + + registerTreeContentProvider(providerId: string, provider: TreeContentProvider): void; + provideTreeContent(providerId: string): TPromise; +} + +export class TreeExplorerViewletService implements ITreeExplorerViewletService { + public _serviceBrand: any; + + private _treeContentProviders: { [providerId: string]: TreeContentProvider; }; + + constructor( + @IInstantiationService private _instantiationService: IInstantiationService, + ) { + this._treeContentProviders = Object.create(null); + } + + registerTreeContentProvider(providerId: string, provider: TreeContentProvider): void { + this._treeContentProviders[providerId] = provider; + } + + provideTreeContent(providerId: string): TPromise { + return TPromise.wrap(this._treeContentProviders[providerId].provideTreeContent()); + } +} diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts index 186a95ae222..411a0733e91 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -16,6 +16,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; @@ -61,7 +62,8 @@ export class TreeView extends CollapsibleViewletView { @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IEditorGroupService private editorGroupService: IEditorGroupService + @IEditorGroupService private editorGroupService: IEditorGroupService, + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService, headerSize); @@ -80,7 +82,9 @@ export class TreeView extends CollapsibleViewletView { DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); this.tree = this.createViewer($(this.treeContainer)); - this.tree.setInput(getTree()); + this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { + this.tree.setInput(tree); + }); } getActions(): IAction[] { @@ -90,7 +94,7 @@ export class TreeView extends CollapsibleViewletView { createViewer(container: Builder): ITree { const dataSource = this.instantiationService.createInstance(TreeDataSource); const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); - const controller = null; + const controller = this.instantiationService.createInstance(TreeController); const sorter = null; const filter = null; const dnd = null; @@ -108,43 +112,19 @@ export class TreeView extends CollapsibleViewletView { } create(): TPromise { - this.toDispose.push(this.editorGroupService.onEditorsChanged(() => this.onEditorsChanged())) - return TPromise.as(null); + return this.setVisible(true); } - private onEditorsChanged() { - const activeInput = this.editorService.getActiveEditorInput(); - - if (activeInput instanceof FileEditorInput) { - const fileResource = activeInput.getResource(); - - this.updateOutlineViewlet(fileResource); - } - } - - refresh(): TPromise { - const input = this.tree.getInput(); - return this.doRefresh(); - } - - private doRefresh(): TPromise { - return TPromise.as(null); - } - - private updateOutlineViewlet(fileURI: URI): TPromise { - this.tree.setInput(getTree()); - /* - documentSymbols(fileURI.path).then(nodes => { - const root = nodes[0]; - this.tree.setInput(root); + setVisible(visible: boolean): TPromise { + return super.setVisible(visible).then(() => { + this.updateInput().done(); }); - */ - - return TPromise.as(null); } - focus(): void { - + private updateInput(): TPromise { + return this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { + this.tree.setInput(tree); + }) } public getOptimalWidth(): number { diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index b6b52f6328e..af9adde2f8e 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -5,6 +5,7 @@ import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/t import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; +import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IActionRunner } from 'vs/base/common/actions'; import { IActionProvider, ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; @@ -25,7 +26,7 @@ export class TreeDataSource implements IDataSource { } public hasChildren(tree: ITree, node: TreeViewNode): boolean { - return node.children.length > 0; + return node.children && node.children.length > 0; } public getChildren(tree: ITree, node: TreeViewNode): TPromise { @@ -74,6 +75,11 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { + /* protected */ public onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { + super.onLeftClick(tree, node, event, origin); + console.log(node.label); + return true; + } } export interface ITreeExplorerViewletState { diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 8d0cd3cdfe6..4a08ef46063 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -1,17 +1,16 @@ - export class TreeViewNode implements vscode.ITreeNode { id: number; label: string; isExpanded: boolean; - parent: vscode.ITreeNode; - children: vscode.ITreeNode[]; + parent: TreeViewNode + children: TreeViewNode[]; constructor( id: number, label: string, isExpanded: boolean = true, - parent: vscode.ITreeNode = null, - children: vscode.ITreeNode[] = []) { + parent: TreeViewNode = null, + children: TreeViewNode[] = []) { this.id = id; this.label = label; this.isExpanded = isExpanded; @@ -19,7 +18,7 @@ export class TreeViewNode implements vscode.ITreeNode { this.children = children; } - addChild(child: vscode.ITreeNode) { + addChild(child: TreeViewNode) { this.children.push(child); child.parent = this; } From 5276b19f7262ece8d46635192f6abde896752db7 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 3 Oct 2016 10:31:19 -0700 Subject: [PATCH 006/119] Clean up --- .../parts/explorers/browser/views/treeView.ts | 14 ------------- .../explorers/browser/views/treeViewer.ts | 4 +++- .../parts/explorers/common/treeViewModel.ts | 21 +++++-------------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts index 411a0733e91..fa83d67f709 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -25,22 +25,8 @@ import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -// import { documentSymbols } from '../../common/goOutline'; import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; -function getTree(): TreeViewNode { - const root = new TreeViewNode(1, "foo"); - const node1 = new TreeViewNode(2, "bar"); - const node2 = new TreeViewNode(3, "baz"); - const node11 = new TreeViewNode(4, "qux"); - - root.addChild(node1); - root.addChild(node2); - node1.addChild(node11); - - return root; -} - export class TreeView extends CollapsibleViewletView { private workspace: IWorkspace; private treeViewer: ITree; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index af9adde2f8e..0ba9f357861 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -75,9 +75,11 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { - /* protected */ public onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { + public onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); + console.log(node.label); + return true; } } diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 4a08ef46063..540a57a395f 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -1,21 +1,10 @@ export class TreeViewNode implements vscode.ITreeNode { - id: number; - label: string; - isExpanded: boolean; - parent: TreeViewNode - children: TreeViewNode[]; - constructor( - id: number, - label: string, - isExpanded: boolean = true, - parent: TreeViewNode = null, - children: TreeViewNode[] = []) { - this.id = id; - this.label = label; - this.isExpanded = isExpanded; - this.parent = parent; - this.children = children; + public id: number, + public label: string, + public isExpanded: boolean = true, + public parent: TreeViewNode = null, + public children: TreeViewNode[] = []) { } addChild(child: TreeViewNode) { From 8081e2e3955d243b577c9b09ac74766bb78b3c11 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 3 Oct 2016 14:04:54 -0700 Subject: [PATCH 007/119] async loading children --- src/vs/vscode.d.ts | 4 ++- src/vs/workbench/api/node/extHost.protocol.ts | 1 + src/vs/workbench/api/node/extHostExplorers.ts | 11 ++++++ .../workbench/api/node/mainThreadExplorers.ts | 5 +++ .../browser/treeExplorerViewletService.ts | 8 +++-- .../explorers/browser/views/treeViewer.ts | 34 ++++++++++++++----- .../parts/explorers/common/treeViewModel.ts | 3 +- 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 97e1ac32a48..2f4b56a8a87 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1350,12 +1350,14 @@ declare module 'vscode' { export interface TreeContentProvider { provideTreeContent(): Thenable; + resolveChildren(node: ITreeNode): Thenable; } export interface ITreeNode { label: string; isExpanded: boolean; - children: ITreeNode[] + children: ITreeNode[]; + isChildrenResolved: boolean; } /** diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 43ab9e5fbd2..f84739f296f 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -264,6 +264,7 @@ export abstract class ExtHostEditorsShape { export abstract class ExtHostExplorersShape { $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; + $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index f0be05d4693..4cdd46858d6 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -46,4 +46,15 @@ export class ExtHostExplorers extends ExtHostExplorersShape { return JSON.stringify(treeContent); })); } + + $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { + const provider = this._treeContentProviders[treeContentProviderId]; + if (!provider) { + throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); + } + + return TPromise.wrap(provider.resolveChildren(node).then(children => { + return JSON.stringify(children); + })); + } } diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 3e31c82261e..04e0c080600 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -28,6 +28,11 @@ export class MainThreadExplorers extends MainThreadExplorersShape { return this._proxy.$provideTreeContent(providerId).then(jsonTree => { return JSON.parse(jsonTree); }) + }, + resolveChildren: (node: ITreeNode): TPromise => { + return this._proxy.$resolveChildren(providerId, node).then(jsonChildren => { + return JSON.parse(jsonChildren); + }) } }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index f899fc22680..b9171622480 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -4,7 +4,6 @@ import { ITreeNode, TreeContentProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; export const ITreeExplorerViewletService = createDecorator('customViewletService'); @@ -13,6 +12,7 @@ export interface ITreeExplorerViewletService { registerTreeContentProvider(providerId: string, provider: TreeContentProvider): void; provideTreeContent(providerId: string): TPromise; + resolveChildren(providerId: string, node: ITreeNode): TPromise; } export class TreeExplorerViewletService implements ITreeExplorerViewletService { @@ -21,7 +21,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { private _treeContentProviders: { [providerId: string]: TreeContentProvider; }; constructor( - @IInstantiationService private _instantiationService: IInstantiationService, + @IInstantiationService private _instantiationService: IInstantiationService ) { this._treeContentProviders = Object.create(null); } @@ -33,4 +33,8 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { provideTreeContent(providerId: string): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].provideTreeContent()); } + + resolveChildren(providerId: string, node: ITreeNode): TPromise { + return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); + } } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index 0ba9f357861..69634812c3a 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -14,23 +14,41 @@ import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegis import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; + +const providerId = 'pineTree'; export class TreeDataSource implements IDataSource { - - constructor() { + constructor( + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + ) { } - public getId(tree: ITree, node: TreeViewNode): string { + public getId(tree: ITree, node: vscode.ITreeNode): string { return node.label; } - public hasChildren(tree: ITree, node: TreeViewNode): boolean { - return node.children && node.children.length > 0; + public hasChildren(tree: ITree, node: vscode.ITreeNode): boolean { + if (node.isChildrenResolved) { + return node.children && node.children.length > 0; + } else { + return true; + } } - public getChildren(tree: ITree, node: TreeViewNode): TPromise { - return TPromise.as(node.children); + public getChildren(tree: ITree, node: vscode.ITreeNode): TPromise { + if (node.isChildrenResolved) { + return TPromise.as(node.children); + } else { + return this.treeExplorerViewletService.resolveChildren(providerId, node).then(children => { + children.forEach(child => { + node.children.push(child); + }); + node.isChildrenResolved = true; + return node.children; + }); + } } public getParent(tree: ITree, node: TreeViewNode): TPromise { @@ -79,7 +97,7 @@ export class TreeController extends DefaultController { super.onLeftClick(tree, node, event, origin); console.log(node.label); - + return true; } } diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 540a57a395f..0457c25afcd 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -4,7 +4,8 @@ export class TreeViewNode implements vscode.ITreeNode { public label: string, public isExpanded: boolean = true, public parent: TreeViewNode = null, - public children: TreeViewNode[] = []) { + public children: TreeViewNode[] = [], + public isChildrenResolved: boolean = true) { } addChild(child: TreeViewNode) { From 10af4d75f6e4590c6817f4abf6df30aa7b335d42 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 4 Oct 2016 10:46:21 -0700 Subject: [PATCH 008/119] Add click behavior to Controller --- .../parts/explorers/browser/views/treeViewer.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index 69634812c3a..248cf0a75a1 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -15,6 +15,7 @@ import { IContextViewService, IContextMenuService } from 'vs/platform/contextvie import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ClickBehavior } from 'vs/base/parts/tree/browser/treeDefaults'; const providerId = 'pineTree'; @@ -93,11 +94,15 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { + constructor() { + super(); + // todo: pine: figure out if I need this + // super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); + } + public onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); - console.log(node.label); - return true; } } From 6f4de8b5a0318a16aaa85ee048e71bbc999ba30a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 4 Oct 2016 15:08:56 -0700 Subject: [PATCH 009/119] Remove isChildrenResolved from ITreeNode --- src/vs/vscode.d.ts | 1 - src/vs/workbench/api/node/extHostExplorers.ts | 2 +- .../workbench/api/node/mainThreadExplorers.ts | 3 ++- .../parts/explorers/browser/views/treeView.ts | 6 ++--- .../explorers/browser/views/treeViewer.ts | 24 ++++++++----------- .../parts/explorers/common/treeViewModel.ts | 23 +++++++++++------- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 2f4b56a8a87..1fb1fea6d95 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1357,7 +1357,6 @@ declare module 'vscode' { label: string; isExpanded: boolean; children: ITreeNode[]; - isChildrenResolved: boolean; } /** diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index 4cdd46858d6..fda9fc6ed4f 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -25,7 +25,7 @@ export class ExtHostExplorers extends ExtHostExplorersShape { this._treeContentProviders = Object.create(null); } - public registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider): vscode.Disposable { + registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider): vscode.Disposable { this._proxy.$registerTreeContentProvider(providerId); this._treeContentProviders[providerId] = provider; diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 04e0c080600..3224c78c5bc 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -4,11 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { ITreeNode } from 'vscode'; +import {ITreeNode} from 'vscode'; import {TPromise} from 'vs/base/common/winjs.base'; import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from './extHost.protocol'; import {ITreeExplorerViewletService} from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import {TreeViewNode} from 'vs/workbench/parts/explorers/common/treeViewModel'; export class MainThreadExplorers extends MainThreadExplorersShape { private _proxy: ExtHostExplorersShape; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts index fa83d67f709..9e4b8097c2d 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -68,9 +68,7 @@ export class TreeView extends CollapsibleViewletView { DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); this.tree = this.createViewer($(this.treeContainer)); - this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { - this.tree.setInput(tree); - }); + this.updateInput(); } getActions(): IAction[] { @@ -109,7 +107,7 @@ export class TreeView extends CollapsibleViewletView { private updateInput(): TPromise { return this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { - this.tree.setInput(tree); + this.tree.setInput(TreeViewNode.create(tree)); }) } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index 248cf0a75a1..86adaed917c 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -26,25 +26,21 @@ export class TreeDataSource implements IDataSource { } - public getId(tree: ITree, node: vscode.ITreeNode): string { - return node.label; + getId(tree: ITree, node: TreeViewNode): string { + return node.id.toString(); } - public hasChildren(tree: ITree, node: vscode.ITreeNode): boolean { - if (node.isChildrenResolved) { - return node.children && node.children.length > 0; - } else { - return true; - } + hasChildren(tree: ITree, node: TreeViewNode): boolean { + return node.hasChildren; } - public getChildren(tree: ITree, node: vscode.ITreeNode): TPromise { + getChildren(tree: ITree, node: TreeViewNode): TPromise { if (node.isChildrenResolved) { return TPromise.as(node.children); } else { return this.treeExplorerViewletService.resolveChildren(providerId, node).then(children => { children.forEach(child => { - node.children.push(child); + node.children.push(TreeViewNode.create(child)); }); node.isChildrenResolved = true; return node.children; @@ -52,7 +48,7 @@ export class TreeDataSource implements IDataSource { } } - public getParent(tree: ITree, node: TreeViewNode): TPromise { + getParent(tree: ITree, node: TreeViewNode): TPromise { return TPromise.as(null); } } @@ -73,11 +69,11 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { }); } - public getContentHeight(tree: ITree, element: any): number { + getContentHeight(tree: ITree, element: any): number { return 22; } - public renderContents(tree: ITree, node: TreeViewNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { + renderContents(tree: ITree, node: TreeViewNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { const el = $(domElement).clearChildren(); const item = $('.custom-viewlet-tree-node-item'); item.appendTo(el); @@ -100,7 +96,7 @@ export class TreeController extends DefaultController { // super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } - public onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { + onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); return true; diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 0457c25afcd..56d5ba3497d 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -1,15 +1,22 @@ -export class TreeViewNode implements vscode.ITreeNode { +import { ITreeNode } from 'vscode'; + +export class TreeViewNode implements ITreeNode { + static idCounter = 1; + + id: number; + hasChildren: boolean = true; + isChildrenResolved: boolean = false; + constructor( - public id: number, public label: string, public isExpanded: boolean = true, - public parent: TreeViewNode = null, - public children: TreeViewNode[] = [], - public isChildrenResolved: boolean = true) { + public children: TreeViewNode[] = [] + ) { + this.id = TreeViewNode.idCounter++; } - addChild(child: TreeViewNode) { - this.children.push(child); - child.parent = this; + public static create(node: ITreeNode): TreeViewNode { + const children = node.children.map(TreeViewNode.create); + return new TreeViewNode(node.label, node.isExpanded, children) } } From 61639c0b36e22c1d745cabb8fb1464c2e1a5573a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 5 Oct 2016 10:44:37 -0700 Subject: [PATCH 010/119] Clean up --- src/vs/workbench/parts/explorers/browser/views/treeViewer.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index 86adaed917c..cc680bc4950 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -91,9 +91,7 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { constructor() { - super(); - // todo: pine: figure out if I need this - // super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); + super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { From c8bbaaa507f9c8c3674a7cc013566f6a855e4f97 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 5 Oct 2016 10:53:31 -0700 Subject: [PATCH 011/119] Remove JSON as ITreeNode is all primitives --- src/vs/workbench/api/node/extHost.protocol.ts | 4 ++-- src/vs/workbench/api/node/extHostExplorers.ts | 10 +++++----- src/vs/workbench/api/node/mainThreadExplorers.ts | 8 ++------ .../parts/explorers/browser/views/treeViewer.ts | 3 +-- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index f84739f296f..c4c9bafd776 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -263,8 +263,8 @@ export abstract class ExtHostEditorsShape { } export abstract class ExtHostExplorersShape { - $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; - $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { throw ni(); } + $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; + $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index fda9fc6ed4f..fe35e0142da 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -13,7 +13,7 @@ import {MainContext, ExtHostExplorersShape, MainThreadExplorersShape} from './ex export class ExtHostExplorers extends ExtHostExplorersShape { private _proxy: MainThreadExplorersShape; - private _treeContentProviders: { [treeContentProviderId: string]: vscode.TreeContentProvider; }; + private _treeContentProviders: { [treeContentProviderId: string]: vscode.TreeContentProvider }; constructor( threadService: IThreadService @@ -36,25 +36,25 @@ export class ExtHostExplorers extends ExtHostExplorersShape { }); } - $provideTreeContent(treeContentProviderId: string): TPromise { + $provideTreeContent(treeContentProviderId: string): TPromise { const provider = this._treeContentProviders[treeContentProviderId]; if (!provider) { throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); } return TPromise.wrap(provider.provideTreeContent().then(treeContent => { - return JSON.stringify(treeContent); + return treeContent; })); } - $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { + $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { const provider = this._treeContentProviders[treeContentProviderId]; if (!provider) { throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); } return TPromise.wrap(provider.resolveChildren(node).then(children => { - return JSON.stringify(children); + return children; })); } } diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 3224c78c5bc..9241903c304 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -26,14 +26,10 @@ export class MainThreadExplorers extends MainThreadExplorersShape { $registerTreeContentProvider(providerId: string): void { this.treeExplorerViewletService.registerTreeContentProvider(providerId, { provideTreeContent: (): TPromise => { - return this._proxy.$provideTreeContent(providerId).then(jsonTree => { - return JSON.parse(jsonTree); - }) + return this._proxy.$provideTreeContent(providerId); }, resolveChildren: (node: ITreeNode): TPromise => { - return this._proxy.$resolveChildren(providerId, node).then(jsonChildren => { - return JSON.parse(jsonChildren); - }) + return this._proxy.$resolveChildren(providerId, node); } }); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts index cc680bc4950..6b8ca83d8c5 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts @@ -4,7 +4,7 @@ import { $, Builder } from 'vs/base/browser/builder'; import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; -import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; +import { ClickBehavior, DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IActionRunner } from 'vs/base/common/actions'; @@ -15,7 +15,6 @@ import { IContextViewService, IContextMenuService } from 'vs/platform/contextvie import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; -import { ClickBehavior } from 'vs/base/parts/tree/browser/treeDefaults'; const providerId = 'pineTree'; From f36453850f4ba7ae591522463657fe2a511ddbde Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 5 Oct 2016 15:26:37 -0700 Subject: [PATCH 012/119] Reduce calls to refresh tree to one call --- .../workbench/parts/explorers/browser/treeExplorerViewlet.ts | 2 -- src/vs/workbench/parts/explorers/browser/views/treeView.ts | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index a1c991eb346..534a3833f56 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -40,8 +40,6 @@ export class TreeExplorerViewlet extends Viewlet { this.viewletContainer = parent.div().addClass('custom-viewlet'); this.addTreeView('Tree1'); - this.setVisible(true).then(() => this.focus()); - const settings = this.configurationService.getConfiguration(); return this.onConfigurationUpdated(settings); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeView.ts index 9e4b8097c2d..a34e0814dc5 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeView.ts @@ -68,7 +68,6 @@ export class TreeView extends CollapsibleViewletView { DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); this.tree = this.createViewer($(this.treeContainer)); - this.updateInput(); } getActions(): IAction[] { @@ -96,7 +95,7 @@ export class TreeView extends CollapsibleViewletView { } create(): TPromise { - return this.setVisible(true); + return TPromise.as(null); } setVisible(visible: boolean): TPromise { From 154cdf9103a23f860b4772ff33242e533267dc4c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 5 Oct 2016 15:27:01 -0700 Subject: [PATCH 013/119] Keep a local tree at extHostExplorer side --- src/vs/workbench/api/node/extHost.protocol.ts | 6 ++- src/vs/workbench/api/node/extHostExplorers.ts | 51 ++++++++++++++++--- .../workbench/api/node/mainThreadExplorers.ts | 14 +++-- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index c4c9bafd776..a94a24cb8a3 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -34,6 +34,8 @@ import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker'; +import { ExtHostTreeNode } from 'vs/workbench/api/node/extHostExplorers'; + export interface InstanceSetter { set(instance: T): R; } @@ -263,8 +265,8 @@ export abstract class ExtHostEditorsShape { } export abstract class ExtHostExplorersShape { - $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; - $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { throw ni(); } + $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; + $resolveChildren(treeContentProviderId: string, node: ExtHostTreeNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index fe35e0142da..802343a2cde 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as vscode from 'vscode'; +import { ITreeNode, TreeContentProvider } from 'vscode'; import {TPromise} from 'vs/base/common/winjs.base'; import {Disposable} from 'vs/workbench/api/node/extHostTypes'; import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; @@ -13,7 +13,9 @@ import {MainContext, ExtHostExplorersShape, MainThreadExplorersShape} from './ex export class ExtHostExplorers extends ExtHostExplorersShape { private _proxy: MainThreadExplorersShape; - private _treeContentProviders: { [treeContentProviderId: string]: vscode.TreeContentProvider }; + private _treeContentProviders: { [treeContentProviderId: string]: TreeContentProvider }; + private _treeContents: { [treeContentProviderId: string]: ExtHostTreeNode }; + private _treeNodeMaps: { [treeContentProviderId: string]: { [id: number]: ExtHostTreeNode }}; constructor( threadService: IThreadService @@ -23,9 +25,11 @@ export class ExtHostExplorers extends ExtHostExplorersShape { this._proxy = threadService.get(MainContext.MainThreadExplorers); this._treeContentProviders = Object.create(null); + this._treeContents = Object.create(null); + this._treeNodeMaps = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider): vscode.Disposable { + registerTreeContentProvider(providerId: string, provider: TreeContentProvider): Disposable { this._proxy.$registerTreeContentProvider(providerId); this._treeContentProviders[providerId] = provider; @@ -36,25 +40,56 @@ export class ExtHostExplorers extends ExtHostExplorersShape { }); } - $provideTreeContent(treeContentProviderId: string): TPromise { + $provideTreeContent(treeContentProviderId: string): TPromise { const provider = this._treeContentProviders[treeContentProviderId]; if (!provider) { throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); } return TPromise.wrap(provider.provideTreeContent().then(treeContent => { - return treeContent; + const treeNodeMap = Object.create(null); + this._treeNodeMaps[treeContentProviderId] = treeNodeMap; + this._treeContents[treeContentProviderId] = new ExtHostTreeNode(treeContent, null, treeNodeMap); + return this._treeContents[treeContentProviderId]; })); } - $resolveChildren(treeContentProviderId: string, node: vscode.ITreeNode): TPromise { + $resolveChildren(treeContentProviderId: string, mainThreadNode: ExtHostTreeNode): TPromise { const provider = this._treeContentProviders[treeContentProviderId]; if (!provider) { throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); } - return TPromise.wrap(provider.resolveChildren(node).then(children => { - return children; + const treeNodeMap = this._treeNodeMaps[treeContentProviderId]; + const extHostNode = treeNodeMap[mainThreadNode.id]; + + return TPromise.wrap(provider.resolveChildren(extHostNode).then(children => { + extHostNode.children = children.map(child => { + return new ExtHostTreeNode(child, extHostNode, treeNodeMap); + }); + return extHostNode.children; })); } } + +export class ExtHostTreeNode implements ITreeNode { + static idCounter = 1; + + id: number; + + label: string; + isExpanded: boolean; + children: ExtHostTreeNode[]; + + constructor(node: ITreeNode, parent: ExtHostTreeNode, treeNodeMap: { [id: number]: ExtHostTreeNode}) { + this.id = ExtHostTreeNode.idCounter++; + + this.label = node.label; + this.isExpanded = node.isExpanded; + this.children = node.children.map(child => { + return new ExtHostTreeNode(child, this, treeNodeMap); + }) + + treeNodeMap[this.id] = this; + } +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 9241903c304..7eb3270c23b 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -11,9 +11,13 @@ import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from '. import {ITreeExplorerViewletService} from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import {TreeViewNode} from 'vs/workbench/parts/explorers/common/treeViewModel'; +import { ExtHostTreeNode } from 'vs/workbench/api/node/extHostExplorers'; + export class MainThreadExplorers extends MainThreadExplorersShape { private _proxy: ExtHostExplorersShape; + private _treeContents: { [treeContentProviderId: string]: ExtHostTreeNode }; + constructor( @IThreadService threadService: IThreadService, @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService @@ -21,14 +25,18 @@ export class MainThreadExplorers extends MainThreadExplorersShape { super(); this._proxy = threadService.get(ExtHostContext.ExtHostExplorers); + this._treeContents = Object.create(null); } $registerTreeContentProvider(providerId: string): void { this.treeExplorerViewletService.registerTreeContentProvider(providerId, { - provideTreeContent: (): TPromise => { - return this._proxy.$provideTreeContent(providerId); + provideTreeContent: (): TPromise => { + return this._proxy.$provideTreeContent(providerId).then(treeContent => { + this._treeContents[providerId] = treeContent; + return treeContent; + }) }, - resolveChildren: (node: ITreeNode): TPromise => { + resolveChildren: (node: ExtHostTreeNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); } }); From ec1cc0dc9dd865c6439a159c49166b5f077a6e0b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 6 Oct 2016 09:37:39 -0700 Subject: [PATCH 014/119] Better naming and some doc --- src/vs/vscode.d.ts | 38 +++++++++++++++++-- src/vs/workbench/api/node/extHostExplorers.ts | 6 +-- .../workbench/api/node/mainThreadExplorers.ts | 2 +- .../browser/treeExplorerViewletService.ts | 10 ++--- .../parts/explorers/common/treeViewModel.ts | 6 +-- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1fb1fea6d95..a58b7ccef5c 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,15 +1348,37 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } + /** + * A tree content provider allows extension to contribute a custom tree-like + * explorer as a Viewlet. + * + * Tree content providers are registered through [workspace.registerTreeContentProvider](#workspace.registerTreeContentProvider). + */ export interface TreeContentProvider { - provideTreeContent(): Thenable; - resolveChildren(node: ITreeNode): Thenable; + provideTreeContent(): Thenable; + resolveChildren(node: TreeContentNode): Thenable; } - export interface ITreeNode { + /** + * Represents a tree node on the tree explorer. + */ + export interface TreeContentNode { + + /** + * A human readable string used to render the tree node. + */ label: string; + + /** + * Whether the tree node is expanded. + */ isExpanded: boolean; - children: ITreeNode[]; + + /** + * Children of the current node. Can be empty initially and later + * resolved through [TreeContentProvider.resolveChildren](#TreeContentProvider.resolveChildren) + */ + children: TreeContentNode[]; } /** @@ -3814,6 +3836,14 @@ declare module 'vscode' { */ export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; + /** + * Register a tree content provider, used as a data source + * for custom tree explorers. + * + * @param providerId A unique id that identifies the provider. + * @param provider A [TreeContentProvider](#TreeContentProvider) + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ export function registerTreeContentProvider(providerId: string, provider: TreeContentProvider): Disposable; /** diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index 802343a2cde..833a78d0b9a 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { ITreeNode, TreeContentProvider } from 'vscode'; +import { TreeContentNode, TreeContentProvider } from 'vscode'; import {TPromise} from 'vs/base/common/winjs.base'; import {Disposable} from 'vs/workbench/api/node/extHostTypes'; import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; @@ -72,7 +72,7 @@ export class ExtHostExplorers extends ExtHostExplorersShape { } } -export class ExtHostTreeNode implements ITreeNode { +export class ExtHostTreeNode implements TreeContentNode { static idCounter = 1; id: number; @@ -81,7 +81,7 @@ export class ExtHostTreeNode implements ITreeNode { isExpanded: boolean; children: ExtHostTreeNode[]; - constructor(node: ITreeNode, parent: ExtHostTreeNode, treeNodeMap: { [id: number]: ExtHostTreeNode}) { + constructor(node: TreeContentNode, parent: ExtHostTreeNode, treeNodeMap: { [id: number]: ExtHostTreeNode}) { this.id = ExtHostTreeNode.idCounter++; this.label = node.label; diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadExplorers.ts index 7eb3270c23b..c014a864424 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadExplorers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {ITreeNode} from 'vscode'; +import {TreeContentNode} from 'vscode'; import {TPromise} from 'vs/base/common/winjs.base'; import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from './extHost.protocol'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index b9171622480..15d8f5fdd7d 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -1,6 +1,6 @@ 'use strict'; -import { ITreeNode, TreeContentProvider } from 'vscode'; +import { TreeContentNode, TreeContentProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -11,8 +11,8 @@ export interface ITreeExplorerViewletService { _serviceBrand: any; registerTreeContentProvider(providerId: string, provider: TreeContentProvider): void; - provideTreeContent(providerId: string): TPromise; - resolveChildren(providerId: string, node: ITreeNode): TPromise; + provideTreeContent(providerId: string): TPromise; + resolveChildren(providerId: string, node: TreeContentNode): TPromise; } export class TreeExplorerViewletService implements ITreeExplorerViewletService { @@ -30,11 +30,11 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { this._treeContentProviders[providerId] = provider; } - provideTreeContent(providerId: string): TPromise { + provideTreeContent(providerId: string): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].provideTreeContent()); } - resolveChildren(providerId: string, node: ITreeNode): TPromise { + resolveChildren(providerId: string, node: TreeContentNode): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); } } diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 56d5ba3497d..3f88d4d07dd 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -1,6 +1,6 @@ -import { ITreeNode } from 'vscode'; +import { TreeContentNode } from 'vscode'; -export class TreeViewNode implements ITreeNode { +export class TreeViewNode implements TreeContentNode { static idCounter = 1; id: number; @@ -15,7 +15,7 @@ export class TreeViewNode implements ITreeNode { this.id = TreeViewNode.idCounter++; } - public static create(node: ITreeNode): TreeViewNode { + public static create(node: TreeContentNode): TreeViewNode { const children = node.children.map(TreeViewNode.create); return new TreeViewNode(node.label, node.isExpanded, children) } From e88e3f00ef984646a309e2df78082136e3117068 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 6 Oct 2016 10:23:09 -0700 Subject: [PATCH 015/119] More consistent naming and clean up random strings --- .../parts/explorers/browser/treeExplorerViewlet.ts | 14 ++++++++------ .../views/{treeView.ts => treeExplorerView.ts} | 10 ++++++---- .../views/{treeViewer.ts => treeExplorerViewer.ts} | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) rename src/vs/workbench/parts/explorers/browser/views/{treeView.ts => treeExplorerView.ts} (96%) rename src/vs/workbench/parts/explorers/browser/views/{treeViewer.ts => treeExplorerViewer.ts} (98%) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 534a3833f56..880c28cc602 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -8,11 +8,13 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { TreeView } from 'vs/workbench/parts/explorers/browser/views/treeView'; -import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; +import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; +import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; + +const TREE_NAME = 'pineTree'; // For now export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.treeExplorerViewlet.'; -const ID = 'workbench.view.customViewlet.' + 'pineTree'; // for now +const ID = 'workbench.view.customTreeExplorerViewlet.' + TREE_NAME; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; @@ -37,8 +39,8 @@ export class TreeExplorerViewlet extends Viewlet { create(parent: Builder): TPromise { super.create(parent); - this.viewletContainer = parent.div().addClass('custom-viewlet'); - this.addTreeView('Tree1'); + this.viewletContainer = parent.div().addClass('custom-tree-explorer-viewlet'); + this.addTreeView(TREE_NAME); const settings = this.configurationService.getConfiguration(); return this.onConfigurationUpdated(settings); @@ -62,7 +64,7 @@ export class TreeExplorerViewlet extends Viewlet { // 0 for now, add back header later if needed const headerSize = 0; - this.view = this.instantiationService.createInstance(TreeView, this.viewletState, treeName, this.getActionRunner(), headerSize); + this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, treeName, this.getActionRunner(), headerSize); this.view.render(this.viewletContainer.getHTMLElement(), Orientation.VERTICAL); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts similarity index 96% rename from src/vs/workbench/parts/explorers/browser/views/treeView.ts rename to src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index a34e0814dc5..f396ef0299a 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -21,19 +21,19 @@ import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browse import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; -import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeViewer'; +import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; -export class TreeView extends CollapsibleViewletView { +export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; private treeViewer: ITree; private viewletState: TreeExplorerViewletState; - private _treeName: string = "TreeExplorer"; + private _treeName: string; get treeName(): string { return this._treeName; } @@ -53,9 +53,11 @@ export class TreeView extends CollapsibleViewletView { ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService, headerSize); + this.viewletState = viewletState; + this._treeName = treeName; + this.workspace = contextService.getWorkspace(); - this.viewletState = viewletState; this.create(); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts similarity index 98% rename from src/vs/workbench/parts/explorers/browser/views/treeViewer.ts rename to src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 6b8ca83d8c5..ad8292db207 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -16,7 +16,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; -const providerId = 'pineTree'; +const providerId = 'pineTree'; // For now export class TreeDataSource implements IDataSource { constructor( From 373829a4ad2c15f9241f6428c33cb6c55cf41b38 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 6 Oct 2016 10:35:39 -0700 Subject: [PATCH 016/119] Allow tree label to be set --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index bb2e096b51b..6311181f9c9 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -213,6 +213,7 @@ namespace schema { export interface IExplorer { treeContentProviderId: string; + treeLabel: string; icon: IUserFriendlyIcon; } @@ -224,6 +225,10 @@ namespace schema { description: localize('vscode.extension.contributes.explorer.treeContentProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeContentProvider'), type: 'string' }, + treeLabel: { + description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree Viewlet'), + type: 'string' + }, icon: { description: localize('vscode.extension.contributes.explorer.icon', 'Icon to put on activity bar'), type: 'string' @@ -335,13 +340,13 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { for (let extension of extensions) { - const { treeContentProviderId, icon } = extension.value; + const { treeContentProviderId, treeLabel, icon } = extension.value; Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', 'workbench.view.customViewlet.' + treeContentProviderId, - treeContentProviderId, + treeLabel, treeContentProviderId, 125 )); From 7f5e03f496cff717115b1a7fee75d402bdd3c904 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 6 Oct 2016 10:38:01 -0700 Subject: [PATCH 017/119] Avoid same order for multiple viewlets Revisit after discussing Viewlet ordering --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 6311181f9c9..c7e7e55b34d 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -339,6 +339,7 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM }); ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { + let baseOrder = 200; for (let extension of extensions) { const { treeContentProviderId, treeLabel, icon } = extension.value; @@ -348,7 +349,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e 'workbench.view.customViewlet.' + treeContentProviderId, treeLabel, treeContentProviderId, - 125 + baseOrder++ )); } }); \ No newline at end of file From 230ac468ea7796ca64b8487a73cbb7bd3759696b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 6 Oct 2016 11:15:21 -0700 Subject: [PATCH 018/119] Allow icon to be set via explorer contribution --- .../actions/browser/menusExtensionPoint.ts | 15 +++++++++++++++ .../media/treeExplorerViewlet.contribution.css | 9 --------- .../browser/treeExplorerViewlet.contribution.ts | 2 -- 3 files changed, 15 insertions(+), 11 deletions(-) delete mode 100644 src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index c7e7e55b34d..039112e561b 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -340,9 +340,24 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { let baseOrder = 200; + for (let extension of extensions) { const { treeContentProviderId, treeLabel, icon } = extension.value; + const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; + if (icon) { + if (typeof icon === 'string') { + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; + const iconPath = join(extension.description.extensionFolderPath, icon); + createCSSRule(iconClass, getIconRule(iconPath)); + } else { + const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; + const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; + createCSSRule(lightIconClass, getIconRule(icon.light)); + createCSSRule(darkIconClass, getIconRule(icon.dark)); + } + } + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', diff --git a/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css b/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css deleted file mode 100644 index 255fb5a7d8b..00000000000 --- a/src/vs/workbench/parts/explorers/browser/media/treeExplorerViewlet.contribution.css +++ /dev/null @@ -1,9 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Activity Bar */ -.monaco-workbench > .activitybar .monaco-action-bar .action-label.pineTree { - background-image: url('files-dark.svg'); -} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 758d1f57b3e..df1d4bb28a0 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -1,7 +1,5 @@ 'use strict'; -import 'vs/css!./media/treeExplorerViewlet.contribution'; - import {ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; From eced815a8d86387f6800bc346c66d5796d032710 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 7 Oct 2016 10:02:38 -0700 Subject: [PATCH 019/119] Descriptor id needs to correspond to Viewlet's --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 039112e561b..1f353593406 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -361,7 +361,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - 'workbench.view.customViewlet.' + treeContentProviderId, + 'workbench.view.customTreeExplorerViewlet.' + treeContentProviderId, treeLabel, treeContentProviderId, baseOrder++ From 8e9982c1b02359bdd5c89f9950add2e992664d64 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 7 Oct 2016 14:41:32 -0700 Subject: [PATCH 020/119] isExpanded -> shouldInitiallyExpand --- src/vs/vscode.d.ts | 6 ++++-- src/vs/workbench/api/node/extHostExplorers.ts | 4 ++-- src/vs/workbench/parts/explorers/common/treeViewModel.ts | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index a58b7ccef5c..5610598bc8a 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1370,9 +1370,11 @@ declare module 'vscode' { label: string; /** - * Whether the tree node is expanded. + * Wheather the tree node should be initially be expanded. + * If set to true, [TreeContentProvider.resolveChildren](#TreeContentProvider.resolveChildren) will + * be called on the node after rendering. */ - isExpanded: boolean; + shouldInitiallyExpand: boolean; /** * Children of the current node. Can be empty initially and later diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts index 833a78d0b9a..2d6c7f0dcc4 100644 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ b/src/vs/workbench/api/node/extHostExplorers.ts @@ -78,14 +78,14 @@ export class ExtHostTreeNode implements TreeContentNode { id: number; label: string; - isExpanded: boolean; + shouldInitiallyExpand: boolean; children: ExtHostTreeNode[]; constructor(node: TreeContentNode, parent: ExtHostTreeNode, treeNodeMap: { [id: number]: ExtHostTreeNode}) { this.id = ExtHostTreeNode.idCounter++; this.label = node.label; - this.isExpanded = node.isExpanded; + this.shouldInitiallyExpand = node.shouldInitiallyExpand; this.children = node.children.map(child => { return new ExtHostTreeNode(child, this, treeNodeMap); }) diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts index 3f88d4d07dd..1c4b17c4c7d 100644 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeViewModel.ts @@ -9,7 +9,7 @@ export class TreeViewNode implements TreeContentNode { constructor( public label: string, - public isExpanded: boolean = true, + public shouldInitiallyExpand: boolean = true, public children: TreeViewNode[] = [] ) { this.id = TreeViewNode.idCounter++; @@ -17,6 +17,6 @@ export class TreeViewNode implements TreeContentNode { public static create(node: TreeContentNode): TreeViewNode { const children = node.children.map(TreeViewNode.create); - return new TreeViewNode(node.label, node.isExpanded, children) + return new TreeViewNode(node.label, node.shouldInitiallyExpand, children) } } From fb032eb0f80e427d178a949d54520cc7fff58b4e Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 7 Oct 2016 16:27:31 -0700 Subject: [PATCH 021/119] Remove unused go outline stuff --- .../parts/explorers/common/goOutline.ts | 60 -------------- .../parts/explorers/common/goPath.ts | 78 ------------------- 2 files changed, 138 deletions(-) delete mode 100644 src/vs/workbench/parts/explorers/common/goOutline.ts delete mode 100644 src/vs/workbench/parts/explorers/common/goPath.ts diff --git a/src/vs/workbench/parts/explorers/common/goOutline.ts b/src/vs/workbench/parts/explorers/common/goOutline.ts deleted file mode 100644 index 88bde4d2969..00000000000 --- a/src/vs/workbench/parts/explorers/common/goOutline.ts +++ /dev/null @@ -1,60 +0,0 @@ -/*--------------------------------------------------------- - * 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 cp = require('child_process'); -import path = require('path'); -import { getBinPath } from './goPath'; - -import { TreeViewNode } from './treeViewModel'; - -// Keep in sync with https://github.com/lukehoban/go-outline -export interface GoOutlineRange { - start: number; - end: number; -} - -export interface GoOutlineDeclaration { - label: string; - type: string; - receiverType?: string; - icon?: string; // icon class or null to use the default images based on the type - start: number; - end: number; - children?: GoOutlineDeclaration[]; - signature?: GoOutlineRange; - comment?: GoOutlineRange; -} - -// function documentSymbolToSymbolStat(decl: GoOutlineDeclaration): TreeViewNode { -// const children = decl.children && decl.children.length > 0 -// ? decl.children.map(documentSymbolToSymbolStat) -// : []; - -// return new TreeViewNode(decl.label, decl.type, decl.start, decl.end, children); -// } - -// export function documentSymbols(filename: string): Promise { -// return new Promise((resolve, reject) => { -// let gooutline = getBinPath('go-outline'); -// // Spawn `go-outline` process -// let p = cp.execFile(gooutline, ['-f', filename], {}, (err, stdout, stderr) => { -// try { -// if (err && (err).code === 'ENOENT') { -// console.log('Go-outline not installed'); -// // promptForMissingTool('go-outline'); -// } -// if (err) return resolve(null); -// let result = stdout.toString(); -// let decls = JSON.parse(result); -// let symbols = decls.map(documentSymbolToSymbolStat); -// return resolve(symbols); -// } catch (e) { -// reject(e); -// } -// }); -// }); -// } \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/goPath.ts b/src/vs/workbench/parts/explorers/common/goPath.ts deleted file mode 100644 index 07e51376aa0..00000000000 --- a/src/vs/workbench/parts/explorers/common/goPath.ts +++ /dev/null @@ -1,78 +0,0 @@ -/*--------------------------------------------------------- - * 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 fs = require('fs'); -import path = require('path'); -import os = require('os'); - -let binPathCache: { [bin: string]: string; } = {}; -let runtimePathCache: string = null; - -export function getBinPath(binname: string) { - binname = correctBinname(binname); - if (binPathCache[binname]) return binPathCache[binname]; - - // First search each GOPATH workspace's bin folder - if (process.env['GOPATH']) { - let workspaces = process.env['GOPATH'].split(path.delimiter); - for (let i = 0; i < workspaces.length; i++) { - let binpath = path.join(workspaces[i], 'bin', binname); - if (fs.existsSync(binpath)) { - binPathCache[binname] = binpath; - return binpath; - } - } - } - - // Then search PATH parts - if (process.env['PATH']) { - let pathparts = process.env['PATH'].split(path.delimiter); - for (let i = 0; i < pathparts.length; i++) { - let binpath = path.join(pathparts[i], binname); - if (fs.existsSync(binpath)) { - binPathCache[binname] = binpath; - return binpath; - } - } - } - - // Finally check GOROOT just in case - if (process.env['GOROOT']) { - let binpath = path.join(process.env['GOROOT'], 'bin', binname); - if (fs.existsSync(binpath)) { - binPathCache[binname] = binpath; - return binpath; - } - } - - // Else return the binary name directly (this will likely always fail downstream) - binPathCache[binname] = binname; - return binname; -} - -function correctBinname(binname: string) { - if (process.platform === 'win32') - return binname + '.exe'; - else - return binname; -} - -/** - * Returns Go runtime binary path. - * - * @return the path to the Go binary. - */ -export function getGoRuntimePath(): string { - if (runtimePathCache) return runtimePathCache; - if (process.env['GOROOT']) { - runtimePathCache = path.join(process.env['GOROOT'], 'bin', correctBinname('go')); - } else if (process.env['PATH']) { - let pathparts = (process.env.PATH).split(path.delimiter); - runtimePathCache = pathparts.map(dir => path.join(dir, correctBinname('go'))).filter(candidate => fs.existsSync(candidate))[0]; - } - return runtimePathCache; -} \ No newline at end of file From 29c03eaa5852efe85778273f25a31602394c1fe4 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 11 Oct 2016 07:48:34 -0700 Subject: [PATCH 022/119] Remove children on ExtHost side and refactor --- src/vs/vscode.d.ts | 35 +------ src/vs/workbench/api/node/extHost.api.impl.ts | 6 +- .../api/node/extHost.contribution.ts | 4 +- src/vs/workbench/api/node/extHost.protocol.ts | 14 +-- src/vs/workbench/api/node/extHostExplorers.ts | 95 ------------------- .../api/node/extHostTreeExplorers.ts | 79 +++++++++++++++ ...xplorers.ts => mainThreadTreeExplorers.ts} | 26 +++-- .../browser/treeExplorerViewletService.ts | 18 ++-- .../browser/views/treeExplorerView.ts | 5 +- .../browser/views/treeExplorerViewer.ts | 2 +- .../explorers/common/treeExplorerViewModel.ts | 39 ++++++++ .../parts/explorers/common/treeViewModel.ts | 22 ----- 12 files changed, 159 insertions(+), 186 deletions(-) delete mode 100644 src/vs/workbench/api/node/extHostExplorers.ts create mode 100644 src/vs/workbench/api/node/extHostTreeExplorers.ts rename src/vs/workbench/api/node/{mainThreadExplorers.ts => mainThreadTreeExplorers.ts} (52%) create mode 100644 src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts delete mode 100644 src/vs/workbench/parts/explorers/common/treeViewModel.ts diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 5610598bc8a..b6d90e0f35c 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,39 +1348,14 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } - /** - * A tree content provider allows extension to contribute a custom tree-like - * explorer as a Viewlet. - * - * Tree content providers are registered through [workspace.registerTreeContentProvider](#workspace.registerTreeContentProvider). - */ - export interface TreeContentProvider { - provideTreeContent(): Thenable; - resolveChildren(node: TreeContentNode): Thenable; + export interface TreeExplorerNodeProvider { + provideRootNode(): Thenable; + resolveChildren(node: TreeExplorerNode): Thenable; } - /** - * Represents a tree node on the tree explorer. - */ - export interface TreeContentNode { - - /** - * A human readable string used to render the tree node. - */ + export interface TreeExplorerNode { label: string; - - /** - * Wheather the tree node should be initially be expanded. - * If set to true, [TreeContentProvider.resolveChildren](#TreeContentProvider.resolveChildren) will - * be called on the node after rendering. - */ shouldInitiallyExpand: boolean; - - /** - * Children of the current node. Can be empty initially and later - * resolved through [TreeContentProvider.resolveChildren](#TreeContentProvider.resolveChildren) - */ - children: TreeContentNode[]; } /** @@ -3846,7 +3821,7 @@ declare module 'vscode' { * @param provider A [TreeContentProvider](#TreeContentProvider) * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ - export function registerTreeContentProvider(providerId: string, provider: TreeContentProvider): Disposable; + export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; /** * An event that is emitted when a [text document](#TextDocument) is opened. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index e04975b4841..e51010b1de3 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -18,7 +18,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; -import { ExtHostExplorers } from 'vs/workbench/api/node/extHostExplorers'; +import { ExtHostTreeExplorers } from 'vs/workbench/api/node/extHostTreeExplorers'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen'; import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService'; @@ -66,7 +66,7 @@ export function createApiFactory(threadService: IThreadService, extensionService const extHostDocuments = col.define(ExtHostContext.ExtHostDocuments).set(new ExtHostDocuments(threadService)); const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocuments)); - const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostExplorers(threadService)); + const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostTreeExplorers(threadService)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostEditors, extHostHeapService)); const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration))); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); @@ -335,7 +335,7 @@ export function createApiFactory(threadService: IThreadService, extensionService onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables); }, - registerTreeContentProvider(providerId: string, provider: vscode.TreeContentProvider) { + registerTreeExplorerNodeProvider(providerId: string, provider: vscode.TreeExplorerNodeProvider) { return extHostExplorers.registerTreeContentProvider(providerId, provider); }, onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { diff --git a/src/vs/workbench/api/node/extHost.contribution.ts b/src/vs/workbench/api/node/extHost.contribution.ts index 040b1453475..8c92f83ba0f 100644 --- a/src/vs/workbench/api/node/extHost.contribution.ts +++ b/src/vs/workbench/api/node/extHost.contribution.ts @@ -20,7 +20,7 @@ import { MainThreadDiagnostics } from './mainThreadDiagnostics'; import { MainThreadDocuments } from './mainThreadDocuments'; import { MainThreadEditors } from './mainThreadEditors'; import { MainThreadErrors } from './mainThreadErrors'; -import { MainThreadExplorers } from './mainThreadExplorers'; +import { MainThreadTreeExplorers } from './mainThreadTreeExplorers'; import { MainThreadLanguageFeatures } from './mainThreadLanguageFeatures'; import { MainThreadLanguages } from './mainThreadLanguages'; import { MainThreadMessageService } from './mainThreadMessageService'; @@ -71,7 +71,7 @@ export class ExtHostContribution implements IWorkbenchContribution { col.define(MainContext.MainThreadDocuments).set(create(MainThreadDocuments)); col.define(MainContext.MainThreadEditors).set(create(MainThreadEditors)); col.define(MainContext.MainThreadErrors).set(create(MainThreadErrors)); - col.define(MainContext.MainThreadExplorers).set(create(MainThreadExplorers)); + col.define(MainContext.MainThreadExplorers).set(create(MainThreadTreeExplorers)); col.define(MainContext.MainThreadLanguageFeatures).set(create(MainThreadLanguageFeatures)); col.define(MainContext.MainThreadLanguages).set(create(MainThreadLanguages)); col.define(MainContext.MainThreadMessageService).set(create(MainThreadMessageService)); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index a94a24cb8a3..702ea0a5378 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -34,7 +34,7 @@ import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker'; -import { ExtHostTreeNode } from 'vs/workbench/api/node/extHostExplorers'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export interface InstanceSetter { set(instance: T): R; @@ -117,7 +117,7 @@ export abstract class MainThreadEditorsShape { $tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise { throw ni(); } } -export abstract class MainThreadExplorersShape { +export abstract class MainThreadTreeExplorersShape { $registerTreeContentProvider(treeContentProviderId: string): void { throw ni(); } $unregisterTreeContentProvider(treeContentProviderId: string): void { throw ni(); } } @@ -264,9 +264,9 @@ export abstract class ExtHostEditorsShape { $acceptTextEditorRemove(id: string): void { throw ni(); } } -export abstract class ExtHostExplorersShape { - $provideTreeContent(treeContentProviderId: string): TPromise { throw ni(); }; - $resolveChildren(treeContentProviderId: string, node: ExtHostTreeNode): TPromise { throw ni(); } +export abstract class ExtHostTreeExplorersShape { + $provideRootNode(providerId: string): TPromise { throw ni(); }; + $resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { @@ -343,7 +343,7 @@ export const MainContext = { MainThreadDocuments: createMainId('MainThreadDocuments', MainThreadDocumentsShape), MainThreadEditors: createMainId('MainThreadEditors', MainThreadEditorsShape), MainThreadErrors: createMainId('MainThreadErrors', MainThreadErrorsShape), - MainThreadExplorers: createMainId('MainThreadExplorers', MainThreadExplorersShape), + MainThreadExplorers: createMainId('MainThreadExplorers', MainThreadTreeExplorersShape), MainThreadLanguageFeatures: createMainId('MainThreadLanguageFeatures', MainThreadLanguageFeaturesShape), MainThreadLanguages: createMainId('MainThreadLanguages', MainThreadLanguagesShape), MainThreadMessageService: createMainId('MainThreadMessageService', MainThreadMessageServiceShape), @@ -364,7 +364,7 @@ export const ExtHostContext = { ExtHostDocuments: createExtId('ExtHostDocuments', ExtHostDocumentsShape), ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant', ExtHostDocumentSaveParticipantShape), ExtHostEditors: createExtId('ExtHostEditors', ExtHostEditorsShape), - ExtHostExplorers: createExtId('ExtHostExplorers',ExtHostExplorersShape), + ExtHostExplorers: createExtId('ExtHostExplorers',ExtHostTreeExplorersShape), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService', ExtHostFileSystemEventServiceShape), ExtHostHeapService: createExtId('ExtHostHeapMonitor', ExtHostHeapServiceShape), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures', ExtHostLanguageFeaturesShape), diff --git a/src/vs/workbench/api/node/extHostExplorers.ts b/src/vs/workbench/api/node/extHostExplorers.ts deleted file mode 100644 index 2d6c7f0dcc4..00000000000 --- a/src/vs/workbench/api/node/extHostExplorers.ts +++ /dev/null @@ -1,95 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { TreeContentNode, TreeContentProvider } from 'vscode'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {Disposable} from 'vs/workbench/api/node/extHostTypes'; -import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; -import {MainContext, ExtHostExplorersShape, MainThreadExplorersShape} from './extHost.protocol'; - -export class ExtHostExplorers extends ExtHostExplorersShape { - private _proxy: MainThreadExplorersShape; - - private _treeContentProviders: { [treeContentProviderId: string]: TreeContentProvider }; - private _treeContents: { [treeContentProviderId: string]: ExtHostTreeNode }; - private _treeNodeMaps: { [treeContentProviderId: string]: { [id: number]: ExtHostTreeNode }}; - - constructor( - threadService: IThreadService - ) { - super(); - - this._proxy = threadService.get(MainContext.MainThreadExplorers); - - this._treeContentProviders = Object.create(null); - this._treeContents = Object.create(null); - this._treeNodeMaps = Object.create(null); - } - - registerTreeContentProvider(providerId: string, provider: TreeContentProvider): Disposable { - this._proxy.$registerTreeContentProvider(providerId); - this._treeContentProviders[providerId] = provider; - - return new Disposable(() => { - if (delete this._treeContentProviders[providerId]) { - this._proxy.$unregisterTreeContentProvider(providerId); - } - }); - } - - $provideTreeContent(treeContentProviderId: string): TPromise { - const provider = this._treeContentProviders[treeContentProviderId]; - if (!provider) { - throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); - } - - return TPromise.wrap(provider.provideTreeContent().then(treeContent => { - const treeNodeMap = Object.create(null); - this._treeNodeMaps[treeContentProviderId] = treeNodeMap; - this._treeContents[treeContentProviderId] = new ExtHostTreeNode(treeContent, null, treeNodeMap); - return this._treeContents[treeContentProviderId]; - })); - } - - $resolveChildren(treeContentProviderId: string, mainThreadNode: ExtHostTreeNode): TPromise { - const provider = this._treeContentProviders[treeContentProviderId]; - if (!provider) { - throw new Error(`no TreeContentProvider registered with id '${treeContentProviderId}'`); - } - - const treeNodeMap = this._treeNodeMaps[treeContentProviderId]; - const extHostNode = treeNodeMap[mainThreadNode.id]; - - return TPromise.wrap(provider.resolveChildren(extHostNode).then(children => { - extHostNode.children = children.map(child => { - return new ExtHostTreeNode(child, extHostNode, treeNodeMap); - }); - return extHostNode.children; - })); - } -} - -export class ExtHostTreeNode implements TreeContentNode { - static idCounter = 1; - - id: number; - - label: string; - shouldInitiallyExpand: boolean; - children: ExtHostTreeNode[]; - - constructor(node: TreeContentNode, parent: ExtHostTreeNode, treeNodeMap: { [id: number]: ExtHostTreeNode}) { - this.id = ExtHostTreeNode.idCounter++; - - this.label = node.label; - this.shouldInitiallyExpand = node.shouldInitiallyExpand; - this.children = node.children.map(child => { - return new ExtHostTreeNode(child, this, treeNodeMap); - }) - - treeNodeMap[this.id] = this; - } -} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts new file mode 100644 index 00000000000..88600fda806 --- /dev/null +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Disposable } from 'vs/workbench/api/node/extHostTypes'; +import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; +import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } from './extHost.protocol'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; + +export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { + private _proxy: MainThreadTreeExplorersShape; + + private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; + + private _trees: { [providerId: string]: InternalTreeExplorerNode }; + private _treeNodeMaps: { [providerId: string]: { [id: number]: InternalTreeExplorerNode }}; + + constructor( + threadService: IThreadService + ) { + super(); + + this._proxy = threadService.get(MainContext.MainThreadExplorers); + + this._treeExplorerNodeProviders = Object.create(null); + this._trees = Object.create(null); + this._treeNodeMaps = Object.create(null); + } + + registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { + this._proxy.$registerTreeContentProvider(providerId); + this._treeExplorerNodeProviders[providerId] = provider; + + return new Disposable(() => { + if (delete this._treeExplorerNodeProviders[providerId]) { + this._proxy.$unregisterTreeContentProvider(providerId); + } + }); + } + + $provideRootNode(providerId: string): TPromise { + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + } + + return TPromise.wrap(provider.provideRootNode().then(rootNode => { + const treeNodeMap = Object.create(null); + this._treeNodeMaps[providerId] = treeNodeMap; + + const internalRootNode = new InternalTreeExplorerNode(rootNode); + this._trees[providerId] = internalRootNode; + this._treeNodeMaps[providerId][internalRootNode.id] = internalRootNode; + return this._trees[providerId]; + })); + } + + $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + } + + const treeNodeMap = this._treeNodeMaps[providerId]; + const extHostTreeContentNode = treeNodeMap[mainThreadNode.id]; + + return TPromise.wrap(provider.resolveChildren(extHostTreeContentNode).then(children => { + return children.map(child => { + const internalChild = new InternalTreeExplorerNode(child); + treeNodeMap[internalChild.id] = internalChild; + return internalChild; + }); + })); + } +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/mainThreadExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts similarity index 52% rename from src/vs/workbench/api/node/mainThreadExplorers.ts rename to src/vs/workbench/api/node/mainThreadTreeExplorers.ts index c014a864424..0b6d9dae494 100644 --- a/src/vs/workbench/api/node/mainThreadExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -4,19 +4,17 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {TreeContentNode} from 'vscode'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {IThreadService} from 'vs/workbench/services/thread/common/threadService'; -import {ExtHostContext, MainThreadExplorersShape, ExtHostExplorersShape} from './extHost.protocol'; -import {ITreeExplorerViewletService} from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; -import {TreeViewNode} from 'vs/workbench/parts/explorers/common/treeViewModel'; +import { TreeExplorerNode } from 'vscode'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; +import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; -import { ExtHostTreeNode } from 'vs/workbench/api/node/extHostExplorers'; +export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { + private _proxy: ExtHostTreeExplorersShape; -export class MainThreadExplorers extends MainThreadExplorersShape { - private _proxy: ExtHostExplorersShape; - - private _treeContents: { [treeContentProviderId: string]: ExtHostTreeNode }; + private _treeContents: { [treeContentProviderId: string]: InternalTreeExplorerNode }; constructor( @IThreadService threadService: IThreadService, @@ -30,13 +28,13 @@ export class MainThreadExplorers extends MainThreadExplorersShape { $registerTreeContentProvider(providerId: string): void { this.treeExplorerViewletService.registerTreeContentProvider(providerId, { - provideTreeContent: (): TPromise => { - return this._proxy.$provideTreeContent(providerId).then(treeContent => { + provideRootNode: (): TPromise => { + return this._proxy.$provideRootNode(providerId).then(treeContent => { this._treeContents[providerId] = treeContent; return treeContent; }) }, - resolveChildren: (node: ExtHostTreeNode): TPromise => { + resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); } }); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 15d8f5fdd7d..bba11ff12c1 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -1,6 +1,6 @@ 'use strict'; -import { TreeContentNode, TreeContentProvider } from 'vscode'; +import { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -10,15 +10,15 @@ export const ITreeExplorerViewletService = createDecorator; - resolveChildren(providerId: string, node: TreeContentNode): TPromise; + registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): void; + provideTreeContent(providerId: string): TPromise; + resolveChildren(providerId: string, node: TreeExplorerNode): TPromise; } export class TreeExplorerViewletService implements ITreeExplorerViewletService { public _serviceBrand: any; - private _treeContentProviders: { [providerId: string]: TreeContentProvider; }; + private _treeContentProviders: { [providerId: string]: TreeExplorerNodeProvider; }; constructor( @IInstantiationService private _instantiationService: IInstantiationService @@ -26,15 +26,15 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { this._treeContentProviders = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: TreeContentProvider): void { + registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): void { this._treeContentProviders[providerId] = provider; } - provideTreeContent(providerId: string): TPromise { - return TPromise.wrap(this._treeContentProviders[providerId].provideTreeContent()); + provideTreeContent(providerId: string): TPromise { + return TPromise.wrap(this._treeContentProviders[providerId].provideRootNode()); } - resolveChildren(providerId: string, node: TreeContentNode): TPromise { + resolveChildren(providerId: string, node: TreeExplorerNode): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); } } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index f396ef0299a..a6a3f5f0432 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -22,10 +22,9 @@ import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; - import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; +import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; @@ -51,7 +50,7 @@ export class TreeExplorerView extends CollapsibleViewletView { @IEditorGroupService private editorGroupService: IEditorGroupService, @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { - super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Tree Section"), messageService, keybindingService, contextMenuService, headerSize); + super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); this.viewletState = viewletState; this._treeName = treeName; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index ad8292db207..639c6007a9d 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -3,7 +3,7 @@ import { $, Builder } from 'vs/base/browser/builder'; import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeViewModel'; +import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ClickBehavior, DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts new file mode 100644 index 00000000000..0aea2077a7e --- /dev/null +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -0,0 +1,39 @@ +import { TreeExplorerNode } from 'vscode'; + +export class TreeViewNode implements TreeExplorerNode { + static idCounter = 1; + + id: number; + hasChildren: boolean = true; + isChildrenResolved: boolean = false; + + constructor( + public label: string, + public shouldInitiallyExpand: boolean = true, + public children: TreeViewNode[] = [] + ) { + this.id = TreeViewNode.idCounter++; + } + + public static create(node: TreeExplorerNode): TreeViewNode { + const children = node.children.map(TreeViewNode.create); + return new TreeViewNode(node.label, node.shouldInitiallyExpand, children) + } +} + +export class InternalTreeExplorerNode implements TreeExplorerNode { + static idCounter = 1; + + id: number; + + // Property on TreeContentNode + label: string; + shouldInitiallyExpand: boolean; + + constructor(node: TreeExplorerNode) { + this.id = InternalTreeExplorerNode.idCounter++; + + this.label = node.label; + this.shouldInitiallyExpand = node.shouldInitiallyExpand; + } +} diff --git a/src/vs/workbench/parts/explorers/common/treeViewModel.ts b/src/vs/workbench/parts/explorers/common/treeViewModel.ts deleted file mode 100644 index 1c4b17c4c7d..00000000000 --- a/src/vs/workbench/parts/explorers/common/treeViewModel.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { TreeContentNode } from 'vscode'; - -export class TreeViewNode implements TreeContentNode { - static idCounter = 1; - - id: number; - hasChildren: boolean = true; - isChildrenResolved: boolean = false; - - constructor( - public label: string, - public shouldInitiallyExpand: boolean = true, - public children: TreeViewNode[] = [] - ) { - this.id = TreeViewNode.idCounter++; - } - - public static create(node: TreeContentNode): TreeViewNode { - const children = node.children.map(TreeViewNode.create); - return new TreeViewNode(node.label, node.shouldInitiallyExpand, children) - } -} From f366857f8bddc133598bf3e1b7372026fe4f2e1c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 11 Oct 2016 09:25:07 -0700 Subject: [PATCH 023/119] Completely remove children --- src/vs/monaco.d.ts | 14 +++++++++ .../api/node/extHostTreeExplorers.ts | 25 +++++++--------- .../browser/treeExplorerViewletService.ts | 11 +++---- .../browser/views/treeExplorerView.ts | 4 +-- .../browser/views/treeExplorerViewer.ts | 30 +++++++------------ .../explorers/common/treeExplorerViewModel.ts | 21 ------------- 6 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index adaa36fa7af..3bf3adbe4ef 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2788,6 +2788,20 @@ declare module monaco.editor { * An array of keybindings for the action. */ keybindings?: number[]; + /** + * Control if the action should show up in the context menu and where. + * The context menu of the editor has these default: + * navigation - The navigation group comes first in all cases. + * 1_modification - This group comes next and contains commands that modify your code. + * 9_cutcopypaste - The last default group with the basic editing commands. + * You can also create your own group. + * Defaults to null (don't show in context menu). + */ + contextMenuGroupId?: string; + /** + * Control the order in the context menu group. + */ + contextMenuOrder?: number; /** * The keybinding rule. */ diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 88600fda806..593846a46cb 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -16,8 +16,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - private _trees: { [providerId: string]: InternalTreeExplorerNode }; - private _treeNodeMaps: { [providerId: string]: { [id: number]: InternalTreeExplorerNode }}; + private _externalNodeMaps: { [providerId: string]: { [id: number]: TreeExplorerNode }}; constructor( threadService: IThreadService @@ -27,8 +26,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._proxy = threadService.get(MainContext.MainThreadExplorers); this._treeExplorerNodeProviders = Object.create(null); - this._trees = Object.create(null); - this._treeNodeMaps = Object.create(null); + this._externalNodeMaps = Object.create(null); } registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { @@ -48,14 +46,13 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { throw new Error(`no TreeContentProvider registered with id '${providerId}'`); } - return TPromise.wrap(provider.provideRootNode().then(rootNode => { + return TPromise.wrap(provider.provideRootNode().then(externalRootNode => { const treeNodeMap = Object.create(null); - this._treeNodeMaps[providerId] = treeNodeMap; + this._externalNodeMaps[providerId] = treeNodeMap; - const internalRootNode = new InternalTreeExplorerNode(rootNode); - this._trees[providerId] = internalRootNode; - this._treeNodeMaps[providerId][internalRootNode.id] = internalRootNode; - return this._trees[providerId]; + const internalRootNode = new InternalTreeExplorerNode(externalRootNode); + this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; + return internalRootNode; })); } @@ -65,13 +62,13 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { throw new Error(`no TreeContentProvider registered with id '${providerId}'`); } - const treeNodeMap = this._treeNodeMaps[providerId]; - const extHostTreeContentNode = treeNodeMap[mainThreadNode.id]; + const externalNodeMap = this._externalNodeMaps[providerId]; + const externalNode = externalNodeMap[mainThreadNode.id]; - return TPromise.wrap(provider.resolveChildren(extHostTreeContentNode).then(children => { + return TPromise.wrap(provider.resolveChildren(externalNode).then(children => { return children.map(child => { const internalChild = new InternalTreeExplorerNode(child); - treeNodeMap[internalChild.id] = internalChild; + externalNodeMap[internalChild.id] = externalNode; return internalChild; }); })); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index bba11ff12c1..27f7571c618 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -1,9 +1,10 @@ 'use strict'; -import { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; +import { TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export const ITreeExplorerViewletService = createDecorator('customViewletService'); @@ -11,8 +12,8 @@ export interface ITreeExplorerViewletService { _serviceBrand: any; registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): void; - provideTreeContent(providerId: string): TPromise; - resolveChildren(providerId: string, node: TreeExplorerNode): TPromise; + provideTreeContent(providerId: string): TPromise; + resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise; } export class TreeExplorerViewletService implements ITreeExplorerViewletService { @@ -30,11 +31,11 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { this._treeContentProviders[providerId] = provider; } - provideTreeContent(providerId: string): TPromise { + provideTreeContent(providerId: string): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].provideRootNode()); } - resolveChildren(providerId: string, node: TreeExplorerNode): TPromise { + resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); } } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index a6a3f5f0432..cb7b8d3a7fe 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -24,7 +24,7 @@ import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; @@ -107,7 +107,7 @@ export class TreeExplorerView extends CollapsibleViewletView { private updateInput(): TPromise { return this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { - this.tree.setInput(TreeViewNode.create(tree)); + this.tree.setInput(tree); }) } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 639c6007a9d..8d754a4f14e 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -3,7 +3,7 @@ import { $, Builder } from 'vs/base/browser/builder'; import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { TreeViewNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ClickBehavior, DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -25,29 +25,19 @@ export class TreeDataSource implements IDataSource { } - getId(tree: ITree, node: TreeViewNode): string { + getId(tree: ITree, node: InternalTreeExplorerNode): string { return node.id.toString(); } - hasChildren(tree: ITree, node: TreeViewNode): boolean { - return node.hasChildren; + hasChildren(tree: ITree, node: InternalTreeExplorerNode): boolean { + return true; } - getChildren(tree: ITree, node: TreeViewNode): TPromise { - if (node.isChildrenResolved) { - return TPromise.as(node.children); - } else { - return this.treeExplorerViewletService.resolveChildren(providerId, node).then(children => { - children.forEach(child => { - node.children.push(TreeViewNode.create(child)); - }); - node.isChildrenResolved = true; - return node.children; - }); - } + getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { + return this.treeExplorerViewletService.resolveChildren('pineTree', node); } - getParent(tree: ITree, node: TreeViewNode): TPromise { + getParent(tree: ITree, node: InternalTreeExplorerNode): TPromise { return TPromise.as(null); } } @@ -72,14 +62,14 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { return 22; } - renderContents(tree: ITree, node: TreeViewNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { + renderContents(tree: ITree, node: InternalTreeExplorerNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { const el = $(domElement).clearChildren(); const item = $('.custom-viewlet-tree-node-item'); item.appendTo(el); return this.renderFileFolderLabel(item, node); } - private renderFileFolderLabel(container: Builder, node: TreeViewNode): IElementCallback { + private renderFileFolderLabel(container: Builder, node: InternalTreeExplorerNode): IElementCallback { const label = $('.custom-viewlet-tree-node-item-label').appendTo(container); $('a.plain').text(node.label).title(node.label).appendTo(label); @@ -93,7 +83,7 @@ export class TreeController extends DefaultController { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } - onLeftClick(tree: ITree, node: TreeViewNode, event: IMouseEvent, origin: string = 'mouse'): boolean { + onLeftClick(tree: ITree, node: InternalTreeExplorerNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); return true; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 0aea2077a7e..b5b3ed5c031 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -1,26 +1,5 @@ import { TreeExplorerNode } from 'vscode'; -export class TreeViewNode implements TreeExplorerNode { - static idCounter = 1; - - id: number; - hasChildren: boolean = true; - isChildrenResolved: boolean = false; - - constructor( - public label: string, - public shouldInitiallyExpand: boolean = true, - public children: TreeViewNode[] = [] - ) { - this.id = TreeViewNode.idCounter++; - } - - public static create(node: TreeExplorerNode): TreeViewNode { - const children = node.children.map(TreeViewNode.create); - return new TreeViewNode(node.label, node.shouldInitiallyExpand, children) - } -} - export class InternalTreeExplorerNode implements TreeExplorerNode { static idCounter = 1; From 09703d267e087b08942ad8630081cddf67293f0d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 11 Oct 2016 12:45:39 -0700 Subject: [PATCH 024/119] Add initial onClickCommand --- src/vs/vscode.d.ts | 1 + src/vs/workbench/api/node/extHostTreeExplorers.ts | 6 +++--- .../parts/explorers/browser/views/treeExplorerViewer.ts | 9 ++++++++- .../parts/explorers/common/treeExplorerViewModel.ts | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b6d90e0f35c..fcfd7ce317f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1356,6 +1356,7 @@ declare module 'vscode' { export interface TreeExplorerNode { label: string; shouldInitiallyExpand: boolean; + onClickCommand: string; } /** diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 593846a46cb..22f3761d48c 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -66,9 +66,9 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const externalNode = externalNodeMap[mainThreadNode.id]; return TPromise.wrap(provider.resolveChildren(externalNode).then(children => { - return children.map(child => { - const internalChild = new InternalTreeExplorerNode(child); - externalNodeMap[internalChild.id] = externalNode; + return children.map(externalChild => { + const internalChild = new InternalTreeExplorerNode(externalChild); + externalNodeMap[internalChild.id] = externalChild; return internalChild; }); })); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 8d754a4f14e..f8d04029fca 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -10,6 +10,7 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IActionRunner } from 'vs/base/common/actions'; import { IActionProvider, ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -79,13 +80,19 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { - constructor() { + constructor( + @ICommandService private commandService: ICommandService, + ) { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } onLeftClick(tree: ITree, node: InternalTreeExplorerNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); + if (node.onClickCommand) { + this.commandService.executeCommand(node.onClickCommand).done(); + } + return true; } } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index b5b3ed5c031..55cd5b0201b 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -8,11 +8,13 @@ export class InternalTreeExplorerNode implements TreeExplorerNode { // Property on TreeContentNode label: string; shouldInitiallyExpand: boolean; + onClickCommand: string; constructor(node: TreeExplorerNode) { this.id = InternalTreeExplorerNode.idCounter++; this.label = node.label; this.shouldInitiallyExpand = node.shouldInitiallyExpand; + this.onClickCommand = node.onClickCommand; } } From c7f2d3d1f1a1c93ff925284fa06c22a12284439b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 11 Oct 2016 15:24:34 -0700 Subject: [PATCH 025/119] Resolving onClickCommand and clean up Drop the viewlet part in treeExplorerViewletService --- src/vs/vscode.d.ts | 2 +- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- src/vs/workbench/api/node/extHost.protocol.ts | 1 + .../api/node/extHostTreeExplorers.ts | 20 ++++++++++++++++++- .../api/node/mainThreadTreeExplorers.ts | 7 +++++-- ...ewletService.ts => treeExplorerService.ts} | 19 +++++++++++------- .../treeExplorerViewlet.contribution.ts | 4 ++-- .../browser/views/treeExplorerView.ts | 4 ++-- .../browser/views/treeExplorerViewer.ts | 9 ++++----- .../explorers/common/treeExplorerViewModel.ts | 7 ++++++- 10 files changed, 53 insertions(+), 22 deletions(-) rename src/vs/workbench/parts/explorers/browser/{treeExplorerViewletService.ts => treeExplorerService.ts} (58%) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index fcfd7ce317f..1eb985a0519 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1356,7 +1356,7 @@ declare module 'vscode' { export interface TreeExplorerNode { label: string; shouldInitiallyExpand: boolean; - onClickCommand: string; + onClickCommand?: string; } /** diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index e51010b1de3..a58824db37f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -66,7 +66,7 @@ export function createApiFactory(threadService: IThreadService, extensionService const extHostDocuments = col.define(ExtHostContext.ExtHostDocuments).set(new ExtHostDocuments(threadService)); const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocuments)); - const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostTreeExplorers(threadService)); + const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostTreeExplorers(threadService, extHostCommands)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostEditors, extHostHeapService)); const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration))); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 702ea0a5378..fd2e4b519ab 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -267,6 +267,7 @@ export abstract class ExtHostEditorsShape { export abstract class ExtHostTreeExplorersShape { $provideRootNode(providerId: string): TPromise { throw ni(); }; $resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } + $resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 22f3761d48c..dd33dcaf4b3 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -10,6 +10,7 @@ import { Disposable } from 'vs/workbench/api/node/extHostTypes'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } from './extHost.protocol'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; @@ -19,7 +20,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _externalNodeMaps: { [providerId: string]: { [id: number]: TreeExplorerNode }}; constructor( - threadService: IThreadService + threadService: IThreadService, + private commands: ExtHostCommands ) { super(); @@ -73,4 +75,20 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { }); })); } + + $resolveCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + } + + if (mainThreadNode.onClickCommand) { + return TPromise.wrap(this.commands.executeCommand(mainThreadNode.onClickCommand, this._externalNodeMaps[providerId][mainThreadNode.id]).then(() => { + // Todo: error handling + return null; + })); + } + + return TPromise.as(null); + } } \ No newline at end of file diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 0b6d9dae494..f80326583e4 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -8,7 +8,7 @@ import { TreeExplorerNode } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { @@ -18,7 +18,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { constructor( @IThreadService threadService: IThreadService, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { super(); @@ -36,6 +36,9 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { }, resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); + }, + resolveCommand: (node: InternalTreeExplorerNode): TPromise => { + return this._proxy.$resolveCommand(providerId, node); } }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts similarity index 58% rename from src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts rename to src/vs/workbench/parts/explorers/browser/treeExplorerService.ts index 27f7571c618..2f8f56c40a7 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts @@ -4,22 +4,23 @@ import { TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; -export const ITreeExplorerViewletService = createDecorator('customViewletService'); +export const ITreeExplorerService = createDecorator('customViewletService'); -export interface ITreeExplorerViewletService { +export interface ITreeExplorerService { _serviceBrand: any; - registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): void; + registerTreeContentProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void; provideTreeContent(providerId: string): TPromise; resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise; + resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; } -export class TreeExplorerViewletService implements ITreeExplorerViewletService { +export class TreeExplorerViewletService implements ITreeExplorerService { public _serviceBrand: any; - private _treeContentProviders: { [providerId: string]: TreeExplorerNodeProvider; }; + private _treeContentProviders: { [providerId: string]: InternalTreeExplorerNodeProvider }; constructor( @IInstantiationService private _instantiationService: IInstantiationService @@ -27,7 +28,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { this._treeContentProviders = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): void { + registerTreeContentProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { this._treeContentProviders[providerId] = provider; } @@ -38,4 +39,8 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); } + + resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { + return TPromise.wrap(this._treeContentProviders[providerId].resolveCommand(node)); + } } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index df1d4bb28a0..ecfbdb6770b 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -1,6 +1,6 @@ 'use strict'; -import {ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import {ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); \ No newline at end of file +registerSingleton(ITreeExplorerService, TreeExplorerViewletService); \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index cb7b8d3a7fe..5f3095604d8 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -16,7 +16,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; @@ -48,7 +48,7 @@ export class TreeExplorerView extends CollapsibleViewletView { @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index f8d04029fca..4349b94da9a 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -10,18 +10,17 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { IActionRunner } from 'vs/base/common/actions'; import { IActionProvider, ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; -import { ICommandService } from 'vs/platform/commands/common/commands'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; const providerId = 'pineTree'; // For now export class TreeDataSource implements IDataSource { constructor( - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { } @@ -81,7 +80,7 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { constructor( - @ICommandService private commandService: ICommandService, + @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } @@ -90,7 +89,7 @@ export class TreeController extends DefaultController { super.onLeftClick(tree, node, event, origin); if (node.onClickCommand) { - this.commandService.executeCommand(node.onClickCommand).done(); + this.treeExplorerViewletService.resolveCommand('pineTree', node); } return true; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 55cd5b0201b..836fb5bb1fd 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -1,4 +1,5 @@ -import { TreeExplorerNode } from 'vscode'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; export class InternalTreeExplorerNode implements TreeExplorerNode { static idCounter = 1; @@ -18,3 +19,7 @@ export class InternalTreeExplorerNode implements TreeExplorerNode { this.onClickCommand = node.onClickCommand; } } + +export interface InternalTreeExplorerNodeProvider extends TreeExplorerNodeProvider { + resolveCommand(node: TreeExplorerNode): TPromise; +} \ No newline at end of file From 30e3be2c435ba29eb5c3e463a31550d66f138c2b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 12 Oct 2016 11:51:03 -0700 Subject: [PATCH 026/119] Rename treeContentProviderId to treeExplorerNodeProviderId --- .../actions/browser/menusExtensionPoint.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 1f353593406..0f4c6fce494 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -212,7 +212,7 @@ namespace schema { // --- treeExplorers contribution point export interface IExplorer { - treeContentProviderId: string; + treeExplorerNodeProviderId: string; treeLabel: string; icon: IUserFriendlyIcon; } @@ -222,7 +222,7 @@ namespace schema { type: 'object', properties: { treeContentProviderId: { - description: localize('vscode.extension.contributes.explorer.treeContentProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeContentProvider'), + description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), type: 'string' }, treeLabel: { @@ -342,17 +342,17 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e let baseOrder = 200; for (let extension of extensions) { - const { treeContentProviderId, treeLabel, icon } = extension.value; + const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; if (icon) { if (typeof icon === 'string') { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; const iconPath = join(extension.description.extensionFolderPath, icon); createCSSRule(iconClass, getIconRule(iconPath)); } else { - const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; - const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeContentProviderId}`; + const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; createCSSRule(lightIconClass, getIconRule(icon.light)); createCSSRule(darkIconClass, getIconRule(icon.dark)); } @@ -361,9 +361,9 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - 'workbench.view.customTreeExplorerViewlet.' + treeContentProviderId, + 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, treeLabel, - treeContentProviderId, + treeExplorerNodeProviderId, baseOrder++ )); } From b8ce9ad7682c81f8f789e49b53620a47c27db3dc Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 13 Oct 2016 10:38:18 -0700 Subject: [PATCH 027/119] Make nodeProvider generic and add contentProvider --- src/vs/vscode.d.ts | 17 +++++++++++------ src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- .../api/node/extHostTreeExplorers.ts | 19 ++++++++++--------- .../api/node/mainThreadTreeExplorers.ts | 6 +++--- .../explorers/common/treeExplorerViewModel.ts | 13 +++++++------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1eb985a0519..c49833b1d55 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,12 +1348,17 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } - export interface TreeExplorerNodeProvider { - provideRootNode(): Thenable; - resolveChildren(node: TreeExplorerNode): Thenable; + export interface TreeExplorerNodeProvider { + contentProvider: TreeExplorerNodeContentProvider; + provideRootNode(): Thenable; + resolveChildren(node: T): Thenable; } - export interface TreeExplorerNode { + export interface TreeExplorerNodeContentProvider { + provideNodeContent(node: T): TreeExplorerNodeContent; + } + + export interface TreeExplorerNodeContent { label: string; shouldInitiallyExpand: boolean; onClickCommand?: string; @@ -3815,14 +3820,14 @@ declare module 'vscode' { export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; /** - * Register a tree content provider, used as a data source + * Register a tree explorer node provider, used as a data source * for custom tree explorers. * * @param providerId A unique id that identifies the provider. * @param provider A [TreeContentProvider](#TreeContentProvider) * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ - export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; + export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; /** * An event that is emitted when a [text document](#TextDocument) is opened. diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index a58824db37f..114417f743b 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -335,7 +335,7 @@ export function createApiFactory(threadService: IThreadService, extensionService onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables); }, - registerTreeExplorerNodeProvider(providerId: string, provider: vscode.TreeExplorerNodeProvider) { + registerTreeExplorerNodeProvider(providerId: string, provider: vscode.TreeExplorerNodeProvider) { return extHostExplorers.registerTreeContentProvider(providerId, provider); }, onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index dd33dcaf4b3..edc514323ce 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; +import { TreeExplorerNodeContent, TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/workbench/api/node/extHostTypes'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; @@ -15,9 +15,8 @@ import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; - private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - - private _externalNodeMaps: { [providerId: string]: { [id: number]: TreeExplorerNode }}; + private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; + private _externalNodeMaps: { [providerId: string]: { [id: number]: TreeExplorerNodeContent }}; constructor( threadService: IThreadService, @@ -31,7 +30,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._externalNodeMaps = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { + registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { this._proxy.$registerTreeContentProvider(providerId); this._treeExplorerNodeProviders[providerId] = provider; @@ -52,7 +51,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const treeNodeMap = Object.create(null); this._externalNodeMaps[providerId] = treeNodeMap; - const internalRootNode = new InternalTreeExplorerNode(externalRootNode); + const externalNodeContent = provider.contentProvider.provideNodeContent(externalRootNode); + const internalRootNode = new InternalTreeExplorerNode(externalNodeContent); this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; })); @@ -69,7 +69,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return TPromise.wrap(provider.resolveChildren(externalNode).then(children => { return children.map(externalChild => { - const internalChild = new InternalTreeExplorerNode(externalChild); + const externalChildContent = provider.contentProvider.provideNodeContent(externalChild); + const internalChild = new InternalTreeExplorerNode(externalChildContent); externalNodeMap[internalChild.id] = externalChild; return internalChild; }); @@ -83,8 +84,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { } if (mainThreadNode.onClickCommand) { - return TPromise.wrap(this.commands.executeCommand(mainThreadNode.onClickCommand, this._externalNodeMaps[providerId][mainThreadNode.id]).then(() => { - // Todo: error handling + const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; + return TPromise.wrap(this.commands.executeCommand(mainThreadNode.onClickCommand, externalNode).then(() => { return null; })); } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index f80326583e4..6abf836587f 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TreeExplorerNode } from 'vscode'; +import { TreeExplorerNodeContent } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; @@ -18,7 +18,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { constructor( @IThreadService threadService: IThreadService, - @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService + @ITreeExplorerService private treeExplorerService: ITreeExplorerService ) { super(); @@ -27,7 +27,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { } $registerTreeContentProvider(providerId: string): void { - this.treeExplorerViewletService.registerTreeContentProvider(providerId, { + this.treeExplorerService.registerTreeContentProvider(providerId, { provideRootNode: (): TPromise => { return this._proxy.$provideRootNode(providerId).then(treeContent => { this._treeContents[providerId] = treeContent; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 836fb5bb1fd..3ee31534bbb 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -1,17 +1,16 @@ import { TPromise } from 'vs/base/common/winjs.base'; -import { TreeExplorerNode, TreeExplorerNodeProvider } from 'vscode'; +import { TreeExplorerNodeContent, TreeExplorerNodeProvider } from 'vscode'; -export class InternalTreeExplorerNode implements TreeExplorerNode { +export class InternalTreeExplorerNode implements TreeExplorerNodeContent { static idCounter = 1; id: number; - // Property on TreeContentNode label: string; shouldInitiallyExpand: boolean; onClickCommand: string; - constructor(node: TreeExplorerNode) { + constructor(node: TreeExplorerNodeContent) { this.id = InternalTreeExplorerNode.idCounter++; this.label = node.label; @@ -20,6 +19,8 @@ export class InternalTreeExplorerNode implements TreeExplorerNode { } } -export interface InternalTreeExplorerNodeProvider extends TreeExplorerNodeProvider { - resolveCommand(node: TreeExplorerNode): TPromise; +export interface InternalTreeExplorerNodeProvider { + resolveCommand(node: TreeExplorerNodeContent): TPromise; + provideRootNode(): Thenable; + resolveChildren(node: InternalTreeExplorerNode): Thenable; } \ No newline at end of file From 668aa6556b38d2e930de985a5a8ca33ada2413a8 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 13 Oct 2016 10:53:22 -0700 Subject: [PATCH 028/119] onClickCommand -> clickCommand --- src/vs/vscode.d.ts | 2 +- src/vs/workbench/api/node/extHostTreeExplorers.ts | 4 ++-- .../parts/explorers/browser/views/treeExplorerViewer.ts | 2 +- .../workbench/parts/explorers/common/treeExplorerViewModel.ts | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index c49833b1d55..a5504996d22 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1361,7 +1361,7 @@ declare module 'vscode' { export interface TreeExplorerNodeContent { label: string; shouldInitiallyExpand: boolean; - onClickCommand?: string; + clickCommand?: string; } /** diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index edc514323ce..bd2a6f92e87 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -83,9 +83,9 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { throw new Error(`no TreeContentProvider registered with id '${providerId}'`); } - if (mainThreadNode.onClickCommand) { + if (mainThreadNode.clickCommand) { const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; - return TPromise.wrap(this.commands.executeCommand(mainThreadNode.onClickCommand, externalNode).then(() => { + return TPromise.wrap(this.commands.executeCommand(mainThreadNode.clickCommand, externalNode).then(() => { return null; })); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 4349b94da9a..31aa66fec8a 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -88,7 +88,7 @@ export class TreeController extends DefaultController { onLeftClick(tree: ITree, node: InternalTreeExplorerNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); - if (node.onClickCommand) { + if (node.clickCommand) { this.treeExplorerViewletService.resolveCommand('pineTree', node); } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 3ee31534bbb..b41757b01a5 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -8,14 +8,14 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { label: string; shouldInitiallyExpand: boolean; - onClickCommand: string; + clickCommand: string; constructor(node: TreeExplorerNodeContent) { this.id = InternalTreeExplorerNode.idCounter++; this.label = node.label; this.shouldInitiallyExpand = node.shouldInitiallyExpand; - this.onClickCommand = node.onClickCommand; + this.clickCommand = node.clickCommand; } } From f660ca6aa7d61c7b39236276b5222bceb049ad19 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 13 Oct 2016 13:59:06 -0700 Subject: [PATCH 029/119] Update API --- src/vs/vscode.d.ts | 18 ++++++------------ .../api/node/extHostTreeExplorers.ts | 12 +++++------- .../api/node/mainThreadTreeExplorers.ts | 1 - .../explorers/common/treeExplorerViewModel.ts | 19 ++++++++++++++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index a5504996d22..063369c683f 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1349,19 +1349,13 @@ declare module 'vscode' { } export interface TreeExplorerNodeProvider { - contentProvider: TreeExplorerNodeContentProvider; - provideRootNode(): Thenable; - resolveChildren(node: T): Thenable; - } + provideRootNode(): T | Thenable; + resolveChildren(node: T): T | Thenable; - export interface TreeExplorerNodeContentProvider { - provideNodeContent(node: T): TreeExplorerNodeContent; - } - - export interface TreeExplorerNodeContent { - label: string; - shouldInitiallyExpand: boolean; - clickCommand?: string; + getLabel?(node: T): string; + getShouldInitiallyExpand?(node: T): boolean; + getHasChildren?(node: T): boolean; + getClickCommand?(node: T): string; } /** diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index bd2a6f92e87..aea10450afd 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -4,19 +4,19 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TreeExplorerNodeContent, TreeExplorerNodeProvider } from 'vscode'; +import { TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/workbench/api/node/extHostTypes'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } from './extHost.protocol'; -import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNode, TreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - private _externalNodeMaps: { [providerId: string]: { [id: number]: TreeExplorerNodeContent }}; + private _externalNodeMaps: { [providerId: string]: { [id: number]: any }}; constructor( threadService: IThreadService, @@ -51,8 +51,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const treeNodeMap = Object.create(null); this._externalNodeMaps[providerId] = treeNodeMap; - const externalNodeContent = provider.contentProvider.provideNodeContent(externalRootNode); - const internalRootNode = new InternalTreeExplorerNode(externalNodeContent); + const internalRootNode = new InternalTreeExplorerNode(externalRootNode, provider); this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; })); @@ -69,8 +68,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return TPromise.wrap(provider.resolveChildren(externalNode).then(children => { return children.map(externalChild => { - const externalChildContent = provider.contentProvider.provideNodeContent(externalChild); - const internalChild = new InternalTreeExplorerNode(externalChildContent); + const internalChild = new InternalTreeExplorerNode(externalChild, provider); externalNodeMap[internalChild.id] = externalChild; return internalChild; }); diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 6abf836587f..f403461afb9 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TreeExplorerNodeContent } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index b41757b01a5..16e74334385 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -1,5 +1,5 @@ import { TPromise } from 'vs/base/common/winjs.base'; -import { TreeExplorerNodeContent, TreeExplorerNodeProvider } from 'vscode'; +import { TreeExplorerNodeProvider } from 'vscode'; export class InternalTreeExplorerNode implements TreeExplorerNodeContent { static idCounter = 1; @@ -7,15 +7,17 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { id: number; label: string; + hasChildren: boolean; shouldInitiallyExpand: boolean; clickCommand: string; - constructor(node: TreeExplorerNodeContent) { + constructor(node: any, provider: TreeExplorerNodeProvider) { this.id = InternalTreeExplorerNode.idCounter++; - this.label = node.label; - this.shouldInitiallyExpand = node.shouldInitiallyExpand; - this.clickCommand = node.clickCommand; + this.label = provider.getLabel(node); + this.hasChildren = provider.getHasChildren(node); + this.shouldInitiallyExpand = provider.getShouldInitiallyExpand(node); + this.clickCommand = provider.getClickCommand(node); } } @@ -23,4 +25,11 @@ export interface InternalTreeExplorerNodeProvider { resolveCommand(node: TreeExplorerNodeContent): TPromise; provideRootNode(): Thenable; resolveChildren(node: InternalTreeExplorerNode): Thenable; +} + +export interface TreeExplorerNodeContent { + label: string; + hasChildren: boolean; + shouldInitiallyExpand: boolean; + clickCommand: string; } \ No newline at end of file From f659fdd33e631cec0b46c09c3bddb6c83b283ab2 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 13 Oct 2016 14:28:20 -0700 Subject: [PATCH 030/119] Add actions --- .../treeExplorerActions.contribution.ts | 33 +++++++++++++++++++ src/vs/workbench/workbench.main.ts | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts new file mode 100644 index 00000000000..bd64f9e06e0 --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -0,0 +1,33 @@ +'use strict'; + +import * as nls from 'vs/nls'; +import { Registry } from 'vs/platform/platform'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; + +const registry = Registry.as(ActionExtensions.WorkbenchActions); + +const VIEWLET_ID = 'test'; + +export class ToggleExternalViewletAction extends ToggleViewletAction { + public static ID = VIEWLET_ID; + public static LABEL = nls.localize('toggleExternalViewlet', "Toggle External Viewlet"); + + constructor( + id: string, + label: string, + @IViewletService viewletService: IViewletService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService + ) { + super(id, label, VIEWLET_ID, viewletService, editorService); + } +} + +registry.registerWorkbenchAction( + new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), + "View: Toggle External Viewlet", + nls.localize('view', "View") +); \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index ea66c2ef039..648fd248b31 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -58,6 +58,7 @@ import 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen'; import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately import 'vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution'; +import 'vs/workbench/parts/explorers/browser/treeExplorerActions.contribution'; import 'vs/workbench/parts/output/browser/output.contribution'; import 'vs/workbench/parts/output/browser/outputPanel'; // can be packaged separately From 6bb82783db08f1671789e9f52034232ff8fc636d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 14 Oct 2016 09:59:33 -0700 Subject: [PATCH 031/119] Hook up hasChildren --- .../parts/explorers/browser/views/treeExplorerViewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 31aa66fec8a..83630b0e907 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -30,7 +30,7 @@ export class TreeDataSource implements IDataSource { } hasChildren(tree: ITree, node: InternalTreeExplorerNode): boolean { - return true; + return node.hasChildren; } getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { From b474369a9e3a8e7f19f8d289c6d838e3dfeb36d2 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 14 Oct 2016 09:59:52 -0700 Subject: [PATCH 032/119] Give default value to label, hasChildren, etc --- .../explorers/common/treeExplorerViewModel.ts | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 16e74334385..3771990167c 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -6,18 +6,26 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { id: number; - label: string; - hasChildren: boolean; - shouldInitiallyExpand: boolean; - clickCommand: string; + label: string = 'label'; + hasChildren: boolean = true; + shouldInitiallyExpand: boolean = false; + clickCommand: string = null; constructor(node: any, provider: TreeExplorerNodeProvider) { this.id = InternalTreeExplorerNode.idCounter++; - this.label = provider.getLabel(node); - this.hasChildren = provider.getHasChildren(node); - this.shouldInitiallyExpand = provider.getShouldInitiallyExpand(node); - this.clickCommand = provider.getClickCommand(node); + if (provider.getLabel) { + this.label = provider.getLabel(node); + } + if (provider.getHasChildren) { + this.hasChildren = provider.getHasChildren(node); + } + if (provider.getShouldInitiallyExpand) { + this.shouldInitiallyExpand = provider.getShouldInitiallyExpand(node); + } + if (provider.getClickCommand) { + this.clickCommand = provider.getClickCommand(node); + } } } From 0cc3fec4fc16af0232b20bba3b5841671ae5bf3c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 14 Oct 2016 10:00:20 -0700 Subject: [PATCH 033/119] Placeholder for toggle external actions --- .../explorers/browser/treeExplorerActions.contribution.ts | 7 ++++--- .../explorers/browser/treeExplorerViewlet.contribution.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index bd64f9e06e0..0d4b66f8ce3 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -10,11 +10,12 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi const registry = Registry.as(ActionExtensions.WorkbenchActions); -const VIEWLET_ID = 'test'; +const treeExplorerNodeProviderId = 'pineTree'; +const VIEWLET_ID = 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId; export class ToggleExternalViewletAction extends ToggleViewletAction { public static ID = VIEWLET_ID; - public static LABEL = nls.localize('toggleExternalViewlet', "Toggle External Viewlet"); + public static LABEL = nls.localize('toggleExternalViewlet', "Toggle External Viewlet pineTree"); constructor( id: string, @@ -28,6 +29,6 @@ export class ToggleExternalViewletAction extends ToggleViewletAction { registry.registerWorkbenchAction( new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), - "View: Toggle External Viewlet", + "View: Toggle External Viewlet pineTree", nls.localize('view', "View") ); \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index ecfbdb6770b..b1ff3fb7fb2 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -1,6 +1,6 @@ 'use strict'; -import {ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; +import { ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; registerSingleton(ITreeExplorerService, TreeExplorerViewletService); \ No newline at end of file From c24338d32023683771743db0a5e4d065960e21ab Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 14 Oct 2016 11:27:31 -0700 Subject: [PATCH 034/119] Fix API --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 063369c683f..3962a904105 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1350,7 +1350,7 @@ declare module 'vscode' { export interface TreeExplorerNodeProvider { provideRootNode(): T | Thenable; - resolveChildren(node: T): T | Thenable; + resolveChildren(node: T): T[] | Thenable; getLabel?(node: T): string; getShouldInitiallyExpand?(node: T): boolean; From af5af7282d99574688eb8a08a33fb4ab6cf950a2 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 14 Oct 2016 14:27:28 -0700 Subject: [PATCH 035/119] Accomondate new non-promise provideRootNode etc --- src/vs/workbench/api/node/extHostTreeExplorers.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index aea10450afd..2af8a9e407b 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -11,6 +11,7 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } from './extHost.protocol'; import { InternalTreeExplorerNode, TreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; +import { asWinJsPromise } from 'vs/base/common/async'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; @@ -47,14 +48,14 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { throw new Error(`no TreeContentProvider registered with id '${providerId}'`); } - return TPromise.wrap(provider.provideRootNode().then(externalRootNode => { + return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { const treeNodeMap = Object.create(null); this._externalNodeMaps[providerId] = treeNodeMap; const internalRootNode = new InternalTreeExplorerNode(externalRootNode, provider); this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; - })); + }); } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { @@ -66,13 +67,13 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const externalNodeMap = this._externalNodeMaps[providerId]; const externalNode = externalNodeMap[mainThreadNode.id]; - return TPromise.wrap(provider.resolveChildren(externalNode).then(children => { + return asWinJsPromise(() => provider.resolveChildren(externalNode)).then(children => { return children.map(externalChild => { const internalChild = new InternalTreeExplorerNode(externalChild, provider); externalNodeMap[internalChild.id] = externalChild; return internalChild; }); - })); + }); } $resolveCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { From 6300fbf987c653ce7cb6d3b873971751f5793517 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 17 Oct 2016 00:21:24 -0700 Subject: [PATCH 036/119] Remove unused svg files --- src/vs/workbench/parts/explorers/browser/media/files-dark.svg | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/vs/workbench/parts/explorers/browser/media/files-dark.svg diff --git a/src/vs/workbench/parts/explorers/browser/media/files-dark.svg b/src/vs/workbench/parts/explorers/browser/media/files-dark.svg deleted file mode 100644 index 7e3e59b370b..00000000000 --- a/src/vs/workbench/parts/explorers/browser/media/files-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 13d56908246717ec85428cba5444ad6ca3a5c8c1 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 17 Oct 2016 00:31:50 -0700 Subject: [PATCH 037/119] Add license --- .../explorers/browser/treeExplorerActions.contribution.ts | 4 ++++ .../parts/explorers/browser/treeExplorerService.ts | 4 ++++ .../explorers/browser/treeExplorerViewlet.contribution.ts | 4 ++++ .../parts/explorers/browser/treeExplorerViewlet.ts | 6 ++++++ .../parts/explorers/browser/views/treeExplorerView.ts | 6 ++++++ .../parts/explorers/browser/views/treeExplorerViewer.ts | 6 ++++++ .../parts/explorers/common/treeExplorerViewModel.ts | 6 ++++++ 7 files changed, 36 insertions(+) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 0d4b66f8ce3..59f3d14ab18 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as nls from 'vs/nls'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts index 2f8f56c40a7..8720ed4d756 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TreeExplorerNodeProvider } from 'vscode'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index b1ff3fb7fb2..60dabc0ad82 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -1,3 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 880c28cc602..c68e853392b 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { SplitView, Orientation } from 'vs/base/browser/ui/splitview/splitview'; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 5f3095604d8..95ab09f9396 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * 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 nls = require('vs/nls'); import labels = require('vs/base/common/labels'); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 83630b0e907..7c16f037a84 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; import { $, Builder } from 'vs/base/browser/builder'; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 3771990167c..275523ceedf 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; import { TreeExplorerNodeProvider } from 'vscode'; From 4eab0dfd9315a5e058c1570c4a772d384d392c0c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 17 Oct 2016 15:44:28 -0700 Subject: [PATCH 038/119] Split explorer's extension point to a separate file --- .../actions/browser/menusExtensionPoint.ts | 60 --------------- .../browser/explorerExtensionPoint.ts | 74 +++++++++++++++++++ src/vs/workbench/workbench.main.ts | 3 + 3 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 src/vs/platform/explorers/browser/explorerExtensionPoint.ts diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 0f4c6fce494..33888567575 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -15,7 +15,6 @@ import { IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry } f import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/platform'; -import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; namespace schema { @@ -208,34 +207,6 @@ namespace schema { } ] }; - - // --- treeExplorers contribution point - - export interface IExplorer { - treeExplorerNodeProviderId: string; - treeLabel: string; - icon: IUserFriendlyIcon; - } - - export const explorerContribtion: IJSONSchema = { - description: localize('vscode.extension.contributes.explorer', "Contributes explorer viewlet to the sidebar"), - type: 'object', - properties: { - treeContentProviderId: { - description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), - type: 'string' - }, - treeLabel: { - description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree Viewlet'), - type: 'string' - }, - icon: { - description: localize('vscode.extension.contributes.explorer.icon', 'Icon to put on activity bar'), - type: 'string' - } - } - }; - } ExtensionsRegistry.registerExtensionPoint('commands', schema.commandsContribution).setHandler(extensions => { @@ -336,35 +307,4 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM } }); } -}); - -ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { - let baseOrder = 200; - - for (let extension of extensions) { - const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; - - const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; - if (icon) { - if (typeof icon === 'string') { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - const iconPath = join(extension.description.extensionFolderPath, icon); - createCSSRule(iconClass, getIconRule(iconPath)); - } else { - const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - createCSSRule(lightIconClass, getIconRule(icon.light)); - createCSSRule(darkIconClass, getIconRule(icon.dark)); - } - } - - Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', - 'TreeExplorerViewlet', - 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, - treeLabel, - treeExplorerNodeProviderId, - baseOrder++ - )); - } }); \ No newline at end of file diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts new file mode 100644 index 00000000000..375491b3622 --- /dev/null +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { join } from 'vs/base/common/paths'; +import { createCSSRule } from 'vs/base/browser/dom'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; +import { Registry } from 'vs/platform/platform'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; + +namespace schema { + + export type IUserFriendlyIcon = string | { light: string; dark: string; }; + + export interface IExplorer { + treeExplorerNodeProviderId: string; + treeLabel: string; + icon: IUserFriendlyIcon; + } + + export const explorerContribtion: IJSONSchema = { + description: localize('vscode.extension.contributes.explorer', "Contributes explorer viewlet to the sidebar"), + type: 'object', + properties: { + treeContentProviderId: { + description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), + type: 'string' + }, + treeLabel: { + description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree Viewlet'), + type: 'string' + }, + icon: { + description: localize('vscode.extension.contributes.explorer.icon', 'Icon to put on activity bar'), + type: 'string' + } + } + }; +} + +ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { + let baseOrder = 200; + + for (let extension of extensions) { + const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; + + const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; + if (icon) { + if (typeof icon === 'string') { + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const iconPath = join(extension.description.extensionFolderPath, icon); + createCSSRule(iconClass, getIconRule(iconPath)); + } else { + const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + createCSSRule(lightIconClass, getIconRule(icon.light)); + createCSSRule(darkIconClass, getIconRule(icon.dark)); + } + } + + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( + 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', + 'TreeExplorerViewlet', + 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, + treeLabel, + treeExplorerNodeProviderId, + baseOrder++ + )); + } +}) \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 648fd248b31..86a40d61df7 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -19,6 +19,9 @@ import 'vs/editor/browser/editor.all'; // Menus/Actions import 'vs/platform/actions/browser/menusExtensionPoint'; +// External Explorers +import "vs/platform/explorers/browser/explorerExtensionPoint"; + // Workbench import 'vs/workbench/browser/actions/toggleStatusbarVisibility'; import 'vs/workbench/browser/actions/toggleSidebarVisibility'; From 944101c2c135acd86970b78409f335d8f5a9c611 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 17 Oct 2016 16:21:07 -0700 Subject: [PATCH 039/119] Let ViewletRegistry handle batch registration and notify ActivityBarPart --- .../explorers/browser/explorerExtensionPoint.ts | 4 +++- .../browser/parts/activitybar/activitybarPart.ts | 9 ++++++--- src/vs/workbench/browser/viewlet.ts | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 375491b3622..8d47103d4c4 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -44,6 +44,7 @@ namespace schema { ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { let baseOrder = 200; + let descriptors = []; for (let extension of extensions) { const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; @@ -62,7 +63,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e } } - Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( + descriptors.push(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, @@ -71,4 +72,5 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e baseOrder++ )); } + Registry.as(ViewletExtensions.Viewlets).registerExternalViewlets(descriptors); }) \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index b8c7ab81294..e270d9792c4 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -54,12 +54,15 @@ export class ActivitybarPart extends Part implements IActivityService { // Update activity bar on registering an external viewlet this.toUnbind.push( - (Registry.as(ViewletExtensions.Viewlets)).onDidViewletRegister(viewletDescriptor => this.onViewletRegistryUpdated(viewletDescriptor)) + (Registry.as(ViewletExtensions.Viewlets)) + .onDidRegisterExternalViewlets(descriptors => this.onDidRegisterExternalViewlets(descriptors)) ); } - private onViewletRegistryUpdated(viewletDescriptor: ViewletDescriptor) { - this.viewletSwitcherBar.push(this.toAction(viewletDescriptor), { label: true, icon: true }); + private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) { + descriptors.forEach(descriptor => { + this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); + }) } private onActiveCompositeChanged(composite: IComposite): void { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 4bd63e7f8c5..245bfe8c42d 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -165,16 +165,25 @@ export const Extensions = { export class ViewletRegistry extends CompositeRegistry { private defaultViewletId: string; - private _onDidViewletRegister = new Emitter(); + private _onDidRegisterExternalViewlets = new Emitter(); - public get onDidViewletRegister() { return this._onDidViewletRegister.event; } + public get onDidRegisterExternalViewlets() { return this._onDidRegisterExternalViewlets.event; } /** * Registers a viewlet to the platform. */ public registerViewlet(descriptor: ViewletDescriptor): void { super.registerComposite(descriptor); - this._onDidViewletRegister.fire(descriptor); + } + + /** + * Registers multiple external viewlets. + */ + public registerExternalViewlets(descriptors: ViewletDescriptor[]): void { + descriptors.forEach(d => { + super.registerComposite(d); + }); + this._onDidRegisterExternalViewlets.fire(descriptors); } /** From 1c28702c56ce91d8e7e8348fc4208fdd30550a8a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 17 Oct 2016 16:41:33 -0700 Subject: [PATCH 040/119] Read config from global storage --- .../workbench/browser/parts/activitybar/activitybarPart.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index e270d9792c4..2564746bdf1 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -22,6 +22,7 @@ import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IStorageService } from 'vs/platform/storage/common/storage'; export class ActivitybarPart extends Part implements IActivityService { public _serviceBrand: any; @@ -34,7 +35,8 @@ export class ActivitybarPart extends Part implements IActivityService { @IViewletService private viewletService: IViewletService, @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, - @IPartService private partService: IPartService + @IPartService private partService: IPartService, + @IStorageService private storageService: IStorageService ) { super(id); @@ -60,9 +62,10 @@ export class ActivitybarPart extends Part implements IActivityService { } private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) { + const enabledViewlets = JSON.parse(this.storageService.get("enabledExternalViewlets")); descriptors.forEach(descriptor => { this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); - }) + }); } private onActiveCompositeChanged(composite: IComposite): void { From 940a7fafb226f8851273fe3f54b47ff50bbdb7f7 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 09:41:08 -0700 Subject: [PATCH 041/119] Only display whitelisted viewlet icons on activity bar --- .../browser/parts/activitybar/activitybarPart.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 2564746bdf1..9a182dec591 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -30,6 +30,8 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; + private ENABLED_VIEWLETS_KEY = "workbench.activityBar.enabledExternalViewlets"; + constructor( id: string, @IViewletService private viewletService: IViewletService, @@ -62,9 +64,12 @@ export class ActivitybarPart extends Part implements IActivityService { } private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) { - const enabledViewlets = JSON.parse(this.storageService.get("enabledExternalViewlets")); + const enabledViewletsJson = this.storageService.get(this.ENABLED_VIEWLETS_KEY); + const enabledViewlets: string[] = enabledViewletsJson ? JSON.parse(enabledViewletsJson) : []; descriptors.forEach(descriptor => { - this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); + if (enabledViewlets.indexOf(descriptor.id) !== -1) { + this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); + } }); } From 2e0f8d0d21d98b8be17b4c6c9092919ad8fccd5a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 10:39:52 -0700 Subject: [PATCH 042/119] Populate command with enabled/disabled viewlets --- .../parts/activitybar/activitybarPart.ts | 11 +++++ .../treeExplorerActions.contribution.ts | 48 ++++++++++++++----- .../activity/common/activityService.ts | 5 ++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 9a182dec591..1a97cbfa485 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -30,6 +30,8 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; + private viewletsToggleStatus: { [viewletId: string]: boolean; }; + private ENABLED_VIEWLETS_KEY = "workbench.activityBar.enabledExternalViewlets"; constructor( @@ -45,6 +47,8 @@ export class ActivitybarPart extends Part implements IActivityService { this.activityActionItems = {}; this.compositeIdToActions = {}; + this.viewletsToggleStatus = {}; + this.registerListeners(); } @@ -68,7 +72,10 @@ export class ActivitybarPart extends Part implements IActivityService { const enabledViewlets: string[] = enabledViewletsJson ? JSON.parse(enabledViewletsJson) : []; descriptors.forEach(descriptor => { if (enabledViewlets.indexOf(descriptor.id) !== -1) { + this.viewletsToggleStatus[descriptor.id] = true; this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); + } else { + this.viewletsToggleStatus[descriptor.id] = false; } }); } @@ -85,6 +92,10 @@ export class ActivitybarPart extends Part implements IActivityService { } } + public getViewletsToggleStatus(): { [viewletId: string]: boolean } { + return this.viewletsToggleStatus; + } + public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 59f3d14ab18..f4ab9fed894 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -5,34 +5,60 @@ 'use strict'; import * as nls from 'vs/nls'; +import { TPromise } from 'vs/base/common/winjs.base'; import { Registry } from 'vs/platform/platform'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; +import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; const registry = Registry.as(ActionExtensions.WorkbenchActions); -const treeExplorerNodeProviderId = 'pineTree'; -const VIEWLET_ID = 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId; +export class ToggleExternalViewletAction extends Action { + public static ID = 'workbench.view.customTreeExplorerViewlet'; + public static LABEL = nls.localize('toggleCustomExplorer', 'Toggle Custom Explorer'); -export class ToggleExternalViewletAction extends ToggleViewletAction { - public static ID = VIEWLET_ID; - public static LABEL = nls.localize('toggleExternalViewlet', "Toggle External Viewlet pineTree"); + private viewletId: string; constructor( id: string, label: string, - @IViewletService viewletService: IViewletService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IActivityService private activityService: IActivityService ) { - super(id, label, VIEWLET_ID, viewletService, editorService); + super(id, name); + } + + run(): TPromise { + const viewletsToggleStataus = this.activityService.getViewletsToggleStatus(); + + const picks = []; + for (let viewletId in viewletsToggleStataus) { + picks.push({ + id: viewletId, + label: (viewletsToggleStataus[viewletId] ? "Disable " : "Enable ") + this.getShortViewletId(viewletId), + description: "" + }); + } + + return TPromise.timeout(50).then(() => { + this.quickOpenService.pick(picks, { placeHolder: 'select viewlet to enable', autoFocus: 2 }).then(pick => { + if (pick) { + + } + }); + }); + } + + private getShortViewletId(viewletId: string): string { + return viewletId.split('.').pop(); } } registry.registerWorkbenchAction( new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), - "View: Toggle External Viewlet pineTree", + "View: Toggle Custom Explorer", nls.localize('view', "View") ); \ No newline at end of file diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index bdc5638ac0a..e43360de602 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -70,4 +70,9 @@ export interface IActivityService { * Clears activity shown in the activitybar for the given viewlet or panel. */ clearActivity(compositeId: string): void; + + /** + * Get all registered viewlets and whether they are enabled/disabled + */ + getViewletsToggleStatus(): { [viewletId: string]: boolean }; } \ No newline at end of file From 13641598acfb3687797e74ad7b40f2ea0c28ecdb Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 11:28:49 -0700 Subject: [PATCH 043/119] Retrieve list of registered viewletes to populate toggle custom explorer command --- .../parts/activitybar/activitybarPart.ts | 33 +++++++++++++------ .../treeExplorerActions.contribution.ts | 8 ++--- .../activity/common/activityService.ts | 7 +++- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 1a97cbfa485..f9adac7f479 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -31,8 +31,9 @@ export class ActivitybarPart extends Part implements IActivityService { private compositeIdToActions: { [compositeId: string]: ActivityAction; }; private viewletsToggleStatus: { [viewletId: string]: boolean; }; + private registeredViewlets: string[]; - private ENABLED_VIEWLETS_KEY = "workbench.activityBar.enabledExternalViewlets"; + private VIEWLETS_TOGGLE_STATUS = "workbench.activityBar.enabledExternalViewlets"; constructor( id: string, @@ -47,7 +48,10 @@ export class ActivitybarPart extends Part implements IActivityService { this.activityActionItems = {}; this.compositeIdToActions = {}; - this.viewletsToggleStatus = {}; + const viewletsToggleStatusJson = this.storageService.get(this.VIEWLETS_TOGGLE_STATUS); + this.viewletsToggleStatus = viewletsToggleStatusJson ? JSON.parse(viewletsToggleStatusJson) : {}; + + this.registeredViewlets = []; this.registerListeners(); } @@ -68,14 +72,10 @@ export class ActivitybarPart extends Part implements IActivityService { } private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) { - const enabledViewletsJson = this.storageService.get(this.ENABLED_VIEWLETS_KEY); - const enabledViewlets: string[] = enabledViewletsJson ? JSON.parse(enabledViewletsJson) : []; descriptors.forEach(descriptor => { - if (enabledViewlets.indexOf(descriptor.id) !== -1) { - this.viewletsToggleStatus[descriptor.id] = true; + this.registeredViewlets.push(descriptor.id); + if (this.viewletsToggleStatus[descriptor.id]) { this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); - } else { - this.viewletsToggleStatus[descriptor.id] = false; } }); } @@ -92,8 +92,21 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getViewletsToggleStatus(): { [viewletId: string]: boolean } { - return this.viewletsToggleStatus; + public getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean } { + const result = {}; + this.registeredViewlets.forEach(viewletId => { + result[viewletId] = this.viewletsToggleStatus[viewletId]; + }); + return result; + } + + public toggleViewlet(viewletId: string): void { + this.viewletsToggleStatus[viewletId] = !this.viewletsToggleStatus[viewletId]; + this.setViewletsToggleStatus(); + } + + private setViewletsToggleStatus(): void { + this.storageService.store(this.VIEWLETS_TOGGLE_STATUS, JSON.stringify(this.viewletsToggleStatus)); } public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index f4ab9fed894..a04ec714619 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -11,7 +11,7 @@ import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, To import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; -import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; const registry = Registry.as(ActionExtensions.WorkbenchActions); @@ -32,9 +32,9 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const viewletsToggleStataus = this.activityService.getViewletsToggleStatus(); + const viewletsToggleStataus = this.activityService.getRegisteredViewletsToggleStatus(); - const picks = []; + const picks: IPickOpenEntry[] = []; for (let viewletId in viewletsToggleStataus) { picks.push({ id: viewletId, @@ -46,7 +46,7 @@ export class ToggleExternalViewletAction extends Action { return TPromise.timeout(50).then(() => { this.quickOpenService.pick(picks, { placeHolder: 'select viewlet to enable', autoFocus: 2 }).then(pick => { if (pick) { - + this.activityService.toggleViewlet(pick.id); } }); }); diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index e43360de602..0324c692985 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -74,5 +74,10 @@ export interface IActivityService { /** * Get all registered viewlets and whether they are enabled/disabled */ - getViewletsToggleStatus(): { [viewletId: string]: boolean }; + getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean }; + + /** + * Enable/disable viewlet + */ + toggleViewlet(viewletId: string): void; } \ No newline at end of file From 88e869a924fa5c46a2201152f63e5cf4d82b5735 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 14:52:45 -0700 Subject: [PATCH 044/119] Refactor activitybar and clean up --- .../browser/explorerExtensionPoint.ts | 5 ++- .../parts/activitybar/activitybarPart.ts | 37 ++++++++++++------- src/vs/workbench/browser/viewlet.ts | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 8d47103d4c4..455607a10ae 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -43,7 +43,7 @@ namespace schema { } ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { - let baseOrder = 200; + let baseOrder = 200; // Stock viewlet order goes up to 100 let descriptors = []; for (let extension of extensions) { @@ -69,7 +69,8 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, treeLabel, treeExplorerNodeProviderId, - baseOrder++ + baseOrder++, + true )); } Registry.as(ViewletExtensions.Viewlets).registerExternalViewlets(descriptors); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index f9adac7f479..237f987bfa0 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -33,7 +33,7 @@ export class ActivitybarPart extends Part implements IActivityService { private viewletsToggleStatus: { [viewletId: string]: boolean; }; private registeredViewlets: string[]; - private VIEWLETS_TOGGLE_STATUS = "workbench.activityBar.enabledExternalViewlets"; + private VIEWLETS_TOGGLE_STATUS = "workbench.activityBar.viewletsToggleStatus"; constructor( id: string, @@ -103,6 +103,7 @@ export class ActivitybarPart extends Part implements IActivityService { public toggleViewlet(viewletId: string): void { this.viewletsToggleStatus[viewletId] = !this.viewletsToggleStatus[viewletId]; this.setViewletsToggleStatus(); + this.refreshViewletSwitcher(); } private setViewletsToggleStatus(): void { @@ -128,25 +129,40 @@ export class ActivitybarPart extends Part implements IActivityService { const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.createViewletSwitcher($result.clone()); + this.createViewletSwitcher($result.clone().addClass('position-top')); return $result; } private createViewletSwitcher(div: Builder): void { - - // Composite switcher is on top this.viewletSwitcherBar = new ActionBar(div, { actionItemProvider: (action: Action) => this.activityActionItems[action.id], orientation: ActionsOrientation.VERTICAL, ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher") }); - this.viewletSwitcherBar.getContainer().addClass('position-top'); + // Load stock viewlets + const allViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(v => !v.isExternal); + this.fillViewletSwitcher(allViewlets); + } + + private refreshViewletSwitcher(): void { + this.viewletSwitcherBar.clear(); + + // Load stock viewlets + enabled external viewlets + const allEnabledViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => { + if (!descriptor.isExternal) { + return true; + } else { + return this.viewletsToggleStatus[descriptor.id]; + } + }); + this.fillViewletSwitcher(allEnabledViewlets); + } + + private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { // Build Viewlet Actions in correct order - const allViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); - const viewletActions = allViewlets.sort((v1, v2) => v1.order - v2.order).map(viewlet => this.toAction(viewlet)); - + const viewletActions = viewlets.sort((v1, v2) => v1.order - v2.order).map(v => this.toAction(v)); this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } @@ -157,11 +173,6 @@ export class ActivitybarPart extends Part implements IActivityService { this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); this.compositeIdToActions[composite.id] = action; - // Mark active viewlet as active - if (activeViewlet && activeViewlet.getId() === composite.id) { - action.activate(); - } - return action; }; diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 245bfe8c42d..f4c1c1049d9 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -154,7 +154,7 @@ export abstract class ViewerViewlet extends Viewlet { */ export class ViewletDescriptor extends CompositeDescriptor { - constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number) { + constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExternal: boolean = false) { super(moduleId, ctorName, id, name, cssClass, order); } } From 0031078bacb0cc9c544d131dd8af75ebb36d2b7b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 15:10:48 -0700 Subject: [PATCH 045/119] Clean up --- .../actions/browser/menusExtensionPoint.ts | 1 - .../browser/explorerExtensionPoint.ts | 2 +- .../api/node/extHostTreeExplorers.ts | 2 +- .../api/node/mainThreadTreeExplorers.ts | 2 +- .../parts/activitybar/activitybarPart.ts | 1 - src/vs/workbench/browser/viewlet.ts | 2 +- .../treeExplorerActions.contribution.ts | 10 +++----- .../explorers/browser/treeExplorerService.ts | 2 -- .../explorers/browser/treeExplorerViewlet.ts | 25 +++---------------- .../browser/views/treeExplorerView.ts | 14 ++--------- .../browser/views/treeExplorerViewer.ts | 8 +----- 11 files changed, 14 insertions(+), 55 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 33888567575..a842132d5e8 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -14,7 +14,6 @@ import { forEach } from 'vs/base/common/collections'; import { IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; -import { Registry } from 'vs/platform/platform'; namespace schema { diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 455607a10ae..0432deabaa8 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -74,4 +74,4 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e )); } Registry.as(ViewletExtensions.Viewlets).registerExternalViewlets(descriptors); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 2af8a9e407b..1ac9f29ea8f 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/workbench/api/node/extHostTypes'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } from './extHost.protocol'; -import { InternalTreeExplorerNode, TreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index f403461afb9..aec3a6bbfec 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -31,7 +31,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { return this._proxy.$provideRootNode(providerId).then(treeContent => { this._treeContents[providerId] = treeContent; return treeContent; - }) + }); }, resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 237f987bfa0..980043b4ab9 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -167,7 +167,6 @@ export class ActivitybarPart extends Part implements IActivityService { } private toAction(composite: ViewletDescriptor): ActivityAction { - const activeViewlet = this.viewletService.getActiveViewlet(); const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index f4c1c1049d9..39b4105ad32 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -7,7 +7,7 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); -import Event, { Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/platform'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index a04ec714619..72a459a4f9c 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -7,10 +7,9 @@ import * as nls from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { Registry } from 'vs/platform/platform'; -import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ToggleViewletAction } from 'vs/workbench/browser/viewlet'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; +import { Action } from 'vs/base/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; @@ -20,8 +19,6 @@ export class ToggleExternalViewletAction extends Action { public static ID = 'workbench.view.customTreeExplorerViewlet'; public static LABEL = nls.localize('toggleCustomExplorer', 'Toggle Custom Explorer'); - private viewletId: string; - constructor( id: string, label: string, @@ -38,13 +35,12 @@ export class ToggleExternalViewletAction extends Action { for (let viewletId in viewletsToggleStataus) { picks.push({ id: viewletId, - label: (viewletsToggleStataus[viewletId] ? "Disable " : "Enable ") + this.getShortViewletId(viewletId), - description: "" + label: (viewletsToggleStataus[viewletId] ? "Disable " : "Enable ") + this.getShortViewletId(viewletId) }); } return TPromise.timeout(50).then(() => { - this.quickOpenService.pick(picks, { placeHolder: 'select viewlet to enable', autoFocus: 2 }).then(pick => { + this.quickOpenService.pick(picks, { placeHolder: 'Select Viewlet to toggle', autoFocus: 2 }).then(pick => { if (pick) { this.activityService.toggleViewlet(pick.id); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts index 8720ed4d756..b60941de482 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts @@ -4,9 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; -import Event, {Emitter} from 'vs/base/common/event'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index c68e853392b..3f252a60fd4 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -6,14 +6,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, Dimension } from 'vs/base/browser/builder'; -import { SplitView, Orientation } from 'vs/base/browser/ui/splitview/splitview'; - +import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { IViewletView, Viewlet } from 'vs/workbench/browser/viewlet'; - import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; - import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; @@ -32,7 +28,6 @@ export class TreeExplorerViewlet extends Viewlet { constructor( @ITelemetryService telemetryService: ITelemetryService, - @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService ) { super(ID, telemetryService); @@ -48,8 +43,7 @@ export class TreeExplorerViewlet extends Viewlet { this.viewletContainer = parent.div().addClass('custom-tree-explorer-viewlet'); this.addTreeView(TREE_NAME); - const settings = this.configurationService.getConfiguration(); - return this.onConfigurationUpdated(settings); + return TPromise.as(null); } layout(dimension: Dimension): void { @@ -59,15 +53,11 @@ export class TreeExplorerViewlet extends Viewlet { setVisible(visible: boolean): TPromise { return super.setVisible(visible).then(() => { this.view.setVisible(visible).done(); - }) - } - - private onConfigurationUpdated(config: ICustomViewletConfiguration): TPromise { - return TPromise.as(null); + }); } private addTreeView(treeName: string): void { - // 0 for now, add back header later if needed + // Hide header (root node) by default const headerSize = 0; this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, treeName, this.getActionRunner(), headerSize); @@ -77,11 +67,4 @@ export class TreeExplorerViewlet extends Viewlet { dispose(): void { this.view = null; } -} - - -export interface ICustomViewletConfiguration { - viewlet: { - - } } \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 95ab09f9396..0962ff2df9b 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -5,15 +5,11 @@ 'use strict'; import nls = require('vs/nls'); -import labels = require('vs/base/common/labels'); - -import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import * as DOM from 'vs/base/browser/dom'; import { Builder, $ } from 'vs/base/browser/builder'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet'; - import { IActionRunner, IAction } from 'vs/base/common/actions'; import { IMessageService } from 'vs/platform/message/common/message'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -23,18 +19,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; - -import { ITree, IDataSource, IRenderer } from 'vs/base/parts/tree/browser/tree'; +import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; -import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; - -import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; - private treeViewer: ITree; private viewletState: TreeExplorerViewletState; @@ -114,7 +104,7 @@ export class TreeExplorerView extends CollapsibleViewletView { private updateInput(): TPromise { return this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { this.tree.setInput(tree); - }) + }); } public getOptimalWidth(): number { diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 7c16f037a84..f90cc35dacc 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -6,24 +6,18 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { $, Builder } from 'vs/base/browser/builder'; - import { ITree, IDataSource, IRenderer, IElementCallback } from 'vs/base/parts/tree/browser/tree'; -import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ClickBehavior, DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; - import { IActionRunner } from 'vs/base/common/actions'; import { IActionProvider, ActionsRenderer } from 'vs/base/parts/tree/browser/actionsRenderer'; import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; - -import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; -const providerId = 'pineTree'; // For now - export class TreeDataSource implements IDataSource { constructor( @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService From 0471662bf455732e95dade163d1f6bf06c751651 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 15:17:35 -0700 Subject: [PATCH 046/119] Add back pre-commit hygiene --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 3d4454ffec2..c06abe95d10 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,9 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "config": { + "ghooks": { + "pre-commit": "node build/gulpfile.hygiene.js" + } }, "optionalDependencies": { "windows-foreground-love": "0.1.0", From 5b1ba3cec2a10536e6c2cd8e3d011dbb15c0ea3d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 15:25:09 -0700 Subject: [PATCH 047/119] Fix lint error --- src/vs/workbench/browser/viewlet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 39b4105ad32..0badabe1aa7 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -7,7 +7,7 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); -import { Emitter } from 'vs/base/common/event'; +import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/platform'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; @@ -167,7 +167,7 @@ export class ViewletRegistry extends CompositeRegistry { private defaultViewletId: string; private _onDidRegisterExternalViewlets = new Emitter(); - public get onDidRegisterExternalViewlets() { return this._onDidRegisterExternalViewlets.event; } + public get onDidRegisterExternalViewlets(): Event { return this._onDidRegisterExternalViewlets.event; } /** * Registers a viewlet to the platform. From 31afc0339e959e2bd06732fb25b07eb0f6df8654 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 18 Oct 2016 15:35:16 -0700 Subject: [PATCH 048/119] Clean up format issues --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 2 +- .../explorers/browser/explorerExtensionPoint.ts | 10 +++++----- .../extensionManagement/common/extensionManagement.ts | 3 ++- src/vs/workbench/api/node/extHost.api.impl.ts | 1 - src/vs/workbench/api/node/extHostTreeExplorers.ts | 4 ++-- src/vs/workbench/api/node/mainThreadDocuments.ts | 1 - src/vs/workbench/api/node/mainThreadTreeExplorers.ts | 2 +- .../browser/treeExplorerActions.contribution.ts | 2 +- .../browser/treeExplorerViewlet.contribution.ts | 2 +- .../parts/explorers/browser/treeExplorerViewlet.ts | 2 +- .../parts/explorers/browser/views/treeExplorerView.ts | 2 +- .../explorers/browser/views/treeExplorerViewer.ts | 2 +- .../parts/explorers/common/treeExplorerViewModel.ts | 2 +- 13 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index a842132d5e8..42e12353fdf 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -306,4 +306,4 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM } }); } -}); \ No newline at end of file +}); diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 0432deabaa8..7de0aaed5a2 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -23,19 +23,19 @@ namespace schema { } export const explorerContribtion: IJSONSchema = { - description: localize('vscode.extension.contributes.explorer', "Contributes explorer viewlet to the sidebar"), + description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), type: 'object', properties: { - treeContentProviderId: { + treeExplorerNodeProviderId: { description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), type: 'string' }, treeLabel: { - description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree Viewlet'), + description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree viewlet'), type: 'string' }, icon: { - description: localize('vscode.extension.contributes.explorer.icon', 'Icon to put on activity bar'), + description: localize('vscode.extension.contributes.explorer.icon', 'Path to the viewlet icon on the activity bar'), type: 'string' } } @@ -74,4 +74,4 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e )); } Registry.as(ViewletExtensions.Viewlets).registerExternalViewlets(descriptors); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index f3aef501a95..e23a7cf10ba 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -75,7 +75,8 @@ export interface ITheme { } export interface ITreeExplorer { - treeContentProviderId: string; + treeExplorerNodeProviderId: string; + treeLabel: string; icon: string; } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 114417f743b..ba5043d3146 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -12,7 +12,6 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import * as errors from 'vs/base/common/errors'; import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; - import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant'; diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 1ac9f29ea8f..fa843da3c7f 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -17,7 +17,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - private _externalNodeMaps: { [providerId: string]: { [id: number]: any }}; + private _externalNodeMaps: { [providerId: string]: { [id: number]: any } }; constructor( threadService: IThreadService, @@ -91,4 +91,4 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return TPromise.as(null); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index 2f5c1ff3583..b39faff7845 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -264,5 +264,4 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { } }, onUnexpectedError); } - } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index aec3a6bbfec..9853af80b34 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -45,4 +45,4 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { $unregisterTreeContentProvider(treeContentProviderId: string): void { } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 72a459a4f9c..7ca60d9e729 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -57,4 +57,4 @@ registry.registerWorkbenchAction( new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), "View: Toggle Custom Explorer", nls.localize('view', "View") -); \ No newline at end of file +); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 60dabc0ad82..858e2f47e3f 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -7,4 +7,4 @@ import { ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -registerSingleton(ITreeExplorerService, TreeExplorerViewletService); \ No newline at end of file +registerSingleton(ITreeExplorerService, TreeExplorerViewletService); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 3f252a60fd4..03d516c0b04 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -67,4 +67,4 @@ export class TreeExplorerViewlet extends Viewlet { dispose(): void { this.view = null; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 0962ff2df9b..b67699df936 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -113,4 +113,4 @@ export class TreeExplorerView extends CollapsibleViewletView { return DOM.getLargestChildWidth(parentNode, childNodes); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index f90cc35dacc..c6507f92c65 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -118,4 +118,4 @@ export class TreeExplorerViewletState implements ITreeExplorerViewletState { } get actionProvider() { return this._actionProvider; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 275523ceedf..45a003fd572 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -46,4 +46,4 @@ export interface TreeExplorerNodeContent { hasChildren: boolean; shouldInitiallyExpand: boolean; clickCommand: string; -} \ No newline at end of file +} From 09eebc5bbb75e5a408b430bcdcf2fd186d36d042 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 08:50:39 -0700 Subject: [PATCH 049/119] Use providerId instead of 'pineTree'! --- .../parts/activitybar/activitybarPart.ts | 20 +++++++++++-- .../explorers/browser/treeExplorerViewlet.ts | 28 +++++++++++++------ .../browser/views/treeExplorerView.ts | 12 ++++---- .../browser/views/treeExplorerViewer.ts | 6 ++-- .../activity/common/activityService.ts | 5 ++++ 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 980043b4ab9..e493065e34d 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,6 +8,7 @@ import 'vs/css!./media/activitybarpart'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; import { Builder, $ } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; import errors = require('vs/base/common/errors'); @@ -33,7 +34,9 @@ export class ActivitybarPart extends Part implements IActivityService { private viewletsToggleStatus: { [viewletId: string]: boolean; }; private registeredViewlets: string[]; - private VIEWLETS_TOGGLE_STATUS = "workbench.activityBar.viewletsToggleStatus"; + private externalViewletIdToOpen: string; + + private VIEWLETS_TOGGLE_STATUS = 'workbench.activityBar.viewletsToggleStatus'; constructor( id: string, @@ -92,7 +95,7 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean } { + getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean } { const result = {}; this.registeredViewlets.forEach(viewletId => { result[viewletId] = this.viewletsToggleStatus[viewletId]; @@ -100,7 +103,7 @@ export class ActivitybarPart extends Part implements IActivityService { return result; } - public toggleViewlet(viewletId: string): void { + toggleViewlet(viewletId: string): void { this.viewletsToggleStatus[viewletId] = !this.viewletsToggleStatus[viewletId]; this.setViewletsToggleStatus(); this.refreshViewletSwitcher(); @@ -110,6 +113,10 @@ export class ActivitybarPart extends Part implements IActivityService { this.storageService.store(this.VIEWLETS_TOGGLE_STATUS, JSON.stringify(this.viewletsToggleStatus)); } + getExternalViewletIdToOpen(): string { + return this.externalViewletIdToOpen; + } + public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -168,6 +175,9 @@ export class ActivitybarPart extends Part implements IActivityService { private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); + action.onOpenViewlet((viewletId) => { + this.externalViewletIdToOpen = viewletId; + }); this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); this.compositeIdToActions[composite.id] = action; @@ -198,6 +208,9 @@ class ViewletActivityAction extends ActivityAction { private static preventDoubleClickDelay = 300; private lastRun: number = 0; + private _onOpenViewlet = new Emitter(); + get onOpenViewlet(): Event { return this._onOpenViewlet.event; }; + constructor( id: string, private viewlet: ViewletDescriptor, @IViewletService private viewletService: IViewletService, @@ -222,6 +235,7 @@ class ViewletActivityAction extends ActivityAction { if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) { this.partService.setSideBarHidden(true); } else { + this._onOpenViewlet.fire(this.viewlet.id); this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); this.activate(); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 03d516c0b04..3d1f05da41d 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -12,11 +12,9 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; +import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; -const TREE_NAME = 'pineTree'; // For now - -export const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.treeExplorerViewlet.'; -const ID = 'workbench.view.customTreeExplorerViewlet.' + TREE_NAME; +export const VIEWLET_ID_ROOT = 'workbench.view.customTreeExplorerViewlet.'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; @@ -26,14 +24,21 @@ export class TreeExplorerViewlet extends Viewlet { private viewletState: TreeExplorerViewletState; + private externalViewletId: string; + private treeNodeProviderId: string; + constructor( @ITelemetryService telemetryService: ITelemetryService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IActivityService private activityService: IActivityService ) { - super(ID, telemetryService); + super(VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter, telemetryService); this.viewletState = new TreeExplorerViewletState(); + this.externalViewletId = this.activityService.getExternalViewletIdToOpen(); + this.treeNodeProviderId = this.getTreeProviderName(this.externalViewletId); + TreeExplorerViewlet._idCounter++; } @@ -41,7 +46,7 @@ export class TreeExplorerViewlet extends Viewlet { super.create(parent); this.viewletContainer = parent.div().addClass('custom-tree-explorer-viewlet'); - this.addTreeView(TREE_NAME); + this.addTreeView(this.treeNodeProviderId); return TPromise.as(null); } @@ -56,14 +61,19 @@ export class TreeExplorerViewlet extends Viewlet { }); } - private addTreeView(treeName: string): void { + private addTreeView(treeNodeProviderId: string): void { // Hide header (root node) by default const headerSize = 0; - this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, treeName, this.getActionRunner(), headerSize); + this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, treeNodeProviderId, this.getActionRunner(), headerSize); this.view.render(this.viewletContainer.getHTMLElement(), Orientation.VERTICAL); } + private getTreeProviderName(viewletId: string): string { + const tokens = viewletId.split('.'); + return tokens[tokens.length - 1]; + } + dispose(): void { this.view = null; } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index b67699df936..f793a68a04d 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -28,9 +28,7 @@ export class TreeExplorerView extends CollapsibleViewletView { private viewletState: TreeExplorerViewletState; - private _treeName: string; - - get treeName(): string { return this._treeName; } + private treeNodeProviderIdName: string; constructor( viewletState: TreeExplorerViewletState, @@ -49,7 +47,7 @@ export class TreeExplorerView extends CollapsibleViewletView { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); this.viewletState = viewletState; - this._treeName = treeName; + this.treeNodeProviderIdName = treeName; this.workspace = contextService.getWorkspace(); @@ -72,9 +70,9 @@ export class TreeExplorerView extends CollapsibleViewletView { } createViewer(container: Builder): ITree { - const dataSource = this.instantiationService.createInstance(TreeDataSource); + const dataSource = this.instantiationService.createInstance(TreeDataSource, this.treeNodeProviderIdName); const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); - const controller = this.instantiationService.createInstance(TreeController); + const controller = this.instantiationService.createInstance(TreeController, this.treeNodeProviderIdName); const sorter = null; const filter = null; const dnd = null; @@ -102,7 +100,7 @@ export class TreeExplorerView extends CollapsibleViewletView { } private updateInput(): TPromise { - return this.treeExplorerViewletService.provideTreeContent('pineTree').then(tree => { + return this.treeExplorerViewletService.provideTreeContent(this.treeNodeProviderIdName).then(tree => { this.tree.setInput(tree); }); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index c6507f92c65..6b350ca6dde 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -20,6 +20,7 @@ import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeE export class TreeDataSource implements IDataSource { constructor( + private treeNodeProviderId: string, @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { @@ -34,7 +35,7 @@ export class TreeDataSource implements IDataSource { } getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { - return this.treeExplorerViewletService.resolveChildren('pineTree', node); + return this.treeExplorerViewletService.resolveChildren(this.treeNodeProviderId, node); } getParent(tree: ITree, node: InternalTreeExplorerNode): TPromise { @@ -80,6 +81,7 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { export class TreeController extends DefaultController { constructor( + private treeNodeProviderId: string, @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService ) { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); @@ -89,7 +91,7 @@ export class TreeController extends DefaultController { super.onLeftClick(tree, node, event, origin); if (node.clickCommand) { - this.treeExplorerViewletService.resolveCommand('pineTree', node); + this.treeExplorerViewletService.resolveCommand(this.treeNodeProviderId, node); } return true; diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 0324c692985..181f2d1d2e7 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -80,4 +80,9 @@ export interface IActivityService { * Enable/disable viewlet */ toggleViewlet(viewletId: string): void; + + /** + * Get the external viewlet id to open + */ + getExternalViewletIdToOpen(): string; } \ No newline at end of file From 857411d10851c73776216bfddee950ddf862df74 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 09:14:21 -0700 Subject: [PATCH 050/119] Make naming consistent --- src/vs/workbench/api/node/mainThreadTreeExplorers.ts | 4 ++-- .../explorers/browser/treeExplorerViewlet.contribution.ts | 4 ++-- ...treeExplorerService.ts => treeExplorerViewletService.ts} | 6 +++--- .../parts/explorers/browser/views/treeExplorerView.ts | 4 ++-- .../parts/explorers/browser/views/treeExplorerViewer.ts | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/vs/workbench/parts/explorers/browser/{treeExplorerService.ts => treeExplorerViewletService.ts} (92%) diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 9853af80b34..a2de571cbbd 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; -import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { @@ -17,7 +17,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { constructor( @IThreadService threadService: IThreadService, - @ITreeExplorerService private treeExplorerService: ITreeExplorerService + @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService ) { super(); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 858e2f47e3f..7f61735dd4a 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { ITreeExplorerService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; +import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -registerSingleton(ITreeExplorerService, TreeExplorerViewletService); +registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts similarity index 92% rename from src/vs/workbench/parts/explorers/browser/treeExplorerService.ts rename to src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index b60941de482..33827b60785 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -8,9 +8,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; -export const ITreeExplorerService = createDecorator('customViewletService'); +export const ITreeExplorerViewletService = createDecorator('customViewletService'); -export interface ITreeExplorerService { +export interface ITreeExplorerViewletService { _serviceBrand: any; registerTreeContentProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void; @@ -19,7 +19,7 @@ export interface ITreeExplorerService { resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; } -export class TreeExplorerViewletService implements ITreeExplorerService { +export class TreeExplorerViewletService implements ITreeExplorerViewletService { public _serviceBrand: any; private _treeContentProviders: { [providerId: string]: InternalTreeExplorerNodeProvider }; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index f793a68a04d..6e08d5b5c6a 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -18,7 +18,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; @@ -42,7 +42,7 @@ export class TreeExplorerView extends CollapsibleViewletView { @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 6b350ca6dde..f15bc3bf256 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -16,12 +16,12 @@ import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegis import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { ITreeExplorerService } from 'vs/workbench/parts/explorers/browser/treeExplorerService'; +import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; export class TreeDataSource implements IDataSource { constructor( private treeNodeProviderId: string, - @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { } @@ -82,7 +82,7 @@ export class TreeController extends DefaultController { constructor( private treeNodeProviderId: string, - @ITreeExplorerService private treeExplorerViewletService: ITreeExplorerService + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService ) { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } From 0c189793a3d0e49b987b10e1bc678277d28b8731 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 09:57:36 -0700 Subject: [PATCH 051/119] Handle errors caused by provider --- .../workbench/api/node/extHostTreeExplorers.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index fa843da3c7f..e70900db733 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -45,7 +45,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { $provideRootNode(providerId: string): TPromise { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { - throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); } return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { @@ -55,13 +55,15 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const internalRootNode = new InternalTreeExplorerNode(externalRootNode, provider); this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; + }, err => { + throw new Error(`TreeExplorerNodeProvider '${providerId}' failed to provide root node`); }); } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { - throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); } const externalNodeMap = this._externalNodeMaps[providerId]; @@ -73,20 +75,24 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { externalNodeMap[internalChild.id] = externalChild; return internalChild; }); + }, err => { + throw new Error(`TreeExplorerNodeProvider '${providerId}' failed to resolveChildren`); }); } $resolveCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { - throw new Error(`no TreeContentProvider registered with id '${providerId}'`); + throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); } if (mainThreadNode.clickCommand) { const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; - return TPromise.wrap(this.commands.executeCommand(mainThreadNode.clickCommand, externalNode).then(() => { + return asWinJsPromise(() => this.commands.executeCommand(mainThreadNode.clickCommand, externalNode)).then(() => { return null; - })); + }, err => { + throw new Error(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'`); + }); } return TPromise.as(null); From 045aeddd152f40da2a81bd6bb94c8fb9ed61644d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 10:09:19 -0700 Subject: [PATCH 052/119] ContentProvider -> TreeExplorerNodeProvider --- src/vs/vscode.d.ts | 2 +- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- src/vs/workbench/api/node/extHost.protocol.ts | 6 +++--- .../workbench/api/node/extHostTreeExplorers.ts | 6 +++--- .../api/node/mainThreadTreeExplorers.ts | 14 ++++---------- .../browser/treeExplorerViewletService.ts | 16 ++++++++-------- 6 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 3962a904105..dd95cebbc0d 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3818,7 +3818,7 @@ declare module 'vscode' { * for custom tree explorers. * * @param providerId A unique id that identifies the provider. - * @param provider A [TreeContentProvider](#TreeContentProvider) + * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider) * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index ba5043d3146..002c2feb846 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -335,7 +335,7 @@ export function createApiFactory(threadService: IThreadService, extensionService return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables); }, registerTreeExplorerNodeProvider(providerId: string, provider: vscode.TreeExplorerNodeProvider) { - return extHostExplorers.registerTreeContentProvider(providerId, provider); + return extHostExplorers.registerTreeExplorerNodeProvider(providerId, provider); }, onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index fd2e4b519ab..5e3415d42cb 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -118,8 +118,8 @@ export abstract class MainThreadEditorsShape { } export abstract class MainThreadTreeExplorersShape { - $registerTreeContentProvider(treeContentProviderId: string): void { throw ni(); } - $unregisterTreeContentProvider(treeContentProviderId: string): void { throw ni(); } + $registerTreeExplorerNodeProvider(providerId: string): void { throw ni(); } + $unregisterTreeExplorerNodeProvider(providerId: string): void { throw ni(); } } export abstract class MainThreadErrorsShape { @@ -365,7 +365,7 @@ export const ExtHostContext = { ExtHostDocuments: createExtId('ExtHostDocuments', ExtHostDocumentsShape), ExtHostDocumentSaveParticipant: createExtId('ExtHostDocumentSaveParticipant', ExtHostDocumentSaveParticipantShape), ExtHostEditors: createExtId('ExtHostEditors', ExtHostEditorsShape), - ExtHostExplorers: createExtId('ExtHostExplorers',ExtHostTreeExplorersShape), + ExtHostExplorers: createExtId('ExtHostExplorers', ExtHostTreeExplorersShape), ExtHostFileSystemEventService: createExtId('ExtHostFileSystemEventService', ExtHostFileSystemEventServiceShape), ExtHostHeapService: createExtId('ExtHostHeapMonitor', ExtHostHeapServiceShape), ExtHostLanguageFeatures: createExtId('ExtHostLanguageFeatures', ExtHostLanguageFeaturesShape), diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index e70900db733..869cf0ddf16 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -31,13 +31,13 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._externalNodeMaps = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { - this._proxy.$registerTreeContentProvider(providerId); + registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { + this._proxy.$registerTreeExplorerNodeProvider(providerId); this._treeExplorerNodeProviders[providerId] = provider; return new Disposable(() => { if (delete this._treeExplorerNodeProviders[providerId]) { - this._proxy.$unregisterTreeContentProvider(providerId); + this._proxy.$unregisterTreeExplorerNodeProvider(providerId); } }); } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index a2de571cbbd..4c4b37d61fe 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -13,8 +13,6 @@ import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/tr export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { private _proxy: ExtHostTreeExplorersShape; - private _treeContents: { [treeContentProviderId: string]: InternalTreeExplorerNode }; - constructor( @IThreadService threadService: IThreadService, @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService @@ -22,16 +20,12 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { super(); this._proxy = threadService.get(ExtHostContext.ExtHostExplorers); - this._treeContents = Object.create(null); } - $registerTreeContentProvider(providerId: string): void { - this.treeExplorerService.registerTreeContentProvider(providerId, { + $registerTreeExplorerNodeProvider(providerId: string): void { + this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, { provideRootNode: (): TPromise => { - return this._proxy.$provideRootNode(providerId).then(treeContent => { - this._treeContents[providerId] = treeContent; - return treeContent; - }); + return this._proxy.$provideRootNode(providerId); }, resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); @@ -42,7 +36,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { }); } - $unregisterTreeContentProvider(treeContentProviderId: string): void { + $unregisterTreeExplorerNodeProvider(providerId: string): void { } } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 33827b60785..2946bd3d38b 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -13,7 +13,7 @@ export const ITreeExplorerViewletService = createDecorator; resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise; resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; @@ -22,27 +22,27 @@ export interface ITreeExplorerViewletService { export class TreeExplorerViewletService implements ITreeExplorerViewletService { public _serviceBrand: any; - private _treeContentProviders: { [providerId: string]: InternalTreeExplorerNodeProvider }; + private _treeExplorerNodeProvider: { [providerId: string]: InternalTreeExplorerNodeProvider }; constructor( @IInstantiationService private _instantiationService: IInstantiationService ) { - this._treeContentProviders = Object.create(null); + this._treeExplorerNodeProvider = Object.create(null); } - registerTreeContentProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { - this._treeContentProviders[providerId] = provider; + registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { + this._treeExplorerNodeProvider[providerId] = provider; } provideTreeContent(providerId: string): TPromise { - return TPromise.wrap(this._treeContentProviders[providerId].provideRootNode()); + return TPromise.wrap(this._treeExplorerNodeProvider[providerId].provideRootNode()); } resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { - return TPromise.wrap(this._treeContentProviders[providerId].resolveChildren(node)); + return TPromise.wrap(this._treeExplorerNodeProvider[providerId].resolveChildren(node)); } resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { - return TPromise.wrap(this._treeContentProviders[providerId].resolveCommand(node)); + return TPromise.wrap(this._treeExplorerNodeProvider[providerId].resolveCommand(node)); } } From f19446e63905bb933a636399120c4fd392b51d91 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 10:51:37 -0700 Subject: [PATCH 053/119] Avoid re-rendering the tree when icon is clicked --- .../parts/activitybar/activitybarPart.ts | 23 ++++++++++++++++--- .../explorers/browser/treeExplorerViewlet.ts | 1 + .../browser/views/treeExplorerView.ts | 6 ++--- .../activity/common/activityService.ts | 6 +++++ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index e493065e34d..538e3270e0c 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -34,6 +34,10 @@ export class ActivitybarPart extends Part implements IActivityService { private viewletsToggleStatus: { [viewletId: string]: boolean; }; private registeredViewlets: string[]; + // Since the internal viewlet can't get the external viewlet's id upon initialization, + // internal viewlet initializes with id like 'workbench.view.customTreeExplorerViewlet.1'. + // This maps the internal viewlet id to externalId like 'workbench.view.customTreeExplorerViewlet.myTree' + private internalViewletIdMap: { [externalViewletId: string]: string; }; private externalViewletIdToOpen: string; private VIEWLETS_TOGGLE_STATUS = 'workbench.activityBar.viewletsToggleStatus'; @@ -56,6 +60,8 @@ export class ActivitybarPart extends Part implements IActivityService { this.registeredViewlets = []; + this.internalViewletIdMap = {}; + this.registerListeners(); } @@ -117,6 +123,10 @@ export class ActivitybarPart extends Part implements IActivityService { return this.externalViewletIdToOpen; } + setInternalViewletId(externalViewletId: string, internalViewletId: string): void { + this.internalViewletIdMap[externalViewletId] = internalViewletId; + } + public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -174,7 +184,7 @@ export class ActivitybarPart extends Part implements IActivityService { } private toAction(composite: ViewletDescriptor): ActivityAction { - const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); + const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite, this.internalViewletIdMap); action.onOpenViewlet((viewletId) => { this.externalViewletIdToOpen = viewletId; }); @@ -212,7 +222,9 @@ class ViewletActivityAction extends ActivityAction { get onOpenViewlet(): Event { return this._onOpenViewlet.event; }; constructor( - id: string, private viewlet: ViewletDescriptor, + id: string, + private viewlet: ViewletDescriptor, + private internalViewletIdMap: { [externalViewletId: string]: string; }, @IViewletService private viewletService: IViewletService, @IPartService private partService: IPartService ) { @@ -236,7 +248,12 @@ class ViewletActivityAction extends ActivityAction { this.partService.setSideBarHidden(true); } else { this._onOpenViewlet.fire(this.viewlet.id); - this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); + // If the viewlet is external and has been initialized, find the internal viewlet id for opening + if (this.viewlet.isExternal && this.internalViewletIdMap[this.viewlet.id]) { + this.viewletService.openViewlet(this.internalViewletIdMap[this.viewlet.id], true).done(null, errors.onUnexpectedError); + } else { + this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); + } this.activate(); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 3d1f05da41d..13dd40129d4 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -38,6 +38,7 @@ export class TreeExplorerViewlet extends Viewlet { this.externalViewletId = this.activityService.getExternalViewletIdToOpen(); this.treeNodeProviderId = this.getTreeProviderName(this.externalViewletId); + this.activityService.setInternalViewletId(this.externalViewletId, VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter); TreeExplorerViewlet._idCounter++; } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 6e08d5b5c6a..2dbadda755b 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -90,13 +90,11 @@ export class TreeExplorerView extends CollapsibleViewletView { } create(): TPromise { - return TPromise.as(null); + return this.updateInput(); } setVisible(visible: boolean): TPromise { - return super.setVisible(visible).then(() => { - this.updateInput().done(); - }); + return super.setVisible(visible); } private updateInput(): TPromise { diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 181f2d1d2e7..fef5f870279 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -85,4 +85,10 @@ export interface IActivityService { * Get the external viewlet id to open */ getExternalViewletIdToOpen(): string; + + /** + * Tell activitybar the internal viewlet id corresponding to the external viewlet id + * once the viewlet is initialized + */ + setInternalViewletId(externalViewletId: string, internalViewletId: string): void; } \ No newline at end of file From ec7f0779d64b9ce8a1d66b7f17532e6f4b62188a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 11:10:38 -0700 Subject: [PATCH 054/119] Naming --- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- src/vs/workbench/api/node/extHostTreeExplorers.ts | 2 +- src/vs/workbench/api/node/mainThreadTreeExplorers.ts | 4 ++-- .../parts/explorers/browser/treeExplorerViewletService.ts | 2 +- .../workbench/parts/explorers/common/treeExplorerViewModel.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 5e3415d42cb..b1fbc64c189 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -267,7 +267,7 @@ export abstract class ExtHostEditorsShape { export abstract class ExtHostTreeExplorersShape { $provideRootNode(providerId: string): TPromise { throw ni(); }; $resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } - $resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } + $executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 869cf0ddf16..d03a9096e7c 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -80,7 +80,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { }); } - $resolveCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { + $executeCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 4c4b37d61fe..149fbc41cd5 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -30,8 +30,8 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node); }, - resolveCommand: (node: InternalTreeExplorerNode): TPromise => { - return this._proxy.$resolveCommand(providerId, node); + executeCommand: (node: InternalTreeExplorerNode): TPromise => { + return this._proxy.$executeCommand(providerId, node); } }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 2946bd3d38b..afbff616aed 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -43,6 +43,6 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { } resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { - return TPromise.wrap(this._treeExplorerNodeProvider[providerId].resolveCommand(node)); + return TPromise.wrap(this._treeExplorerNodeProvider[providerId].executeCommand(node)); } } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 45a003fd572..6c8b5c51595 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -36,9 +36,9 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { } export interface InternalTreeExplorerNodeProvider { - resolveCommand(node: TreeExplorerNodeContent): TPromise; provideRootNode(): Thenable; resolveChildren(node: InternalTreeExplorerNode): Thenable; + executeCommand(node: TreeExplorerNodeContent): TPromise; } export interface TreeExplorerNodeContent { From 7750596d1537fb58bd62e42e370fe45b75c1d43b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 14:19:34 -0700 Subject: [PATCH 055/119] Remove shouldInitiallyExpand --- src/vs/vscode.d.ts | 1 - .../parts/explorers/common/treeExplorerViewModel.ts | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index dd95cebbc0d..d3bb5722c51 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1353,7 +1353,6 @@ declare module 'vscode' { resolveChildren(node: T): T[] | Thenable; getLabel?(node: T): string; - getShouldInitiallyExpand?(node: T): boolean; getHasChildren?(node: T): boolean; getClickCommand?(node: T): string; } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index 6c8b5c51595..f68bba6dffb 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -14,7 +14,6 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { label: string = 'label'; hasChildren: boolean = true; - shouldInitiallyExpand: boolean = false; clickCommand: string = null; constructor(node: any, provider: TreeExplorerNodeProvider) { @@ -26,9 +25,6 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { if (provider.getHasChildren) { this.hasChildren = provider.getHasChildren(node); } - if (provider.getShouldInitiallyExpand) { - this.shouldInitiallyExpand = provider.getShouldInitiallyExpand(node); - } if (provider.getClickCommand) { this.clickCommand = provider.getClickCommand(node); } @@ -44,6 +40,5 @@ export interface InternalTreeExplorerNodeProvider { export interface TreeExplorerNodeContent { label: string; hasChildren: boolean; - shouldInitiallyExpand: boolean; clickCommand: string; } From c49e7bc7f714ece3c6752b4be8af63d95cc881f0 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 14:46:31 -0700 Subject: [PATCH 056/119] Fix active viewlet highlighting and double click hide for sidebar --- .../parts/activitybar/activitybarPart.ts | 20 ++----------------- .../explorers/browser/treeExplorerViewlet.ts | 5 ++++- .../activity/common/activityService.ts | 6 ------ 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 538e3270e0c..cc59727ad79 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -34,10 +34,6 @@ export class ActivitybarPart extends Part implements IActivityService { private viewletsToggleStatus: { [viewletId: string]: boolean; }; private registeredViewlets: string[]; - // Since the internal viewlet can't get the external viewlet's id upon initialization, - // internal viewlet initializes with id like 'workbench.view.customTreeExplorerViewlet.1'. - // This maps the internal viewlet id to externalId like 'workbench.view.customTreeExplorerViewlet.myTree' - private internalViewletIdMap: { [externalViewletId: string]: string; }; private externalViewletIdToOpen: string; private VIEWLETS_TOGGLE_STATUS = 'workbench.activityBar.viewletsToggleStatus'; @@ -60,8 +56,6 @@ export class ActivitybarPart extends Part implements IActivityService { this.registeredViewlets = []; - this.internalViewletIdMap = {}; - this.registerListeners(); } @@ -123,10 +117,6 @@ export class ActivitybarPart extends Part implements IActivityService { return this.externalViewletIdToOpen; } - setInternalViewletId(externalViewletId: string, internalViewletId: string): void { - this.internalViewletIdMap[externalViewletId] = internalViewletId; - } - public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -184,7 +174,7 @@ export class ActivitybarPart extends Part implements IActivityService { } private toAction(composite: ViewletDescriptor): ActivityAction { - const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite, this.internalViewletIdMap); + const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); action.onOpenViewlet((viewletId) => { this.externalViewletIdToOpen = viewletId; }); @@ -224,7 +214,6 @@ class ViewletActivityAction extends ActivityAction { constructor( id: string, private viewlet: ViewletDescriptor, - private internalViewletIdMap: { [externalViewletId: string]: string; }, @IViewletService private viewletService: IViewletService, @IPartService private partService: IPartService ) { @@ -248,12 +237,7 @@ class ViewletActivityAction extends ActivityAction { this.partService.setSideBarHidden(true); } else { this._onOpenViewlet.fire(this.viewlet.id); - // If the viewlet is external and has been initialized, find the internal viewlet id for opening - if (this.viewlet.isExternal && this.internalViewletIdMap[this.viewlet.id]) { - this.viewletService.openViewlet(this.internalViewletIdMap[this.viewlet.id], true).done(null, errors.onUnexpectedError); - } else { - this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); - } + this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); this.activate(); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 13dd40129d4..7a20643059e 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -38,11 +38,14 @@ export class TreeExplorerViewlet extends Viewlet { this.externalViewletId = this.activityService.getExternalViewletIdToOpen(); this.treeNodeProviderId = this.getTreeProviderName(this.externalViewletId); - this.activityService.setInternalViewletId(this.externalViewletId, VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter); TreeExplorerViewlet._idCounter++; } + getId(): string { + return this.externalViewletId; + } + create(parent: Builder): TPromise { super.create(parent); diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index fef5f870279..181f2d1d2e7 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -85,10 +85,4 @@ export interface IActivityService { * Get the external viewlet id to open */ getExternalViewletIdToOpen(): string; - - /** - * Tell activitybar the internal viewlet id corresponding to the external viewlet id - * once the viewlet is initialized - */ - setInternalViewletId(externalViewletId: string, internalViewletId: string): void; } \ No newline at end of file From 7642976661ababce967c20b5c2fb7d9efca7755e Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 15:22:23 -0700 Subject: [PATCH 057/119] Open file explorer if last viewlet before close is external --- src/vs/workbench/electron-browser/workbench.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 606a1b58a59..5882db5826a 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -241,6 +241,11 @@ export class Workbench implements IPartService { viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId()); // help developers and restore last view } + // If an external viewlet is the default viewlet, restore File Explorer viewlet on startup for now + if (!viewletRegistry.getViewlet(viewletId)) { + viewletId = 'workbench.view.explorer'; + } + if (!this.sideBarHidden && !!viewletId) { const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); From b654b539be2053690bccf44796daa75110264edf Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 16:00:26 -0700 Subject: [PATCH 058/119] Update doc --- src/vs/vscode.d.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index d3bb5722c51..b7c504681f0 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,12 +1348,69 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } + /** + * A node provider for the tree explorer viewlet contributed by extension. + * + * Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a + * `providerId` that should be identical to the `treeExplorerNodeProviderId` in the extension's + * `contributes.explorer` section. + * + * The contributed tree explorer viewlet will ask provider with the same providerId to provide + * the root node and resolve children for each node. In addition, the provider could **optionally** + * provide the following information for each node: + * - label: A human-readable string used for rendering the tree node. + * - hasChildren: A boolean that determines if the node has children and is expandable. + * - clickCommand: A command that will be executed when the node is clicked. + */ export interface TreeExplorerNodeProvider { + + /** + * Provide the root node. This function will be called when the viewlet is first opened. + * The root node is hidden and its direct children will be displayed on the first level of + * the tree explorer. + * + * @return The root node. + */ provideRootNode(): T | Thenable; + + /** + * Resolve the children of the `node`. + * + * @param node The node from which the provider resolves children. + * @return Children of `node`. + */ resolveChildren(node: T): T[] | Thenable; + /** + * Provide the human-readable label for `node` that will be used for rendering. + * + * Default to use `node.toString()` if not provided. + * + * @param node The node from which the provider computes label. + * @return A human-readable label. + */ getLabel?(node: T): string; + + /** + * Determine if `node` has children and is expandable. + * A `true` return value will let the tree explorer render the node with a triangle on its side. + * + * Default to return `true` if not provided. + * + * @param node The node to determine if it has children and is expandable. + * @return Whether the current `node` has children and is expandable. + */ getHasChildren?(node: T): boolean; + + /** + * Get the click command that should be executed when the node is clicked. + * + * Commands can be registered through (#commands.registerCommand). `node` will be provided + * as the first argument to the command's callback function. + * + * @param node The node that the command is associated with. + * @return The command string that denotes the command to execute upon click. + */ getClickCommand?(node: T): string; } From 4cc76f5401c354d3f803100a8efa19ba2b2831e6 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 19:44:02 -0700 Subject: [PATCH 059/119] Remember order of external viewlets --- .../parts/activitybar/activitybarPart.ts | 71 +++++++++++-------- .../treeExplorerActions.contribution.ts | 6 +- .../activity/common/activityService.ts | 8 +-- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index cc59727ad79..1882b1ca97f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -31,12 +31,12 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; - private viewletsToggleStatus: { [viewletId: string]: boolean; }; - private registeredViewlets: string[]; + private enabledExternalViewlets: string[]; + private registeredViewlets: { [viewletId: string]: ViewletDescriptor; }; private externalViewletIdToOpen: string; - private VIEWLETS_TOGGLE_STATUS = 'workbench.activityBar.viewletsToggleStatus'; + private static ENABLED_EXTERNAL_VIEWLETS = 'workbench.activityBar.enabledExternalViewlets'; constructor( id: string, @@ -51,10 +51,9 @@ export class ActivitybarPart extends Part implements IActivityService { this.activityActionItems = {}; this.compositeIdToActions = {}; - const viewletsToggleStatusJson = this.storageService.get(this.VIEWLETS_TOGGLE_STATUS); - this.viewletsToggleStatus = viewletsToggleStatusJson ? JSON.parse(viewletsToggleStatusJson) : {}; - - this.registeredViewlets = []; + const enabledExternalViewletsJson = this.storageService.get(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS); + this.enabledExternalViewlets = enabledExternalViewletsJson ? JSON.parse(enabledExternalViewletsJson) : []; + this.registeredViewlets = {}; this.registerListeners(); } @@ -74,13 +73,23 @@ export class ActivitybarPart extends Part implements IActivityService { ); } - private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]) { - descriptors.forEach(descriptor => { - this.registeredViewlets.push(descriptor.id); - if (this.viewletsToggleStatus[descriptor.id]) { - this.viewletSwitcherBar.push(this.toAction(descriptor), { label: true, icon: true }); + private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]): void { + descriptors.forEach(d => { + this.registeredViewlets[d.id] = d; + }); + + this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); + } + + // Get an ordered list of all enabled external viewlets + private getAllEnabledExternalViewlets(): ViewletDescriptor[] { + const externalViewletsToShow: ViewletDescriptor[] = []; + this.enabledExternalViewlets.forEach(viewletId => { + if (this.registeredViewlets[viewletId]) { + externalViewletsToShow.push(this.registeredViewlets[viewletId]); } }); + return externalViewletsToShow; } private onActiveCompositeChanged(composite: IComposite): void { @@ -95,22 +104,28 @@ export class ActivitybarPart extends Part implements IActivityService { } } - getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean } { + getRegisteredViewletsIsEnabled(): { [viewletId: string]: boolean } { const result = {}; - this.registeredViewlets.forEach(viewletId => { - result[viewletId] = this.viewletsToggleStatus[viewletId]; - }); + for (let viewletId in this.registeredViewlets) { + result[viewletId] = (this.enabledExternalViewlets.indexOf(viewletId) !== -1); + } return result; } toggleViewlet(viewletId: string): void { - this.viewletsToggleStatus[viewletId] = !this.viewletsToggleStatus[viewletId]; - this.setViewletsToggleStatus(); + const index = this.enabledExternalViewlets.indexOf(viewletId); + if (index === -1) { + this.enabledExternalViewlets.push(viewletId); + } else { + this.enabledExternalViewlets.splice(index, 1); + } + + this.setEnabledExternalViewlets(); this.refreshViewletSwitcher(); } - private setViewletsToggleStatus(): void { - this.storageService.store(this.VIEWLETS_TOGGLE_STATUS, JSON.stringify(this.viewletsToggleStatus)); + private setEnabledExternalViewlets(): void { + this.storageService.store(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS, JSON.stringify(this.enabledExternalViewlets)); } getExternalViewletIdToOpen(): string { @@ -156,20 +171,16 @@ export class ActivitybarPart extends Part implements IActivityService { private refreshViewletSwitcher(): void { this.viewletSwitcherBar.clear(); - // Load stock viewlets + enabled external viewlets - const allEnabledViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => { - if (!descriptor.isExternal) { - return true; - } else { - return this.viewletsToggleStatus[descriptor.id]; - } + // Load stock viewlets + const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => { + return !descriptor.isExternal; }); - this.fillViewletSwitcher(allEnabledViewlets); + const allEnabledExternalViewlets = this.getAllEnabledExternalViewlets(); + this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExternalViewlets)); } private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { - // Build Viewlet Actions in correct order - const viewletActions = viewlets.sort((v1, v2) => v1.order - v2.order).map(v => this.toAction(v)); + const viewletActions = viewlets.map(v => this.toAction(v)); this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 7ca60d9e729..f325a767a38 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -29,13 +29,13 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const viewletsToggleStataus = this.activityService.getRegisteredViewletsToggleStatus(); + const viewletsToggleStataus = this.activityService.getRegisteredViewletsIsEnabled(); const picks: IPickOpenEntry[] = []; for (let viewletId in viewletsToggleStataus) { picks.push({ id: viewletId, - label: (viewletsToggleStataus[viewletId] ? "Disable " : "Enable ") + this.getShortViewletId(viewletId) + label: (viewletsToggleStataus[viewletId] ? 'Disable ' : 'Enable ') + this.getShortViewletId(viewletId) }); } @@ -55,6 +55,6 @@ export class ToggleExternalViewletAction extends Action { registry.registerWorkbenchAction( new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), - "View: Toggle Custom Explorer", + 'View: Toggle Custom Explorer', nls.localize('view', "View") ); diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 181f2d1d2e7..465be4e5ded 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -72,17 +72,17 @@ export interface IActivityService { clearActivity(compositeId: string): void; /** - * Get all registered viewlets and whether they are enabled/disabled + * Get all registered viewlets and whether they are enabled/disabled. */ - getRegisteredViewletsToggleStatus(): { [viewletId: string]: boolean }; + getRegisteredViewletsIsEnabled(): { [viewletId: string]: boolean }; /** - * Enable/disable viewlet + * Enable/disable viewlet. */ toggleViewlet(viewletId: string): void; /** - * Get the external viewlet id to open + * Get the external viewlet id that is about to open. */ getExternalViewletIdToOpen(): string; } \ No newline at end of file From 16dd5f9fe83c9334ff0c1ed792a589c161a054b9 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 22:00:41 -0700 Subject: [PATCH 060/119] Clean up --- .../parts/activitybar/activitybarPart.ts | 41 ++++++++++--------- .../activity/common/activityService.ts | 4 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 1882b1ca97f..de55f75e502 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -27,6 +27,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; export class ActivitybarPart extends Part implements IActivityService { public _serviceBrand: any; + private viewletSwitcherBar: ActionBar; private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; @@ -81,17 +82,6 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); } - // Get an ordered list of all enabled external viewlets - private getAllEnabledExternalViewlets(): ViewletDescriptor[] { - const externalViewletsToShow: ViewletDescriptor[] = []; - this.enabledExternalViewlets.forEach(viewletId => { - if (this.registeredViewlets[viewletId]) { - externalViewletsToShow.push(this.registeredViewlets[viewletId]); - } - }); - return externalViewletsToShow; - } - private onActiveCompositeChanged(composite: IComposite): void { if (this.compositeIdToActions[composite.getId()]) { this.compositeIdToActions[composite.getId()].activate(); @@ -128,10 +118,6 @@ export class ActivitybarPart extends Part implements IActivityService { this.storageService.store(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS, JSON.stringify(this.enabledExternalViewlets)); } - getExternalViewletIdToOpen(): string { - return this.externalViewletIdToOpen; - } - public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -184,9 +170,20 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } + // Get an ordered list of all enabled external viewlets + private getAllEnabledExternalViewlets(): ViewletDescriptor[] { + const externalViewletsToShow: ViewletDescriptor[] = []; + this.enabledExternalViewlets.forEach(viewletId => { + if (this.registeredViewlets[viewletId]) { + externalViewletsToShow.push(this.registeredViewlets[viewletId]); + } + }); + return externalViewletsToShow; + } + private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); - action.onOpenViewlet((viewletId) => { + action.onOpenExternalViewlet((viewletId) => { this.externalViewletIdToOpen = viewletId; }); @@ -196,6 +193,10 @@ export class ActivitybarPart extends Part implements IActivityService { return action; }; + getExternalViewletIdToOpen(): string { + return this.externalViewletIdToOpen; + } + private getKeybindingLabel(id: string): string { const keys = this.keybindingService.lookupKeybindings(id).map(k => this.keybindingService.getLabelFor(k)); if (keys && keys.length) { @@ -219,8 +220,8 @@ class ViewletActivityAction extends ActivityAction { private static preventDoubleClickDelay = 300; private lastRun: number = 0; - private _onOpenViewlet = new Emitter(); - get onOpenViewlet(): Event { return this._onOpenViewlet.event; }; + private _onOpenExternalViewlet = new Emitter(); + get onOpenExternalViewlet(): Event { return this._onOpenExternalViewlet.event; }; constructor( id: string, @@ -247,7 +248,9 @@ class ViewletActivityAction extends ActivityAction { if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) { this.partService.setSideBarHidden(true); } else { - this._onOpenViewlet.fire(this.viewlet.id); + if (this.viewlet.isExternal) { + this._onOpenExternalViewlet.fire(this.viewlet.id); + } this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); this.activate(); } diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 465be4e5ded..8ff5afdd99a 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -72,12 +72,12 @@ export interface IActivityService { clearActivity(compositeId: string): void; /** - * Get all registered viewlets and whether they are enabled/disabled. + * Get all registered external viewlets and whether they are enabled/disabled. */ getRegisteredViewletsIsEnabled(): { [viewletId: string]: boolean }; /** - * Enable/disable viewlet. + * Enable/disable an external viewlet. */ toggleViewlet(viewletId: string): void; From 313df776af09dce7f68d9a15c4553878f3ffecab Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 19 Oct 2016 23:02:26 -0700 Subject: [PATCH 061/119] Polish doc language --- src/vs/vscode.d.ts | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b7c504681f0..f7718f038b9 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1349,23 +1349,24 @@ declare module 'vscode' { } /** - * A node provider for the tree explorer viewlet contributed by extension. + * A node provider for the tree explorer contributed by extension. * * Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a - * `providerId` that should be identical to the `treeExplorerNodeProviderId` in the extension's + * `providerId` that corresponds to the `treeExplorerNodeProviderId` in the extension's * `contributes.explorer` section. * - * The contributed tree explorer viewlet will ask provider with the same providerId to provide - * the root node and resolve children for each node. In addition, the provider could **optionally** + * The contributed tree explorer will ask the corresponding provider to provide the root + * node and resolve children for each node. In addition, the provider could **optionally** * provide the following information for each node: - * - label: A human-readable string used for rendering the tree node. - * - hasChildren: A boolean that determines if the node has children and is expandable. - * - clickCommand: A command that will be executed when the node is clicked. + * - label: A human-readable label used for rendering the node. + * - hasChildren: Whether the node has children and is expandable. + * - clickCommand: A command to execute when the node is clicked. */ export interface TreeExplorerNodeProvider { /** - * Provide the root node. This function will be called when the viewlet is first opened. + * Provide the root node. This function will be called when the tree explorer is activated + * for the first time. * The root node is hidden and its direct children will be displayed on the first level of * the tree explorer. * @@ -1374,7 +1375,7 @@ declare module 'vscode' { provideRootNode(): T | Thenable; /** - * Resolve the children of the `node`. + * Resolve the children of `node`. * * @param node The node from which the provider resolves children. * @return Children of `node`. @@ -1382,7 +1383,7 @@ declare module 'vscode' { resolveChildren(node: T): T[] | Thenable; /** - * Provide the human-readable label for `node` that will be used for rendering. + * Provide a human-readable string that will be used for rendering the node. * * Default to use `node.toString()` if not provided. * @@ -1393,23 +1394,22 @@ declare module 'vscode' { /** * Determine if `node` has children and is expandable. - * A `true` return value will let the tree explorer render the node with a triangle on its side. * * Default to return `true` if not provided. * * @param node The node to determine if it has children and is expandable. - * @return Whether the current `node` has children and is expandable. + * @return A boolean that determines if `node` has children and is expandable. */ getHasChildren?(node: T): boolean; /** - * Get the click command that should be executed when the node is clicked. + * Get the command to execute when `node` is clicked. * * Commands can be registered through (#commands.registerCommand). `node` will be provided * as the first argument to the command's callback function. * * @param node The node that the command is associated with. - * @return The command string that denotes the command to execute upon click. + * @return The command to execute when `node` is clicked. */ getClickCommand?(node: T): string; } @@ -3870,11 +3870,10 @@ declare module 'vscode' { export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; /** - * Register a tree explorer node provider, used as a data source - * for custom tree explorers. + * Register a [tree explorer node provider](#TreeExplorerNodeProvider). * * @param providerId A unique id that identifies the provider. - * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider) + * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; From b14150705021dded242cce979dbc4bf122a0d0b8 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 00:21:19 -0700 Subject: [PATCH 062/119] Minor clean up --- src/vs/workbench/api/node/extHost.protocol.ts | 1 - src/vs/workbench/api/node/extHostTreeExplorers.ts | 4 +--- .../workbench/api/node/mainThreadTreeExplorers.ts | 4 ---- .../browser/parts/activitybar/activitybarPart.ts | 13 ++++++------- .../browser/treeExplorerActions.contribution.ts | 2 +- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index b1fbc64c189..35fc36042a6 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -119,7 +119,6 @@ export abstract class MainThreadEditorsShape { export abstract class MainThreadTreeExplorersShape { $registerTreeExplorerNodeProvider(providerId: string): void { throw ni(); } - $unregisterTreeExplorerNodeProvider(providerId: string): void { throw ni(); } } export abstract class MainThreadErrorsShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index d03a9096e7c..6c2b28020d5 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -36,9 +36,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._treeExplorerNodeProviders[providerId] = provider; return new Disposable(() => { - if (delete this._treeExplorerNodeProviders[providerId]) { - this._proxy.$unregisterTreeExplorerNodeProvider(providerId); - } + delete this._treeExplorerNodeProviders[providerId]; }); } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 149fbc41cd5..fc8985d8399 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -35,8 +35,4 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { } }); } - - $unregisterTreeExplorerNodeProvider(providerId: string): void { - - } } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index de55f75e502..b42f546a2a7 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -149,18 +149,14 @@ export class ActivitybarPart extends Part implements IActivityService { ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher") }); - // Load stock viewlets - const allViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(v => !v.isExternal); - this.fillViewletSwitcher(allViewlets); + const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => !descriptor.isExternal); + this.fillViewletSwitcher(allStockViewlets); } private refreshViewletSwitcher(): void { this.viewletSwitcherBar.clear(); - // Load stock viewlets - const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => { - return !descriptor.isExternal; - }); + const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => !descriptor.isExternal); const allEnabledExternalViewlets = this.getAllEnabledExternalViewlets(); this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExternalViewlets)); } @@ -183,6 +179,9 @@ export class ActivitybarPart extends Part implements IActivityService { private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); + // Store the viewletId of the external viewlet that is about to open. + // Later retrieved by TreeExplorerViewlet, which wouldn't know its id until + // its construction at runtime. action.onOpenExternalViewlet((viewletId) => { this.externalViewletIdToOpen = viewletId; }); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index f325a767a38..86785a5ff04 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -39,7 +39,7 @@ export class ToggleExternalViewletAction extends Action { }); } - return TPromise.timeout(50).then(() => { + return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { this.quickOpenService.pick(picks, { placeHolder: 'Select Viewlet to toggle', autoFocus: 2 }).then(pick => { if (pick) { this.activityService.toggleViewlet(pick.id); From 6fd1c54bb73aff224107857810a05b4bc2d71f75 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 11:00:59 -0700 Subject: [PATCH 063/119] Move VIEWLET_ID_ROOT to one place --- .../platform/explorers/browser/explorerExtensionPoint.ts | 3 ++- .../parts/explorers/browser/treeExplorerViewlet.ts | 3 +-- src/vs/workbench/parts/explorers/common/treeExplorer.ts | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/vs/workbench/parts/explorers/common/treeExplorer.ts diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 7de0aaed5a2..287d95dd19a 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -11,6 +11,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { Registry } from 'vs/platform/platform'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; namespace schema { @@ -66,7 +67,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e descriptors.push(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - 'workbench.view.customTreeExplorerViewlet.' + treeExplorerNodeProviderId, + VIEWLET_ID_ROOT + treeExplorerNodeProviderId, treeLabel, treeExplorerNodeProviderId, baseOrder++, diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 7a20643059e..5f8c05dea2a 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -13,8 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; - -export const VIEWLET_ID_ROOT = 'workbench.view.customTreeExplorerViewlet.'; +import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts new file mode 100644 index 00000000000..ece9cb0eca6 --- /dev/null +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -0,0 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +export const VIEWLET_ID_ROOT = 'workbench.view.customTreeExplorer.'; \ No newline at end of file From 267aab6b52c117fe971b5fef98b34b6341314f73 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 11:05:29 -0700 Subject: [PATCH 064/119] Correct ID for toggle action --- .../parts/explorers/browser/treeExplorerActions.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 86785a5ff04..b788e74f7fd 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -16,7 +16,7 @@ import { IActivityService } from 'vs/workbench/services/activity/common/activity const registry = Registry.as(ActionExtensions.WorkbenchActions); export class ToggleExternalViewletAction extends Action { - public static ID = 'workbench.view.customTreeExplorerViewlet'; + public static ID = 'workbench.action.customTreeExplorer.toggle'; public static LABEL = nls.localize('toggleCustomExplorer', 'Toggle Custom Explorer'); constructor( From 6e868d65d94e0826efa2444e45f8890f58ed0a24 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 11:43:14 -0700 Subject: [PATCH 065/119] Add refresh button to toolBar --- .../explorers/browser/treeExplorerActions.ts | 18 ++++++++++++++++++ .../treeExplorerViewlet.contribution.ts | 2 ++ .../explorers/browser/treeExplorerViewlet.ts | 7 +++++++ .../browser/views/treeExplorerView.ts | 10 +--------- .../parts/explorers/media/Refresh.svg | 1 + .../parts/explorers/media/Refresh_inverse.svg | 1 + .../media/treeExplorer.contribution.css | 13 +++++++++++++ 7 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts create mode 100644 src/vs/workbench/parts/explorers/media/Refresh.svg create mode 100644 src/vs/workbench/parts/explorers/media/Refresh_inverse.svg create mode 100644 src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts new file mode 100644 index 00000000000..9d23fb5bcf3 --- /dev/null +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import * as nls from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; + +export class RefreshViewExplorerAction extends Action { + + constructor() { + super('workbench.action.customTreeExplorer.refresh', nls.localize('refresh', "Refresh"), 'customTreeExplorer-action toggle', true, () => { + return TPromise.as(null); + }); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 7f61735dd4a..869fe46876d 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import 'vs/css!../media/treeExplorer.contribution'; + import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 5f8c05dea2a..967c73e255e 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; +import { IAction } from 'vs/base/common/actions'; import { IViewletView, Viewlet } from 'vs/workbench/browser/viewlet'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -14,6 +15,7 @@ import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/tre import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/browser/treeExplorerActions'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; @@ -64,6 +66,11 @@ export class TreeExplorerViewlet extends Viewlet { }); } + getActions(): IAction[] { + const refresh = this.instantiationService.createInstance(RefreshViewExplorerAction); + return [refresh]; + } + private addTreeView(treeNodeProviderId: string): void { // Hide header (root node) by default const headerSize = 0; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 2dbadda755b..2cd65494ea6 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -10,7 +10,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Builder, $ } from 'vs/base/browser/builder'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet'; -import { IActionRunner, IAction } from 'vs/base/common/actions'; +import { IActionRunner } from 'vs/base/common/actions'; import { IMessageService } from 'vs/platform/message/common/message'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -54,10 +54,6 @@ export class TreeExplorerView extends CollapsibleViewletView { this.create(); } - renderHeader(container: HTMLElement): void { - - } - renderBody(container: HTMLElement): void { this.treeContainer = super.renderViewTree(container); DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); @@ -65,10 +61,6 @@ export class TreeExplorerView extends CollapsibleViewletView { this.tree = this.createViewer($(this.treeContainer)); } - getActions(): IAction[] { - return []; - } - createViewer(container: Builder): ITree { const dataSource = this.instantiationService.createInstance(TreeDataSource, this.treeNodeProviderIdName); const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); diff --git a/src/vs/workbench/parts/explorers/media/Refresh.svg b/src/vs/workbench/parts/explorers/media/Refresh.svg new file mode 100644 index 00000000000..e0345748192 --- /dev/null +++ b/src/vs/workbench/parts/explorers/media/Refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/media/Refresh_inverse.svg b/src/vs/workbench/parts/explorers/media/Refresh_inverse.svg new file mode 100644 index 00000000000..d79fdaa4e8e --- /dev/null +++ b/src/vs/workbench/parts/explorers/media/Refresh_inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css new file mode 100644 index 00000000000..b1415ac281c --- /dev/null +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .customTreeExplorer-action.toggle { + background: url('Refresh.svg') center center no-repeat; +} + +.vs-dark .monaco-workbench .customTreeExplorer-action.toggle, +.hc-black .monaco-workbench .customTreeExplorer-action.toggle { + background: url('Refresh_inverse.svg') center center no-repeat; +} From a5adf500bf6ddb71d4b2ef552be63ee287ca9e7c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 11:58:19 -0700 Subject: [PATCH 066/119] Always preserve stock viewlets order --- .../parts/activitybar/activitybarPart.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index b42f546a2a7..bd85fd02d3e 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -70,13 +70,13 @@ export class ActivitybarPart extends Part implements IActivityService { // Update activity bar on registering an external viewlet this.toUnbind.push( (Registry.as(ViewletExtensions.Viewlets)) - .onDidRegisterExternalViewlets(descriptors => this.onDidRegisterExternalViewlets(descriptors)) + .onDidRegisterExternalViewlets(viewlets => this.onDidRegisterExternalViewlets(viewlets)) ); } - private onDidRegisterExternalViewlets(descriptors: ViewletDescriptor[]): void { - descriptors.forEach(d => { - this.registeredViewlets[d.id] = d; + private onDidRegisterExternalViewlets(viewlets: ViewletDescriptor[]): void { + viewlets.forEach(v => { + this.registeredViewlets[v.id] = v; }); this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); @@ -149,14 +149,14 @@ export class ActivitybarPart extends Part implements IActivityService { ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher") }); - const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => !descriptor.isExternal); + const allStockViewlets = this.getAllStockViewlets(); this.fillViewletSwitcher(allStockViewlets); } private refreshViewletSwitcher(): void { this.viewletSwitcherBar.clear(); - const allStockViewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets().filter(descriptor => !descriptor.isExternal); + const allStockViewlets = this.getAllStockViewlets(); const allEnabledExternalViewlets = this.getAllEnabledExternalViewlets(); this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExternalViewlets)); } @@ -166,6 +166,14 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } + // Get an ordered list of all stock viewlets + private getAllStockViewlets(): ViewletDescriptor[] { + return (Registry.as(ViewletExtensions.Viewlets)) + .getViewlets() + .filter(viewlet => !viewlet.isExternal) + .sort((v1, v2) => v1.order - v2.order); + } + // Get an ordered list of all enabled external viewlets private getAllEnabledExternalViewlets(): ViewletDescriptor[] { const externalViewletsToShow: ViewletDescriptor[] = []; From d579cb84cf993b05ac35fa0d1d004538bb139cdb Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 12:29:25 -0700 Subject: [PATCH 067/119] Hook refresh button to update input --- .../parts/explorers/browser/treeExplorerActions.ts | 4 +++- .../parts/explorers/browser/treeExplorerViewlet.ts | 4 +--- .../parts/explorers/browser/views/treeExplorerView.ts | 10 ++++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts index 9d23fb5bcf3..7a59b318bd0 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts @@ -7,11 +7,13 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; +import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; export class RefreshViewExplorerAction extends Action { - constructor() { + constructor(view: TreeExplorerView) { super('workbench.action.customTreeExplorer.refresh', nls.localize('refresh', "Refresh"), 'customTreeExplorer-action toggle', true, () => { + view.updateInput(); return TPromise.as(null); }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 967c73e255e..1914cc66a9e 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -15,7 +15,6 @@ import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/tre import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; -import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/browser/treeExplorerActions'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; @@ -67,8 +66,7 @@ export class TreeExplorerViewlet extends Viewlet { } getActions(): IAction[] { - const refresh = this.instantiationService.createInstance(RefreshViewExplorerAction); - return [refresh]; + return this.view.getActions(); } private addTreeView(treeNodeProviderId: string): void { diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 2cd65494ea6..df4326ccb5f 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -10,7 +10,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Builder, $ } from 'vs/base/browser/builder'; import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet'; -import { IActionRunner } from 'vs/base/common/actions'; +import { IAction, IActionRunner } from 'vs/base/common/actions'; import { IMessageService } from 'vs/platform/message/common/message'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -22,6 +22,7 @@ import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browse import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; +import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/browser/treeExplorerActions'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; @@ -81,6 +82,11 @@ export class TreeExplorerView extends CollapsibleViewletView { }); } + getActions(): IAction[] { + const refresh = this.instantiationService.createInstance(RefreshViewExplorerAction, this); + return [refresh]; + } + create(): TPromise { return this.updateInput(); } @@ -89,7 +95,7 @@ export class TreeExplorerView extends CollapsibleViewletView { return super.setVisible(visible); } - private updateInput(): TPromise { + updateInput(): TPromise { return this.treeExplorerViewletService.provideTreeContent(this.treeNodeProviderIdName).then(tree => { this.tree.setInput(tree); }); From 0b84a56e4f41211d0d9fd0bddc8af5f7ac3164cf Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 19:36:58 -0700 Subject: [PATCH 068/119] Consistent naming --- .../parts/explorers/browser/treeExplorerViewletService.ts | 4 ++-- .../parts/explorers/browser/views/treeExplorerViewer.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index afbff616aed..50c83853cac 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -16,7 +16,7 @@ export interface ITreeExplorerViewletService { registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void; provideTreeContent(providerId: string): TPromise; resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise; - resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; + executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; } export class TreeExplorerViewletService implements ITreeExplorerViewletService { @@ -42,7 +42,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { return TPromise.wrap(this._treeExplorerNodeProvider[providerId].resolveChildren(node)); } - resolveCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { + executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { return TPromise.wrap(this._treeExplorerNodeProvider[providerId].executeCommand(node)); } } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index f15bc3bf256..5a06b82cf99 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -91,7 +91,7 @@ export class TreeController extends DefaultController { super.onLeftClick(tree, node, event, origin); if (node.clickCommand) { - this.treeExplorerViewletService.resolveCommand(this.treeNodeProviderId, node); + this.treeExplorerViewletService.executeCommand(this.treeNodeProviderId, node); } return true; From 37398ea53e6eca59b99b7e2884a62f9918feec51 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 22:54:52 -0700 Subject: [PATCH 069/119] Handle all error by showing message --- src/vs/workbench/api/node/extHost.protocol.ts | 1 + .../api/node/extHostTreeExplorers.ts | 35 ++++++++++--------- .../api/node/mainThreadTreeExplorers.ts | 8 ++++- .../browser/treeExplorerViewletService.ts | 23 +++++++++--- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 35fc36042a6..643722e1b8c 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -119,6 +119,7 @@ export abstract class MainThreadEditorsShape { export abstract class MainThreadTreeExplorersShape { $registerTreeExplorerNodeProvider(providerId: string): void { throw ni(); } + $showMessage(severity: Severity, message: string): void { throw ni(); } } export abstract class MainThreadErrorsShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 6c2b28020d5..53a903c16d8 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -12,6 +12,7 @@ import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; +import { Severity } from 'vs/platform/message/common/message'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; @@ -41,10 +42,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { } $provideRootNode(providerId: string): TPromise { - const provider = this._treeExplorerNodeProviders[providerId]; - if (!provider) { - throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); - } + const provider = this.getProvider(providerId); return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { const treeNodeMap = Object.create(null); @@ -54,15 +52,12 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; }, err => { - throw new Error(`TreeExplorerNodeProvider '${providerId}' failed to provide root node`); + this.showErrorMessage(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); }); } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { - const provider = this._treeExplorerNodeProviders[providerId]; - if (!provider) { - throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); - } + const provider = this.getProvider(providerId); const externalNodeMap = this._externalNodeMaps[providerId]; const externalNode = externalNodeMap[mainThreadNode.id]; @@ -74,25 +69,33 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return internalChild; }); }, err => { - throw new Error(`TreeExplorerNodeProvider '${providerId}' failed to resolveChildren`); + this.showErrorMessage(`TreeExplorerNodeProvider '${providerId}' failed to resolve children.`); }); } $executeCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { - const provider = this._treeExplorerNodeProviders[providerId]; - if (!provider) { - throw new Error(`no TreeExplorerNodeProvider registered with id '${providerId}'`); - } - if (mainThreadNode.clickCommand) { const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; return asWinJsPromise(() => this.commands.executeCommand(mainThreadNode.clickCommand, externalNode)).then(() => { return null; }, err => { - throw new Error(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'`); + this.showErrorMessage(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'.`); }); } return TPromise.as(null); } + + getProvider(providerId: string): TreeExplorerNodeProvider { + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + this.showErrorMessage(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); + } + + return provider; + } + + private showErrorMessage(message: string): void { + this._proxy.$showMessage(Severity.Error, message); + } } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index fc8985d8399..463051e0053 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -9,13 +9,15 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { private _proxy: ExtHostTreeExplorersShape; constructor( @IThreadService threadService: IThreadService, - @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService + @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService, + @IMessageService private messageService: IMessageService ) { super(); @@ -35,4 +37,8 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { } }); } + + $showMessage(severity: Severity, message: string): void { + this.messageService.show(severity, message); + } } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 50c83853cac..e731c121ad4 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; export const ITreeExplorerViewletService = createDecorator('customViewletService'); @@ -25,7 +26,8 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { private _treeExplorerNodeProvider: { [providerId: string]: InternalTreeExplorerNodeProvider }; constructor( - @IInstantiationService private _instantiationService: IInstantiationService + @IInstantiationService private _instantiationService: IInstantiationService, + @IMessageService private messageService: IMessageService, ) { this._treeExplorerNodeProvider = Object.create(null); } @@ -35,14 +37,27 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { } provideTreeContent(providerId: string): TPromise { - return TPromise.wrap(this._treeExplorerNodeProvider[providerId].provideRootNode()); + const provider = this.getProvider(providerId); + return TPromise.wrap(provider.provideRootNode()); } resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { - return TPromise.wrap(this._treeExplorerNodeProvider[providerId].resolveChildren(node)); + const provider = this.getProvider(providerId); + return TPromise.wrap(provider.resolveChildren(node)); } executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { - return TPromise.wrap(this._treeExplorerNodeProvider[providerId].executeCommand(node)); + const provider = this.getProvider(providerId); + return TPromise.wrap(provider.executeCommand(node)); + } + + private getProvider(providerId: string): InternalTreeExplorerNodeProvider { + const provider = this._treeExplorerNodeProvider[providerId]; + + if (!provider) { + this.messageService.show(Severity.Error, `No TreeExplorerNodeProvider with id '${providerId}' registered.`); + } + + return provider; } } From bc573a72f569fa326a1c5b23f3c740c6f9f33ac9 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 20 Oct 2016 23:57:09 -0700 Subject: [PATCH 070/119] Let user contributed explorer icon be a string Later to style the bg svg to show activation, and adjust between light/dark theme --- .../explorers/browser/explorerExtensionPoint.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 287d95dd19a..50959fa18d6 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -15,12 +15,10 @@ import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplore namespace schema { - export type IUserFriendlyIcon = string | { light: string; dark: string; }; - export interface IExplorer { treeExplorerNodeProviderId: string; treeLabel: string; - icon: IUserFriendlyIcon; + icon: string; } export const explorerContribtion: IJSONSchema = { @@ -52,16 +50,9 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; if (icon) { - if (typeof icon === 'string') { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - const iconPath = join(extension.description.extensionFolderPath, icon); - createCSSRule(iconClass, getIconRule(iconPath)); - } else { - const lightIconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - const darkIconClass = `.vs-dark .monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - createCSSRule(lightIconClass, getIconRule(icon.light)); - createCSSRule(darkIconClass, getIconRule(icon.dark)); - } + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const iconPath = join(extension.description.extensionFolderPath, icon); + createCSSRule(iconClass, getIconRule(iconPath)); } descriptors.push(new ViewletDescriptor( From 0e9aecd492770eee8db85676d23b327a7490b84c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 21 Oct 2016 00:07:25 -0700 Subject: [PATCH 071/119] Clarify some code --- .../workbench/browser/parts/activitybar/activitybarPart.ts | 6 +++--- .../explorers/browser/treeExplorerActions.contribution.ts | 2 +- .../workbench/services/activity/common/activityService.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index bd85fd02d3e..c7c56839750 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -67,7 +67,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - // Update activity bar on registering an external viewlet + // Update activity bar on registering external viewlets this.toUnbind.push( (Registry.as(ViewletExtensions.Viewlets)) .onDidRegisterExternalViewlets(viewlets => this.onDidRegisterExternalViewlets(viewlets)) @@ -94,7 +94,7 @@ export class ActivitybarPart extends Part implements IActivityService { } } - getRegisteredViewletsIsEnabled(): { [viewletId: string]: boolean } { + getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean } { const result = {}; for (let viewletId in this.registeredViewlets) { result[viewletId] = (this.enabledExternalViewlets.indexOf(viewletId) !== -1); @@ -174,7 +174,7 @@ export class ActivitybarPart extends Part implements IActivityService { .sort((v1, v2) => v1.order - v2.order); } - // Get an ordered list of all enabled external viewlets + // Get a list of all enabled external viewlets, ordered by the enabling sequence private getAllEnabledExternalViewlets(): ViewletDescriptor[] { const externalViewletsToShow: ViewletDescriptor[] = []; this.enabledExternalViewlets.forEach(viewletId => { diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index b788e74f7fd..07b2dc48f0a 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -29,7 +29,7 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const viewletsToggleStataus = this.activityService.getRegisteredViewletsIsEnabled(); + const viewletsToggleStataus = this.activityService.getIsEnabledForRegisteredViewlets(); const picks: IPickOpenEntry[] = []; for (let viewletId in viewletsToggleStataus) { diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 8ff5afdd99a..711630394d8 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -74,7 +74,7 @@ export interface IActivityService { /** * Get all registered external viewlets and whether they are enabled/disabled. */ - getRegisteredViewletsIsEnabled(): { [viewletId: string]: boolean }; + getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean }; /** * Enable/disable an external viewlet. @@ -85,4 +85,4 @@ export interface IActivityService { * Get the external viewlet id that is about to open. */ getExternalViewletIdToOpen(): string; -} \ No newline at end of file +} From 60574ba461f61a2653121ee7746aaff1d4cbbf79 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 21 Oct 2016 09:55:58 -0700 Subject: [PATCH 072/119] Add progress indication for long running resolveChildren --- .../explorers/browser/views/treeExplorerViewer.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 5a06b82cf99..f6b8bf9e5bb 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -17,11 +17,13 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { IProgressService } from 'vs/platform/progress/common/progress'; export class TreeDataSource implements IDataSource { constructor( private treeNodeProviderId: string, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService, + @IProgressService private progressService: IProgressService ) { } @@ -35,7 +37,11 @@ export class TreeDataSource implements IDataSource { } getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { - return this.treeExplorerViewletService.resolveChildren(this.treeNodeProviderId, node); + const promise = this.treeExplorerViewletService.resolveChildren(this.treeNodeProviderId, node); + + this.progressService.showWhile(promise, 800); + + return promise; } getParent(tree: ITree, node: InternalTreeExplorerNode): TPromise { From a21ac50b5e4bd15ccec058f5ca3f8f6d42ad2afa Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 21 Oct 2016 10:03:49 -0700 Subject: [PATCH 073/119] Fix use before initialization --- src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 002c2feb846..2d866a4b7d7 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -65,8 +65,8 @@ export function createApiFactory(threadService: IThreadService, extensionService const extHostDocuments = col.define(ExtHostContext.ExtHostDocuments).set(new ExtHostDocuments(threadService)); const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocuments)); - const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostTreeExplorers(threadService, extHostCommands)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostEditors, extHostHeapService)); + const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set(new ExtHostTreeExplorers(threadService, extHostCommands)); const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration))); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); From 39ecfd33897ca88e27e26ef0b63f37c0d3b2c789 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 21 Oct 2016 14:07:02 -0700 Subject: [PATCH 074/119] Restore external viewlet on startup --- .../parts/activitybar/activitybarPart.ts | 7 ++++ .../workbench/electron-browser/workbench.ts | 16 ++++----- .../explorers/browser/treeExplorerViewlet.ts | 6 ++-- .../browser/treeExplorerViewletService.ts | 25 ++++++++++---- .../browser/views/treeExplorerView.ts | 33 +++++++++++-------- .../browser/views/treeExplorerViewer.ts | 1 + 6 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index c7c56839750..f4832b27765 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -80,6 +80,9 @@ export class ActivitybarPart extends Part implements IActivityService { }); this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); + if (this.externalViewletIdToOpen) { + this.compositeIdToActions[this.externalViewletIdToOpen].run().done(); + } } private onActiveCompositeChanged(composite: IComposite): void { @@ -200,6 +203,10 @@ export class ActivitybarPart extends Part implements IActivityService { return action; }; + setExternalViewletIdToOpen(viewletId: string): void { + this.externalViewletIdToOpen = viewletId; + } + getExternalViewletIdToOpen(): string { return this.externalViewletIdToOpen; } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 5882db5826a..ed4e03b49e4 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -238,17 +238,17 @@ export class Workbench implements IPartService { const viewletRegistry = Registry.as(ViewletExtensions.Viewlets); let viewletId = viewletRegistry.getDefaultViewletId(); if (this.shouldRestoreSidebar()) { - viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId()); // help developers and restore last view + viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletId); // help developers and restore last view } - // If an external viewlet is the default viewlet, restore File Explorer viewlet on startup for now + // If external viewlet is the last active viewlet, defer its construction until extensions get registered if (!viewletRegistry.getViewlet(viewletId)) { - viewletId = 'workbench.view.explorer'; - } - - if (!this.sideBarHidden && !!viewletId) { - const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); - compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); + this.activitybarPart.setExternalViewletIdToOpen(viewletId); + } else { + if (!this.sideBarHidden && !!viewletId) { + const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); + compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); + } } // Load Panel diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 1914cc66a9e..2ef048e54df 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -50,7 +50,7 @@ export class TreeExplorerViewlet extends Viewlet { super.create(parent); this.viewletContainer = parent.div().addClass('custom-tree-explorer-viewlet'); - this.addTreeView(this.treeNodeProviderId); + this.addTreeView(); return TPromise.as(null); } @@ -69,11 +69,11 @@ export class TreeExplorerViewlet extends Viewlet { return this.view.getActions(); } - private addTreeView(treeNodeProviderId: string): void { + private addTreeView(): void { // Hide header (root node) by default const headerSize = 0; - this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, treeNodeProviderId, this.getActionRunner(), headerSize); + this.view = this.instantiationService.createInstance(TreeExplorerView, this.viewletState, this.treeNodeProviderId, this.getActionRunner(), headerSize); this.view.render(this.viewletContainer.getHTMLElement(), Orientation.VERTICAL); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index e731c121ad4..8970f95934c 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -8,14 +8,19 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; +import Event, { Emitter } from 'vs/base/common/event'; export const ITreeExplorerViewletService = createDecorator('customViewletService'); export interface ITreeExplorerViewletService { _serviceBrand: any; + onTreeExplorerNodeProviderRegistered: Event; + registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void; - provideTreeContent(providerId: string): TPromise; + hasProvider(providerId: string): boolean; + + provideRootNode(providerId: string): TPromise; resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise; executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; } @@ -23,20 +28,28 @@ export interface ITreeExplorerViewletService { export class TreeExplorerViewletService implements ITreeExplorerViewletService { public _serviceBrand: any; - private _treeExplorerNodeProvider: { [providerId: string]: InternalTreeExplorerNodeProvider }; + private _onTreeExplorerNodeProviderRegistered = new Emitter(); + get onTreeExplorerNodeProviderRegistered(): Event { return this._onTreeExplorerNodeProviderRegistered.event; }; + + private _treeExplorerNodeProviders: { [providerId: string]: InternalTreeExplorerNodeProvider }; constructor( @IInstantiationService private _instantiationService: IInstantiationService, @IMessageService private messageService: IMessageService, ) { - this._treeExplorerNodeProvider = Object.create(null); + this._treeExplorerNodeProviders = Object.create(null); } registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { - this._treeExplorerNodeProvider[providerId] = provider; + this._treeExplorerNodeProviders[providerId] = provider; + this._onTreeExplorerNodeProviderRegistered.fire(providerId); } - provideTreeContent(providerId: string): TPromise { + hasProvider(providerId: string): boolean { + return !!this._treeExplorerNodeProviders[providerId]; + } + + provideRootNode(providerId: string): TPromise { const provider = this.getProvider(providerId); return TPromise.wrap(provider.provideRootNode()); } @@ -52,7 +65,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { } private getProvider(providerId: string): InternalTreeExplorerNodeProvider { - const provider = this._treeExplorerNodeProvider[providerId]; + const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { this.messageService.show(Severity.Error, `No TreeExplorerNodeProvider with id '${providerId}' registered.`); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index df4326ccb5f..102722f3282 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -27,13 +27,9 @@ import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/browser/ export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; - private viewletState: TreeExplorerViewletState; - - private treeNodeProviderIdName: string; - constructor( - viewletState: TreeExplorerViewletState, - treeName: string, + private viewletState: TreeExplorerViewletState, + private treeNodeProviderId: string, actionRunner: IActionRunner, headerSize: number, @IMessageService messageService: IMessageService, @@ -47,9 +43,6 @@ export class TreeExplorerView extends CollapsibleViewletView { ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); - this.viewletState = viewletState; - this.treeNodeProviderIdName = treeName; - this.workspace = contextService.getWorkspace(); this.create(); @@ -63,9 +56,9 @@ export class TreeExplorerView extends CollapsibleViewletView { } createViewer(container: Builder): ITree { - const dataSource = this.instantiationService.createInstance(TreeDataSource, this.treeNodeProviderIdName); + const dataSource = this.instantiationService.createInstance(TreeDataSource, this.treeNodeProviderId); const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); - const controller = this.instantiationService.createInstance(TreeController, this.treeNodeProviderIdName); + const controller = this.instantiationService.createInstance(TreeController, this.treeNodeProviderId); const sorter = null; const filter = null; const dnd = null; @@ -96,9 +89,21 @@ export class TreeExplorerView extends CollapsibleViewletView { } updateInput(): TPromise { - return this.treeExplorerViewletService.provideTreeContent(this.treeNodeProviderIdName).then(tree => { - this.tree.setInput(tree); - }); + if (this.treeExplorerViewletService.hasProvider(this.treeNodeProviderId)) { + return this.treeExplorerViewletService.provideRootNode(this.treeNodeProviderId).then(tree => { + this.tree.setInput(tree); + }); + } else { + this.treeExplorerViewletService.onTreeExplorerNodeProviderRegistered(providerId => { + if (this.treeNodeProviderId === providerId) { + return this.treeExplorerViewletService.provideRootNode(this.treeNodeProviderId).then(tree => { + this.tree.setInput(tree); + }); + } + }); + + return TPromise.as(null); + } } public getOptimalWidth(): number { diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index f6b8bf9e5bb..707323e0aae 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -20,6 +20,7 @@ import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browse import { IProgressService } from 'vs/platform/progress/common/progress'; export class TreeDataSource implements IDataSource { + constructor( private treeNodeProviderId: string, @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService, From e2f4a6b3b057cdb2730adbe02ed562bbd4f1496c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 21 Oct 2016 14:59:10 -0700 Subject: [PATCH 075/119] Coerce external viewlet icons into style similar to stock ones --- src/vs/platform/explorers/browser/explorerExtensionPoint.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 50959fa18d6..232df488e87 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -53,6 +53,8 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.e const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; const iconPath = join(extension.description.extensionFolderPath, icon); createCSSRule(iconClass, getIconRule(iconPath)); + // Coerce the icon into a style similar to stock icons + createCSSRule(iconClass, '-webkit-filter: grayscale(1) invert(1)'); } descriptors.push(new ViewletDescriptor( From 794ad903a6909a916681d403d63ebdbf2d4dd03a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Oct 2016 10:32:16 -0700 Subject: [PATCH 076/119] Address feedback --- .../platform/explorers/browser/explorerExtensionPoint.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index 232df488e87..f9f33ae2597 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -12,15 +12,10 @@ import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegi import { Registry } from 'vs/platform/platform'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; namespace schema { - export interface IExplorer { - treeExplorerNodeProviderId: string; - treeLabel: string; - icon: string; - } - export const explorerContribtion: IJSONSchema = { description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), type: 'object', @@ -41,7 +36,7 @@ namespace schema { }; } -ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { +ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { let baseOrder = 200; // Stock viewlet order goes up to 100 let descriptors = []; From 4ed359a0b255c1e2a06322de2ed22fd8eae3a890 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Oct 2016 11:18:39 -0700 Subject: [PATCH 077/119] Update dts doc --- src/vs/vscode.d.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 9708e61011d..5a6b8b380f8 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1349,7 +1349,7 @@ declare module 'vscode' { } /** - * A node provider for the tree explorer contributed by extension. + * A node provider for a tree explorer contribution. * * Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a * `providerId` that corresponds to the `treeExplorerNodeProviderId` in the extension's @@ -1366,8 +1366,7 @@ declare module 'vscode' { /** * Provide the root node. This function will be called when the tree explorer is activated - * for the first time. - * The root node is hidden and its direct children will be displayed on the first level of + * for the first time. The root node is hidden and its direct children will be displayed on the first level of * the tree explorer. * * @return The root node. @@ -1383,9 +1382,8 @@ declare module 'vscode' { resolveChildren(node: T): T[] | Thenable; /** - * Provide a human-readable string that will be used for rendering the node. - * - * Default to use `node.toString()` if not provided. + * Provide a human-readable string that will be used for rendering the node. Default to use + * `node.toString()` if not provided. * * @param node The node from which the provider computes label. * @return A human-readable label. @@ -1393,9 +1391,7 @@ declare module 'vscode' { getLabel?(node: T): string; /** - * Determine if `node` has children and is expandable. - * - * Default to return `true` if not provided. + * Determine if `node` has children and is expandable. Default to return `true` if not provided. * * @param node The node to determine if it has children and is expandable. * @return A boolean that determines if `node` has children and is expandable. @@ -1405,7 +1401,7 @@ declare module 'vscode' { /** * Get the command to execute when `node` is clicked. * - * Commands can be registered through (#commands.registerCommand). `node` will be provided + * Commands can be registered through [registerCommand](#commands.registerCommand). `node` will be provided * as the first argument to the command's callback function. * * @param node The node that the command is associated with. @@ -3870,7 +3866,7 @@ declare module 'vscode' { export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; /** - * Register a [tree explorer node provider](#TreeExplorerNodeProvider). + * Register a [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). * * @param providerId A unique id that identifies the provider. * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). From a3d577ccd5e838a82774be4bf78c9a70bf56ce28 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Oct 2016 12:52:53 -0700 Subject: [PATCH 078/119] Address feedback --- src/vs/vscode.d.ts | 2 +- .../api/node/extHostTreeExplorers.ts | 1 + .../parts/activitybar/activitybarPart.ts | 8 ++++---- .../treeExplorerActions.contribution.ts | 6 +++--- .../explorers/browser/treeExplorerActions.ts | 2 +- .../explorers/browser/treeExplorerViewlet.ts | 14 ++++++------- .../browser/treeExplorerViewletService.ts | 12 +++++------ .../browser/views/treeExplorerView.ts | 7 ++++++- .../browser/views/treeExplorerViewer.ts | 16 +++++++-------- .../explorers/common/treeExplorerViewModel.ts | 20 +++++++------------ 10 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 5a6b8b380f8..abcd0673d32 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1391,7 +1391,7 @@ declare module 'vscode' { getLabel?(node: T): string; /** - * Determine if `node` has children and is expandable. Default to return `true` if not provided. + * Determine if `node` has children and is expandable. Default to `true` if not provided. * * @param node The node to determine if it has children and is expandable. * @return A boolean that determines if `node` has children and is expandable. diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 53a903c16d8..2ea83e62426 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -38,6 +38,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return new Disposable(() => { delete this._treeExplorerNodeProviders[providerId]; + delete this._treeExplorerNodeProviders[providerId]; }); } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index f4832b27765..52502d758f3 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -97,7 +97,7 @@ export class ActivitybarPart extends Part implements IActivityService { } } - getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean } { + public getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean } { const result = {}; for (let viewletId in this.registeredViewlets) { result[viewletId] = (this.enabledExternalViewlets.indexOf(viewletId) !== -1); @@ -105,7 +105,7 @@ export class ActivitybarPart extends Part implements IActivityService { return result; } - toggleViewlet(viewletId: string): void { + public toggleViewlet(viewletId: string): void { const index = this.enabledExternalViewlets.indexOf(viewletId); if (index === -1) { this.enabledExternalViewlets.push(viewletId); @@ -140,7 +140,7 @@ export class ActivitybarPart extends Part implements IActivityService { const $result = $('.content').appendTo($el); // Top Actionbar with action items for each viewlet action - this.createViewletSwitcher($result.clone().addClass('position-top')); + this.createViewletSwitcher($result.clone()); return $result; } @@ -235,7 +235,7 @@ class ViewletActivityAction extends ActivityAction { private lastRun: number = 0; private _onOpenExternalViewlet = new Emitter(); - get onOpenExternalViewlet(): Event { return this._onOpenExternalViewlet.event; }; + public get onOpenExternalViewlet(): Event { return this._onOpenExternalViewlet.event; }; constructor( id: string, diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 07b2dc48f0a..69d36650044 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -29,13 +29,13 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const viewletsToggleStataus = this.activityService.getIsEnabledForRegisteredViewlets(); + const isEnabledForRegisteredViewlets = this.activityService.getIsEnabledForRegisteredViewlets(); const picks: IPickOpenEntry[] = []; - for (let viewletId in viewletsToggleStataus) { + for (let viewletId in isEnabledForRegisteredViewlets) { picks.push({ id: viewletId, - label: (viewletsToggleStataus[viewletId] ? 'Disable ' : 'Enable ') + this.getShortViewletId(viewletId) + label: (isEnabledForRegisteredViewlets[viewletId] ? 'Disable ' : 'Enable ') + this.getShortViewletId(viewletId) }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts index 7a59b318bd0..2d2128b050d 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts @@ -17,4 +17,4 @@ export class RefreshViewExplorerAction extends Action { return TPromise.as(null); }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 2ef048e54df..5bac532fec4 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -42,30 +42,30 @@ export class TreeExplorerViewlet extends Viewlet { TreeExplorerViewlet._idCounter++; } - getId(): string { + public getId(): string { return this.externalViewletId; } - create(parent: Builder): TPromise { + public create(parent: Builder): TPromise { super.create(parent); - this.viewletContainer = parent.div().addClass('custom-tree-explorer-viewlet'); + this.viewletContainer = parent.div(); this.addTreeView(); return TPromise.as(null); } - layout(dimension: Dimension): void { + public layout(dimension: Dimension): void { this.view.layout(dimension.height, Orientation.VERTICAL); } - setVisible(visible: boolean): TPromise { + public setVisible(visible: boolean): TPromise { return super.setVisible(visible).then(() => { this.view.setVisible(visible).done(); }); } - getActions(): IAction[] { + public getActions(): IAction[] { return this.view.getActions(); } @@ -82,7 +82,7 @@ export class TreeExplorerViewlet extends Viewlet { return tokens[tokens.length - 1]; } - dispose(): void { + public dispose(): void { this.view = null; } } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 8970f95934c..531c7185d38 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -29,7 +29,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { public _serviceBrand: any; private _onTreeExplorerNodeProviderRegistered = new Emitter(); - get onTreeExplorerNodeProviderRegistered(): Event { return this._onTreeExplorerNodeProviderRegistered.event; }; + public get onTreeExplorerNodeProviderRegistered(): Event { return this._onTreeExplorerNodeProviderRegistered.event; }; private _treeExplorerNodeProviders: { [providerId: string]: InternalTreeExplorerNodeProvider }; @@ -40,26 +40,26 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { this._treeExplorerNodeProviders = Object.create(null); } - registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { + public registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void { this._treeExplorerNodeProviders[providerId] = provider; this._onTreeExplorerNodeProviderRegistered.fire(providerId); } - hasProvider(providerId: string): boolean { + public hasProvider(providerId: string): boolean { return !!this._treeExplorerNodeProviders[providerId]; } - provideRootNode(providerId: string): TPromise { + public provideRootNode(providerId: string): TPromise { const provider = this.getProvider(providerId); return TPromise.wrap(provider.provideRootNode()); } - resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { + public resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { const provider = this.getProvider(providerId); return TPromise.wrap(provider.resolveChildren(node)); } - executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { + public executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { const provider = this.getProvider(providerId); return TPromise.wrap(provider.executeCommand(node)); } diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 102722f3282..d4c7d632573 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -93,7 +93,12 @@ export class TreeExplorerView extends CollapsibleViewletView { return this.treeExplorerViewletService.provideRootNode(this.treeNodeProviderId).then(tree => { this.tree.setInput(tree); }); - } else { + } + // Provider registration happens independently of the reading of extension's contribution, + // which constructs the viewlet, so it's possible the viewlet is constructed before a provider + // is registered. + // This renders the viewlet first and wait for a corresponding provider is registered. + else { this.treeExplorerViewletService.onTreeExplorerNodeProviderRegistered(providerId => { if (this.treeNodeProviderId === providerId) { return this.treeExplorerViewletService.provideRootNode(this.treeNodeProviderId).then(tree => { diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 707323e0aae..345c470c1eb 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -29,15 +29,15 @@ export class TreeDataSource implements IDataSource { } - getId(tree: ITree, node: InternalTreeExplorerNode): string { + public getId(tree: ITree, node: InternalTreeExplorerNode): string { return node.id.toString(); } - hasChildren(tree: ITree, node: InternalTreeExplorerNode): boolean { + public hasChildren(tree: ITree, node: InternalTreeExplorerNode): boolean { return node.hasChildren; } - getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { + public getChildren(tree: ITree, node: InternalTreeExplorerNode): TPromise { const promise = this.treeExplorerViewletService.resolveChildren(this.treeNodeProviderId, node); this.progressService.showWhile(promise, 800); @@ -45,7 +45,7 @@ export class TreeDataSource implements IDataSource { return promise; } - getParent(tree: ITree, node: InternalTreeExplorerNode): TPromise { + public getParent(tree: ITree, node: InternalTreeExplorerNode): TPromise { return TPromise.as(null); } } @@ -66,11 +66,11 @@ export class TreeRenderer extends ActionsRenderer implements IRenderer { }); } - getContentHeight(tree: ITree, element: any): number { + public getContentHeight(tree: ITree, element: any): number { return 22; } - renderContents(tree: ITree, node: InternalTreeExplorerNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { + public renderContents(tree: ITree, node: InternalTreeExplorerNode, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { const el = $(domElement).clearChildren(); const item = $('.custom-viewlet-tree-node-item'); item.appendTo(el); @@ -94,7 +94,7 @@ export class TreeController extends DefaultController { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } - onLeftClick(tree: ITree, node: InternalTreeExplorerNode, event: IMouseEvent, origin: string = 'mouse'): boolean { + public onLeftClick(tree: ITree, node: InternalTreeExplorerNode, event: IMouseEvent, origin: string = 'mouse'): boolean { super.onLeftClick(tree, node, event, origin); if (node.clickCommand) { @@ -126,5 +126,5 @@ export class TreeExplorerViewletState implements ITreeExplorerViewletState { this._actionProvider = new TreeExplorerActionProvider(this); } - get actionProvider() { return this._actionProvider; } + public get actionProvider() { return this._actionProvider; } } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index f68bba6dffb..e86f91d4510 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -8,26 +8,20 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { TreeExplorerNodeProvider } from 'vscode'; export class InternalTreeExplorerNode implements TreeExplorerNodeContent { - static idCounter = 1; + private static idCounter = 1; id: number; - label: string = 'label'; - hasChildren: boolean = true; - clickCommand: string = null; + label: string; + hasChildren: boolean; + clickCommand: string; constructor(node: any, provider: TreeExplorerNodeProvider) { this.id = InternalTreeExplorerNode.idCounter++; - if (provider.getLabel) { - this.label = provider.getLabel(node); - } - if (provider.getHasChildren) { - this.hasChildren = provider.getHasChildren(node); - } - if (provider.getClickCommand) { - this.clickCommand = provider.getClickCommand(node); - } + this.label = provider.getLabel ? provider.getLabel(node) : node.toString(); + this.hasChildren = provider.getHasChildren ? provider.getHasChildren(node) : true; + this.clickCommand = provider.getClickCommand ? provider.getClickCommand(node) : null; } } From a196d7f8c101274892010e6eaeb6829ba54dfbb8 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Oct 2016 13:59:20 -0700 Subject: [PATCH 079/119] Move static css rules to css file --- src/vs/platform/explorers/browser/explorerExtensionPoint.ts | 2 -- .../parts/explorers/media/treeExplorer.contribution.css | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index f9f33ae2597..af7e847f431 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -48,8 +48,6 @@ ExtensionsRegistry.registerExtensionPoint('explorer', schema.expl const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; const iconPath = join(extension.description.extensionFolderPath, icon); createCSSRule(iconClass, getIconRule(iconPath)); - // Coerce the icon into a style similar to stock icons - createCSSRule(iconClass, '-webkit-filter: grayscale(1) invert(1)'); } descriptors.push(new ViewletDescriptor( diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css index b1415ac281c..cf959184ef9 100644 --- a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -11,3 +11,8 @@ .hc-black .monaco-workbench .customTreeExplorer-action.toggle { background: url('Refresh_inverse.svg') center center no-repeat; } + +/* Coerce external icon into a style similar to stock icons */ +.monaco-workbench > .activitybar .monaco-action-bar .action-item:nth-child(n+6) .action-label { + -webkit-filter: grayscale(1) invert(1); +} \ No newline at end of file From 70be684134bc81dd61c50cd5dad300605230f30b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 24 Oct 2016 14:19:17 -0700 Subject: [PATCH 080/119] Use treeLabel in toggle command --- .../browser/parts/activitybar/activitybarPart.ts | 12 ++++++++++-- .../browser/treeExplorerActions.contribution.ts | 11 ++++------- .../services/activity/common/activityService.ts | 9 +++++++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 52502d758f3..dc24872e283 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -97,10 +97,18 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean } { + public getInfoForRegisteredViewlets(): { + [viewletId: string]: { + isEnabled: boolean; + treeLabel: string; + } + } { const result = {}; for (let viewletId in this.registeredViewlets) { - result[viewletId] = (this.enabledExternalViewlets.indexOf(viewletId) !== -1); + result[viewletId] = { + isEnabled: (this.enabledExternalViewlets.indexOf(viewletId) !== -1), + treeLabel: this.registeredViewlets[viewletId].name + }; } return result; } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 69d36650044..c340caf20d2 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -29,13 +29,14 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const isEnabledForRegisteredViewlets = this.activityService.getIsEnabledForRegisteredViewlets(); + const infoForRegisteredViewlets = this.activityService.getInfoForRegisteredViewlets(); const picks: IPickOpenEntry[] = []; - for (let viewletId in isEnabledForRegisteredViewlets) { + for (let viewletId in infoForRegisteredViewlets) { + const { isEnabled, treeLabel } = infoForRegisteredViewlets[viewletId]; picks.push({ id: viewletId, - label: (isEnabledForRegisteredViewlets[viewletId] ? 'Disable ' : 'Enable ') + this.getShortViewletId(viewletId) + label: (isEnabled ? 'Disable ' : 'Enable ') + treeLabel }); } @@ -47,10 +48,6 @@ export class ToggleExternalViewletAction extends Action { }); }); } - - private getShortViewletId(viewletId: string): string { - return viewletId.split('.').pop(); - } } registry.registerWorkbenchAction( diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 711630394d8..cc947ec1f27 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -72,9 +72,14 @@ export interface IActivityService { clearActivity(compositeId: string): void; /** - * Get all registered external viewlets and whether they are enabled/disabled. + * Get registered external viewlets' info for populating 'Toggle Custom Explorer' command picks. */ - getIsEnabledForRegisteredViewlets(): { [viewletId: string]: boolean }; + getInfoForRegisteredViewlets(): { + [viewletId: string]: { + isEnabled: boolean; + treeLabel: string; + } + }; /** * Enable/disable an external viewlet. From 09c11fe3df4109c5466af1b6db45068fd6a296d5 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 31 Oct 2016 12:56:11 -0700 Subject: [PATCH 081/119] Move API to proposed dts --- src/vs/vscode.d.ts | 71 ----------------------------------- src/vs/vscode.proposed.d.ts | 74 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index de1ab884c88..538ad400800 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1348,68 +1348,6 @@ declare module 'vscode' { provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable; } - /** - * A node provider for a tree explorer contribution. - * - * Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a - * `providerId` that corresponds to the `treeExplorerNodeProviderId` in the extension's - * `contributes.explorer` section. - * - * The contributed tree explorer will ask the corresponding provider to provide the root - * node and resolve children for each node. In addition, the provider could **optionally** - * provide the following information for each node: - * - label: A human-readable label used for rendering the node. - * - hasChildren: Whether the node has children and is expandable. - * - clickCommand: A command to execute when the node is clicked. - */ - export interface TreeExplorerNodeProvider { - - /** - * Provide the root node. This function will be called when the tree explorer is activated - * for the first time. The root node is hidden and its direct children will be displayed on the first level of - * the tree explorer. - * - * @return The root node. - */ - provideRootNode(): T | Thenable; - - /** - * Resolve the children of `node`. - * - * @param node The node from which the provider resolves children. - * @return Children of `node`. - */ - resolveChildren(node: T): T[] | Thenable; - - /** - * Provide a human-readable string that will be used for rendering the node. Default to use - * `node.toString()` if not provided. - * - * @param node The node from which the provider computes label. - * @return A human-readable label. - */ - getLabel?(node: T): string; - - /** - * Determine if `node` has children and is expandable. Default to `true` if not provided. - * - * @param node The node to determine if it has children and is expandable. - * @return A boolean that determines if `node` has children and is expandable. - */ - getHasChildren?(node: T): boolean; - - /** - * Get the command to execute when `node` is clicked. - * - * Commands can be registered through [registerCommand](#commands.registerCommand). `node` will be provided - * as the first argument to the command's callback function. - * - * @param node The node that the command is associated with. - * @return The command to execute when `node` is clicked. - */ - getClickCommand?(node: T): string; - } - /** * Represents an item that can be selected from * a list of items. @@ -3865,15 +3803,6 @@ declare module 'vscode' { */ export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; - /** - * Register a [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). - * - * @param providerId A unique id that identifies the provider. - * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. - */ - export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; - /** * An event that is emitted when a [text document](#TextDocument) is opened. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 08e11e65f46..bfef30db3ac 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -11,4 +11,78 @@ declare module 'vscode' { export function sampleFunction(): Thenable; } + + export namespace workspace { + + /** + * Register a [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). + * + * @param providerId A unique id that identifies the provider. + * @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider). + * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + */ + export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable; + } + + /** + * A node provider for a tree explorer contribution. + * + * Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a + * `providerId` that corresponds to the `treeExplorerNodeProviderId` in the extension's + * `contributes.explorer` section. + * + * The contributed tree explorer will ask the corresponding provider to provide the root + * node and resolve children for each node. In addition, the provider could **optionally** + * provide the following information for each node: + * - label: A human-readable label used for rendering the node. + * - hasChildren: Whether the node has children and is expandable. + * - clickCommand: A command to execute when the node is clicked. + */ + export interface TreeExplorerNodeProvider { + + /** + * Provide the root node. This function will be called when the tree explorer is activated + * for the first time. The root node is hidden and its direct children will be displayed on the first level of + * the tree explorer. + * + * @return The root node. + */ + provideRootNode(): T | Thenable; + + /** + * Resolve the children of `node`. + * + * @param node The node from which the provider resolves children. + * @return Children of `node`. + */ + resolveChildren(node: T): T[] | Thenable; + + /** + * Provide a human-readable string that will be used for rendering the node. Default to use + * `node.toString()` if not provided. + * + * @param node The node from which the provider computes label. + * @return A human-readable label. + */ + getLabel?(node: T): string; + + /** + * Determine if `node` has children and is expandable. Default to `true` if not provided. + * + * @param node The node to determine if it has children and is expandable. + * @return A boolean that determines if `node` has children and is expandable. + */ + getHasChildren?(node: T): boolean; + + /** + * Get the command to execute when `node` is clicked. + * + * Commands can be registered through [registerCommand](#commands.registerCommand). `node` will be provided + * as the first argument to the command's callback function. + * + * @param node The node that the command is associated with. + * @return The command to execute when `node` is clicked. + */ + getClickCommand?(node: T): string; + } } \ No newline at end of file From f18fa6e1451b0783074e8439b500f01b39d03963 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 31 Oct 2016 12:57:49 -0700 Subject: [PATCH 082/119] Fix build error --- src/vs/platform/explorers/browser/explorerExtensionPoint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts index af7e847f431..daa60ad2f2d 100644 --- a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts +++ b/src/vs/platform/explorers/browser/explorerExtensionPoint.ts @@ -36,7 +36,7 @@ namespace schema { }; } -ExtensionsRegistry.registerExtensionPoint('explorer', schema.explorerContribtion).setHandler(extensions => { +ExtensionsRegistry.registerExtensionPoint('explorer', [], schema.explorerContribtion).setHandler(extensions => { let baseOrder = 200; // Stock viewlet order goes up to 100 let descriptors = []; From c47693723a9e2d3e97e90c73c676df903825cd66 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 10:11:35 -0700 Subject: [PATCH 083/119] Set registerTreeExplorerNodeProvider as proposed API --- src/vs/workbench/api/node/extHost.api.impl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 1bb20cb4dbd..aef4f716268 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -342,9 +342,9 @@ export function createApiFactory(initDataConfiguration: IInitConfiguration, init onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables); }, - registerTreeExplorerNodeProvider(providerId: string, provider: vscode.TreeExplorerNodeProvider) { + registerTreeExplorerNodeProvider: proposedApiFunction(extension, (providerId: string, provider: vscode.TreeExplorerNodeProvider) => { return extHostExplorers.registerTreeExplorerNodeProvider(providerId, provider); - }, + }), onDidChangeConfiguration: (listener: () => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables); }, From 31960a77d3e862cb289cb71c3da215613367978f Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 10:11:53 -0700 Subject: [PATCH 084/119] Move error handling to main side --- src/vs/workbench/api/node/extHost.protocol.ts | 1 - .../api/node/extHostTreeExplorers.ts | 30 +++++++------------ .../api/node/mainThreadTreeExplorers.ts | 12 ++++---- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index e4d9a3bc3f7..930889dba15 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -143,7 +143,6 @@ export abstract class MainThreadEditorsShape { export abstract class MainThreadTreeExplorersShape { $registerTreeExplorerNodeProvider(providerId: string): void { throw ni(); } - $showMessage(severity: Severity, message: string): void { throw ni(); } } export abstract class MainThreadErrorsShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 2ea83e62426..4659b8f7acf 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -12,7 +12,6 @@ import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; -import { Severity } from 'vs/platform/message/common/message'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; @@ -43,7 +42,10 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { } $provideRootNode(providerId: string): TPromise { - const provider = this.getProvider(providerId); + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); + } return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { const treeNodeMap = Object.create(null); @@ -53,12 +55,15 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; }, err => { - this.showErrorMessage(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); + return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); }); } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { - const provider = this.getProvider(providerId); + const provider = this._treeExplorerNodeProviders[providerId]; + if (!provider) { + return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); + } const externalNodeMap = this._externalNodeMaps[providerId]; const externalNode = externalNodeMap[mainThreadNode.id]; @@ -70,7 +75,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return internalChild; }); }, err => { - this.showErrorMessage(`TreeExplorerNodeProvider '${providerId}' failed to resolve children.`); + return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to resolve children.`); }); } @@ -80,23 +85,10 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return asWinJsPromise(() => this.commands.executeCommand(mainThreadNode.clickCommand, externalNode)).then(() => { return null; }, err => { - this.showErrorMessage(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'.`); + return TPromise.wrapError(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'.`); }); } return TPromise.as(null); } - - getProvider(providerId: string): TreeExplorerNodeProvider { - const provider = this._treeExplorerNodeProviders[providerId]; - if (!provider) { - this.showErrorMessage(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); - } - - return provider; - } - - private showErrorMessage(message: string): void { - this._proxy.$showMessage(Severity.Error, message); - } } diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 463051e0053..54ac3c368c2 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -15,7 +15,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { private _proxy: ExtHostTreeExplorersShape; constructor( - @IThreadService threadService: IThreadService, + @IThreadService private threadService: IThreadService, @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService, @IMessageService private messageService: IMessageService ) { @@ -25,20 +25,18 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { } $registerTreeExplorerNodeProvider(providerId: string): void { + const onError = err => { this.messageService.show(Severity.Error, err); }; + this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, { provideRootNode: (): TPromise => { - return this._proxy.$provideRootNode(providerId); + return this._proxy.$provideRootNode(providerId).then(rootNode => rootNode, onError); }, resolveChildren: (node: InternalTreeExplorerNode): TPromise => { - return this._proxy.$resolveChildren(providerId, node); + return this._proxy.$resolveChildren(providerId, node).then(children => children, onError); }, executeCommand: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$executeCommand(providerId, node); } }); } - - $showMessage(severity: Severity, message: string): void { - this.messageService.show(severity, message); - } } From 84dd43b63a2576f31ff41fa04db6d6f75a3653e5 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 11:44:44 -0700 Subject: [PATCH 085/119] Execute onClickCommand on Main side --- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../workbench/api/node/extHostTreeExplorers.ts | 17 ++++++++++++----- .../api/node/mainThreadTreeExplorers.ts | 10 +++++++--- .../browser/treeExplorerViewletService.ts | 2 +- .../explorers/common/treeExplorerViewModel.ts | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 930889dba15..f10d6f271b9 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -289,7 +289,7 @@ export abstract class ExtHostEditorsShape { export abstract class ExtHostTreeExplorersShape { $provideRootNode(providerId: string): TPromise { throw ni(); }; $resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } - $executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } + $getInternalCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 4659b8f7acf..11d88c548ee 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -12,6 +12,7 @@ import { MainContext, ExtHostTreeExplorersShape, MainThreadTreeExplorersShape } import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { asWinJsPromise } from 'vs/base/common/async'; +import * as modes from 'vs/editor/common/modes'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; @@ -79,14 +80,20 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { }); } - $executeCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { + // Convert the command on the ExtHost side so we can pass the original externalNode to the registered handler + $getInternalCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { + const commandConverter = this.commands.converter; + if (mainThreadNode.clickCommand) { const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; - return asWinJsPromise(() => this.commands.executeCommand(mainThreadNode.clickCommand, externalNode)).then(() => { - return null; - }, err => { - return TPromise.wrapError(`Failed to execute command '${mainThreadNode.clickCommand}' provided by TreeExplorerNodeProvider '${providerId}'.`); + + const internalCommand = commandConverter.toInternal({ + title: '', + command: mainThreadNode.clickCommand, + arguments: [externalNode] }); + + return TPromise.wrap(internalCommand); } return TPromise.as(null); diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 54ac3c368c2..985fa31c84a 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -10,6 +10,7 @@ import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { private _proxy: ExtHostTreeExplorersShape; @@ -17,7 +18,8 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { constructor( @IThreadService private threadService: IThreadService, @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService, - @IMessageService private messageService: IMessageService + @IMessageService private messageService: IMessageService, + @ICommandService private commandService: ICommandService ) { super(); @@ -34,8 +36,10 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { resolveChildren: (node: InternalTreeExplorerNode): TPromise => { return this._proxy.$resolveChildren(providerId, node).then(children => children, onError); }, - executeCommand: (node: InternalTreeExplorerNode): TPromise => { - return this._proxy.$executeCommand(providerId, node); + executeCommand: (node: InternalTreeExplorerNode): TPromise => { + return this._proxy.$getInternalCommand(providerId, node).then(command => { + return this.commandService.executeCommand(command.id, ...command.arguments); + }); } }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index 531c7185d38..b126224d7f7 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -59,7 +59,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { return TPromise.wrap(provider.resolveChildren(node)); } - public executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { + public executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { const provider = this.getProvider(providerId); return TPromise.wrap(provider.executeCommand(node)); } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index e86f91d4510..a61a951fef7 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -28,7 +28,7 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { export interface InternalTreeExplorerNodeProvider { provideRootNode(): Thenable; resolveChildren(node: InternalTreeExplorerNode): Thenable; - executeCommand(node: TreeExplorerNodeContent): TPromise; + executeCommand(node: TreeExplorerNodeContent): TPromise; } export interface TreeExplorerNodeContent { From a52cfbbc248ae809050c51e0e1e3b69ff5ee867f Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 11:54:36 -0700 Subject: [PATCH 086/119] Move explorerExtensionPoint from platform to workbench --- .../explorers => workbench}/browser/explorerExtensionPoint.ts | 0 src/vs/workbench/workbench.main.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/vs/{platform/explorers => workbench}/browser/explorerExtensionPoint.ts (100%) diff --git a/src/vs/platform/explorers/browser/explorerExtensionPoint.ts b/src/vs/workbench/browser/explorerExtensionPoint.ts similarity index 100% rename from src/vs/platform/explorers/browser/explorerExtensionPoint.ts rename to src/vs/workbench/browser/explorerExtensionPoint.ts diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 59819a4151a..db6f5bf951c 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -20,7 +20,7 @@ import 'vs/editor/browser/editor.all'; import 'vs/platform/actions/browser/menusExtensionPoint'; // External Explorers -import "vs/platform/explorers/browser/explorerExtensionPoint"; +import "vs/workbench/browser/explorerExtensionPoint"; // Workbench import 'vs/workbench/browser/actions/toggleStatusbarVisibility'; From d153d96c23133293bfab64aab7aefc70d12b4d6d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 16:06:17 -0700 Subject: [PATCH 087/119] Display external viewlets on all extensions loaded --- src/vs/workbench/browser/explorerExtensionPoint.ts | 6 ++---- .../browser/parts/activitybar/activitybarPart.ts | 12 +++++++----- src/vs/workbench/browser/viewlet.ts | 14 -------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/browser/explorerExtensionPoint.ts b/src/vs/workbench/browser/explorerExtensionPoint.ts index daa60ad2f2d..38784a5417c 100644 --- a/src/vs/workbench/browser/explorerExtensionPoint.ts +++ b/src/vs/workbench/browser/explorerExtensionPoint.ts @@ -38,7 +38,6 @@ namespace schema { ExtensionsRegistry.registerExtensionPoint('explorer', [], schema.explorerContribtion).setHandler(extensions => { let baseOrder = 200; // Stock viewlet order goes up to 100 - let descriptors = []; for (let extension of extensions) { const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; @@ -50,7 +49,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], schema. createCSSRule(iconClass, getIconRule(iconPath)); } - descriptors.push(new ViewletDescriptor( + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', VIEWLET_ID_ROOT + treeExplorerNodeProviderId, @@ -60,5 +59,4 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], schema. true )); } - Registry.as(ViewletExtensions.Viewlets).registerExternalViewlets(descriptors); -}); +}); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index dc24872e283..d5f50ab394f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -24,6 +24,7 @@ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; export class ActivitybarPart extends Part implements IActivityService { public _serviceBrand: any; @@ -45,7 +46,8 @@ export class ActivitybarPart extends Part implements IActivityService { @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, @IPartService private partService: IPartService, - @IStorageService private storageService: IStorageService + @IStorageService private storageService: IStorageService, + @IExtensionService private extensionService: IExtensionService ) { super(id); @@ -68,10 +70,10 @@ export class ActivitybarPart extends Part implements IActivityService { this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); // Update activity bar on registering external viewlets - this.toUnbind.push( - (Registry.as(ViewletExtensions.Viewlets)) - .onDidRegisterExternalViewlets(viewlets => this.onDidRegisterExternalViewlets(viewlets)) - ); + this.extensionService.onReady().then(() => { + const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); + this.onDidRegisterExternalViewlets(viewlets); + }); } private onDidRegisterExternalViewlets(viewlets: ViewletDescriptor[]): void { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 0badabe1aa7..05919949708 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -7,7 +7,6 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); -import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/platform'; import { Dimension, Builder, $ } from 'vs/base/browser/builder'; import { IAction, IActionRunner, Action } from 'vs/base/common/actions'; @@ -165,9 +164,6 @@ export const Extensions = { export class ViewletRegistry extends CompositeRegistry { private defaultViewletId: string; - private _onDidRegisterExternalViewlets = new Emitter(); - - public get onDidRegisterExternalViewlets(): Event { return this._onDidRegisterExternalViewlets.event; } /** * Registers a viewlet to the platform. @@ -176,16 +172,6 @@ export class ViewletRegistry extends CompositeRegistry { super.registerComposite(descriptor); } - /** - * Registers multiple external viewlets. - */ - public registerExternalViewlets(descriptors: ViewletDescriptor[]): void { - descriptors.forEach(d => { - super.registerComposite(d); - }); - this._onDidRegisterExternalViewlets.fire(descriptors); - } - /** * Returns the viewlet descriptor for the given id or null if none. */ From 894c3cf4bc8edc02c8512dcbdcdc5491274c0f58 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 22:02:09 -0700 Subject: [PATCH 088/119] Refactor and consistent naming --- .../parts/activitybar/activitybarPart.ts | 53 +++++++++---------- .../workbench/electron-browser/workbench.ts | 4 +- .../treeExplorerActions.contribution.ts | 8 +-- .../explorers/browser/treeExplorerViewlet.ts | 2 +- .../activity/common/activityService.ts | 10 ++-- 5 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index d5f50ab394f..69a0b4dffcb 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -34,9 +34,16 @@ export class ActivitybarPart extends Part implements IActivityService { private compositeIdToActions: { [compositeId: string]: ActivityAction; }; private enabledExternalViewlets: string[]; - private registeredViewlets: { [viewletId: string]: ViewletDescriptor; }; + private externalViewlets: { [viewletId: string]: ViewletDescriptor; }; - private externalViewletIdToOpen: string; + // Serves two purposes: + // 1. Expose the viewletId that will be assigned to an external Viewlet, + // which wouldn't know its viewletId until construction time. + // 2. When workbench restores sidebar, if the last-opened Viewlet is external, + // it'll set this value and defer restoration until all extensions are loaded. + private _externalViewletIdToOpen: string; + public get externalViewletIdToOpen() { return this._externalViewletIdToOpen; }; + public set externalViewletIdToOpen(viewletId: string) { this._externalViewletIdToOpen = viewletId; }; private static ENABLED_EXTERNAL_VIEWLETS = 'workbench.activityBar.enabledExternalViewlets'; @@ -56,7 +63,7 @@ export class ActivitybarPart extends Part implements IActivityService { const enabledExternalViewletsJson = this.storageService.get(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS); this.enabledExternalViewlets = enabledExternalViewletsJson ? JSON.parse(enabledExternalViewletsJson) : []; - this.registeredViewlets = {}; + this.externalViewlets = {}; this.registerListeners(); } @@ -72,18 +79,20 @@ export class ActivitybarPart extends Part implements IActivityService { // Update activity bar on registering external viewlets this.extensionService.onReady().then(() => { const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); - this.onDidRegisterExternalViewlets(viewlets); + this.onExtensionServiceReady(viewlets); }); } - private onDidRegisterExternalViewlets(viewlets: ViewletDescriptor[]): void { + private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { viewlets.forEach(v => { - this.registeredViewlets[v.id] = v; + if (v.isExternal) { + this.externalViewlets[v.id] = v; + } }); this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); - if (this.externalViewletIdToOpen) { - this.compositeIdToActions[this.externalViewletIdToOpen].run().done(); + if (this._externalViewletIdToOpen) { + this.compositeIdToActions[this._externalViewletIdToOpen].run().done(); } } @@ -99,23 +108,23 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getInfoForRegisteredViewlets(): { + public getInfoForExternalViewlets(): { [viewletId: string]: { isEnabled: boolean; treeLabel: string; } } { const result = {}; - for (let viewletId in this.registeredViewlets) { + for (let viewletId in this.externalViewlets) { result[viewletId] = { isEnabled: (this.enabledExternalViewlets.indexOf(viewletId) !== -1), - treeLabel: this.registeredViewlets[viewletId].name + treeLabel: this.externalViewlets[viewletId].name }; } return result; } - public toggleViewlet(viewletId: string): void { + public toggleExternalViewlet(viewletId: string): void { const index = this.enabledExternalViewlets.indexOf(viewletId); if (index === -1) { this.enabledExternalViewlets.push(viewletId); @@ -189,13 +198,9 @@ export class ActivitybarPart extends Part implements IActivityService { // Get a list of all enabled external viewlets, ordered by the enabling sequence private getAllEnabledExternalViewlets(): ViewletDescriptor[] { - const externalViewletsToShow: ViewletDescriptor[] = []; - this.enabledExternalViewlets.forEach(viewletId => { - if (this.registeredViewlets[viewletId]) { - externalViewletsToShow.push(this.registeredViewlets[viewletId]); - } - }); - return externalViewletsToShow; + return this.enabledExternalViewlets + .filter(viewletId => this.externalViewlets[viewletId]) + .map(viewletId => this.externalViewlets[viewletId]); } private toAction(composite: ViewletDescriptor): ActivityAction { @@ -204,7 +209,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Later retrieved by TreeExplorerViewlet, which wouldn't know its id until // its construction at runtime. action.onOpenExternalViewlet((viewletId) => { - this.externalViewletIdToOpen = viewletId; + this._externalViewletIdToOpen = viewletId; }); this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); @@ -213,14 +218,6 @@ export class ActivitybarPart extends Part implements IActivityService { return action; }; - setExternalViewletIdToOpen(viewletId: string): void { - this.externalViewletIdToOpen = viewletId; - } - - getExternalViewletIdToOpen(): string { - return this.externalViewletIdToOpen; - } - private getKeybindingLabel(id: string): string { const keys = this.keybindingService.lookupKeybindings(id).map(k => this.keybindingService.getLabelFor(k)); if (keys && keys.length) { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 505196579aa..d6d0e978c3d 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -228,9 +228,9 @@ export class Workbench implements IPartService { viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletId); // help developers and restore last view } - // If external viewlet is the last active viewlet, defer its construction until extensions get registered + // If external viewlet is the last active viewlet, defer its construction until all extensions are loaded if (!viewletRegistry.getViewlet(viewletId)) { - this.activitybarPart.setExternalViewletIdToOpen(viewletId); + this.activitybarPart.externalViewletIdToOpen = viewletId; } else { if (!this.sideBarHidden && !!viewletId) { const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index c340caf20d2..11f514b114c 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -29,11 +29,11 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const infoForRegisteredViewlets = this.activityService.getInfoForRegisteredViewlets(); + const infoForExternalViewlets = this.activityService.getInfoForExternalViewlets(); const picks: IPickOpenEntry[] = []; - for (let viewletId in infoForRegisteredViewlets) { - const { isEnabled, treeLabel } = infoForRegisteredViewlets[viewletId]; + for (let viewletId in infoForExternalViewlets) { + const { isEnabled, treeLabel } = infoForExternalViewlets[viewletId]; picks.push({ id: viewletId, label: (isEnabled ? 'Disable ' : 'Enable ') + treeLabel @@ -43,7 +43,7 @@ export class ToggleExternalViewletAction extends Action { return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { this.quickOpenService.pick(picks, { placeHolder: 'Select Viewlet to toggle', autoFocus: 2 }).then(pick => { if (pick) { - this.activityService.toggleViewlet(pick.id); + this.activityService.toggleExternalViewlet(pick.id); } }); }); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 5bac532fec4..c44355022bb 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -36,7 +36,7 @@ export class TreeExplorerViewlet extends Viewlet { this.viewletState = new TreeExplorerViewletState(); - this.externalViewletId = this.activityService.getExternalViewletIdToOpen(); + this.externalViewletId = this.activityService.externalViewletIdToOpen; this.treeNodeProviderId = this.getTreeProviderName(this.externalViewletId); TreeExplorerViewlet._idCounter++; diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index cc947ec1f27..4f3974c63b8 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -60,6 +60,7 @@ export const IActivityService = createDecorator('activityServi export interface IActivityService { _serviceBrand: any; + externalViewletIdToOpen: string; /** * Show activity in the activitybar for the given viewlet or panel. @@ -74,7 +75,7 @@ export interface IActivityService { /** * Get registered external viewlets' info for populating 'Toggle Custom Explorer' command picks. */ - getInfoForRegisteredViewlets(): { + getInfoForExternalViewlets(): { [viewletId: string]: { isEnabled: boolean; treeLabel: string; @@ -84,10 +85,5 @@ export interface IActivityService { /** * Enable/disable an external viewlet. */ - toggleViewlet(viewletId: string): void; - - /** - * Get the external viewlet id that is about to open. - */ - getExternalViewletIdToOpen(): string; + toggleExternalViewlet(viewletId: string): void; } From 355f1159cbb8a82489c13521db4b860f8c3bfe8c Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 22:28:11 -0700 Subject: [PATCH 089/119] Use JSON/interface over the wire --- src/vs/workbench/api/node/extHost.protocol.ts | 8 ++++---- .../api/node/mainThreadTreeExplorers.ts | 8 ++++---- .../explorers/common/treeExplorerViewModel.ts | 20 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index f10d6f271b9..6be0bb349cf 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -35,7 +35,7 @@ import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker'; -import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; export interface IEnvironment { appSettingsHome: string; @@ -287,9 +287,9 @@ export abstract class ExtHostEditorsShape { } export abstract class ExtHostTreeExplorersShape { - $provideRootNode(providerId: string): TPromise { throw ni(); }; - $resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } - $getInternalCommand(providerId: string, node: InternalTreeExplorerNode): TPromise { throw ni(); } + $provideRootNode(providerId: string): TPromise { throw ni(); }; + $resolveChildren(providerId: string, node: InternalTreeExplorerNodeContent): TPromise { throw ni(); } + $getInternalCommand(providerId: string, node: InternalTreeExplorerNodeContent): TPromise { throw ni(); } } export abstract class ExtHostExtensionServiceShape { diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 985fa31c84a..27c4ea6ca01 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -8,7 +8,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; -import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; +import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -30,13 +30,13 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { const onError = err => { this.messageService.show(Severity.Error, err); }; this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, { - provideRootNode: (): TPromise => { + provideRootNode: (): TPromise => { return this._proxy.$provideRootNode(providerId).then(rootNode => rootNode, onError); }, - resolveChildren: (node: InternalTreeExplorerNode): TPromise => { + resolveChildren: (node: InternalTreeExplorerNodeContent): TPromise => { return this._proxy.$resolveChildren(providerId, node).then(children => children, onError); }, - executeCommand: (node: InternalTreeExplorerNode): TPromise => { + executeCommand: (node: InternalTreeExplorerNodeContent): TPromise => { return this._proxy.$getInternalCommand(providerId, node).then(command => { return this.commandService.executeCommand(command.id, ...command.arguments); }); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts index a61a951fef7..f82df34a574 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerViewModel.ts @@ -7,7 +7,13 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { TreeExplorerNodeProvider } from 'vscode'; -export class InternalTreeExplorerNode implements TreeExplorerNodeContent { +export interface InternalTreeExplorerNodeContent { + label: string; + hasChildren: boolean; + clickCommand: string; +} + +export class InternalTreeExplorerNode implements InternalTreeExplorerNodeContent { private static idCounter = 1; id: number; @@ -26,13 +32,7 @@ export class InternalTreeExplorerNode implements TreeExplorerNodeContent { } export interface InternalTreeExplorerNodeProvider { - provideRootNode(): Thenable; - resolveChildren(node: InternalTreeExplorerNode): Thenable; - executeCommand(node: TreeExplorerNodeContent): TPromise; -} - -export interface TreeExplorerNodeContent { - label: string; - hasChildren: boolean; - clickCommand: string; + provideRootNode(): Thenable; + resolveChildren(node: InternalTreeExplorerNodeContent): Thenable; + executeCommand(node: InternalTreeExplorerNodeContent): TPromise; } From 1ed2912966d6f4e4fdc454e46524ad727e4467ac Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 22:34:30 -0700 Subject: [PATCH 090/119] Clean up unused external viewlet order --- src/vs/workbench/browser/explorerExtensionPoint.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/explorerExtensionPoint.ts b/src/vs/workbench/browser/explorerExtensionPoint.ts index 38784a5417c..2ae7c09739c 100644 --- a/src/vs/workbench/browser/explorerExtensionPoint.ts +++ b/src/vs/workbench/browser/explorerExtensionPoint.ts @@ -37,8 +37,6 @@ namespace schema { } ExtensionsRegistry.registerExtensionPoint('explorer', [], schema.explorerContribtion).setHandler(extensions => { - let baseOrder = 200; // Stock viewlet order goes up to 100 - for (let extension of extensions) { const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; @@ -55,7 +53,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], schema. VIEWLET_ID_ROOT + treeExplorerNodeProviderId, treeLabel, treeExplorerNodeProviderId, - baseOrder++, + -1, // External viewlets are ordered by enabling sequence, so order here doesn't matter. true )); } From 68284bbdabcfd51f6a86cffe48739ced928780b5 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 1 Nov 2016 22:48:32 -0700 Subject: [PATCH 091/119] Access modifiers --- .../explorers/browser/views/treeExplorerView.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index d4c7d632573..e57399d45f6 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -48,14 +48,14 @@ export class TreeExplorerView extends CollapsibleViewletView { this.create(); } - renderBody(container: HTMLElement): void { + public renderBody(container: HTMLElement): void { this.treeContainer = super.renderViewTree(container); DOM.addClass(this.treeContainer, 'tree-explorer-viewlet-tree-view'); this.tree = this.createViewer($(this.treeContainer)); } - createViewer(container: Builder): ITree { + public createViewer(container: Builder): ITree { const dataSource = this.instantiationService.createInstance(TreeDataSource, this.treeNodeProviderId); const renderer = this.instantiationService.createInstance(TreeRenderer, this.viewletState, this.actionRunner, container.getHTMLElement()); const controller = this.instantiationService.createInstance(TreeController, this.treeNodeProviderId); @@ -75,20 +75,20 @@ export class TreeExplorerView extends CollapsibleViewletView { }); } - getActions(): IAction[] { + public getActions(): IAction[] { const refresh = this.instantiationService.createInstance(RefreshViewExplorerAction, this); return [refresh]; } - create(): TPromise { + public create(): TPromise { return this.updateInput(); } - setVisible(visible: boolean): TPromise { + public setVisible(visible: boolean): TPromise { return super.setVisible(visible); } - updateInput(): TPromise { + public updateInput(): TPromise { if (this.treeExplorerViewletService.hasProvider(this.treeNodeProviderId)) { return this.treeExplorerViewletService.provideRootNode(this.treeNodeProviderId).then(tree => { this.tree.setInput(tree); From 46604554ebc2b4b43b7f36665aa7d5e584e5a658 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 10:08:22 -0700 Subject: [PATCH 092/119] Move explorer entry point to parts/explorers --- .../browser/explorerExtensionPoint.ts | 60 ------------------- .../treeExplorerViewlet.contribution.ts | 51 ++++++++++++++++ src/vs/workbench/workbench.main.ts | 3 - 3 files changed, 51 insertions(+), 63 deletions(-) delete mode 100644 src/vs/workbench/browser/explorerExtensionPoint.ts diff --git a/src/vs/workbench/browser/explorerExtensionPoint.ts b/src/vs/workbench/browser/explorerExtensionPoint.ts deleted file mode 100644 index 2ae7c09739c..00000000000 --- a/src/vs/workbench/browser/explorerExtensionPoint.ts +++ /dev/null @@ -1,60 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { join } from 'vs/base/common/paths'; -import { createCSSRule } from 'vs/base/browser/dom'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; -import { Registry } from 'vs/platform/platform'; -import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; -import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; - -namespace schema { - - export const explorerContribtion: IJSONSchema = { - description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), - type: 'object', - properties: { - treeExplorerNodeProviderId: { - description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), - type: 'string' - }, - treeLabel: { - description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree viewlet'), - type: 'string' - }, - icon: { - description: localize('vscode.extension.contributes.explorer.icon', 'Path to the viewlet icon on the activity bar'), - type: 'string' - } - } - }; -} - -ExtensionsRegistry.registerExtensionPoint('explorer', [], schema.explorerContribtion).setHandler(extensions => { - for (let extension of extensions) { - const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; - - const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; - if (icon) { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; - const iconPath = join(extension.description.extensionFolderPath, icon); - createCSSRule(iconClass, getIconRule(iconPath)); - } - - Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', - 'TreeExplorerViewlet', - VIEWLET_ID_ROOT + treeExplorerNodeProviderId, - treeLabel, - treeExplorerNodeProviderId, - -1, // External viewlets are ordered by enabling sequence, so order here doesn't matter. - true - )); - } -}); \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 869fe46876d..223f368b3db 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -6,7 +6,58 @@ import 'vs/css!../media/treeExplorer.contribution'; +import { localize } from 'vs/nls'; +import { join } from 'vs/base/common/paths'; +import { createCSSRule } from 'vs/base/browser/dom'; +import { Registry } from 'vs/platform/platform'; +import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); + +const explorerContribtion: IJSONSchema = { + description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), + type: 'object', + properties: { + treeExplorerNodeProviderId: { + description: localize('vscode.extension.contributes.explorer.treeExplorerNodeProviderId', 'Unique id used to identify provider registered through vscode.workspace.registerTreeExplorerNodeProvider'), + type: 'string' + }, + treeLabel: { + description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree viewlet'), + type: 'string' + }, + icon: { + description: localize('vscode.extension.contributes.explorer.icon', 'Path to the viewlet icon on the activity bar'), + type: 'string' + } + } +}; + +ExtensionsRegistry.registerExtensionPoint('explorer', [], explorerContribtion).setHandler(extensions => { + for (let extension of extensions) { + const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; + + const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; + if (icon) { + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const iconPath = join(extension.description.extensionFolderPath, icon); + createCSSRule(iconClass, getIconRule(iconPath)); + } + + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( + 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', + 'TreeExplorerViewlet', + VIEWLET_ID_ROOT + treeExplorerNodeProviderId, + treeLabel, + treeExplorerNodeProviderId, + -1, // External viewlets are ordered by enabling sequence, so order here doesn't matter. + true + )); + } +}); \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 5b880768ba8..791c93c68eb 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -19,9 +19,6 @@ import 'vs/editor/browser/editor.all'; // Menus/Actions import 'vs/platform/actions/browser/menusExtensionPoint'; -// External Explorers -import "vs/workbench/browser/explorerExtensionPoint"; - // Workbench import 'vs/workbench/browser/actions/toggleStatusbarVisibility'; import 'vs/workbench/browser/actions/toggleSidebarVisibility'; From 50eb47150647168d0921fe5dcb7ad31d513e1538 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 10:21:28 -0700 Subject: [PATCH 093/119] External Viewlet -> ExtViewlet --- .../api/node/extHostTreeExplorers.ts | 12 +-- .../parts/activitybar/activitybarPart.ts | 80 +++++++++---------- .../workbench/electron-browser/workbench.ts | 4 +- .../treeExplorerActions.contribution.ts | 12 +-- .../treeExplorerViewlet.contribution.ts | 2 +- .../explorers/browser/treeExplorerViewlet.ts | 8 +- .../activity/common/activityService.ts | 10 +-- 7 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 11d88c548ee..2ab92b3ad03 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -18,7 +18,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - private _externalNodeMaps: { [providerId: string]: { [id: number]: any } }; + private _treeExplorerNodeMaps: { [providerId: string]: { [id: number]: any } }; constructor( threadService: IThreadService, @@ -29,7 +29,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._proxy = threadService.get(MainContext.MainThreadExplorers); this._treeExplorerNodeProviders = Object.create(null); - this._externalNodeMaps = Object.create(null); + this._treeExplorerNodeMaps = Object.create(null); } registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { @@ -50,10 +50,10 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { const treeNodeMap = Object.create(null); - this._externalNodeMaps[providerId] = treeNodeMap; + this._treeExplorerNodeMaps[providerId] = treeNodeMap; const internalRootNode = new InternalTreeExplorerNode(externalRootNode, provider); - this._externalNodeMaps[providerId][internalRootNode.id] = externalRootNode; + this._treeExplorerNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; }, err => { return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); @@ -66,7 +66,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); } - const externalNodeMap = this._externalNodeMaps[providerId]; + const externalNodeMap = this._treeExplorerNodeMaps[providerId]; const externalNode = externalNodeMap[mainThreadNode.id]; return asWinJsPromise(() => provider.resolveChildren(externalNode)).then(children => { @@ -85,7 +85,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const commandConverter = this.commands.converter; if (mainThreadNode.clickCommand) { - const externalNode = this._externalNodeMaps[providerId][mainThreadNode.id]; + const externalNode = this._treeExplorerNodeMaps[providerId][mainThreadNode.id]; const internalCommand = commandConverter.toInternal({ title: '', diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 69a0b4dffcb..d49e39395cb 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -33,19 +33,19 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; - private enabledExternalViewlets: string[]; - private externalViewlets: { [viewletId: string]: ViewletDescriptor; }; + private enabledExtViewlets: string[]; + private extViewlets: { [viewletId: string]: ViewletDescriptor; }; // Serves two purposes: - // 1. Expose the viewletId that will be assigned to an external Viewlet, + // 1. Expose the viewletId that will be assigned to an extension viewlet, // which wouldn't know its viewletId until construction time. - // 2. When workbench restores sidebar, if the last-opened Viewlet is external, + // 2. When workbench restores sidebar, if the last-opened viewlet is an extension viewlet, // it'll set this value and defer restoration until all extensions are loaded. - private _externalViewletIdToOpen: string; - public get externalViewletIdToOpen() { return this._externalViewletIdToOpen; }; - public set externalViewletIdToOpen(viewletId: string) { this._externalViewletIdToOpen = viewletId; }; + private _extViewletIdToOpen: string; + public get extViewletIdToOpen() { return this._extViewletIdToOpen; }; + public set extViewletIdToOpen(viewletId: string) { this._extViewletIdToOpen = viewletId; }; - private static ENABLED_EXTERNAL_VIEWLETS = 'workbench.activityBar.enabledExternalViewlets'; + private static ENABLED_EXT_VIEWLETS = 'workbench.activityBar.enabledExtViewlets'; constructor( id: string, @@ -61,9 +61,9 @@ export class ActivitybarPart extends Part implements IActivityService { this.activityActionItems = {}; this.compositeIdToActions = {}; - const enabledExternalViewletsJson = this.storageService.get(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS); - this.enabledExternalViewlets = enabledExternalViewletsJson ? JSON.parse(enabledExternalViewletsJson) : []; - this.externalViewlets = {}; + const enabledExtViewletsJson = this.storageService.get(ActivitybarPart.ENABLED_EXT_VIEWLETS); + this.enabledExtViewlets = enabledExtViewletsJson ? JSON.parse(enabledExtViewletsJson) : []; + this.extViewlets = {}; this.registerListeners(); } @@ -76,7 +76,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - // Update activity bar on registering external viewlets + // Update activity bar on registering extension viewlets this.extensionService.onReady().then(() => { const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); this.onExtensionServiceReady(viewlets); @@ -86,13 +86,13 @@ export class ActivitybarPart extends Part implements IActivityService { private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { viewlets.forEach(v => { if (v.isExternal) { - this.externalViewlets[v.id] = v; + this.extViewlets[v.id] = v; } }); - this.viewletSwitcherBar.push(this.getAllEnabledExternalViewlets().map(d => this.toAction(d)), { label: true, icon: true }); - if (this._externalViewletIdToOpen) { - this.compositeIdToActions[this._externalViewletIdToOpen].run().done(); + this.viewletSwitcherBar.push(this.getAllEnabledExtViewlets().map(d => this.toAction(d)), { label: true, icon: true }); + if (this._extViewletIdToOpen) { + this.compositeIdToActions[this._extViewletIdToOpen].run().done(); } } @@ -108,36 +108,36 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getInfoForExternalViewlets(): { + public getInfoForExtViewlets(): { [viewletId: string]: { isEnabled: boolean; treeLabel: string; } } { const result = {}; - for (let viewletId in this.externalViewlets) { + for (let viewletId in this.extViewlets) { result[viewletId] = { - isEnabled: (this.enabledExternalViewlets.indexOf(viewletId) !== -1), - treeLabel: this.externalViewlets[viewletId].name + isEnabled: (this.enabledExtViewlets.indexOf(viewletId) !== -1), + treeLabel: this.extViewlets[viewletId].name }; } return result; } - public toggleExternalViewlet(viewletId: string): void { - const index = this.enabledExternalViewlets.indexOf(viewletId); + public toggleExtViewlet(viewletId: string): void { + const index = this.enabledExtViewlets.indexOf(viewletId); if (index === -1) { - this.enabledExternalViewlets.push(viewletId); + this.enabledExtViewlets.push(viewletId); } else { - this.enabledExternalViewlets.splice(index, 1); + this.enabledExtViewlets.splice(index, 1); } - this.setEnabledExternalViewlets(); + this.setEnabledExtViewlets(); this.refreshViewletSwitcher(); } - private setEnabledExternalViewlets(): void { - this.storageService.store(ActivitybarPart.ENABLED_EXTERNAL_VIEWLETS, JSON.stringify(this.enabledExternalViewlets)); + private setEnabledExtViewlets(): void { + this.storageService.store(ActivitybarPart.ENABLED_EXT_VIEWLETS, JSON.stringify(this.enabledExtViewlets)); } public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { @@ -179,8 +179,8 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.clear(); const allStockViewlets = this.getAllStockViewlets(); - const allEnabledExternalViewlets = this.getAllEnabledExternalViewlets(); - this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExternalViewlets)); + const allEnabledExtViewlets = this.getAllEnabledExtViewlets(); + this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExtViewlets)); } private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { @@ -196,20 +196,20 @@ export class ActivitybarPart extends Part implements IActivityService { .sort((v1, v2) => v1.order - v2.order); } - // Get a list of all enabled external viewlets, ordered by the enabling sequence - private getAllEnabledExternalViewlets(): ViewletDescriptor[] { - return this.enabledExternalViewlets - .filter(viewletId => this.externalViewlets[viewletId]) - .map(viewletId => this.externalViewlets[viewletId]); + // Get a list of all enabled extension viewlets, ordered by the enabling sequence + private getAllEnabledExtViewlets(): ViewletDescriptor[] { + return this.enabledExtViewlets + .filter(viewletId => this.extViewlets[viewletId]) + .map(viewletId => this.extViewlets[viewletId]); } private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); - // Store the viewletId of the external viewlet that is about to open. + // Store the viewletId of the extension viewlet that is about to open. // Later retrieved by TreeExplorerViewlet, which wouldn't know its id until // its construction at runtime. - action.onOpenExternalViewlet((viewletId) => { - this._externalViewletIdToOpen = viewletId; + action.onOpenExtViewlet((viewletId) => { + this._extViewletIdToOpen = viewletId; }); this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); @@ -241,8 +241,8 @@ class ViewletActivityAction extends ActivityAction { private static preventDoubleClickDelay = 300; private lastRun: number = 0; - private _onOpenExternalViewlet = new Emitter(); - public get onOpenExternalViewlet(): Event { return this._onOpenExternalViewlet.event; }; + private _onOpenExtViewlet = new Emitter(); + public get onOpenExtViewlet(): Event { return this._onOpenExtViewlet.event; }; constructor( id: string, @@ -270,7 +270,7 @@ class ViewletActivityAction extends ActivityAction { this.partService.setSideBarHidden(true); } else { if (this.viewlet.isExternal) { - this._onOpenExternalViewlet.fire(this.viewlet.id); + this._onOpenExtViewlet.fire(this.viewlet.id); } this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); this.activate(); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index d6d0e978c3d..af46ceed8b3 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -228,9 +228,9 @@ export class Workbench implements IPartService { viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletId); // help developers and restore last view } - // If external viewlet is the last active viewlet, defer its construction until all extensions are loaded + // If extension viewlet is the last active viewlet, defer its construction until all extensions are loaded if (!viewletRegistry.getViewlet(viewletId)) { - this.activitybarPart.externalViewletIdToOpen = viewletId; + this.activitybarPart.extViewletIdToOpen = viewletId; } else { if (!this.sideBarHidden && !!viewletId) { const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts index 11f514b114c..d047c85d58e 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts @@ -15,7 +15,7 @@ import { IActivityService } from 'vs/workbench/services/activity/common/activity const registry = Registry.as(ActionExtensions.WorkbenchActions); -export class ToggleExternalViewletAction extends Action { +export class ToggleExtViewletAction extends Action { public static ID = 'workbench.action.customTreeExplorer.toggle'; public static LABEL = nls.localize('toggleCustomExplorer', 'Toggle Custom Explorer'); @@ -29,11 +29,11 @@ export class ToggleExternalViewletAction extends Action { } run(): TPromise { - const infoForExternalViewlets = this.activityService.getInfoForExternalViewlets(); + const infoForExtViewlets = this.activityService.getInfoForExtViewlets(); const picks: IPickOpenEntry[] = []; - for (let viewletId in infoForExternalViewlets) { - const { isEnabled, treeLabel } = infoForExternalViewlets[viewletId]; + for (let viewletId in infoForExtViewlets) { + const { isEnabled, treeLabel } = infoForExtViewlets[viewletId]; picks.push({ id: viewletId, label: (isEnabled ? 'Disable ' : 'Enable ') + treeLabel @@ -43,7 +43,7 @@ export class ToggleExternalViewletAction extends Action { return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { this.quickOpenService.pick(picks, { placeHolder: 'Select Viewlet to toggle', autoFocus: 2 }).then(pick => { if (pick) { - this.activityService.toggleExternalViewlet(pick.id); + this.activityService.toggleExtViewlet(pick.id); } }); }); @@ -51,7 +51,7 @@ export class ToggleExternalViewletAction extends Action { } registry.registerWorkbenchAction( - new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), + new SyncActionDescriptor(ToggleExtViewletAction, ToggleExtViewletAction.ID, ToggleExtViewletAction.LABEL), 'View: Toggle Custom Explorer', nls.localize('view', "View") ); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 223f368b3db..6e54fb78c87 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -56,7 +56,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], explore VIEWLET_ID_ROOT + treeExplorerNodeProviderId, treeLabel, treeExplorerNodeProviderId, - -1, // External viewlets are ordered by enabling sequence, so order here doesn't matter. + -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. true )); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index c44355022bb..6d72798616b 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -24,7 +24,7 @@ export class TreeExplorerViewlet extends Viewlet { private viewletState: TreeExplorerViewletState; - private externalViewletId: string; + private extViewletId: string; private treeNodeProviderId: string; constructor( @@ -36,14 +36,14 @@ export class TreeExplorerViewlet extends Viewlet { this.viewletState = new TreeExplorerViewletState(); - this.externalViewletId = this.activityService.externalViewletIdToOpen; - this.treeNodeProviderId = this.getTreeProviderName(this.externalViewletId); + this.extViewletId = this.activityService.extViewletIdToOpen; + this.treeNodeProviderId = this.getTreeProviderName(this.extViewletId); TreeExplorerViewlet._idCounter++; } public getId(): string { - return this.externalViewletId; + return this.extViewletId; } public create(parent: Builder): TPromise { diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 4f3974c63b8..a5534dce44b 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -60,7 +60,7 @@ export const IActivityService = createDecorator('activityServi export interface IActivityService { _serviceBrand: any; - externalViewletIdToOpen: string; + extViewletIdToOpen: string; /** * Show activity in the activitybar for the given viewlet or panel. @@ -73,9 +73,9 @@ export interface IActivityService { clearActivity(compositeId: string): void; /** - * Get registered external viewlets' info for populating 'Toggle Custom Explorer' command picks. + * Get registered extension viewlets' info for populating 'Toggle Custom Explorer' command picks. */ - getInfoForExternalViewlets(): { + getInfoForExtViewlets(): { [viewletId: string]: { isEnabled: boolean; treeLabel: string; @@ -83,7 +83,7 @@ export interface IActivityService { }; /** - * Enable/disable an external viewlet. + * Enable/disable an extension viewlet. */ - toggleExternalViewlet(viewletId: string): void; + toggleExtViewlet(viewletId: string): void; } From 387017337fae3c4319b22130bfdf23ca45765015 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 10:28:08 -0700 Subject: [PATCH 094/119] Put actions for tree explorers to common layer --- .../workbench/parts/explorers/browser/views/treeExplorerView.ts | 2 +- .../{browser => common}/treeExplorerActions.contribution.ts | 0 .../parts/explorers/{browser => common}/treeExplorerActions.ts | 0 src/vs/workbench/workbench.main.ts | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/workbench/parts/explorers/{browser => common}/treeExplorerActions.contribution.ts (100%) rename src/vs/workbench/parts/explorers/{browser => common}/treeExplorerActions.ts (100%) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index e57399d45f6..7baa88f1000 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -22,7 +22,7 @@ import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browse import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; -import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/browser/treeExplorerActions'; +import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/common/treeExplorerActions'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts similarity index 100% rename from src/vs/workbench/parts/explorers/browser/treeExplorerActions.contribution.ts rename to src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts similarity index 100% rename from src/vs/workbench/parts/explorers/browser/treeExplorerActions.ts rename to src/vs/workbench/parts/explorers/common/treeExplorerActions.ts diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 791c93c68eb..a113bda4283 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -58,7 +58,7 @@ import 'vs/workbench/parts/extensions/browser/extensionsQuickOpen'; import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately import 'vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution'; -import 'vs/workbench/parts/explorers/browser/treeExplorerActions.contribution'; +import 'vs/workbench/parts/explorers/common/treeExplorerActions.contribution'; import 'vs/workbench/parts/output/browser/output.contribution'; import 'vs/workbench/parts/output/browser/outputPanel'; // can be packaged separately From a6f8b94521af00a3ed0ac0a950634d9a24d10379 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 10:58:21 -0700 Subject: [PATCH 095/119] nls and consistent naming for toggle tree explorer action --- .../common/treeExplorerActions.contribution.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index d047c85d58e..261b8e1594b 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { Registry } from 'vs/platform/platform'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; @@ -17,7 +17,7 @@ const registry = Registry.as(ActionExtensions.Workbenc export class ToggleExtViewletAction extends Action { public static ID = 'workbench.action.customTreeExplorer.toggle'; - public static LABEL = nls.localize('toggleCustomExplorer', 'Toggle Custom Explorer'); + public static LABEL = localize('toggleCustomExplorer', 'Toggle Custom Explorer'); constructor( id: string, @@ -34,14 +34,15 @@ export class ToggleExtViewletAction extends Action { const picks: IPickOpenEntry[] = []; for (let viewletId in infoForExtViewlets) { const { isEnabled, treeLabel } = infoForExtViewlets[viewletId]; + const actionLabel = isEnabled ? localize('disable', 'Disable') : localize('enable', 'Enable'); picks.push({ id: viewletId, - label: (isEnabled ? 'Disable ' : 'Enable ') + treeLabel + label: `${actionLabel} ${treeLabel}` }); } return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { - this.quickOpenService.pick(picks, { placeHolder: 'Select Viewlet to toggle', autoFocus: 2 }).then(pick => { + this.quickOpenService.pick(picks, { placeHolder: 'Select Custom Explorer to toggle' }).then(pick => { if (pick) { this.activityService.toggleExtViewlet(pick.id); } @@ -53,5 +54,5 @@ export class ToggleExtViewletAction extends Action { registry.registerWorkbenchAction( new SyncActionDescriptor(ToggleExtViewletAction, ToggleExtViewletAction.ID, ToggleExtViewletAction.LABEL), 'View: Toggle Custom Explorer', - nls.localize('view', "View") + localize('view', "View") ); From 3b5e3eafe8b06099351ea2ab3c682f5c7fc967d9 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 11:45:04 -0700 Subject: [PATCH 096/119] Clean up treeExplorer's ID --- .../browser/treeExplorerViewlet.contribution.ts | 4 ++-- .../parts/explorers/browser/treeExplorerViewlet.ts | 4 ++-- .../workbench/parts/explorers/common/treeExplorer.ts | 11 ++++++++++- .../common/treeExplorerActions.contribution.ts | 3 ++- .../parts/explorers/common/treeExplorerActions.ts | 3 ++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 6e54fb78c87..2e691419aca 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -16,7 +16,7 @@ import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/work import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); @@ -53,7 +53,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], explore Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - VIEWLET_ID_ROOT + treeExplorerNodeProviderId, + toCustomViewletId(treeExplorerNodeProviderId), treeLabel, treeExplorerNodeProviderId, -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 6d72798616b..2b15b402897 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; -import { VIEWLET_ID_ROOT } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; export class TreeExplorerViewlet extends Viewlet { private static _idCounter = 1; @@ -32,7 +32,7 @@ export class TreeExplorerViewlet extends Viewlet { @IInstantiationService private instantiationService: IInstantiationService, @IActivityService private activityService: IActivityService ) { - super(VIEWLET_ID_ROOT + TreeExplorerViewlet._idCounter, telemetryService); + super(toCustomViewletId(TreeExplorerViewlet._idCounter.toString()), telemetryService); this.viewletState = new TreeExplorerViewletState(); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts index ece9cb0eca6..80fca4a8d49 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorer.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -4,4 +4,13 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -export const VIEWLET_ID_ROOT = 'workbench.view.customTreeExplorer.'; \ No newline at end of file +const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.customExplorer.'; +const CUSTOM_VIEWLET_ACTION_ID_ROOT = 'workbench.action.customExplorer.'; + +export function toCustomViewletId(viewletId: string): string { + return CUSTOM_VIEWLET_ID_ROOT + viewletId; +} + +export function toCustomViewletActionId(viewletId: string): string { + return CUSTOM_VIEWLET_ACTION_ID_ROOT + viewletId; +} diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index 261b8e1594b..b5701a67ffc 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -12,11 +12,12 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Action } from 'vs/base/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; +import { toCustomViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; const registry = Registry.as(ActionExtensions.WorkbenchActions); export class ToggleExtViewletAction extends Action { - public static ID = 'workbench.action.customTreeExplorer.toggle'; + public static ID = toCustomViewletActionId('toggle'); public static LABEL = localize('toggleCustomExplorer', 'Toggle Custom Explorer'); constructor( diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts index 2d2128b050d..8ae5054e5e8 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts @@ -8,11 +8,12 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; +import { toCustomViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; export class RefreshViewExplorerAction extends Action { constructor(view: TreeExplorerView) { - super('workbench.action.customTreeExplorer.refresh', nls.localize('refresh', "Refresh"), 'customTreeExplorer-action toggle', true, () => { + super(toCustomViewletActionId('refresh'), nls.localize('refresh', 'Refresh'), 'customExplorer-action toggle', true, () => { view.updateInput(); return TPromise.as(null); }); From 9cf01e889f51bda8acc75915e9e695370ee73e81 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 11:45:44 -0700 Subject: [PATCH 097/119] For the sake of browser compatibility and linting --- .../parts/explorers/media/treeExplorer.contribution.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css index cf959184ef9..c10bd3f6c72 100644 --- a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -3,16 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .customTreeExplorer-action.toggle { +.monaco-workbench .customExplorer-action.toggle { background: url('Refresh.svg') center center no-repeat; } -.vs-dark .monaco-workbench .customTreeExplorer-action.toggle, -.hc-black .monaco-workbench .customTreeExplorer-action.toggle { +.vs-dark .monaco-workbench .customExplorer-action.toggle, +.hc-black .monaco-workbench .customExplorer-action.toggle { background: url('Refresh_inverse.svg') center center no-repeat; } /* Coerce external icon into a style similar to stock icons */ .monaco-workbench > .activitybar .monaco-action-bar .action-item:nth-child(n+6) .action-label { -webkit-filter: grayscale(1) invert(1); + filter: grayscale(1) invert(1); } \ No newline at end of file From b205a4c5b40eeb4ba3212f2ab48d06e13c84b8fe Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 12:50:49 -0700 Subject: [PATCH 098/119] Vertical centering text in tree item label --- .../parts/explorers/media/treeExplorer.contribution.css | 5 +++++ src/vs/workbench/parts/files/browser/views/explorerViewer.ts | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css index c10bd3f6c72..592f22c3d42 100644 --- a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -16,4 +16,9 @@ .monaco-workbench > .activitybar .monaco-action-bar .action-item:nth-child(n+6) .action-label { -webkit-filter: grayscale(1) invert(1); filter: grayscale(1) invert(1); +} + +.custom-viewlet-tree-node-item { + height: 22px; + line-height: 22px; } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index fb551a60010..798dee3fb06 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -258,6 +258,9 @@ export class ActionRunner extends BaseActionRunner implements IActionRunner { // Explorer Renderer export class FileRenderer extends ActionsRenderer implements IRenderer { + + private static ITEM_HEIGHT = 22; + private state: FileViewletState; constructor( @@ -275,7 +278,7 @@ export class FileRenderer extends ActionsRenderer implements IRenderer { } public getContentHeight(tree: ITree, element: any): number { - return 22; + return FileRenderer.ITEM_HEIGHT; } public renderContents(tree: ITree, stat: FileStat, domElement: HTMLElement, previousCleanupFn: IElementCallback): IElementCallback { From 1cdbe70c311a933f8b354f221c4ad013149be90e Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 14:12:22 -0700 Subject: [PATCH 099/119] Make activity bar icon class unique --- .../browser/treeExplorerViewlet.contribution.ts | 6 +++--- .../workbench/parts/explorers/common/treeExplorer.ts | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index 2e691419aca..db2744281aa 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -16,7 +16,7 @@ import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/work import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { toCustomViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomViewletId, toCustomViewletCSSClass } from 'vs/workbench/parts/explorers/common/treeExplorer'; registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); @@ -45,7 +45,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], explore const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; if (icon) { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${treeExplorerNodeProviderId}`; + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${toCustomViewletCSSClass(treeExplorerNodeProviderId)}`; const iconPath = join(extension.description.extensionFolderPath, icon); createCSSRule(iconClass, getIconRule(iconPath)); } @@ -55,7 +55,7 @@ ExtensionsRegistry.registerExtensionPoint('explorer', [], explore 'TreeExplorerViewlet', toCustomViewletId(treeExplorerNodeProviderId), treeLabel, - treeExplorerNodeProviderId, + toCustomViewletCSSClass(treeExplorerNodeProviderId), -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. true )); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts index 80fca4a8d49..fc7f6c327cd 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorer.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -4,13 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -const CUSTOM_VIEWLET_ID_ROOT = 'workbench.view.customExplorer.'; -const CUSTOM_VIEWLET_ACTION_ID_ROOT = 'workbench.action.customExplorer.'; - export function toCustomViewletId(viewletId: string): string { - return CUSTOM_VIEWLET_ID_ROOT + viewletId; + return 'workbench.view.customExplorer.' + viewletId; } export function toCustomViewletActionId(viewletId: string): string { - return CUSTOM_VIEWLET_ACTION_ID_ROOT + viewletId; + return 'workbench.action.customExplorer.' + viewletId; } + +export function toCustomViewletCSSClass(viewletId: string): string { + return 'customExplorer-' + viewletId; +} \ No newline at end of file From 13f2dad45a75d341327f5e324a0ec1fba5b290f3 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 16:12:02 -0700 Subject: [PATCH 100/119] Validate user provided viewletId --- .../treeExplorerViewlet.contribution.ts | 70 +++++++++++++------ .../parts/explorers/common/treeExplorer.ts | 5 ++ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts index db2744281aa..7ac981d3419 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts @@ -16,11 +16,14 @@ import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/work import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { toCustomViewletId, toCustomViewletCSSClass } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomViewletId, toCustomViewletCSSClass, isValidViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); -const explorerContribtion: IJSONSchema = { +const explorerSchema: IJSONSchema = { description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), type: 'object', properties: { @@ -29,7 +32,7 @@ const explorerContribtion: IJSONSchema = { type: 'string' }, treeLabel: { - description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree viewlet'), + description: localize('vscode.extension.contributes.explorer.treeLabel', 'Human readable string used to render the custom tree explorer'), type: 'string' }, icon: { @@ -39,25 +42,46 @@ const explorerContribtion: IJSONSchema = { } }; -ExtensionsRegistry.registerExtensionPoint('explorer', [], explorerContribtion).setHandler(extensions => { - for (let extension of extensions) { - const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; +export class ExplorerContribtion implements IWorkbenchContribution { - const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; - if (icon) { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${toCustomViewletCSSClass(treeExplorerNodeProviderId)}`; - const iconPath = join(extension.description.extensionFolderPath, icon); - createCSSRule(iconClass, getIconRule(iconPath)); - } - - Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( - 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', - 'TreeExplorerViewlet', - toCustomViewletId(treeExplorerNodeProviderId), - treeLabel, - toCustomViewletCSSClass(treeExplorerNodeProviderId), - -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. - true - )); + constructor( + @IMessageService private messageService: IMessageService + ) { + this.init(); } -}); \ No newline at end of file + + public getId(): string { + return 'vs.explorer'; + } + + private init() { + ExtensionsRegistry.registerExtensionPoint('explorer', [], explorerSchema).setHandler(extensions => { + for (let extension of extensions) { + const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; + + if (!isValidViewletId(treeExplorerNodeProviderId)) { + return this.messageService.show(Severity.Error, localize('customExplorer.invalidId', 'Tree Explorer extension {0} has invalid id and failed to activate.', treeLabel)); + } + + const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; + if (icon) { + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${toCustomViewletCSSClass(treeExplorerNodeProviderId)}`; + const iconPath = join(extension.description.extensionFolderPath, icon); + createCSSRule(iconClass, getIconRule(iconPath)); + } + + Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( + 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', + 'TreeExplorerViewlet', + toCustomViewletId(treeExplorerNodeProviderId), + treeLabel, + toCustomViewletCSSClass(treeExplorerNodeProviderId), + -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. + true + )); + } + }); + } +} + +(Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution(ExplorerContribtion); \ No newline at end of file diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts index fc7f6c327cd..ea5e59c9e24 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorer.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -14,4 +14,9 @@ export function toCustomViewletActionId(viewletId: string): string { export function toCustomViewletCSSClass(viewletId: string): string { return 'customExplorer-' + viewletId; +} + +export function isValidViewletId(viewletId: string): boolean { + // Only allow alphanumeric letters, `_` and `-`. + return /^[a-z0-9_-]+$/i.test(viewletId); } \ No newline at end of file From 5342705043886d3d426e030418bec9ec8ef49983 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 16:19:04 -0700 Subject: [PATCH 101/119] Better naming --- ...orerViewlet.contribution.ts => treeExplorer.contribution.ts} | 0 src/vs/workbench/workbench.main.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/vs/workbench/parts/explorers/browser/{treeExplorerViewlet.contribution.ts => treeExplorer.contribution.ts} (100%) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts similarity index 100% rename from src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution.ts rename to src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index a113bda4283..478af213ca9 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -57,7 +57,7 @@ import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution'; import 'vs/workbench/parts/extensions/browser/extensionsQuickOpen'; import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately -import 'vs/workbench/parts/explorers/browser/treeExplorerViewlet.contribution'; +import 'vs/workbench/parts/explorers/browser/treeExplorer.contribution'; import 'vs/workbench/parts/explorers/common/treeExplorerActions.contribution'; import 'vs/workbench/parts/output/browser/output.contribution'; From 65f43cc8687ce2d48733b14f00d862c3088de5c3 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 16:19:15 -0700 Subject: [PATCH 102/119] nls --- .../parts/explorers/browser/treeExplorerViewletService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts index b126224d7f7..53b710d4752 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; @@ -68,7 +69,7 @@ export class TreeExplorerViewletService implements ITreeExplorerViewletService { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { - this.messageService.show(Severity.Error, `No TreeExplorerNodeProvider with id '${providerId}' registered.`); + this.messageService.show(Severity.Error, localize('customExplorer.noMatchingProviderId', 'No TreeExplorerNodeProvider with id {providerId} registered.')); } return provider; From 347c2e96d411f3886e7ec5ec4a84913661fd0856 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 16:30:33 -0700 Subject: [PATCH 103/119] External -> Extension --- .../api/node/extHostTreeExplorers.ts | 45 ++++++++++--------- .../parts/activitybar/activitybarPart.ts | 6 +-- src/vs/workbench/browser/viewlet.ts | 2 +- .../media/treeExplorer.contribution.css | 2 +- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 2ab92b3ad03..37cb31ca2e0 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -17,8 +17,8 @@ import * as modes from 'vs/editor/common/modes'; export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { private _proxy: MainThreadTreeExplorersShape; - private _treeExplorerNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; - private _treeExplorerNodeMaps: { [providerId: string]: { [id: number]: any } }; + private _extNodeProviders: { [providerId: string]: TreeExplorerNodeProvider }; + private _extNodeMaps: { [providerId: string]: { [id: number]: any } }; constructor( threadService: IThreadService, @@ -28,32 +28,33 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { this._proxy = threadService.get(MainContext.MainThreadExplorers); - this._treeExplorerNodeProviders = Object.create(null); - this._treeExplorerNodeMaps = Object.create(null); + this._extNodeProviders = Object.create(null); + this._extNodeMaps = Object.create(null); } registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider): Disposable { this._proxy.$registerTreeExplorerNodeProvider(providerId); - this._treeExplorerNodeProviders[providerId] = provider; + this._extNodeProviders[providerId] = provider; return new Disposable(() => { - delete this._treeExplorerNodeProviders[providerId]; - delete this._treeExplorerNodeProviders[providerId]; + delete this._extNodeProviders[providerId]; + delete this._extNodeProviders[providerId]; }); } $provideRootNode(providerId: string): TPromise { - const provider = this._treeExplorerNodeProviders[providerId]; + const provider = this._extNodeProviders[providerId]; if (!provider) { return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); } - return asWinJsPromise(() => provider.provideRootNode()).then(externalRootNode => { - const treeNodeMap = Object.create(null); - this._treeExplorerNodeMaps[providerId] = treeNodeMap; + return asWinJsPromise(() => provider.provideRootNode()).then(extRootNode => { + const extNodeMap = Object.create(null); + const internalRootNode = new InternalTreeExplorerNode(extRootNode, provider); + + extNodeMap[internalRootNode.id] = extRootNode; + this._extNodeMaps[providerId] = extNodeMap; - const internalRootNode = new InternalTreeExplorerNode(externalRootNode, provider); - this._treeExplorerNodeMaps[providerId][internalRootNode.id] = externalRootNode; return internalRootNode; }, err => { return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); @@ -61,18 +62,18 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { - const provider = this._treeExplorerNodeProviders[providerId]; + const provider = this._extNodeProviders[providerId]; if (!provider) { return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); } - const externalNodeMap = this._treeExplorerNodeMaps[providerId]; - const externalNode = externalNodeMap[mainThreadNode.id]; + const extNodeMap = this._extNodeMaps[providerId]; + const extNode = extNodeMap[mainThreadNode.id]; - return asWinJsPromise(() => provider.resolveChildren(externalNode)).then(children => { - return children.map(externalChild => { - const internalChild = new InternalTreeExplorerNode(externalChild, provider); - externalNodeMap[internalChild.id] = externalChild; + return asWinJsPromise(() => provider.resolveChildren(extNode)).then(children => { + return children.map(extChild => { + const internalChild = new InternalTreeExplorerNode(extChild, provider); + extNodeMap[internalChild.id] = extChild; return internalChild; }); }, err => { @@ -85,12 +86,12 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { const commandConverter = this.commands.converter; if (mainThreadNode.clickCommand) { - const externalNode = this._treeExplorerNodeMaps[providerId][mainThreadNode.id]; + const extNode = this._extNodeMaps[providerId][mainThreadNode.id]; const internalCommand = commandConverter.toInternal({ title: '', command: mainThreadNode.clickCommand, - arguments: [externalNode] + arguments: [extNode] }); return TPromise.wrap(internalCommand); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index d49e39395cb..24f9a3528b4 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -85,7 +85,7 @@ export class ActivitybarPart extends Part implements IActivityService { private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { viewlets.forEach(v => { - if (v.isExternal) { + if (v.isExtension) { this.extViewlets[v.id] = v; } }); @@ -192,7 +192,7 @@ export class ActivitybarPart extends Part implements IActivityService { private getAllStockViewlets(): ViewletDescriptor[] { return (Registry.as(ViewletExtensions.Viewlets)) .getViewlets() - .filter(viewlet => !viewlet.isExternal) + .filter(viewlet => !viewlet.isExtension) .sort((v1, v2) => v1.order - v2.order); } @@ -269,7 +269,7 @@ class ViewletActivityAction extends ActivityAction { if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) { this.partService.setSideBarHidden(true); } else { - if (this.viewlet.isExternal) { + if (this.viewlet.isExtension) { this._onOpenExtViewlet.fire(this.viewlet.id); } this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 05919949708..607fe6df408 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -153,7 +153,7 @@ export abstract class ViewerViewlet extends Viewlet { */ export class ViewletDescriptor extends CompositeDescriptor { - constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExternal: boolean = false) { + constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExtension: boolean = false) { super(moduleId, ctorName, id, name, cssClass, order); } } diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css index 592f22c3d42..9390933b8b2 100644 --- a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -12,7 +12,7 @@ background: url('Refresh_inverse.svg') center center no-repeat; } -/* Coerce external icon into a style similar to stock icons */ +/* Coerce extension-contributed viewlet icon into a style similar to stock icons */ .monaco-workbench > .activitybar .monaco-action-bar .action-item:nth-child(n+6) .action-label { -webkit-filter: grayscale(1) invert(1); filter: grayscale(1) invert(1); From 11486b8291e7fcd8b75c3af672afdfa8db021e15 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 3 Nov 2016 22:45:20 -0700 Subject: [PATCH 104/119] Rename confusing service --- src/vs/workbench/api/node/mainThreadTreeExplorers.ts | 4 ++-- ...plorerViewletService.ts => customTreeExplorerService.ts} | 6 +++--- .../parts/explorers/browser/treeExplorer.contribution.ts | 4 ++-- .../parts/explorers/browser/views/treeExplorerView.ts | 4 ++-- .../parts/explorers/browser/views/treeExplorerViewer.ts | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/vs/workbench/parts/explorers/browser/{treeExplorerViewletService.ts => customTreeExplorerService.ts} (92%) diff --git a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts index 27c4ea6ca01..7095b535668 100644 --- a/src/vs/workbench/api/node/mainThreadTreeExplorers.ts +++ b/src/vs/workbench/api/node/mainThreadTreeExplorers.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ICustomTreeExplorerService } from 'vs/workbench/parts/explorers/browser/customTreeExplorerService'; import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -17,7 +17,7 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape { constructor( @IThreadService private threadService: IThreadService, - @ITreeExplorerViewletService private treeExplorerService: ITreeExplorerViewletService, + @ICustomTreeExplorerService private treeExplorerService: ICustomTreeExplorerService, @IMessageService private messageService: IMessageService, @ICommandService private commandService: ICommandService ) { diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts b/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts similarity index 92% rename from src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts rename to src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts index 53b710d4752..b7e8194dc01 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewletService.ts +++ b/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts @@ -11,9 +11,9 @@ import { InternalTreeExplorerNode, InternalTreeExplorerNodeProvider } from 'vs/w import { IMessageService, Severity } from 'vs/platform/message/common/message'; import Event, { Emitter } from 'vs/base/common/event'; -export const ITreeExplorerViewletService = createDecorator('customViewletService'); +export const ICustomTreeExplorerService = createDecorator('customTreeExplorerService'); -export interface ITreeExplorerViewletService { +export interface ICustomTreeExplorerService { _serviceBrand: any; onTreeExplorerNodeProviderRegistered: Event; @@ -26,7 +26,7 @@ export interface ITreeExplorerViewletService { executeCommand(providerId: string, node: InternalTreeExplorerNode): TPromise; } -export class TreeExplorerViewletService implements ITreeExplorerViewletService { +export class CustomTreeExplorerService implements ICustomTreeExplorerService { public _serviceBrand: any; private _onTreeExplorerNodeProviderRegistered = new Emitter(); diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts index 7ac981d3419..bfbc7505902 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts @@ -12,7 +12,7 @@ import { createCSSRule } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/platform'; import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { ITreeExplorerViewletService, TreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ICustomTreeExplorerService, CustomTreeExplorerService } from 'vs/workbench/parts/explorers/browser/customTreeExplorerService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -21,7 +21,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; -registerSingleton(ITreeExplorerViewletService, TreeExplorerViewletService); +registerSingleton(ICustomTreeExplorerService, CustomTreeExplorerService); const explorerSchema: IJSONSchema = { description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 7baa88f1000..74c67832978 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -18,7 +18,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ICustomTreeExplorerService } from 'vs/workbench/parts/explorers/browser/customTreeExplorerService'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; @@ -39,7 +39,7 @@ export class TreeExplorerView extends CollapsibleViewletView { @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService ) { super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts index 345c470c1eb..ae13a5c041b 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerViewer.ts @@ -16,14 +16,14 @@ import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegis import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { ITreeExplorerViewletService } from 'vs/workbench/parts/explorers/browser/treeExplorerViewletService'; +import { ICustomTreeExplorerService } from 'vs/workbench/parts/explorers/browser/customTreeExplorerService'; import { IProgressService } from 'vs/platform/progress/common/progress'; export class TreeDataSource implements IDataSource { constructor( private treeNodeProviderId: string, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService, + @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService, @IProgressService private progressService: IProgressService ) { @@ -89,7 +89,7 @@ export class TreeController extends DefaultController { constructor( private treeNodeProviderId: string, - @ITreeExplorerViewletService private treeExplorerViewletService: ITreeExplorerViewletService + @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService ) { super({ clickBehavior: ClickBehavior.ON_MOUSE_UP /* do not change to not break DND */ }); } From 307037cc0cb6dea69d23ad5914ae05d4118fec60 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 7 Nov 2016 10:55:00 -0800 Subject: [PATCH 105/119] Add ViewletService as IViewletService ViewletService -> handling viewlet enabling/disabling, etc. SidebarService -> construct sidebar composite ActivityService -> Badge, etc --- .../browser/parts/sidebar/sidebarPart.ts | 11 ++++- .../workbench/electron-browser/workbench.ts | 9 +++- .../treeExplorerActions.contribution.ts | 27 ++++++---- .../activity/common/activityService.ts | 17 +------ .../viewlet/browser/viewletService.ts | 49 +++++++++++++++++++ .../services/viewlet/common/viewletService.ts | 15 +++++- 6 files changed, 97 insertions(+), 31 deletions(-) create mode 100644 src/vs/workbench/services/viewlet/browser/viewletService.ts diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index b429e7ed4e9..12ea2a40a1c 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -25,7 +25,16 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; -export class SidebarPart extends CompositePart implements IViewletService { +export interface ISidebar { + onDidViewletOpen: Event; + onDidViewletClose: Event; + openViewlet(id: string, focus?: boolean): TPromise; + getActiveViewlet(): IViewlet; + getLastActiveViewletId(): string; + hideActiveViewlet(): TPromise; +} + +export class SidebarPart extends CompositePart implements ISidebar { public static activeViewletSettingsKey = 'workbench.sidebar.activeviewletid'; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index fe08a688f83..3e4e140512c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -53,6 +53,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; +import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService'; import { FileService } from 'vs/workbench/services/files/electron-browser/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -125,6 +126,7 @@ export class Workbench implements IPartService { private workbenchCreated: boolean; private workbenchShutdown: boolean; private editorService: WorkbenchEditorService; + private viewletService: IViewletService; private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private configurationEditingService: IConfigurationEditingService; @@ -368,11 +370,14 @@ export class Workbench implements IPartService { // Menus/Actions serviceCollection.set(IMenuService, new SyncDescriptor(MenuService)); - // Viewlet service (sidebar part) + // Sidebar part this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART); this.toDispose.push(this.sidebarPart); this.toShutdown.push(this.sidebarPart); - serviceCollection.set(IViewletService, this.sidebarPart); + + // Viewlet service + this.viewletService = this.instantiationService.createInstance(ViewletService, this.sidebarPart); + serviceCollection.set(IViewletService, this.viewletService); // Panel service (panel part) this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index b5701a67ffc..c428417ff96 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -11,7 +11,7 @@ import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/wor import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Action } from 'vs/base/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; -import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; +import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; import { toCustomViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; const registry = Registry.as(ActionExtensions.WorkbenchActions); @@ -24,28 +24,35 @@ export class ToggleExtViewletAction extends Action { id: string, label: string, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IActivityService private activityService: IActivityService + @IViewletService private viewletService: IViewletService ) { super(id, name); } run(): TPromise { - const infoForExtViewlets = this.activityService.getInfoForExtViewlets(); + const viewletDescriptors = this.viewletService.getViewletDescriptors(); - const picks: IPickOpenEntry[] = []; - for (let viewletId in infoForExtViewlets) { - const { isEnabled, treeLabel } = infoForExtViewlets[viewletId]; + const picks: IPickOpenEntry[] = viewletDescriptors.map((d) => { + return { + id: d.id, + label: d.name + }; + }); + + viewletDescriptors.forEach(vd => { + const isEnabled = true; const actionLabel = isEnabled ? localize('disable', 'Disable') : localize('enable', 'Enable'); picks.push({ - id: viewletId, - label: `${actionLabel} ${treeLabel}` + id: vd.name, + label: `${actionLabel} ${vd.name}` }); - } + + }); return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { this.quickOpenService.pick(picks, { placeHolder: 'Select Custom Explorer to toggle' }).then(pick => { if (pick) { - this.activityService.toggleExtViewlet(pick.id); + this.viewletService.toggleViewlet(pick.id); } }); }); diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index a5534dce44b..4103d732448 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -71,19 +71,4 @@ export interface IActivityService { * Clears activity shown in the activitybar for the given viewlet or panel. */ clearActivity(compositeId: string): void; - - /** - * Get registered extension viewlets' info for populating 'Toggle Custom Explorer' command picks. - */ - getInfoForExtViewlets(): { - [viewletId: string]: { - isEnabled: boolean; - treeLabel: string; - } - }; - - /** - * Enable/disable an extension viewlet. - */ - toggleExtViewlet(viewletId: string): void; -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts new file mode 100644 index 00000000000..6fe365a2557 --- /dev/null +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; +import { IViewlet } from 'vs/workbench/common/viewlet'; +import { ISidebar } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; +import Event from 'vs/base/common/event'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; + +export class ViewletService implements IViewletService { + + public _serviceBrand: any; + + private sidebarPart: ISidebar; + + constructor( + sidebarPart: ISidebar + ) { + this.sidebarPart = sidebarPart; + } + + public get onDidViewletOpen(): Event { + return this.sidebarPart.onDidViewletOpen; + } + + public get onDidViewletClose(): Event { + return this.sidebarPart.onDidViewletClose; + } + + public openViewlet(id: string, focus?: boolean): TPromise { + return this.sidebarPart.openViewlet(id, focus); + } + + public toggleViewlet(id: string): TPromise { + return TPromise.as(null); + } + + public getActiveViewlet(): IViewlet { + return this.sidebarPart.getActiveViewlet(); + } + + public getViewletDescriptors(): ViewletDescriptor[] { + return []; + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index dcc0621594a..443912acc86 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -8,6 +8,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; export const IViewletService = createDecorator('viewletService'); @@ -24,7 +25,17 @@ export interface IViewletService { openViewlet(id: string, focus?: boolean): TPromise; /** - * Returns the current active viewlet or null if none + * Toggles a viewlet with the given identifier. + */ + toggleViewlet(id: string): TPromise; + + /** + * Returns the current active viewlet or null if none. */ getActiveViewlet(): IViewlet; -} \ No newline at end of file + + /** + * Returns all registered viewlets. + */ + getViewletDescriptors(): ViewletDescriptor[]; +} From 15bf2ec0ed96d3f6a981ed0b3a0d07d4485f0444 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 7 Nov 2016 13:46:47 -0800 Subject: [PATCH 106/119] Put Viewlet related things to ViewletService --- .../parts/activitybar/activitybarPart.ts | 90 ++----------------- .../treeExplorerActions.contribution.ts | 14 ++- .../viewlet/browser/viewletService.ts | 80 ++++++++++++++--- .../services/viewlet/common/viewletService.ts | 19 ++-- 4 files changed, 94 insertions(+), 109 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 24f9a3528b4..58c1c29bb74 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -13,9 +13,8 @@ import { Builder, $ } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; import errors = require('vs/base/common/errors'); import { ActionsOrientation, ActionBar, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { Registry } from 'vs/platform/platform'; import { IComposite } from 'vs/workbench/common/composite'; -import { ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { Part } from 'vs/workbench/browser/part'; import { ActivityAction, ActivityActionItem } from 'vs/workbench/browser/parts/activitybar/activityAction'; import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; @@ -23,8 +22,6 @@ import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IExtensionService } from 'vs/platform/extensions/common/extensions'; export class ActivitybarPart extends Part implements IActivityService { public _serviceBrand: any; @@ -33,9 +30,6 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; - private enabledExtViewlets: string[]; - private extViewlets: { [viewletId: string]: ViewletDescriptor; }; - // Serves two purposes: // 1. Expose the viewletId that will be assigned to an extension viewlet, // which wouldn't know its viewletId until construction time. @@ -45,26 +39,18 @@ export class ActivitybarPart extends Part implements IActivityService { public get extViewletIdToOpen() { return this._extViewletIdToOpen; }; public set extViewletIdToOpen(viewletId: string) { this._extViewletIdToOpen = viewletId; }; - private static ENABLED_EXT_VIEWLETS = 'workbench.activityBar.enabledExtViewlets'; - constructor( id: string, @IViewletService private viewletService: IViewletService, @IKeybindingService private keybindingService: IKeybindingService, @IInstantiationService private instantiationService: IInstantiationService, - @IPartService private partService: IPartService, - @IStorageService private storageService: IStorageService, - @IExtensionService private extensionService: IExtensionService + @IPartService private partService: IPartService ) { super(id); this.activityActionItems = {}; this.compositeIdToActions = {}; - const enabledExtViewletsJson = this.storageService.get(ActivitybarPart.ENABLED_EXT_VIEWLETS); - this.enabledExtViewlets = enabledExtViewletsJson ? JSON.parse(enabledExtViewletsJson) : []; - this.extViewlets = {}; - this.registerListeners(); } @@ -76,24 +62,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - // Update activity bar on registering extension viewlets - this.extensionService.onReady().then(() => { - const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); - this.onExtensionServiceReady(viewlets); - }); - } - - private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { - viewlets.forEach(v => { - if (v.isExtension) { - this.extViewlets[v.id] = v; - } - }); - - this.viewletSwitcherBar.push(this.getAllEnabledExtViewlets().map(d => this.toAction(d)), { label: true, icon: true }); - if (this._extViewletIdToOpen) { - this.compositeIdToActions[this._extViewletIdToOpen].run().done(); - } + this.toUnbind.push(this.viewletService.onDidViewletRegister(() => this.onDidViewletRegister())); } private onActiveCompositeChanged(composite: IComposite): void { @@ -108,38 +77,10 @@ export class ActivitybarPart extends Part implements IActivityService { } } - public getInfoForExtViewlets(): { - [viewletId: string]: { - isEnabled: boolean; - treeLabel: string; - } - } { - const result = {}; - for (let viewletId in this.extViewlets) { - result[viewletId] = { - isEnabled: (this.enabledExtViewlets.indexOf(viewletId) !== -1), - treeLabel: this.extViewlets[viewletId].name - }; - } - return result; - } - - public toggleExtViewlet(viewletId: string): void { - const index = this.enabledExtViewlets.indexOf(viewletId); - if (index === -1) { - this.enabledExtViewlets.push(viewletId); - } else { - this.enabledExtViewlets.splice(index, 1); - } - - this.setEnabledExtViewlets(); + private onDidViewletRegister(): void { this.refreshViewletSwitcher(); } - private setEnabledExtViewlets(): void { - this.storageService.store(ActivitybarPart.ENABLED_EXT_VIEWLETS, JSON.stringify(this.enabledExtViewlets)); - } - public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -171,16 +112,12 @@ export class ActivitybarPart extends Part implements IActivityService { ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher") }); - const allStockViewlets = this.getAllStockViewlets(); - this.fillViewletSwitcher(allStockViewlets); + this.fillViewletSwitcher(this.viewletService.getAllViewlets()); } private refreshViewletSwitcher(): void { this.viewletSwitcherBar.clear(); - - const allStockViewlets = this.getAllStockViewlets(); - const allEnabledExtViewlets = this.getAllEnabledExtViewlets(); - this.fillViewletSwitcher(allStockViewlets.concat(allEnabledExtViewlets)); + this.fillViewletSwitcher(this.viewletService.getAllViewlets()); } private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { @@ -188,21 +125,6 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } - // Get an ordered list of all stock viewlets - private getAllStockViewlets(): ViewletDescriptor[] { - return (Registry.as(ViewletExtensions.Viewlets)) - .getViewlets() - .filter(viewlet => !viewlet.isExtension) - .sort((v1, v2) => v1.order - v2.order); - } - - // Get a list of all enabled extension viewlets, ordered by the enabling sequence - private getAllEnabledExtViewlets(): ViewletDescriptor[] { - return this.enabledExtViewlets - .filter(viewletId => this.extViewlets[viewletId]) - .map(viewletId => this.extViewlets[viewletId]); - } - private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); // Store the viewletId of the extension viewlet that is about to open. diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index c428417ff96..fa1a7aa24a5 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -30,17 +30,13 @@ export class ToggleExtViewletAction extends Action { } run(): TPromise { - const viewletDescriptors = this.viewletService.getViewletDescriptors(); + const viewlets = this.viewletService.getExtViewlets(); + const enabledViewletIds = this.viewletService.getEnabledViewletIds(); - const picks: IPickOpenEntry[] = viewletDescriptors.map((d) => { - return { - id: d.id, - label: d.name - }; - }); + const picks: IPickOpenEntry[] = []; - viewletDescriptors.forEach(vd => { - const isEnabled = true; + viewlets.forEach(vd => { + const isEnabled = enabledViewletIds.indexOf(vd.id) !== -1; const actionLabel = isEnabled ? localize('disable', 'Disable') : localize('enable', 'Enable'); picks.push({ id: vd.name, diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index 6fe365a2557..a828f35daf1 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -4,31 +4,56 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import Event, { Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { ISidebar } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; -import Event from 'vs/base/common/event'; -import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { Registry } from 'vs/platform/platform'; +import { ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; export class ViewletService implements IViewletService { + private static ENABLED_EXT_VIEWLETS = 'workbench.viewlet.enabledExtViewlets'; + public _serviceBrand: any; private sidebarPart: ISidebar; + private enabledExtViewletIds: string[]; + private extViewlets: { [viewletId: string]: ViewletDescriptor; }; + private _onDidViewletRegister = new Emitter(); + + public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; + public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; }; + public get onDidViewletRegister(): Event { return this._onDidViewletRegister.event; }; constructor( - sidebarPart: ISidebar + sidebarPart: ISidebar, + @IStorageService private storageService: IStorageService, + @IExtensionService private extensionService: IExtensionService ) { this.sidebarPart = sidebarPart; + + const enabledExtViewletsJson = this.storageService.get(ViewletService.ENABLED_EXT_VIEWLETS); + this.enabledExtViewletIds = enabledExtViewletsJson ? JSON.parse(enabledExtViewletsJson) : []; + this.extViewlets = {}; + + this.extensionService.onReady().then(() => { + const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); + this.onExtensionServiceReady(viewlets); + }); } - public get onDidViewletOpen(): Event { - return this.sidebarPart.onDidViewletOpen; - } + private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { + viewlets.forEach(v => { + if (v.isExtension) { + this.extViewlets[v.id] = v; + } + }); - public get onDidViewletClose(): Event { - return this.sidebarPart.onDidViewletClose; + this._onDidViewletRegister.fire(null); } public openViewlet(id: string, focus?: boolean): TPromise { @@ -36,6 +61,15 @@ export class ViewletService implements IViewletService { } public toggleViewlet(id: string): TPromise { + const index = this.enabledExtViewletIds.indexOf(id); + if (index === -1) { + this.enabledExtViewletIds.push(id); + } else { + this.enabledExtViewletIds.splice(index, 1); + } + + this.setEnabledExtViewlets(); + this._onDidViewletRegister.fire(); return TPromise.as(null); } @@ -43,7 +77,33 @@ export class ViewletService implements IViewletService { return this.sidebarPart.getActiveViewlet(); } - public getViewletDescriptors(): ViewletDescriptor[] { - return []; + public getAllViewlets(): ViewletDescriptor[] { + const stockViewlets = this.getStockViewlets(); + const extViewlets = this.getExtViewlets(); + return stockViewlets.concat(extViewlets); + } + + // Get an ordered list of all stock viewlets + public getStockViewlets(): ViewletDescriptor[] { + return (Registry.as(ViewletExtensions.Viewlets)) + .getViewlets() + .filter(viewlet => !viewlet.isExtension) + .sort((v1, v2) => v1.order - v2.order); + } + + public getExtViewlets(): ViewletDescriptor[] { + const result = []; + for (let id in this.extViewlets) { + result.push(this.extViewlets[id]); + } + return result; + } + + public getEnabledViewletIds(): string[] { + return this.enabledExtViewletIds; + } + + private setEnabledExtViewlets(): void { + this.storageService.store(ViewletService.ENABLED_EXT_VIEWLETS, JSON.stringify(this.enabledExtViewletIds)); } } \ No newline at end of file diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index 443912acc86..a4c4c7968a8 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -16,8 +16,8 @@ export interface IViewletService { _serviceBrand: ServiceIdentifier; onDidViewletOpen: Event; - onDidViewletClose: Event; + onDidViewletRegister: Event; /** * Opens a viewlet with the given identifier and pass keyboard focus to it if specified. @@ -29,13 +29,20 @@ export interface IViewletService { */ toggleViewlet(id: string): TPromise; + + getExtViewlets(): ViewletDescriptor[]; + + getEnabledViewletIds(): string[]; + + /** + * Get all registered viewlets, ordered by + * - Stock Viewlet: order + * - External Viewlet: enabliing sequence + */ + getAllViewlets(): ViewletDescriptor[]; + /** * Returns the current active viewlet or null if none. */ getActiveViewlet(): IViewlet; - - /** - * Returns all registered viewlets. - */ - getViewletDescriptors(): ViewletDescriptor[]; } From e2b7b52034edbb623da324f85424908f743ea162 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Mon, 7 Nov 2016 15:57:29 -0800 Subject: [PATCH 107/119] Restore enable/disable extensions & preserve enabling order --- .../parts/activitybar/activitybarPart.ts | 4 +- .../treeExplorerActions.contribution.ts | 12 +++--- .../viewlet/browser/viewletService.ts | 37 ++++++++++--------- .../services/viewlet/common/viewletService.ts | 29 +++++++++------ 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 58c1c29bb74..58eace4b573 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -112,12 +112,12 @@ export class ActivitybarPart extends Part implements IActivityService { ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher") }); - this.fillViewletSwitcher(this.viewletService.getAllViewlets()); + this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay()); } private refreshViewletSwitcher(): void { this.viewletSwitcherBar.clear(); - this.fillViewletSwitcher(this.viewletService.getAllViewlets()); + this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay()); } private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index fa1a7aa24a5..1506c5fcb76 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -30,19 +30,17 @@ export class ToggleExtViewletAction extends Action { } run(): TPromise { - const viewlets = this.viewletService.getExtViewlets(); - const enabledViewletIds = this.viewletService.getEnabledViewletIds(); + const extViewlets = this.viewletService.getAllViewlets().filter(viewlet => viewlet.isExtension); const picks: IPickOpenEntry[] = []; - viewlets.forEach(vd => { - const isEnabled = enabledViewletIds.indexOf(vd.id) !== -1; + extViewlets.forEach(viewlet => { + const isEnabled = this.viewletService.isViewletEnabled(viewlet.id); const actionLabel = isEnabled ? localize('disable', 'Disable') : localize('enable', 'Enable'); picks.push({ - id: vd.name, - label: `${actionLabel} ${vd.name}` + id: viewlet.id, + label: `${actionLabel} ${viewlet.name}` }); - }); return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index a828f35daf1..3a0ba17e364 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -22,7 +22,7 @@ export class ViewletService implements IViewletService { private sidebarPart: ISidebar; private enabledExtViewletIds: string[]; - private extViewlets: { [viewletId: string]: ViewletDescriptor; }; + private extViewlets: ViewletDescriptor[]; private _onDidViewletRegister = new Emitter(); public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; @@ -38,7 +38,7 @@ export class ViewletService implements IViewletService { const enabledExtViewletsJson = this.storageService.get(ViewletService.ENABLED_EXT_VIEWLETS); this.enabledExtViewletIds = enabledExtViewletsJson ? JSON.parse(enabledExtViewletsJson) : []; - this.extViewlets = {}; + this.extViewlets = []; this.extensionService.onReady().then(() => { const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); @@ -49,7 +49,7 @@ export class ViewletService implements IViewletService { private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { viewlets.forEach(v => { if (v.isExtension) { - this.extViewlets[v.id] = v; + this.extViewlets.push(v); } }); @@ -79,30 +79,31 @@ export class ViewletService implements IViewletService { public getAllViewlets(): ViewletDescriptor[] { const stockViewlets = this.getStockViewlets(); - const extViewlets = this.getExtViewlets(); - return stockViewlets.concat(extViewlets); + return stockViewlets.concat(this.extViewlets); + } + + public getAllViewletsToDisplay(): ViewletDescriptor[] { + const stockViewlets = this.getStockViewlets(); + const enabledExtViewlets = this.extViewlets + .filter(v => this.enabledExtViewletIds.indexOf(v.id) !== -1) + .sort((v1, v2) => { + return this.enabledExtViewletIds.indexOf(v1.id) - this.enabledExtViewletIds.indexOf(v2.id); + }); + return stockViewlets.concat(enabledExtViewlets); + } + + public isViewletEnabled(id: string): boolean { + return this.enabledExtViewletIds.indexOf(id) !== -1; } // Get an ordered list of all stock viewlets - public getStockViewlets(): ViewletDescriptor[] { + private getStockViewlets(): ViewletDescriptor[] { return (Registry.as(ViewletExtensions.Viewlets)) .getViewlets() .filter(viewlet => !viewlet.isExtension) .sort((v1, v2) => v1.order - v2.order); } - public getExtViewlets(): ViewletDescriptor[] { - const result = []; - for (let id in this.extViewlets) { - result.push(this.extViewlets[id]); - } - return result; - } - - public getEnabledViewletIds(): string[] { - return this.enabledExtViewletIds; - } - private setEnabledExtViewlets(): void { this.storageService.store(ViewletService.ENABLED_EXT_VIEWLETS, JSON.stringify(this.enabledExtViewletIds)); } diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index a4c4c7968a8..4a30370cebe 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -29,20 +29,25 @@ export interface IViewletService { */ toggleViewlet(id: string): TPromise; - - getExtViewlets(): ViewletDescriptor[]; - - getEnabledViewletIds(): string[]; - - /** - * Get all registered viewlets, ordered by - * - Stock Viewlet: order - * - External Viewlet: enabliing sequence - */ - getAllViewlets(): ViewletDescriptor[]; - /** * Returns the current active viewlet or null if none. */ getActiveViewlet(): IViewlet; + + /** + * Returns all registered viewlets + */ + getAllViewlets(): ViewletDescriptor[]; + + /** + * Returns all viewlets that should be displayed, ordered by: + * - Stock Viewlets: order attribute + * - Extension Viewlets: enabling sequence + */ + getAllViewletsToDisplay(): ViewletDescriptor[]; + + /** + * Checks if an extension is enabled + */ + isViewletEnabled(id: string): boolean; } From 6793e088025217ae01a0afffeab194c78887e3dc Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 8 Nov 2016 11:12:20 -0800 Subject: [PATCH 108/119] Remove awkward workaround for extension viewletid --- .../parts/activitybar/activitybarPart.ts | 21 +------------------ src/vs/workbench/browser/viewlet.ts | 4 ++++ .../workbench/electron-browser/workbench.ts | 11 +++------- .../explorers/browser/treeExplorerViewlet.ts | 17 ++++++--------- .../activity/common/activityService.ts | 1 - 5 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 58eace4b573..57934ca3ec5 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -30,15 +30,6 @@ export class ActivitybarPart extends Part implements IActivityService { private activityActionItems: { [actionId: string]: IActionItem; }; private compositeIdToActions: { [compositeId: string]: ActivityAction; }; - // Serves two purposes: - // 1. Expose the viewletId that will be assigned to an extension viewlet, - // which wouldn't know its viewletId until construction time. - // 2. When workbench restores sidebar, if the last-opened viewlet is an extension viewlet, - // it'll set this value and defer restoration until all extensions are loaded. - private _extViewletIdToOpen: string; - public get extViewletIdToOpen() { return this._extViewletIdToOpen; }; - public set extViewletIdToOpen(viewletId: string) { this._extViewletIdToOpen = viewletId; }; - constructor( id: string, @IViewletService private viewletService: IViewletService, @@ -62,7 +53,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - this.toUnbind.push(this.viewletService.onDidViewletRegister(() => this.onDidViewletRegister())); + this.toUnbind.push(this.viewletService.onDidViewletRegister(() => this.refreshViewletSwitcher())); } private onActiveCompositeChanged(composite: IComposite): void { @@ -77,10 +68,6 @@ export class ActivitybarPart extends Part implements IActivityService { } } - private onDidViewletRegister(): void { - this.refreshViewletSwitcher(); - } - public showActivity(compositeId: string, badge: IBadge, clazz?: string): void { const action = this.compositeIdToActions[compositeId]; if (action) { @@ -127,12 +114,6 @@ export class ActivitybarPart extends Part implements IActivityService { private toAction(composite: ViewletDescriptor): ActivityAction { const action = this.instantiationService.createInstance(ViewletActivityAction, composite.id + '.activity-bar-action', composite); - // Store the viewletId of the extension viewlet that is about to open. - // Later retrieved by TreeExplorerViewlet, which wouldn't know its id until - // its construction at runtime. - action.onOpenExtViewlet((viewletId) => { - this._extViewletIdToOpen = viewletId; - }); this.activityActionItems[action.id] = new ActivityActionItem(action, composite.name, this.getKeybindingLabel(composite.id)); this.compositeIdToActions[composite.id] = action; diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 607fe6df408..1c25ad84f16 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -155,6 +155,10 @@ export class ViewletDescriptor extends CompositeDescriptor { constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExtension: boolean = false) { super(moduleId, ctorName, id, name, cssClass, order); + if (isExtension) { + // Pass viewletId to extension viewlet, which doesn't know its id until runtime. + this.appendStaticArguments([id]); + } } } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 3e4e140512c..95955c8a5c1 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -232,14 +232,9 @@ export class Workbench implements IPartService { viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletId); // help developers and restore last view } - // If extension viewlet is the last active viewlet, defer its construction until all extensions are loaded - if (!viewletRegistry.getViewlet(viewletId)) { - this.activitybarPart.extViewletIdToOpen = viewletId; - } else { - if (!this.sideBarHidden && !!viewletId) { - const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); - compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); - } + if (!this.sideBarHidden && !!viewletId) { + const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); + compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); } // Load Panel diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts index 2b15b402897..464065e1e0f 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorerViewlet.ts @@ -14,36 +14,31 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; import { TreeExplorerViewletState } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { IActivityService } from 'vs/workbench/services/activity/common/activityService'; -import { toCustomViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; export class TreeExplorerViewlet extends Viewlet { - private static _idCounter = 1; private viewletContainer: Builder; private view: IViewletView; private viewletState: TreeExplorerViewletState; - - private extViewletId: string; + private viewletId: string; private treeNodeProviderId: string; constructor( + viewletId: string, @ITelemetryService telemetryService: ITelemetryService, @IInstantiationService private instantiationService: IInstantiationService, @IActivityService private activityService: IActivityService ) { - super(toCustomViewletId(TreeExplorerViewlet._idCounter.toString()), telemetryService); + super(viewletId, telemetryService); this.viewletState = new TreeExplorerViewletState(); - - this.extViewletId = this.activityService.extViewletIdToOpen; - this.treeNodeProviderId = this.getTreeProviderName(this.extViewletId); - - TreeExplorerViewlet._idCounter++; + this.viewletId = viewletId; + this.treeNodeProviderId = this.getTreeProviderName(viewletId); } public getId(): string { - return this.extViewletId; + return this.viewletId; } public create(parent: Builder): TPromise { diff --git a/src/vs/workbench/services/activity/common/activityService.ts b/src/vs/workbench/services/activity/common/activityService.ts index 4103d732448..bdc5638ac0a 100644 --- a/src/vs/workbench/services/activity/common/activityService.ts +++ b/src/vs/workbench/services/activity/common/activityService.ts @@ -60,7 +60,6 @@ export const IActivityService = createDecorator('activityServi export interface IActivityService { _serviceBrand: any; - extViewletIdToOpen: string; /** * Show activity in the activitybar for the given viewlet or panel. From c57973fec5db68a4e3f187d5dc84a3d297e32514 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 8 Nov 2016 11:30:04 -0800 Subject: [PATCH 109/119] Remove unused event --- .../workbench/browser/parts/activitybar/activitybarPart.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 57934ca3ec5..3c9d1219548 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -8,7 +8,6 @@ import 'vs/css!./media/activitybarpart'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter } from 'vs/base/common/event'; import { Builder, $ } from 'vs/base/browser/builder'; import { Action } from 'vs/base/common/actions'; import errors = require('vs/base/common/errors'); @@ -144,9 +143,6 @@ class ViewletActivityAction extends ActivityAction { private static preventDoubleClickDelay = 300; private lastRun: number = 0; - private _onOpenExtViewlet = new Emitter(); - public get onOpenExtViewlet(): Event { return this._onOpenExtViewlet.event; }; - constructor( id: string, private viewlet: ViewletDescriptor, @@ -172,9 +168,6 @@ class ViewletActivityAction extends ActivityAction { if (!sideBarHidden && activeViewlet && activeViewlet.getId() === this.viewlet.id) { this.partService.setSideBarHidden(true); } else { - if (this.viewlet.isExtension) { - this._onOpenExtViewlet.fire(this.viewlet.id); - } this.viewletService.openViewlet(this.viewlet.id, true).done(null, errors.onUnexpectedError); this.activate(); } From 85f4204e43c1bd1b2b55154988b194eb8e49bdf0 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 8 Nov 2016 14:25:28 -0800 Subject: [PATCH 110/119] Fix restoring last viewlet --- .../parts/activitybar/activitybarPart.ts | 2 +- .../workbench/electron-browser/workbench.ts | 27 +++++++++++++------ .../viewlet/browser/viewletService.ts | 16 +++++------ .../services/viewlet/common/viewletService.ts | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 3c9d1219548..de218a2a1a1 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -52,7 +52,7 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - this.toUnbind.push(this.viewletService.onDidViewletRegister(() => this.refreshViewletSwitcher())); + this.toUnbind.push(this.viewletService.onDidExtensionViewletsLoad(() => this.refreshViewletSwitcher())); } private onActiveCompositeChanged(composite: IComposite): void { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 95955c8a5c1..fef09ce5c7e 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -225,16 +225,27 @@ export class Workbench implements IPartService { // Load composits and editors in parallel const compositeAndEditorPromises: TPromise[] = []; - // Load Viewlet + // Restore last opened viewlet const viewletRegistry = Registry.as(ViewletExtensions.Viewlets); - let viewletId = viewletRegistry.getDefaultViewletId(); - if (this.shouldRestoreSidebar()) { - viewletId = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletId); // help developers and restore last view - } + if (this.shouldRestoreSidebar() && !this.sideBarHidden) { + const lastOpenedViewlet = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); - if (!this.sideBarHidden && !!viewletId) { - const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); - compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); + // If last viewlet is extension viewlet and enabled, delay its restoration until extension loading + if (!viewletRegistry.getViewlet(lastOpenedViewlet) && this.viewletService.isViewletEnabled(lastOpenedViewlet)) { + this.viewletService.onDidExtensionViewletsLoad(() => { + this.sidebarPart.openViewlet(lastOpenedViewlet, false).done(); + }); + } + // Load last viewlet immediately + else { + let viewletId = lastOpenedViewlet; + // If last viewlet is extension viewlet and disabled, load default (File Explorer) viewlet + if (!viewletRegistry.getViewlet(lastOpenedViewlet)) { + viewletId = viewletRegistry.getDefaultViewletId(); + } + const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); + compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); + } } // Load Panel diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index 3a0ba17e364..dfbc940e3ed 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -16,18 +16,18 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; export class ViewletService implements IViewletService { - private static ENABLED_EXT_VIEWLETS = 'workbench.viewlet.enabledExtViewlets'; + public static readonly ENABLED_EXT_VIEWLETS = 'workbench.viewlet.enabledExtViewlets'; public _serviceBrand: any; private sidebarPart: ISidebar; private enabledExtViewletIds: string[]; private extViewlets: ViewletDescriptor[]; - private _onDidViewletRegister = new Emitter(); + private _onDidExtensionViewletsLoad = new Emitter(); public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; }; - public get onDidViewletRegister(): Event { return this._onDidViewletRegister.event; }; + public get onDidExtensionViewletsLoad(): Event { return this._onDidExtensionViewletsLoad.event; }; constructor( sidebarPart: ISidebar, @@ -41,19 +41,19 @@ export class ViewletService implements IViewletService { this.extViewlets = []; this.extensionService.onReady().then(() => { - const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); - this.onExtensionServiceReady(viewlets); + this.onExtensionServiceReady(); }); } - private onExtensionServiceReady(viewlets: ViewletDescriptor[]): void { + private onExtensionServiceReady(): void { + const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); viewlets.forEach(v => { if (v.isExtension) { this.extViewlets.push(v); } }); - this._onDidViewletRegister.fire(null); + this._onDidExtensionViewletsLoad.fire(null); } public openViewlet(id: string, focus?: boolean): TPromise { @@ -69,7 +69,7 @@ export class ViewletService implements IViewletService { } this.setEnabledExtViewlets(); - this._onDidViewletRegister.fire(); + this._onDidExtensionViewletsLoad.fire(); return TPromise.as(null); } diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index 4a30370cebe..1468d2e38fb 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -17,7 +17,7 @@ export interface IViewletService { onDidViewletOpen: Event; onDidViewletClose: Event; - onDidViewletRegister: Event; + onDidExtensionViewletsLoad: Event; /** * Opens a viewlet with the given identifier and pass keyboard focus to it if specified. From 0b15cbb028efb326e97c0ad3eae8159333ac746d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 8 Nov 2016 16:18:53 -0800 Subject: [PATCH 111/119] Preserve badge on add/remove viewlet --- src/vs/base/browser/ui/actionbar/actionbar.ts | 8 ++++++ .../parts/activitybar/activitybarPart.ts | 27 ++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index f2e40528c9c..fa8ac25cdb0 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -529,6 +529,14 @@ export class ActionBar extends EventEmitter implements IActionRunner { }); } + public pull(index: number): void { + const itemLength = this.items.length; + if (index >= 0 && index < itemLength) { + this.items.splice(index, 1); + this.actionsList.removeChild(this.actionsList.childNodes[index]); + } + } + public clear(): void { // Do not dispose action items if they were provided from outside this.items = this.options.actionItemProvider ? [] : lifecycle.dispose(this.items); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index de218a2a1a1..7b8a956624b 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -102,13 +102,32 @@ export class ActivitybarPart extends Part implements IActivityService { } private refreshViewletSwitcher(): void { - this.viewletSwitcherBar.clear(); this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay()); } - private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { - const viewletActions = viewlets.map(v => this.toAction(v)); - this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); + private fillViewletSwitcher(newViewlets: ViewletDescriptor[]) { + // Pull out viewlets no longer needed + const newViewletIds = newViewlets.map(v => v.id); + Object.keys(this.compositeIdToActions).forEach(viewletId => { + if (newViewletIds.indexOf(viewletId) === -1) { + this.pullViewlet(viewletId); + } + }); + + const actionsToPush = newViewlets + .filter(viewlet => !this.compositeIdToActions[viewlet.id]) + .map(viewlet => this.toAction(viewlet)); + + this.viewletSwitcherBar.push(actionsToPush, { label: true, icon: true }); + } + + private pullViewlet(viewletId: string): void { + const index = Object.keys(this.compositeIdToActions).indexOf(viewletId); + const action = this.compositeIdToActions[viewletId]; + const actionItem = this.activityActionItems[action.id]; + action.dispose(); + actionItem.dispose(); + this.viewletSwitcherBar.pull(index); } private toAction(composite: ViewletDescriptor): ActivityAction { From 902137c4b4e2b2ffb8e78afc15b0b2ab6a313482 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 8 Nov 2016 23:30:11 -0800 Subject: [PATCH 112/119] Fix compile error, will write test later --- .../workbench/test/browser/services.test.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index 73b9e94ddd6..d52e0705abf 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -26,6 +26,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { Position, Direction, IEditor } from 'vs/platform/editor/common/editor'; import { Emitter } from 'vs/base/common/event'; +import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; let activeViewlet: Viewlet = {}; let activeEditor: BaseEditor = { @@ -105,14 +106,33 @@ class TestViewletService implements IViewletService { onDidViewletCloseEmitter = new Emitter(); onDidViewletClose = this.onDidViewletCloseEmitter.event; - public openViewlet(id: string, focus?: boolean): Promise { + onDidExtensionViewletsLoadEmitter = new Emitter(); + onDidExtensionViewletsLoad = this.onDidExtensionViewletsLoadEmitter.event; + + public openViewlet(id: string, focus?: boolean): TPromise { return TPromise.as(null); } + public toggleViewlet(id: string): TPromise { + return TPromise.as(null); + } + + public getAllViewlets(): ViewletDescriptor[] { + return []; + } + + public getAllViewletsToDisplay(): ViewletDescriptor[] { + return []; + } + public getActiveViewlet(): IViewlet { return activeViewlet; } + public isViewletEnabled(id: string): boolean { + return true; + } + public dispose() { } From 06b82f52cb8f988ea31186bed7fc697f8152ace1 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 00:08:51 -0800 Subject: [PATCH 113/119] Split didExtensionViewletLoad from didViewletToggle --- .../browser/parts/activitybar/activitybarPart.ts | 4 ++++ .../services/viewlet/browser/viewletService.ts | 8 +++++--- .../services/viewlet/common/viewletService.ts | 3 ++- src/vs/workbench/test/browser/services.test.ts | 11 ++++++----- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 7b8a956624b..0396247c95f 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -52,7 +52,11 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); + // Update viewlet switcher when extension viewlets become ready this.toUnbind.push(this.viewletService.onDidExtensionViewletsLoad(() => this.refreshViewletSwitcher())); + + // Update viewlet switcher on toggling of a viewlet + this.toUnbind.push(this.viewletService.onDidViewletToggle(() => this.refreshViewletSwitcher())); } private onActiveCompositeChanged(composite: IComposite): void { diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index dfbc940e3ed..33ba3566243 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -24,10 +24,12 @@ export class ViewletService implements IViewletService { private enabledExtViewletIds: string[]; private extViewlets: ViewletDescriptor[]; private _onDidExtensionViewletsLoad = new Emitter(); + private _onDidViewletToggle = new Emitter(); public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; }; public get onDidExtensionViewletsLoad(): Event { return this._onDidExtensionViewletsLoad.event; }; + public get onDidViewletToggle(): Event { return this._onDidViewletToggle.event; }; constructor( sidebarPart: ISidebar, @@ -53,14 +55,14 @@ export class ViewletService implements IViewletService { } }); - this._onDidExtensionViewletsLoad.fire(null); + this._onDidExtensionViewletsLoad.fire(); } public openViewlet(id: string, focus?: boolean): TPromise { return this.sidebarPart.openViewlet(id, focus); } - public toggleViewlet(id: string): TPromise { + public toggleViewlet(id: string): TPromise { const index = this.enabledExtViewletIds.indexOf(id); if (index === -1) { this.enabledExtViewletIds.push(id); @@ -69,7 +71,7 @@ export class ViewletService implements IViewletService { } this.setEnabledExtViewlets(); - this._onDidExtensionViewletsLoad.fire(); + this._onDidViewletToggle.fire(); return TPromise.as(null); } diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index 1468d2e38fb..d52b94601dd 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -18,6 +18,7 @@ export interface IViewletService { onDidViewletOpen: Event; onDidViewletClose: Event; onDidExtensionViewletsLoad: Event; + onDidViewletToggle: Event; /** * Opens a viewlet with the given identifier and pass keyboard focus to it if specified. @@ -27,7 +28,7 @@ export interface IViewletService { /** * Toggles a viewlet with the given identifier. */ - toggleViewlet(id: string): TPromise; + toggleViewlet(id: string): TPromise; /** * Returns the current active viewlet or null if none. diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index d52e0705abf..bc1da1ce009 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -101,19 +101,20 @@ class TestViewletService implements IViewletService { public _serviceBrand: any; onDidViewletOpenEmitter = new Emitter(); - onDidViewletOpen = this.onDidViewletOpenEmitter.event; - onDidViewletCloseEmitter = new Emitter(); - onDidViewletClose = this.onDidViewletCloseEmitter.event; - onDidExtensionViewletsLoadEmitter = new Emitter(); + onDidViewletToggleEmitter = new Emitter(); + + onDidViewletOpen = this.onDidViewletOpenEmitter.event; + onDidViewletClose = this.onDidViewletCloseEmitter.event; onDidExtensionViewletsLoad = this.onDidExtensionViewletsLoadEmitter.event; + onDidViewletToggle = this.onDidViewletToggleEmitter.event; public openViewlet(id: string, focus?: boolean): TPromise { return TPromise.as(null); } - public toggleViewlet(id: string): TPromise { + public toggleViewlet(id: string): TPromise { return TPromise.as(null); } From 4d2551726528cc5aa407f0fb402cda04ae810d77 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 00:27:08 -0800 Subject: [PATCH 114/119] Open viewlet/switch to default viewlet when toggling extension --- .../parts/activitybar/activitybarPart.ts | 2 ++ .../treeExplorerActions.contribution.ts | 21 +++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 0396247c95f..d3b5abab171 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -129,6 +129,8 @@ export class ActivitybarPart extends Part implements IActivityService { const index = Object.keys(this.compositeIdToActions).indexOf(viewletId); const action = this.compositeIdToActions[viewletId]; const actionItem = this.activityActionItems[action.id]; + delete this.compositeIdToActions[viewletId]; + delete this.activityActionItems[action.id]; action.dispose(); actionItem.dispose(); this.viewletSwitcherBar.pull(index); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index 1506c5fcb76..c511b9d0bc3 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -8,6 +8,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { Registry } from 'vs/platform/platform'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Action } from 'vs/base/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; @@ -39,16 +40,24 @@ export class ToggleExtViewletAction extends Action { const actionLabel = isEnabled ? localize('disable', 'Disable') : localize('enable', 'Enable'); picks.push({ id: viewlet.id, - label: `${actionLabel} ${viewlet.name}` + label: `${actionLabel} ${viewlet.name}`, + run: () => { + this.viewletService.toggleViewlet(viewlet.id).then(() => { + if (isEnabled) { + // To disable, so open default viewlet + const defaultViewletId = (Registry.as(ViewletExtensions.Viewlets)).getDefaultViewletId(); + this.viewletService.openViewlet(defaultViewletId); + } else { + // To enable, so open the viewlet to be enabled + this.viewletService.openViewlet(viewlet.id); + } + }); + } }); }); return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => { - this.quickOpenService.pick(picks, { placeHolder: 'Select Custom Explorer to toggle' }).then(pick => { - if (pick) { - this.viewletService.toggleViewlet(pick.id); - } - }); + this.quickOpenService.pick(picks, { placeHolder: 'Select Custom Explorer to toggle' }).done(); }); } } From dd19d5998ac94bcefd46531c6b8fc9d3a6a397e7 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 01:26:49 -0800 Subject: [PATCH 115/119] Various cleanup --- src/vs/base/browser/ui/actionbar/actionbar.ts | 3 +-- src/vs/vscode.proposed.d.ts | 2 +- src/vs/workbench/api/node/extHostTreeExplorers.ts | 13 +++++++++---- src/vs/workbench/electron-browser/workbench.ts | 10 +++------- .../explorers/browser/customTreeExplorerService.ts | 2 +- .../explorers/browser/treeExplorer.contribution.ts | 4 ++-- .../explorers/browser/views/treeExplorerView.ts | 2 +- .../common/treeExplorerActions.contribution.ts | 2 +- .../explorers/media/treeExplorer.contribution.css | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index fa8ac25cdb0..da4f851b097 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -530,8 +530,7 @@ export class ActionBar extends EventEmitter implements IActionRunner { } public pull(index: number): void { - const itemLength = this.items.length; - if (index >= 0 && index < itemLength) { + if (index >= 0 && index < this.items.length) { this.items.splice(index, 1); this.actionsList.removeChild(this.actionsList.childNodes[index]); } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index bfef30db3ac..e881ebc4a0e 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -85,4 +85,4 @@ declare module 'vscode' { */ getClickCommand?(node: T): string; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 37cb31ca2e0..5c216171d73 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import { localize } from 'vs/nls'; import { TreeExplorerNodeProvider } from 'vscode'; import { TPromise } from 'vs/base/common/winjs.base'; import { Disposable } from 'vs/workbench/api/node/extHostTypes'; @@ -45,7 +46,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { $provideRootNode(providerId: string): TPromise { const provider = this._extNodeProviders[providerId]; if (!provider) { - return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); + const errMessage = localize('treeExplorer.notRegistered', 'No TreeExplorerNodeProvider with id \'{0}\' registered.', providerId); + return TPromise.wrapError(errMessage); } return asWinJsPromise(() => provider.provideRootNode()).then(extRootNode => { @@ -57,14 +59,16 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return internalRootNode; }, err => { - return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to provide root node.`); + const errMessage = localize('treeExplorer.failedToProvideRootNode', 'TreeExplorerNodeProvider \'{0}\' failed to provide root node.', providerId); + return TPromise.wrapError(errMessage); }); } $resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise { const provider = this._extNodeProviders[providerId]; if (!provider) { - return TPromise.wrapError(`No TreeExplorerNodeProvider with id '${providerId}' registered.`); + const errMessage = localize('treeExplorer.notRegistered', 'No TreeExplorerNodeProvider with id \'{0}\' registered.', providerId); + return TPromise.wrapError(errMessage); } const extNodeMap = this._extNodeMaps[providerId]; @@ -77,7 +81,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return internalChild; }); }, err => { - return TPromise.wrapError(`TreeExplorerNodeProvider '${providerId}' failed to resolve children.`); + const errMessage = localize('extHostTreeExplorers.ts.failedToResolveChildren', 'TreeExplorerNodeProvider \'{0}\' failed to resolveChildren.', providerId); + return TPromise.wrapError(errMessage); }); } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index cfea6b2440e..27a00689412 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -248,19 +248,15 @@ export class Workbench implements IPartService { if (this.shouldRestoreSidebar() && !this.sideBarHidden) { const lastOpenedViewlet = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); - // If last viewlet is extension viewlet and enabled, delay its restoration until extension loading - if (!viewletRegistry.getViewlet(lastOpenedViewlet) && this.viewletService.isViewletEnabled(lastOpenedViewlet)) { + // If last viewlet is extension viewlet, delay its restoration until extension viewlets loaded + if (!viewletRegistry.getViewlet(lastOpenedViewlet)) { this.viewletService.onDidExtensionViewletsLoad(() => { this.sidebarPart.openViewlet(lastOpenedViewlet, false).done(); }); } - // Load last viewlet immediately + // Otherwise, load last viewlet immediately else { let viewletId = lastOpenedViewlet; - // If last viewlet is extension viewlet and disabled, load default (File Explorer) viewlet - if (!viewletRegistry.getViewlet(lastOpenedViewlet)) { - viewletId = viewletRegistry.getDefaultViewletId(); - } const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); } diff --git a/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts b/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts index b7e8194dc01..37fa4646164 100644 --- a/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts +++ b/src/vs/workbench/parts/explorers/browser/customTreeExplorerService.ts @@ -69,7 +69,7 @@ export class CustomTreeExplorerService implements ICustomTreeExplorerService { const provider = this._treeExplorerNodeProviders[providerId]; if (!provider) { - this.messageService.show(Severity.Error, localize('customExplorer.noMatchingProviderId', 'No TreeExplorerNodeProvider with id {providerId} registered.')); + this.messageService.show(Severity.Error, localize('treeExplorer.noMatchingProviderId', 'No TreeExplorerNodeProvider with id {providerId} registered.')); } return provider; diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts index bfbc7505902..590c6db620f 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts @@ -24,7 +24,7 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message'; registerSingleton(ICustomTreeExplorerService, CustomTreeExplorerService); const explorerSchema: IJSONSchema = { - description: localize('vscode.extension.contributes.explorer', "Contributes custom tree explorer viewlet to the sidebar"), + description: localize('vscode.extension.contributes.explorer', 'Contributes custom tree explorer viewlet to the sidebar'), type: 'object', properties: { treeExplorerNodeProviderId: { @@ -60,7 +60,7 @@ export class ExplorerContribtion implements IWorkbenchContribution { const { treeExplorerNodeProviderId, treeLabel, icon } = extension.value; if (!isValidViewletId(treeExplorerNodeProviderId)) { - return this.messageService.show(Severity.Error, localize('customExplorer.invalidId', 'Tree Explorer extension {0} has invalid id and failed to activate.', treeLabel)); + return this.messageService.show(Severity.Error, localize('treeExplorer.invalidId', 'Tree Explorer extension {0} has invalid id and failed to activate.', treeLabel)); } const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 74c67832978..4ccbd7702d7 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -41,7 +41,7 @@ export class TreeExplorerView extends CollapsibleViewletView { @IEditorGroupService private editorGroupService: IEditorGroupService, @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService ) { - super(actionRunner, false, nls.localize('treeExplorerViewletTree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); + super(actionRunner, false, nls.localize('treeExplorerViewlet.tree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); this.workspace = contextService.getWorkspace(); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index c511b9d0bc3..839cb4b9df4 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -19,7 +19,7 @@ const registry = Registry.as(ActionExtensions.Workbenc export class ToggleExtViewletAction extends Action { public static ID = toCustomViewletActionId('toggle'); - public static LABEL = localize('toggleCustomExplorer', 'Toggle Custom Explorer'); + public static LABEL = localize('treeExplorer.toggle', 'Toggle Custom Explorer'); constructor( id: string, diff --git a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css index 9390933b8b2..b8a051acd61 100644 --- a/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css +++ b/src/vs/workbench/parts/explorers/media/treeExplorer.contribution.css @@ -21,4 +21,4 @@ .custom-viewlet-tree-node-item { height: 22px; line-height: 22px; -} \ No newline at end of file +} From d1114266536c4567d341b15ae335ed47b40270db Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 01:41:27 -0800 Subject: [PATCH 116/119] Naming --- .../parts/explorers/browser/treeExplorer.contribution.ts | 8 ++++---- src/vs/workbench/parts/explorers/common/treeExplorer.ts | 6 +++--- .../explorers/common/treeExplorerActions.contribution.ts | 4 ++-- .../parts/explorers/common/treeExplorerActions.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts index 590c6db620f..4d249455590 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts @@ -16,7 +16,7 @@ import { ICustomTreeExplorerService, CustomTreeExplorerService } from 'vs/workbe import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ITreeExplorer } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { toCustomViewletId, toCustomViewletCSSClass, isValidViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomExplorerViewletId, toCustomExplorerViewletCSSClass, isValidViewletId } from 'vs/workbench/parts/explorers/common/treeExplorer'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; @@ -65,7 +65,7 @@ export class ExplorerContribtion implements IWorkbenchContribution { const getIconRule = (iconPath) => { return `background-image: url('${iconPath}')`; }; if (icon) { - const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${toCustomViewletCSSClass(treeExplorerNodeProviderId)}`; + const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${toCustomExplorerViewletCSSClass(treeExplorerNodeProviderId)}`; const iconPath = join(extension.description.extensionFolderPath, icon); createCSSRule(iconClass, getIconRule(iconPath)); } @@ -73,9 +73,9 @@ export class ExplorerContribtion implements IWorkbenchContribution { Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( 'vs/workbench/parts/explorers/browser/treeExplorerViewlet', 'TreeExplorerViewlet', - toCustomViewletId(treeExplorerNodeProviderId), + toCustomExplorerViewletId(treeExplorerNodeProviderId), treeLabel, - toCustomViewletCSSClass(treeExplorerNodeProviderId), + toCustomExplorerViewletCSSClass(treeExplorerNodeProviderId), -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. true )); diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts index ea5e59c9e24..35a7199d636 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorer.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -4,15 +4,15 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -export function toCustomViewletId(viewletId: string): string { +export function toCustomExplorerViewletId(viewletId: string): string { return 'workbench.view.customExplorer.' + viewletId; } -export function toCustomViewletActionId(viewletId: string): string { +export function toCustomExplorerViewletActionId(viewletId: string): string { return 'workbench.action.customExplorer.' + viewletId; } -export function toCustomViewletCSSClass(viewletId: string): string { +export function toCustomExplorerViewletCSSClass(viewletId: string): string { return 'customExplorer-' + viewletId; } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index 839cb4b9df4..bbf79d5db6d 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -13,12 +13,12 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Action } from 'vs/base/common/actions'; import { IQuickOpenService, IPickOpenEntry } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; -import { toCustomViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomExplorerViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; const registry = Registry.as(ActionExtensions.WorkbenchActions); export class ToggleExtViewletAction extends Action { - public static ID = toCustomViewletActionId('toggle'); + public static ID = toCustomExplorerViewletActionId('toggle'); public static LABEL = localize('treeExplorer.toggle', 'Toggle Custom Explorer'); constructor( diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts index 8ae5054e5e8..226f8dc1b70 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.ts @@ -8,12 +8,12 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { TreeExplorerView } from 'vs/workbench/parts/explorers/browser/views/treeExplorerView'; -import { toCustomViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; +import { toCustomExplorerViewletActionId } from 'vs/workbench/parts/explorers/common/treeExplorer'; export class RefreshViewExplorerAction extends Action { constructor(view: TreeExplorerView) { - super(toCustomViewletActionId('refresh'), nls.localize('refresh', 'Refresh'), 'customExplorer-action toggle', true, () => { + super(toCustomExplorerViewletActionId('refresh'), nls.localize('refresh', 'Refresh'), 'customExplorer-action toggle', true, () => { view.updateInput(); return TPromise.as(null); }); From 25885c6808d841bf996cb264826014d247f13330 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 01:46:58 -0800 Subject: [PATCH 117/119] Remove unused services --- .../parts/explorers/browser/views/treeExplorerView.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts index 4ccbd7702d7..c01cdb5540c 100644 --- a/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts +++ b/src/vs/workbench/parts/explorers/browser/views/treeExplorerView.ts @@ -16,13 +16,12 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ICustomTreeExplorerService } from 'vs/workbench/parts/explorers/browser/customTreeExplorerService'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { TreeExplorerViewletState, TreeDataSource, TreeRenderer, TreeController } from 'vs/workbench/parts/explorers/browser/views/treeExplorerViewer'; import { RefreshViewExplorerAction } from 'vs/workbench/parts/explorers/common/treeExplorerActions'; +import { IProgressService } from 'vs/platform/progress/common/progress'; export class TreeExplorerView extends CollapsibleViewletView { private workspace: IWorkspace; @@ -37,9 +36,8 @@ export class TreeExplorerView extends CollapsibleViewletView { @IContextMenuService contextMenuService: IContextMenuService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IEditorGroupService private editorGroupService: IEditorGroupService, - @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService + @ICustomTreeExplorerService private treeExplorerViewletService: ICustomTreeExplorerService, + @IProgressService private progressService: IProgressService ) { super(actionRunner, false, nls.localize('treeExplorerViewlet.tree', "Tree Explorer Section"), messageService, keybindingService, contextMenuService, headerSize); From 80a0cbf144b43e08537b2d9e5a811f847d01ec9a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 9 Nov 2016 08:48:04 -0800 Subject: [PATCH 118/119] Naming and clean up --- src/vs/workbench/api/node/extHostTreeExplorers.ts | 2 +- .../browser/parts/activitybar/activitybarPart.ts | 13 +++++++------ src/vs/workbench/browser/viewlet.ts | 6 +++--- src/vs/workbench/electron-browser/workbench.ts | 4 ++-- .../explorers/browser/treeExplorer.contribution.ts | 2 +- .../parts/explorers/common/treeExplorer.ts | 2 +- .../common/treeExplorerActions.contribution.ts | 6 +++--- .../services/viewlet/browser/viewletService.ts | 10 +++++----- .../services/viewlet/common/viewletService.ts | 4 ++-- src/vs/workbench/test/browser/services.test.ts | 4 ++-- 10 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/api/node/extHostTreeExplorers.ts b/src/vs/workbench/api/node/extHostTreeExplorers.ts index 5c216171d73..22a6af7a136 100644 --- a/src/vs/workbench/api/node/extHostTreeExplorers.ts +++ b/src/vs/workbench/api/node/extHostTreeExplorers.ts @@ -81,7 +81,7 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape { return internalChild; }); }, err => { - const errMessage = localize('extHostTreeExplorers.ts.failedToResolveChildren', 'TreeExplorerNodeProvider \'{0}\' failed to resolveChildren.', providerId); + const errMessage = localize('treeExplorer.failedToResolveChildren', 'TreeExplorerNodeProvider \'{0}\' failed to resolveChildren.', providerId); return TPromise.wrapError(errMessage); }); } diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index d3b5abab171..6602620942e 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -52,8 +52,8 @@ export class ActivitybarPart extends Part implements IActivityService { // Deactivate viewlet action on close this.toUnbind.push(this.viewletService.onDidViewletClose(viewlet => this.onCompositeClosed(viewlet))); - // Update viewlet switcher when extension viewlets become ready - this.toUnbind.push(this.viewletService.onDidExtensionViewletsLoad(() => this.refreshViewletSwitcher())); + // Update viewlet switcher when external viewlets become ready + this.toUnbind.push(this.viewletService.onDidExtViewletsLoad(() => this.refreshViewletSwitcher())); // Update viewlet switcher on toggling of a viewlet this.toUnbind.push(this.viewletService.onDidViewletToggle(() => this.refreshViewletSwitcher())); @@ -109,16 +109,17 @@ export class ActivitybarPart extends Part implements IActivityService { this.fillViewletSwitcher(this.viewletService.getAllViewletsToDisplay()); } - private fillViewletSwitcher(newViewlets: ViewletDescriptor[]) { + private fillViewletSwitcher(viewlets: ViewletDescriptor[]) { // Pull out viewlets no longer needed - const newViewletIds = newViewlets.map(v => v.id); - Object.keys(this.compositeIdToActions).forEach(viewletId => { + const newViewletIds = viewlets.map(v => v.id); + const existingViewletIds = Object.keys(this.compositeIdToActions); + existingViewletIds.forEach(viewletId => { if (newViewletIds.indexOf(viewletId) === -1) { this.pullViewlet(viewletId); } }); - const actionsToPush = newViewlets + const actionsToPush = viewlets .filter(viewlet => !this.compositeIdToActions[viewlet.id]) .map(viewlet => this.toAction(viewlet)); diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 1c25ad84f16..511418ee269 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -153,10 +153,10 @@ export abstract class ViewerViewlet extends Viewlet { */ export class ViewletDescriptor extends CompositeDescriptor { - constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExtension: boolean = false) { + constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, public isExternal: boolean = false) { super(moduleId, ctorName, id, name, cssClass, order); - if (isExtension) { - // Pass viewletId to extension viewlet, which doesn't know its id until runtime. + if (isExternal) { + // Pass viewletId to external viewlet, which doesn't know its id until runtime. this.appendStaticArguments([id]); } } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 27a00689412..278adf85590 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -248,9 +248,9 @@ export class Workbench implements IPartService { if (this.shouldRestoreSidebar() && !this.sideBarHidden) { const lastOpenedViewlet = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); - // If last viewlet is extension viewlet, delay its restoration until extension viewlets loaded + // If last viewlet is external viewlet, delay its restoration until external viewlets loaded if (!viewletRegistry.getViewlet(lastOpenedViewlet)) { - this.viewletService.onDidExtensionViewletsLoad(() => { + this.viewletService.onDidExtViewletsLoad(() => { this.sidebarPart.openViewlet(lastOpenedViewlet, false).done(); }); } diff --git a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts index 4d249455590..5b999c8dd73 100644 --- a/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts +++ b/src/vs/workbench/parts/explorers/browser/treeExplorer.contribution.ts @@ -76,7 +76,7 @@ export class ExplorerContribtion implements IWorkbenchContribution { toCustomExplorerViewletId(treeExplorerNodeProviderId), treeLabel, toCustomExplorerViewletCSSClass(treeExplorerNodeProviderId), - -1, // Extension viewlets are ordered by enabling sequence, so order here doesn't matter. + -1, // External viewlets are ordered by enabling sequence, so order here doesn't matter. true )); } diff --git a/src/vs/workbench/parts/explorers/common/treeExplorer.ts b/src/vs/workbench/parts/explorers/common/treeExplorer.ts index 35a7199d636..ed1ed85e5e0 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorer.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorer.ts @@ -19,4 +19,4 @@ export function toCustomExplorerViewletCSSClass(viewletId: string): string { export function isValidViewletId(viewletId: string): boolean { // Only allow alphanumeric letters, `_` and `-`. return /^[a-z0-9_-]+$/i.test(viewletId); -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts index bbf79d5db6d..70f36803b4d 100644 --- a/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts +++ b/src/vs/workbench/parts/explorers/common/treeExplorerActions.contribution.ts @@ -17,7 +17,7 @@ import { toCustomExplorerViewletActionId } from 'vs/workbench/parts/explorers/co const registry = Registry.as(ActionExtensions.WorkbenchActions); -export class ToggleExtViewletAction extends Action { +export class ToggleExternalViewletAction extends Action { public static ID = toCustomExplorerViewletActionId('toggle'); public static LABEL = localize('treeExplorer.toggle', 'Toggle Custom Explorer'); @@ -31,7 +31,7 @@ export class ToggleExtViewletAction extends Action { } run(): TPromise { - const extViewlets = this.viewletService.getAllViewlets().filter(viewlet => viewlet.isExtension); + const extViewlets = this.viewletService.getAllViewlets().filter(viewlet => viewlet.isExternal); const picks: IPickOpenEntry[] = []; @@ -63,7 +63,7 @@ export class ToggleExtViewletAction extends Action { } registry.registerWorkbenchAction( - new SyncActionDescriptor(ToggleExtViewletAction, ToggleExtViewletAction.ID, ToggleExtViewletAction.LABEL), + new SyncActionDescriptor(ToggleExternalViewletAction, ToggleExternalViewletAction.ID, ToggleExternalViewletAction.LABEL), 'View: Toggle Custom Explorer', localize('view', "View") ); diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index 33ba3566243..a28a231c2dc 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -23,12 +23,12 @@ export class ViewletService implements IViewletService { private sidebarPart: ISidebar; private enabledExtViewletIds: string[]; private extViewlets: ViewletDescriptor[]; - private _onDidExtensionViewletsLoad = new Emitter(); + private _onDidExtViewletsLoad = new Emitter(); private _onDidViewletToggle = new Emitter(); public get onDidViewletOpen(): Event { return this.sidebarPart.onDidViewletOpen; }; public get onDidViewletClose(): Event { return this.sidebarPart.onDidViewletClose; }; - public get onDidExtensionViewletsLoad(): Event { return this._onDidExtensionViewletsLoad.event; }; + public get onDidExtViewletsLoad(): Event { return this._onDidExtViewletsLoad.event; }; public get onDidViewletToggle(): Event { return this._onDidViewletToggle.event; }; constructor( @@ -50,12 +50,12 @@ export class ViewletService implements IViewletService { private onExtensionServiceReady(): void { const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); viewlets.forEach(v => { - if (v.isExtension) { + if (v.isExternal) { this.extViewlets.push(v); } }); - this._onDidExtensionViewletsLoad.fire(); + this._onDidExtViewletsLoad.fire(); } public openViewlet(id: string, focus?: boolean): TPromise { @@ -102,7 +102,7 @@ export class ViewletService implements IViewletService { private getStockViewlets(): ViewletDescriptor[] { return (Registry.as(ViewletExtensions.Viewlets)) .getViewlets() - .filter(viewlet => !viewlet.isExtension) + .filter(viewlet => !viewlet.isExternal) .sort((v1, v2) => v1.order - v2.order); } diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index d52b94601dd..0186de9ce1a 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -17,7 +17,7 @@ export interface IViewletService { onDidViewletOpen: Event; onDidViewletClose: Event; - onDidExtensionViewletsLoad: Event; + onDidExtViewletsLoad: Event; onDidViewletToggle: Event; /** @@ -43,7 +43,7 @@ export interface IViewletService { /** * Returns all viewlets that should be displayed, ordered by: * - Stock Viewlets: order attribute - * - Extension Viewlets: enabling sequence + * - External Viewlets: enabling sequence */ getAllViewletsToDisplay(): ViewletDescriptor[]; diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index bc1da1ce009..b7d63f3cfb9 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -102,12 +102,12 @@ class TestViewletService implements IViewletService { onDidViewletOpenEmitter = new Emitter(); onDidViewletCloseEmitter = new Emitter(); - onDidExtensionViewletsLoadEmitter = new Emitter(); + onDidExtletsLoadEmitter = new Emitter(); onDidViewletToggleEmitter = new Emitter(); onDidViewletOpen = this.onDidViewletOpenEmitter.event; onDidViewletClose = this.onDidViewletCloseEmitter.event; - onDidExtensionViewletsLoad = this.onDidExtensionViewletsLoadEmitter.event; + onDidExtViewletsLoad = this.onDidExtletsLoadEmitter.event; onDidViewletToggle = this.onDidViewletToggleEmitter.event; public openViewlet(id: string, focus?: boolean): TPromise { From a585a33bdabe0a36bb49d72f28f9f3c5f6dc7e73 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 10 Nov 2016 00:01:50 -0800 Subject: [PATCH 119/119] Move viewlet restore logic to viewletService --- .../workbench/electron-browser/workbench.ts | 25 +++++++--------- .../viewlet/browser/viewletService.ts | 30 +++++++++++++++++-- .../services/viewlet/common/viewletService.ts | 6 ++++ .../workbench/test/browser/services.test.ts | 4 +++ 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 278adf85590..08551469f1f 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -244,22 +244,17 @@ export class Workbench implements IPartService { const compositeAndEditorPromises: TPromise[] = []; // Restore last opened viewlet - const viewletRegistry = Registry.as(ViewletExtensions.Viewlets); - if (this.shouldRestoreSidebar() && !this.sideBarHidden) { - const lastOpenedViewlet = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); + if (!this.sideBarHidden) { + let viewletIdToRestore; - // If last viewlet is external viewlet, delay its restoration until external viewlets loaded - if (!viewletRegistry.getViewlet(lastOpenedViewlet)) { - this.viewletService.onDidExtViewletsLoad(() => { - this.sidebarPart.openViewlet(lastOpenedViewlet, false).done(); - }); - } - // Otherwise, load last viewlet immediately - else { - let viewletId = lastOpenedViewlet; - const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletId)); - compositeAndEditorPromises.push(this.sidebarPart.openViewlet(viewletId, false).then(() => viewletTimerEvent.stop())); + if (this.shouldRestoreLastOpenedViewlet) { + viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); + } else { + viewletIdToRestore = Registry.as(ViewletExtensions.Viewlets).getDefaultViewletId(); } + + const viewletTimerEvent = timer.start(timer.Topic.STARTUP, strings.format('Opening Viewlet: {0}', viewletIdToRestore)); + compositeAndEditorPromises.push(this.viewletService.restoreViewlet(viewletIdToRestore).then(() => viewletTimerEvent.stop())); } // Load Panel @@ -992,7 +987,7 @@ export class Workbench implements IPartService { this.storageService.store(Workbench.sidebarRestoreSettingKey, 'true', StorageScope.WORKSPACE); } - private shouldRestoreSidebar(): boolean { + private shouldRestoreLastOpenedViewlet(): boolean { if (!this.environmentService.isBuilt) { return true; // always restore sidebar when we are in development mode } diff --git a/src/vs/workbench/services/viewlet/browser/viewletService.ts b/src/vs/workbench/services/viewlet/browser/viewletService.ts index a28a231c2dc..3d0df3f9b69 100644 --- a/src/vs/workbench/services/viewlet/browser/viewletService.ts +++ b/src/vs/workbench/services/viewlet/browser/viewletService.ts @@ -21,6 +21,7 @@ export class ViewletService implements IViewletService { public _serviceBrand: any; private sidebarPart: ISidebar; + private viewletRegistry: ViewletRegistry; private enabledExtViewletIds: string[]; private extViewlets: ViewletDescriptor[]; private _onDidExtViewletsLoad = new Emitter(); @@ -37,6 +38,7 @@ export class ViewletService implements IViewletService { @IExtensionService private extensionService: IExtensionService ) { this.sidebarPart = sidebarPart; + this.viewletRegistry = Registry.as(ViewletExtensions.Viewlets); const enabledExtViewletsJson = this.storageService.get(ViewletService.ENABLED_EXT_VIEWLETS); this.enabledExtViewletIds = enabledExtViewletsJson ? JSON.parse(enabledExtViewletsJson) : []; @@ -48,7 +50,7 @@ export class ViewletService implements IViewletService { } private onExtensionServiceReady(): void { - const viewlets = (Registry.as(ViewletExtensions.Viewlets)).getViewlets(); + const viewlets = this.viewletRegistry.getViewlets(); viewlets.forEach(v => { if (v.isExternal) { this.extViewlets.push(v); @@ -62,6 +64,29 @@ export class ViewletService implements IViewletService { return this.sidebarPart.openViewlet(id, focus); } + public restoreViewlet(id: string): TPromise { + const shouldFocus = false; + + const stockViewletIds = this.getStockViewlets().map(v => v.id); + const isStockViewlet = stockViewletIds.indexOf(id) !== -1; + if (isStockViewlet) { + return this.sidebarPart.openViewlet(id, shouldFocus); + } else { + return new TPromise(c => { + this.onDidExtViewletsLoad(() => { + // It's possible the external viewlet is uninstalled and not available. + // Restore file explorer in that case. + if (!this.viewletRegistry.getViewlet(id)) { + const defaultViewletId = this.viewletRegistry.getDefaultViewletId(); + this.sidebarPart.openViewlet(defaultViewletId, shouldFocus).then(viewlet => c(viewlet)); + } else { + this.sidebarPart.openViewlet(id, shouldFocus).then(viewlet => c(viewlet)); + } + }); + }); + } + } + public toggleViewlet(id: string): TPromise { const index = this.enabledExtViewletIds.indexOf(id); if (index === -1) { @@ -100,8 +125,7 @@ export class ViewletService implements IViewletService { // Get an ordered list of all stock viewlets private getStockViewlets(): ViewletDescriptor[] { - return (Registry.as(ViewletExtensions.Viewlets)) - .getViewlets() + return this.viewletRegistry.getViewlets() .filter(viewlet => !viewlet.isExternal) .sort((v1, v2) => v1.order - v2.order); } diff --git a/src/vs/workbench/services/viewlet/common/viewletService.ts b/src/vs/workbench/services/viewlet/common/viewletService.ts index 0186de9ce1a..3611af4dcab 100644 --- a/src/vs/workbench/services/viewlet/common/viewletService.ts +++ b/src/vs/workbench/services/viewlet/common/viewletService.ts @@ -25,6 +25,12 @@ export interface IViewletService { */ openViewlet(id: string, focus?: boolean): TPromise; + /** + * Restores a viewlet during startup. + * If the viewlet to restore is external, delay restoration until extensions finish loading. + */ + restoreViewlet(id: string): TPromise; + /** * Toggles a viewlet with the given identifier. */ diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index b7d63f3cfb9..14b7d284c71 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -114,6 +114,10 @@ class TestViewletService implements IViewletService { return TPromise.as(null); } + public restoreViewlet(id: string): TPromise { + return TPromise.as(null); + } + public toggleViewlet(id: string): TPromise { return TPromise.as(null); }