提交 9eb01697 编写于 作者: S Sandeep Somavarapu

Fix #34789

上级 59b091af
...@@ -31,10 +31,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie ...@@ -31,10 +31,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
ViewsRegistry.registerTreeViewDataProvider(treeViewId, this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.messageService))); ViewsRegistry.registerTreeViewDataProvider(treeViewId, this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.messageService)));
} }
$refresh(treeViewId: string, treeItemHandles: string[]): void { $refresh(treeViewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): void {
const treeViewDataProvider: TreeViewDataProvider = <TreeViewDataProvider>ViewsRegistry.getTreeViewDataProvider(treeViewId); const treeViewDataProvider: TreeViewDataProvider = <TreeViewDataProvider>ViewsRegistry.getTreeViewDataProvider(treeViewId);
if (treeViewDataProvider) { if (treeViewDataProvider) {
treeViewDataProvider.refresh(treeItemHandles); treeViewDataProvider.refresh(itemsToRefresh);
} }
} }
...@@ -54,7 +54,6 @@ class TreeViewDataProvider implements ITreeViewDataProvider { ...@@ -54,7 +54,6 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
private _onDispose: Emitter<void> = new Emitter<void>(); private _onDispose: Emitter<void> = new Emitter<void>();
readonly onDispose: Event<void> = this._onDispose.event; readonly onDispose: Event<void> = this._onDispose.event;
private childrenMap: Map<TreeItemHandle, TreeItemHandle[]> = new Map<TreeItemHandle, TreeItemHandle[]>();
private itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>(); private itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
constructor(private treeViewId: string, constructor(private treeViewId: string,
...@@ -66,8 +65,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider { ...@@ -66,8 +65,7 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
getElements(): TPromise<ITreeItem[]> { getElements(): TPromise<ITreeItem[]> {
return this._proxy.$getElements(this.treeViewId) return this._proxy.$getElements(this.treeViewId)
.then(elements => { .then(elements => {
this.postGetElements(null, elements); return this.postGetElements(elements);
return elements;
}, err => { }, err => {
this.messageService.show(Severity.Error, err); this.messageService.show(Severity.Error, err);
return null; return null;
...@@ -80,28 +78,35 @@ class TreeViewDataProvider implements ITreeViewDataProvider { ...@@ -80,28 +78,35 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
} }
return this._proxy.$getChildren(this.treeViewId, treeItem.handle) return this._proxy.$getChildren(this.treeViewId, treeItem.handle)
.then(children => { .then(children => {
this.postGetElements(treeItem.handle, children); return this.postGetElements(children);
return children;
}, err => { }, err => {
this.messageService.show(Severity.Error, err); this.messageService.show(Severity.Error, err);
return null; return null;
}); });
} }
refresh(treeItemHandles: string[]) { refresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }) {
if (treeItemHandles && treeItemHandles.length) { if (itemsToRefreshByHandle) {
let treeItems = treeItemHandles.map(treeItemHandle => this.itemsMap.get(treeItemHandle)) const itemsToRefresh: ITreeItem[] = [];
.filter(treeItem => !!treeItem); for (const treeItemHandle of Object.keys(itemsToRefreshByHandle)) {
if (treeItems.length) { const currentTreeItem = this.itemsMap.get(treeItemHandle);
this._onDidChange.fire(treeItems); if (currentTreeItem) { // Refresh only if the item exists
} const treeItem = itemsToRefreshByHandle[treeItemHandle];
/*this._proxy.$resolveHandles(this.treeViewId, treeItemHandles) // Update the current item with refreshed item
.then(treeItems => { this.updateTreeItem(currentTreeItem, treeItem);
treeItems = coalesce(treeItems.map(treeItem => this.updateTreeItem(treeItem))); if (treeItemHandle === treeItem.handle) {
if (treeItems.length) { itemsToRefresh.push(currentTreeItem);
this._onDidChange.fire(treeItems); } else {
// Update maps when handle is changed and refresh parent
this.itemsMap.delete(treeItemHandle);
this.itemsMap.set(currentTreeItem.handle, currentTreeItem);
itemsToRefresh.push(this.itemsMap.get(treeItem.parentHandle));
} }
}); */ }
if (itemsToRefresh.length) {
this._onDidChange.fire(itemsToRefresh);
}
}
} else { } else {
this._onDidChange.fire(); this._onDidChange.fire();
} }
...@@ -111,33 +116,28 @@ class TreeViewDataProvider implements ITreeViewDataProvider { ...@@ -111,33 +116,28 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
this._onDispose.fire(); this._onDispose.fire();
} }
private postGetElements(parent: TreeItemHandle, children: ITreeItem[]) { private postGetElements(elements: ITreeItem[]): ITreeItem[] {
this.setElements(parent, children); const result = [];
} if (elements) {
for (const element of elements) {
private setElements(parent: TreeItemHandle, children: ITreeItem[]) { const currentTreeItem = this.itemsMap.get(element.handle);
if (children && children.length) { if (currentTreeItem) {
for (const child of children) { // Update the current item with new item
if (!this.updateTreeItem(child)) { this.updateTreeItem(currentTreeItem, element);
this.itemsMap.set(child.handle, child); } else {
this.itemsMap.set(element.handle, element);
} }
if (child.children && child.children.length) { // Always use the existing items
this.setElements(child.handle, child.children); result.push(this.itemsMap.get(element.handle));
}
}
if (parent) {
this.childrenMap.set(parent, children.map(child => child.handle));
} }
} }
return result;
} }
private updateTreeItem(treeItem: ITreeItem): ITreeItem { private updateTreeItem(current: ITreeItem, treeItem: ITreeItem): void {
const current = this.itemsMap.get(treeItem.handle);
treeItem.children = treeItem.children ? treeItem.children : null; treeItem.children = treeItem.children ? treeItem.children : null;
if (current) { if (current) {
assign(current, treeItem); assign(current, treeItem);
return current;
} }
return null;
} }
} }
\ No newline at end of file
...@@ -238,7 +238,7 @@ export interface MainThreadEditorsShape extends IDisposable { ...@@ -238,7 +238,7 @@ export interface MainThreadEditorsShape extends IDisposable {
export interface MainThreadTreeViewsShape extends IDisposable { export interface MainThreadTreeViewsShape extends IDisposable {
$registerView(treeViewId: string): void; $registerView(treeViewId: string): void;
$refresh(treeViewId: string, treeItemHandles: string[]): void; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): void;
} }
export interface MainThreadErrorsShape extends IDisposable { export interface MainThreadErrorsShape extends IDisposable {
...@@ -495,7 +495,6 @@ export interface ExtHostDocumentsAndEditorsShape { ...@@ -495,7 +495,6 @@ export interface ExtHostDocumentsAndEditorsShape {
export interface ExtHostTreeViewsShape { export interface ExtHostTreeViewsShape {
$getElements(treeViewId: string): TPromise<ITreeItem[]>; $getElements(treeViewId: string): TPromise<ITreeItem[]>;
$getChildren(treeViewId: string, treeItemHandle: string): TPromise<ITreeItem[]>; $getChildren(treeViewId: string, treeItemHandle: string): TPromise<ITreeItem[]>;
// $resolveHandles(treeViewId: string, treeItemHandles: string[]): TPromise<ITreeItem[]>;
} }
export interface ExtHostWorkspaceShape { export interface ExtHostWorkspaceShape {
......
...@@ -62,14 +62,6 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { ...@@ -62,14 +62,6 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
return treeView.getChildren(treeItemHandle); return treeView.getChildren(treeItemHandle);
} }
/* $resolveHandles(treeViewId: string, treeItemHandles: string[]): TPromise<ITreeItem[]> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
return TPromise.wrapError<ITreeItem[]>(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
}
return treeView.resolveHandles(treeItemHandles);
} */
private convertArgument(arg: TreeViewItemHandleArg): any { private convertArgument(arg: TreeViewItemHandleArg): any {
const treeView = this.treeViews.get(arg.$treeViewId); const treeView = this.treeViews.get(arg.$treeViewId);
return treeView ? treeView.getExtensionElement(arg.$treeItemHandle) : null; return treeView ? treeView.getExtensionElement(arg.$treeItemHandle) : null;
...@@ -77,6 +69,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { ...@@ -77,6 +69,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
} }
interface TreeNode { interface TreeNode {
index: number;
handle: TreeItemHandle; handle: TreeItemHandle;
parent: TreeItemHandle; parent: TreeItemHandle;
children: TreeItemHandle[]; children: TreeItemHandle[];
...@@ -84,7 +77,8 @@ interface TreeNode { ...@@ -84,7 +77,8 @@ interface TreeNode {
class ExtHostTreeView<T> extends Disposable { class ExtHostTreeView<T> extends Disposable {
private extElementsMap: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>(); private static ROOT_HANDLE = '0';
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
private nodes: Map<T, TreeNode> = new Map<T, TreeNode>(); private nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) { constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) {
...@@ -98,7 +92,7 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -98,7 +92,7 @@ class ExtHostTreeView<T> extends Disposable {
getTreeItems(): TPromise<ITreeItem[]> { getTreeItems(): TPromise<ITreeItem[]> {
this.clearAll(); this.clearAll();
return asWinJsPromise(() => this.dataProvider.getChildren()) return asWinJsPromise(() => this.dataProvider.getChildren())
.then(elements => this.resolveElements(elements, '0')); .then(elements => this.resolveElements(elements));
} }
getChildren(treeItemHandle: TreeItemHandle): TPromise<ITreeItem[]> { getChildren(treeItemHandle: TreeItemHandle): TPromise<ITreeItem[]> {
...@@ -117,34 +111,23 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -117,34 +111,23 @@ class ExtHostTreeView<T> extends Disposable {
}); });
} }
/* resolveHandles(treeItemHandles: TreeItemHandle[]): TPromise<ITreeItem[]> {
return TPromise.join(treeItemHandles.map(treeItemHandle => {
let extElement = this.getExtensionElement(treeItemHandle);
if (!extElement) {
return TPromise.wrapError<ITreeItem>(new Error(localize('treeItem.notFound', 'No tree item with id \'{0}\' found.', treeItemHandle)));
}
const node = this.nodes.get(extElement);
return this.resolveElement(extElement, node.handle);
})).then(treeItems => coalesce(treeItems));
} */
getExtensionElement(treeItemHandle: TreeItemHandle): T { getExtensionElement(treeItemHandle: TreeItemHandle): T {
return this.extElementsMap.get(treeItemHandle); return this.elements.get(treeItemHandle);
} }
private _refresh(elements: T[]): void { private _refresh(elements: T[]): void {
const hasRoot = elements.some(element => !element); const hasRoot = elements.some(element => !element);
if (hasRoot) { if (hasRoot) {
this.proxy.$refresh(this.viewId, []); this.proxy.$refresh(this.viewId);
} else { } else {
const handlesToUpdate = this.getElementsToUpdate(elements); const handlesToUpdate = this.getHandlesToUpdate(elements);
if (handlesToUpdate.length) { if (handlesToUpdate.length) {
this.proxy.$refresh(this.viewId, handlesToUpdate); this._refreshHandles(handlesToUpdate);
} }
} }
} }
private resolveElements(elements: T[], parentHandle: TreeItemHandle): TPromise<ITreeItem[]> { private resolveElements(elements: T[], parentHandle?: TreeItemHandle): TPromise<ITreeItem[]> {
if (elements && elements.length) { if (elements && elements.length) {
return TPromise.join( return TPromise.join(
elements.filter(element => !!element) elements.filter(element => !!element)
...@@ -153,11 +136,12 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -153,11 +136,12 @@ class ExtHostTreeView<T> extends Disposable {
.then(treeItem => { .then(treeItem => {
if (treeItem) { if (treeItem) {
this.nodes.set(element, { this.nodes.set(element, {
index,
handle: treeItem.handle, handle: treeItem.handle,
parent: parentHandle, parent: parentHandle,
children: void 0 children: void 0
}); });
this.extElementsMap.set(treeItem.handle, element); this.elements.set(treeItem.handle, element);
} }
return treeItem; return treeItem;
}); });
...@@ -167,7 +151,7 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -167,7 +151,7 @@ class ExtHostTreeView<T> extends Disposable {
return TPromise.as([]); return TPromise.as([]);
} }
private resolveElement(element: T, index: number, parentHandle: TreeItemHandle): TPromise<ITreeItem> { private resolveElement(element: T, index: number, parentHandle?: TreeItemHandle): TPromise<ITreeItem> {
return asWinJsPromise(() => this.dataProvider.getTreeItem(element)) return asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => this.massageTreeItem(extTreeItem, index, parentHandle)); .then(extTreeItem => this.massageTreeItem(extTreeItem, index, parentHandle));
} }
...@@ -178,7 +162,8 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -178,7 +162,8 @@ class ExtHostTreeView<T> extends Disposable {
} }
const icon = this.getLightIconPath(extensionTreeItem); const icon = this.getLightIconPath(extensionTreeItem);
return { return {
handle: `${parentHandle}/${index}:${extensionTreeItem.label}`, handle: `${parentHandle ? parentHandle : ExtHostTreeView.ROOT_HANDLE}/${index}:${extensionTreeItem.label}`,
parentHandle,
label: extensionTreeItem.label, label: extensionTreeItem.label,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0, command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
contextValue: extensionTreeItem.contextValue, contextValue: extensionTreeItem.contextValue,
...@@ -212,7 +197,7 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -212,7 +197,7 @@ class ExtHostTreeView<T> extends Disposable {
return URI.file(iconPath).toString(); return URI.file(iconPath).toString();
} }
private getElementsToUpdate(elements: T[]): TreeItemHandle[] { private getHandlesToUpdate(elements: T[]): TreeItemHandle[] {
const elementsToUpdate = new Set<TreeItemHandle>(); const elementsToUpdate = new Set<TreeItemHandle>();
for (const element of elements) { for (const element of elements) {
let elementNode = this.nodes.get(element); let elementNode = this.nodes.get(element);
...@@ -220,10 +205,10 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -220,10 +205,10 @@ class ExtHostTreeView<T> extends Disposable {
// check if an ancestor of extElement is already in the elements to update list // check if an ancestor of extElement is already in the elements to update list
let currentNode = elementNode; let currentNode = elementNode;
while (currentNode && currentNode.parent && !elementsToUpdate.has(currentNode.parent)) { while (currentNode && currentNode.parent && !elementsToUpdate.has(currentNode.parent)) {
const parentElement = this.extElementsMap.get(currentNode.parent); const parentElement = this.elements.get(currentNode.parent);
currentNode = this.nodes.get(parentElement); currentNode = this.nodes.get(parentElement);
} }
if (!currentNode) { if (!currentNode.parent) {
elementsToUpdate.add(elementNode.handle); elementsToUpdate.add(elementNode.handle);
} }
} }
...@@ -232,7 +217,7 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -232,7 +217,7 @@ class ExtHostTreeView<T> extends Disposable {
const handlesToUpdate: TreeItemHandle[] = []; const handlesToUpdate: TreeItemHandle[] = [];
// Take only top level elements // Take only top level elements
elementsToUpdate.forEach((handle) => { elementsToUpdate.forEach((handle) => {
const element = this.extElementsMap.get(handle); const element = this.elements.get(handle);
let node = this.nodes.get(element); let node = this.nodes.get(element);
if (node && !elementsToUpdate.has(node.parent)) { if (node && !elementsToUpdate.has(node.parent)) {
handlesToUpdate.push(handle); handlesToUpdate.push(handle);
...@@ -242,11 +227,49 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -242,11 +227,49 @@ class ExtHostTreeView<T> extends Disposable {
return handlesToUpdate; return handlesToUpdate;
} }
private _refreshHandles(itemHandles: TreeItemHandle[]): TPromise<void> {
const itemsToRefresh: { [handle: string]: ITreeItem } = {};
const promises: TPromise<void>[] = [];
itemHandles.forEach(treeItemHandle => {
const extElement = this.getExtensionElement(treeItemHandle);
const node = this.nodes.get(extElement);
const promise = this.resolveElement(extElement, node.index, node.parent)
.then(treeItem => {
if (treeItemHandle !== treeItem.handle) {
// Update caches if handle changes
this.updateCaches(node, treeItem, extElement);
}
itemsToRefresh[treeItemHandle] = treeItem;
});
promises.push(promise);
});
return TPromise.join(promises)
.then(treeItems => {
this.proxy.$refresh(this.viewId, itemsToRefresh);
});
}
private updateCaches(node: TreeNode, treeItem: ITreeItem, element: T): void {
if (node.parent) {
// Update parent's children handles
const parentElement = this.getExtensionElement(node.parent);
const parentNode = this.nodes.get(parentElement);
parentNode.children[node.index] = treeItem.handle;
}
// Update elements map
this.elements.delete(node.handle);
this.elements.set(treeItem.handle, element);
// Update node
node.handle = treeItem.handle;
}
private clearChildren(element: T): void { private clearChildren(element: T): void {
let node = this.nodes.get(element); let node = this.nodes.get(element);
if (node.children) { if (node.children) {
for (const childHandle of node.children) { for (const childHandle of node.children) {
const childEleement = this.extElementsMap.get(childHandle); const childEleement = this.elements.get(childHandle);
if (childEleement) { if (childEleement) {
this.clear(childEleement); this.clear(childEleement);
} }
...@@ -259,18 +282,18 @@ class ExtHostTreeView<T> extends Disposable { ...@@ -259,18 +282,18 @@ class ExtHostTreeView<T> extends Disposable {
let node = this.nodes.get(element); let node = this.nodes.get(element);
if (node.children) { if (node.children) {
for (const childHandle of node.children) { for (const childHandle of node.children) {
const childEleement = this.extElementsMap.get(childHandle); const childEleement = this.elements.get(childHandle);
if (childEleement) { if (childEleement) {
this.clear(childEleement); this.clear(childEleement);
} }
} }
} }
this.nodes.delete(element); this.nodes.delete(element);
this.extElementsMap.delete(node.handle); this.elements.delete(node.handle);
} }
private clearAll(): void { private clearAll(): void {
this.extElementsMap.clear(); this.elements.clear();
this.nodes.clear(); this.nodes.clear();
} }
......
...@@ -173,10 +173,14 @@ export class TreeView extends TreeViewsViewletPanel { ...@@ -173,10 +173,14 @@ export class TreeView extends TreeViewsViewletPanel {
} }
private refresh(elements: ITreeItem[]): void { private refresh(elements: ITreeItem[]): void {
elements = elements ? elements : [this.tree.getInput()]; if (elements) {
for (const element of elements) { for (const element of elements) {
element.children = null; this.tree.refresh(element);
this.tree.refresh(element); }
} else {
const root: ITreeItem = this.tree.getInput();
root.children = null; // reset children
this.tree.refresh(root);
} }
} }
...@@ -193,6 +197,7 @@ export class TreeView extends TreeViewsViewletPanel { ...@@ -193,6 +197,7 @@ export class TreeView extends TreeViewsViewletPanel {
class Root implements ITreeItem { class Root implements ITreeItem {
label = 'root'; label = 'root';
handle = '0'; handle = '0';
parentHandle = null;
collapsibleState = TreeItemCollapsibleState.Expanded; collapsibleState = TreeItemCollapsibleState.Expanded;
} }
......
...@@ -22,6 +22,8 @@ export interface ITreeItem { ...@@ -22,6 +22,8 @@ export interface ITreeItem {
handle: string; handle: string;
parentHandle: string;
label: string; label: string;
icon?: string; icon?: string;
......
...@@ -19,38 +19,43 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti ...@@ -19,38 +19,43 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { NoopLogService } from 'vs/platform/log/common/log'; import { NoopLogService } from 'vs/platform/log/common/log';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { TreeItemCollapsibleState } from 'vs/workbench/common/views'; import { TreeItemCollapsibleState, ITreeItem } from 'vs/workbench/common/views';
suite('ExtHostTreeView', function () { suite('ExtHostTreeView', function () {
class RecordingShape extends mock<MainThreadTreeViewsShape>() { class RecordingShape extends mock<MainThreadTreeViewsShape>() {
onRefresh = new Emitter<string[]>(); onRefresh = new Emitter<{ [treeItemHandle: string]: ITreeItem }>();
$registerView(treeViewId: string): void { $registerView(treeViewId: string): void {
} }
$refresh(viewId: string, itemHandles: string[]): void { $refresh(viewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): void {
this.onRefresh.fire(itemHandles); this.onRefresh.fire(itemsToRefresh);
} }
} }
let testObject: ExtHostTreeViews; let testObject: ExtHostTreeViews;
let target: RecordingShape; let target: RecordingShape;
let onDidChangeTreeData: Emitter<string>; let onDidChangeTreeData: Emitter<string>;
let tree = { let tree;
'a': { let labels;
'aa': {},
'ab': {}
},
'b': {
'ba': {},
'bb': {}
}
};
setup(() => { setup(() => {
tree = {
'a': {
'aa': {},
'ab': {}
},
'b': {
'ba': {},
'bb': {}
}
};
labels = {};
let threadService = new TestThreadService(); let threadService = new TestThreadService();
// Use IInstantiationService to get typechecking when instantiating // Use IInstantiationService to get typechecking when instantiating
let inst: IInstantiationService; let inst: IInstantiationService;
...@@ -102,23 +107,34 @@ suite('ExtHostTreeView', function () { ...@@ -102,23 +107,34 @@ suite('ExtHostTreeView', function () {
test('refresh root', function (done) { test('refresh root', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.equal(0, actuals.length); assert.equal(undefined, actuals);
done(); done();
}); });
onDidChangeTreeData.fire(); onDidChangeTreeData.fire();
}); });
test('refresh a parent node', function (done) { test('refresh a parent node', () => {
target.onRefresh.event(actuals => { return new TPromise((c, e) => {
assert.deepEqual(['0/1:b'], actuals); target.onRefresh.event(actuals => {
done(); assert.deepEqual(['0/1:b'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
handle: '0/1:b',
label: 'b',
});
c(null);
});
onDidChangeTreeData.fire('b');
}); });
onDidChangeTreeData.fire('b');
}); });
test('refresh a leaf node', function (done) { test('refresh a leaf node', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.deepEqual(['0/1:b/1:bb'], actuals); assert.deepEqual(['0/1:b/1:bb'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/1:b/1:bb']), {
handle: '0/1:b/1:bb',
parentHandle: '0/1:b',
label: 'bb'
});
done(); done();
}); });
onDidChangeTreeData.fire('bb'); onDidChangeTreeData.fire('bb');
...@@ -126,7 +142,16 @@ suite('ExtHostTreeView', function () { ...@@ -126,7 +142,16 @@ suite('ExtHostTreeView', function () {
test('refresh parent and child node trigger refresh only on parent - scenario 1', function (done) { test('refresh parent and child node trigger refresh only on parent - scenario 1', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.deepEqual(['0/1:b', '0/0:a/0:aa'], actuals); assert.deepEqual(['0/1:b', '0/0:a/0:aa'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
handle: '0/1:b',
label: 'b',
});
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
handle: '0/0:a/0:aa',
parentHandle: '0/0:a',
label: 'aa',
});
done(); done();
}); });
onDidChangeTreeData.fire('b'); onDidChangeTreeData.fire('b');
...@@ -136,7 +161,16 @@ suite('ExtHostTreeView', function () { ...@@ -136,7 +161,16 @@ suite('ExtHostTreeView', function () {
test('refresh parent and child node trigger refresh only on parent - scenario 2', function (done) { test('refresh parent and child node trigger refresh only on parent - scenario 2', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.deepEqual(['0/0:a/0:aa', '0/1:b'], actuals); assert.deepEqual(['0/0:a/0:aa', '0/1:b'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
handle: '0/1:b',
label: 'b',
});
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
handle: '0/0:a/0:aa',
parentHandle: '0/0:a',
label: 'aa',
});
done(); done();
}); });
onDidChangeTreeData.fire('bb'); onDidChangeTreeData.fire('bb');
...@@ -144,9 +178,22 @@ suite('ExtHostTreeView', function () { ...@@ -144,9 +178,22 @@ suite('ExtHostTreeView', function () {
onDidChangeTreeData.fire('b'); onDidChangeTreeData.fire('b');
}); });
test('refresh an element for label change', function (done) {
labels['a'] = 'aa';
target.onRefresh.event(actuals => {
assert.deepEqual(['0/0:a'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), {
handle: '0/0:aa',
label: 'aa',
});
done();
});
onDidChangeTreeData.fire('a');
});
test('refresh calls are throttled on roots', function (done) { test('refresh calls are throttled on roots', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.equal(0, actuals.length); assert.equal(undefined, actuals);
done(); done();
}); });
onDidChangeTreeData.fire(); onDidChangeTreeData.fire();
...@@ -157,7 +204,7 @@ suite('ExtHostTreeView', function () { ...@@ -157,7 +204,7 @@ suite('ExtHostTreeView', function () {
test('refresh calls are throttled on elements', function (done) { test('refresh calls are throttled on elements', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.deepEqual(['0/0:a', '0/1:b'], actuals); assert.deepEqual(['0/0:a', '0/1:b'], Object.keys(actuals));
done(); done();
}); });
...@@ -169,7 +216,7 @@ suite('ExtHostTreeView', function () { ...@@ -169,7 +216,7 @@ suite('ExtHostTreeView', function () {
test('refresh calls are throttled on unknown elements', function (done) { test('refresh calls are throttled on unknown elements', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.deepEqual(['0/0:a', '0/1:b'], actuals); assert.deepEqual(['0/0:a', '0/1:b'], Object.keys(actuals));
done(); done();
}); });
...@@ -181,7 +228,7 @@ suite('ExtHostTreeView', function () { ...@@ -181,7 +228,7 @@ suite('ExtHostTreeView', function () {
test('refresh calls are throttled on unknown elements and root', function (done) { test('refresh calls are throttled on unknown elements and root', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.equal(0, actuals.length); assert.equal(undefined, actuals);
done(); done();
}); });
...@@ -193,7 +240,7 @@ suite('ExtHostTreeView', function () { ...@@ -193,7 +240,7 @@ suite('ExtHostTreeView', function () {
test('refresh calls are throttled on elements and root', function (done) { test('refresh calls are throttled on elements and root', function (done) {
target.onRefresh.event(actuals => { target.onRefresh.event(actuals => {
assert.equal(0, actuals.length); assert.equal(undefined, actuals);
done(); done();
}); });
...@@ -203,6 +250,16 @@ suite('ExtHostTreeView', function () { ...@@ -203,6 +250,16 @@ suite('ExtHostTreeView', function () {
onDidChangeTreeData.fire('a'); onDidChangeTreeData.fire('a');
}); });
function removeUnsetKeys(obj: any): any {
const result = {};
for (const key of Object.keys(obj)) {
if (obj[key] !== void 0) {
result[key] = obj[key];
}
}
return result;
}
function aTreeDataProvider(): TreeDataProvider<string> { function aTreeDataProvider(): TreeDataProvider<string> {
const getTreeElement = (element) => { const getTreeElement = (element) => {
let parent = tree; let parent = tree;
...@@ -233,7 +290,7 @@ suite('ExtHostTreeView', function () { ...@@ -233,7 +290,7 @@ suite('ExtHostTreeView', function () {
getTreeItem: (element: string): TreeItem => { getTreeItem: (element: string): TreeItem => {
const treeElement = getTreeElement(element); const treeElement = getTreeElement(element);
return { return {
label: element, label: labels[element] || element,
collapsibleState: treeElement ? treeElement['collapsibleState'] : TreeItemCollapsibleState.Collapsed collapsibleState: treeElement ? treeElement['collapsibleState'] : TreeItemCollapsibleState.Collapsed
}; };
}, },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册