提交 c9c8b8e0 编写于 作者: S Sandeep Somavarapu

Enhance Tree api

- A new approach to register tree node
- Support on change listener to refresh node
上级 87435073
......@@ -400,32 +400,32 @@ declare module 'vscode' {
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env: { [key: string]: string };
};
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env?: { [key: string]: string };
} | {
/**
* The current working directory of the executed shell.
* If omitted VSCode's current workspace root is used.
*/
cwd?: string;
/**
* The additional environment of the executed shell. If omitted
* the parent process' environment is used. If provided it is merged with
* the parent process' environment.
*/
env: { [key: string]: string };
};
/**
* A task that executes a shell command.
......@@ -545,6 +545,15 @@ declare module 'vscode' {
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider<any>): Disposable;
/**
* Register a [TreeNode](#TreeNode).
*
* @param providerId A unique id that identifies the provider.
* @param provider A [TreeNode](#TreeNode).
* @return A [disposable](#Disposable) that unregisters this tree when being disposed.
*/
export function registerTree(id: string, root: TreeNode): Disposable;
}
/**
......@@ -578,7 +587,7 @@ declare module 'vscode' {
* @param node The node from which the provider resolves children.
* @return Children of `node`.
*/
resolveChildren(node: T): T[] | Thenable<T[]>;
resolveChildren?(node: T): T[] | Thenable<T[]>;
/**
* Provide a human-readable string that will be used for rendering the node. Default to use
......@@ -606,7 +615,33 @@ declare module 'vscode' {
* @param node The node that the command is associated with.
* @return The command to execute when `node` is clicked.
*/
getClickCommand?(node: T): string;
getClickCommand?(node: T): Command;
/**
* Event to be listened for any changes
*/
onChange?: Event<T>;
}
export interface TreeNode {
/**
* Human-readable string used for rendering the node.
* Label for Root node is not rendered.
*/
readonly label: string;
/**
* Get the children for the node. If not implemented, the node is not expandable.
*/
getChildren?(): Thenable<TreeNode[]>;
/**
* The [command](#Command) which should be run when the node
* is selected in the View.
*/
command?: Command;
/**
* Event to be listened for any changes on this node
*/
onChange?: Event<void>;
}
/**
......
......@@ -19,6 +19,7 @@ import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDoc
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { ExtHostTreeExplorers } from 'vs/workbench/api/node/extHostTreeExplorers';
import { ExtHostTree } from 'vs/workbench/api/node/extHostTree';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
......@@ -112,6 +113,7 @@ export function createApiFactory(
const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set<ExtHostEditors>(new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set<ExtHostCommands>(new ExtHostCommands(threadService, extHostHeapService));
const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set<ExtHostTreeExplorers>(new ExtHostTreeExplorers(threadService, extHostCommands));
const extHostTree = col.define(ExtHostContext.ExtHostTree).set<ExtHostTree>(new ExtHostTree(threadService, extHostCommands));
const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set<ExtHostConfiguration>(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initData.configuration));
const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set<ExtHostDiagnostics>(new ExtHostDiagnostics(threadService));
const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set<ExtHostLanguageFeatures>(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
......@@ -366,6 +368,9 @@ export function createApiFactory(
registerTreeExplorerNodeProvider: proposedApiFunction(extension, (providerId: string, provider: vscode.TreeExplorerNodeProvider<any>) => {
return extHostExplorers.registerTreeExplorerNodeProvider(providerId, provider);
}),
registerTree: proposedApiFunction(extension, (providerId: string, root: vscode.TreeNode) => {
return extHostTree.registerTree(providerId, root);
})
};
// namespace: workspace
......
......@@ -20,6 +20,7 @@ import { MainThreadDocuments } from './mainThreadDocuments';
import { MainThreadEditors } from './mainThreadEditors';
import { MainThreadErrors } from './mainThreadErrors';
import { MainThreadTreeExplorers } from './mainThreadTreeExplorers';
import { MainThreadTree } from './mainThreadTree';
import { MainThreadLanguageFeatures } from './mainThreadLanguageFeatures';
import { MainThreadLanguages } from './mainThreadLanguages';
import { MainThreadMessageService } from './mainThreadMessageService';
......@@ -75,6 +76,7 @@ export class ExtHostContribution implements IWorkbenchContribution {
col.define(MainContext.MainThreadEditors).set(this.instantiationService.createInstance(MainThreadEditors, documentsAndEditors));
col.define(MainContext.MainThreadErrors).set(create(MainThreadErrors));
col.define(MainContext.MainThreadExplorers).set(create(MainThreadTreeExplorers));
col.define(MainContext.MainThreadTree).set(create(MainThreadTree));
col.define(MainContext.MainThreadLanguageFeatures).set(create(MainThreadLanguageFeatures));
col.define(MainContext.MainThreadLanguages).set(create(MainThreadLanguages));
col.define(MainContext.MainThreadMessageService).set(create(MainThreadMessageService));
......
......@@ -149,6 +149,12 @@ export abstract class MainThreadEditorsShape {
export abstract class MainThreadTreeExplorersShape {
$registerTreeExplorerNodeProvider(providerId: string): void { throw ni(); }
$refresh(providerId: string, node: InternalTreeExplorerNodeContent): void { throw ni(); }
}
export abstract class MainThreadTreeShape {
$registerTreeExplorerNodeProvider(providerId: string, node: InternalTreeExplorerNodeContent): void { throw ni(); }
$refresh(providerId: string, node: InternalTreeExplorerNodeContent): void { throw ni(); }
}
export abstract class MainThreadErrorsShape {
......@@ -358,6 +364,11 @@ export abstract class ExtHostTreeExplorersShape {
$getInternalCommand(providerId: string, node: InternalTreeExplorerNodeContent): TPromise<modes.Command> { throw ni(); }
}
export abstract class ExtHostTreeShape {
$resolveChildren(providerId: string, node: InternalTreeExplorerNodeContent): TPromise<InternalTreeExplorerNodeContent[]> { throw ni(); }
$getInternalCommand(providerId: string, node: InternalTreeExplorerNodeContent): TPromise<modes.Command> { throw ni(); }
}
export abstract class ExtHostExtensionServiceShape {
$localShowMessage(severity: Severity, msg: string): void { throw ni(); }
$activateExtension(extensionDescription: IExtensionDescription): TPromise<void> { throw ni(); }
......@@ -447,6 +458,7 @@ export const MainContext = {
MainThreadEditors: createMainId<MainThreadEditorsShape>('MainThreadEditors', MainThreadEditorsShape),
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors', MainThreadErrorsShape),
MainThreadExplorers: createMainId<MainThreadTreeExplorersShape>('MainThreadExplorers', MainThreadTreeExplorersShape),
MainThreadTree: createMainId<MainThreadTreeShape>('MainThreadTree', MainThreadTreeShape),
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures', MainThreadLanguageFeaturesShape),
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages', MainThreadLanguagesShape),
MainThreadMessageService: createMainId<MainThreadMessageServiceShape>('MainThreadMessageService', MainThreadMessageServiceShape),
......@@ -479,5 +491,6 @@ export const ExtHostContext = {
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService', ExtHostExtensionServiceShape),
ExtHostTerminalService: createExtId<ExtHostTerminalServiceShape>('ExtHostTerminalService', ExtHostTerminalServiceShape),
ExtHostSCM: createExtId<ExtHostSCMShape>('ExtHostSCM', ExtHostSCMShape),
ExtHostTree: createExtId<ExtHostTreeShape>('ExtHostTree', ExtHostTreeShape),
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask', ExtHostTaskShape)
};
/*---------------------------------------------------------------------------------------------
* 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 { TreeNode } from 'vscode';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, ExtHostTreeShape, MainThreadTreeShape } from './extHost.protocol';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
import { localize } from 'vs/nls';
import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import * as modes from 'vs/editor/common/modes';
class InternalTreeExplorerNodeImpl implements InternalTreeExplorerNode {
readonly id: string;
label: string;
hasChildren: boolean;
clickCommand: string;
constructor(node: TreeNode) {
this.id = defaultGenerator.nextId();
this.label = node.label;
this.hasChildren = !!node.getChildren;
this.clickCommand = node.command ? node.command.command : null;
}
}
export class ExtHostTree extends ExtHostTreeShape {
private _proxy: MainThreadTreeShape;
private _providers: Map<string, Map<string, TreeNode>> = new Map<string, Map<string, TreeNode>>();
private _disposables: Map<string, Disposable[]> = new Map<string, Disposable[]>();
private _nodeDisposables: Map<string, Disposable[]> = new Map<string, Disposable[]>();
constructor(
threadService: IThreadService,
private commands: ExtHostCommands
) {
super();
this._proxy = threadService.get(MainContext.MainThreadTree);
}
registerTree(providerId: string, root: TreeNode): Disposable {
this._providers.set(providerId, new Map<string, TreeNode>());
this._disposables.set(providerId, []);
const internalNode = new InternalTreeExplorerNodeImpl(root);
this._providers.get(providerId).set(internalNode.id, root);
const disposable = root.onChange(() => {
this._proxy.$refresh(providerId, internalNode);
});
this._disposables.get(providerId).push(new Disposable(() => disposable.dispose()));
this._proxy.$registerTreeExplorerNodeProvider(providerId, internalNode);
return new Disposable(() => {
this._providers.delete(providerId);
const disposables = this._disposables.get(providerId);
if (disposables) {
for (const disposable of disposables) {
disposable.dispose();
}
}
this._disposables.delete(providerId);
});
}
$resolveChildren(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise<InternalTreeExplorerNode[]> {
const provider = this._providers.get(providerId);
if (!provider) {
const errMessage = localize('treeExplorer.notRegistered', 'No TreeExplorerNodeProvider with id \'{0}\' registered.', providerId);
return TPromise.wrapError(errMessage);
}
const extNode = provider.get(mainThreadNode.id);
const disposables = this._nodeDisposables.get(mainThreadNode.id);
if (disposables) {
for (const disposable of disposables) {
disposable.dispose();
}
}
this._nodeDisposables.set(mainThreadNode.id, []);
return asWinJsPromise(() => extNode.getChildren()).then(children => {
return children.map(extChild => {
const internalChild = new InternalTreeExplorerNodeImpl(extChild);
provider.set(internalChild.id, extChild);
if (extChild.onChange) {
const disposable = extChild.onChange(() => this._proxy.$refresh(providerId, internalChild));
this._disposables.get(providerId).push(new Disposable(() => disposable.dispose()));
this._nodeDisposables.get(mainThreadNode.id).push(new Disposable(() => disposable.dispose()));
}
return internalChild;
});
}, err => {
const errMessage = localize('treeExplorer.failedToResolveChildren', 'TreeExplorerNodeProvider \'{0}\' failed to resolveChildren.', providerId);
return TPromise.wrapError(errMessage);
});
}
// Convert the command on the ExtHost side so we can pass the original externalNode to the registered handler
$getInternalCommand(providerId: string, mainThreadNode: InternalTreeExplorerNode): TPromise<modes.Command> {
const commandConverter = this.commands.converter;
if (mainThreadNode.clickCommand) {
const extNode = this._providers.get(providerId).get(mainThreadNode.id);
const internalCommand = commandConverter.toInternal({
title: '',
command: mainThreadNode.clickCommand,
arguments: [extNode]
});
return TPromise.wrap(internalCommand);
}
return TPromise.as(null);
}
}
\ No newline at end of file
......@@ -21,13 +21,18 @@ class InternalTreeExplorerNodeImpl implements InternalTreeExplorerNode {
readonly id: string;
label: string;
hasChildren: boolean;
clickCommand: string;
clickCommand: string = null;
constructor(node: any, provider: TreeExplorerNodeProvider<any>) {
this.id = defaultGenerator.nextId();
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;
if (provider.getClickCommand) {
const command = provider.getClickCommand(node);
if (command) {
this.clickCommand = command.command;
}
}
}
}
......@@ -36,6 +41,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape {
private _extNodeProviders: { [providerId: string]: TreeExplorerNodeProvider<any> };
private _extNodeMaps: { [providerId: string]: { [id: string]: InternalTreeExplorerNode } };
private _mainNodesMap: Map<string, Map<any, InternalTreeExplorerNode>>;
private _childrenNodesMap: Map<string, Map<any, any[]>>;
constructor(
threadService: IThreadService,
......@@ -47,15 +54,32 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape {
this._extNodeProviders = Object.create(null);
this._extNodeMaps = Object.create(null);
this._mainNodesMap = new Map<string, Map<any, InternalTreeExplorerNode>>();
this._childrenNodesMap = new Map<string, Map<any, any[]>>();
}
registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider<any>): Disposable {
this._proxy.$registerTreeExplorerNodeProvider(providerId);
this._extNodeProviders[providerId] = provider;
this._mainNodesMap.set(providerId, new Map<any, InternalTreeExplorerNode>());
this._childrenNodesMap.set(providerId, new Map<any, any>());
let disposable = null;
if (provider.onChange) {
disposable = provider.onChange(node => {
const mainThreadNode = this._mainNodesMap.get(providerId).get(node);
this._proxy.$refresh(providerId, mainThreadNode);
});
}
return new Disposable(() => {
delete this._extNodeProviders[providerId];
delete this._extNodeProviders[providerId];
this._mainNodesMap.delete(providerId);
this._childrenNodesMap.delete(providerId);
if (disposable) {
disposable.dispose();
}
});
}
......@@ -73,6 +97,8 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape {
extNodeMap[internalRootNode.id] = extRootNode;
this._extNodeMaps[providerId] = extNodeMap;
this._mainNodesMap.get(providerId).set(extRootNode, internalRootNode);
return internalRootNode;
}, err => {
const errMessage = localize('treeExplorer.failedToProvideRootNode', 'TreeExplorerNodeProvider \'{0}\' failed to provide root node.', providerId);
......@@ -90,15 +116,20 @@ export class ExtHostTreeExplorers extends ExtHostTreeExplorersShape {
const extNodeMap = this._extNodeMaps[providerId];
const extNode = extNodeMap[mainThreadNode.id];
const currentChildren = this._childrenNodesMap.get(providerId).get(extNode);
if (currentChildren) {
for (const child of currentChildren) {
this._mainNodesMap.get(providerId).delete(child);
}
}
return asWinJsPromise(() => provider.resolveChildren(extNode)).then(children => {
return children.map(extChild => {
const internalChild = new InternalTreeExplorerNodeImpl(extChild, provider);
extNodeMap[internalChild.id] = extChild;
this._mainNodesMap.get(providerId).set(extChild, internalChild);
return internalChild;
});
}, err => {
const errMessage = localize('treeExplorer.failedToResolveChildren', 'TreeExplorerNodeProvider \'{0}\' failed to resolveChildren.', providerId);
return TPromise.wrapError(errMessage);
});
}
......
/*---------------------------------------------------------------------------------------------
* 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 Event, { Emitter } from 'vs/base/common/event';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, MainThreadTreeShape, ExtHostTreeShape } from './extHost.protocol';
import { ITreeExplorerService } from 'vs/workbench/parts/explorers/common/treeExplorerService';
import { InternalTreeExplorerNodeContent, InternalTreeExplorerNodeProvider } 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 MainThreadTree extends MainThreadTreeShape {
private _proxy: ExtHostTreeShape;
constructor(
@IThreadService threadService: IThreadService,
@ITreeExplorerService private treeExplorerService: ITreeExplorerService,
@IMessageService private messageService: IMessageService,
@ICommandService private commandService: ICommandService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostTree);
}
$registerTreeExplorerNodeProvider(providerId: string, rootNode: InternalTreeExplorerNodeContent): void {
const provider = new TreeExplorerNodeProvider(providerId, rootNode, this._proxy, this.messageService, this.commandService);
this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, provider);
}
$refresh(providerId: string, node: InternalTreeExplorerNodeContent): void {
(<TreeExplorerNodeProvider>this.treeExplorerService.getProvider(providerId))._onRefresh.fire(node);
}
}
class TreeExplorerNodeProvider implements InternalTreeExplorerNodeProvider {
readonly _onRefresh: Emitter<InternalTreeExplorerNodeContent> = new Emitter<InternalTreeExplorerNodeContent>();
readonly onRefresh: Event<InternalTreeExplorerNodeContent> = this._onRefresh.event;
constructor(private providerId: string, private rootNode: InternalTreeExplorerNodeContent, private _proxy: ExtHostTreeShape,
private messageService: IMessageService,
private commandService: ICommandService
) {
}
provideRootNode(): TPromise<InternalTreeExplorerNodeContent> {
return TPromise.as(this.rootNode);
}
resolveChildren(node: InternalTreeExplorerNodeContent): TPromise<InternalTreeExplorerNodeContent[]> {
return this._proxy.$resolveChildren(this.providerId, node).then(children => children, err => this.messageService.show(Severity.Error, err));
}
executeCommand(node: InternalTreeExplorerNodeContent): TPromise<any> {
return this._proxy.$getInternalCommand(this.providerId, node).then(command => {
return this.commandService.executeCommand(command.id, ...command.arguments);
});
}
}
......@@ -5,10 +5,11 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, MainThreadTreeExplorersShape, ExtHostTreeExplorersShape } from './extHost.protocol';
import { ITreeExplorerService } from 'vs/workbench/parts/explorers/common/treeExplorerService';
import { InternalTreeExplorerNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import { InternalTreeExplorerNodeContent, InternalTreeExplorerNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { ICommandService } from 'vs/platform/commands/common/commands';
......@@ -27,20 +28,37 @@ export class MainThreadTreeExplorers extends MainThreadTreeExplorersShape {
}
$registerTreeExplorerNodeProvider(providerId: string): void {
const onError = err => { this.messageService.show(Severity.Error, err); };
this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, {
provideRootNode: (): TPromise<InternalTreeExplorerNodeContent> => {
return this._proxy.$provideRootNode(providerId).then(rootNode => rootNode, onError);
},
resolveChildren: (node: InternalTreeExplorerNodeContent): TPromise<InternalTreeExplorerNodeContent[]> => {
return this._proxy.$resolveChildren(providerId, node).then(children => children, onError);
},
executeCommand: (node: InternalTreeExplorerNodeContent): TPromise<any> => {
return this._proxy.$getInternalCommand(providerId, node).then(command => {
return this.commandService.executeCommand(command.id, ...command.arguments);
});
}
const provider = new TreeExplorerNodeProvider(providerId, this._proxy, this.messageService, this.commandService);
this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, provider);
}
$refresh(providerId: string, node: InternalTreeExplorerNodeContent): void {
(<TreeExplorerNodeProvider>this.treeExplorerService.getProvider(providerId))._onRefresh.fire(node);
}
}
class TreeExplorerNodeProvider implements InternalTreeExplorerNodeProvider {
readonly _onRefresh: Emitter<InternalTreeExplorerNodeContent> = new Emitter<InternalTreeExplorerNodeContent>();
readonly onRefresh: Event<InternalTreeExplorerNodeContent> = this._onRefresh.event;
constructor(private providerId: string, private _proxy: ExtHostTreeExplorersShape,
private messageService: IMessageService,
private commandService: ICommandService
) {
}
provideRootNode(): TPromise<InternalTreeExplorerNodeContent> {
return this._proxy.$provideRootNode(this.providerId).then(rootNode => rootNode, err => this.messageService.show(Severity.Error, err));
}
resolveChildren(node: InternalTreeExplorerNodeContent): TPromise<InternalTreeExplorerNodeContent[]> {
return this._proxy.$resolveChildren(this.providerId, node).then(children => children, err => this.messageService.show(Severity.Error, err));
}
executeCommand(node: InternalTreeExplorerNodeContent): TPromise<any> {
return this._proxy.$getInternalCommand(this.providerId, node).then(command => {
return this.commandService.executeCommand(command.id, ...command.arguments);
});
}
}
......@@ -49,7 +49,7 @@ export class TreeExplorerService implements ITreeExplorerService {
return TPromise.wrap(provider.executeCommand(node));
}
private getProvider(providerId: string): InternalTreeExplorerNodeProvider {
public getProvider(providerId: string): InternalTreeExplorerNodeProvider {
const provider = this._treeExplorerNodeProviders[providerId];
if (!provider) {
......
......@@ -11,6 +11,7 @@ import { Builder, $ } from 'vs/base/browser/builder';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { CollapsibleViewletView } from 'vs/workbench/browser/viewlet';
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IMessageService } from 'vs/platform/message/common/message';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
......@@ -25,6 +26,9 @@ import { attachListStyler } from "vs/platform/theme/common/styler";
import { IThemeService } from "vs/platform/theme/common/themeService";
export class TreeExplorerView extends CollapsibleViewletView {
private providerDisposables = IDisposable[];
constructor(
private viewletState: TreeExplorerViewletState,
private treeNodeProviderId: string,
......@@ -86,9 +90,7 @@ export class TreeExplorerView extends CollapsibleViewletView {
public updateInput(): TPromise<void> {
if (this.treeExplorerService.hasProvider(this.treeNodeProviderId)) {
return this.treeExplorerService.provideRootNode(this.treeNodeProviderId).then(tree => {
this.tree.setInput(tree);
});
return this.updateProvider();
}
// 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
......@@ -97,9 +99,7 @@ export class TreeExplorerView extends CollapsibleViewletView {
else {
this.treeExplorerService.onTreeExplorerNodeProviderRegistered(providerId => {
if (this.treeNodeProviderId === providerId) {
return this.treeExplorerService.provideRootNode(this.treeNodeProviderId).then(tree => {
this.tree.setInput(tree);
});
return this.updateProvider();
}
return undefined;
});
......@@ -114,4 +114,16 @@ export class TreeExplorerView extends CollapsibleViewletView {
return DOM.getLargestChildWidth(parentNode, childNodes);
}
private updateProvider(): TPromise<void> {
if (this.providerDisposables) {
dispose(this.providerDisposables);
}
const provider = this.treeExplorerService.getProvider(this.treeNodeProviderId);
provider.onRefresh(node => this.tree.refresh(node));
return this.treeExplorerService.provideRootNode(this.treeNodeProviderId).then(tree => {
this.tree.setInput(tree);
});
}
}
......@@ -18,6 +18,7 @@ export interface ITreeExplorerService {
registerTreeExplorerNodeProvider(providerId: string, provider: InternalTreeExplorerNodeProvider): void;
hasProvider(providerId: string): boolean;
getProvider(providerId: string): InternalTreeExplorerNodeProvider;
provideRootNode(providerId: string): TPromise<InternalTreeExplorerNode>;
resolveChildren(providerId: string, node: InternalTreeExplorerNode): TPromise<InternalTreeExplorerNode[]>;
......
......@@ -5,6 +5,7 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
export interface InternalTreeExplorerNodeContent {
label: string;
......@@ -20,4 +21,5 @@ export interface InternalTreeExplorerNodeProvider {
provideRootNode(): Thenable<InternalTreeExplorerNodeContent>;
resolveChildren(node: InternalTreeExplorerNodeContent): Thenable<InternalTreeExplorerNodeContent[]>;
executeCommand(node: InternalTreeExplorerNodeContent): TPromise<any>;
onRefresh?: Event<InternalTreeExplorerNodeContent>;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册