提交 94343c80 编写于 作者: J Joao Moreno

use iterators in tree model

上级 66d7ae89
......@@ -6,13 +6,17 @@
'use strict';
import { ISpliceable } from 'vs/base/common/sequence';
import { Tree } from 'vs/base/common/tree';
import { tail2 } from 'vs/base/common/arrays';
import { Trie } from 'vs/base/browser/ui/list/trie';
import { IIterator, map, collect, forEach, iter } from 'vs/base/common/iterator';
/**
* TODO:
* remove trie
* remote base tree
*/
export interface ITreeElement<T> {
readonly element: T;
readonly children: ITreeElement<T>[];
readonly children: IIterator<ITreeElement<T>>;
}
export interface ITreeListElement<T> {
......@@ -22,8 +26,8 @@ export interface ITreeListElement<T> {
class TreeNode<T> implements ITreeListElement<T> {
static createRoot<T>(): TreeNode<T> {
const node = new TreeNode<T>();
static createRoot<T>(element: T): TreeNode<T> {
const node = new TreeNode<T>(element);
node.children = [];
node.count = 1;
node.depth = 0;
......@@ -31,19 +35,18 @@ class TreeNode<T> implements ITreeListElement<T> {
}
static createNode<T>(treeElement: ITreeElement<T>, depth: number, list: ITreeListElement<T>[]): TreeNode<T> {
const node = new TreeNode<T>();
const node = new TreeNode<T>(treeElement.element);
list.push(node);
let count = 1;
const children: TreeNode<T>[] = [];
for (const childItem of treeElement.children) {
const node = TreeNode.createNode<T>(childItem, depth + 1, list);
forEach(treeElement.children, child => {
const node = TreeNode.createNode<T>(child, depth + 1, list);
children.push(node);
count += node.count;
}
});
node.element = treeElement.element;
node.children = children;
node.count = count;
node.depth = depth;
......@@ -51,20 +54,18 @@ class TreeNode<T> implements ITreeListElement<T> {
return node;
}
element: T;
children: TreeNode<T>[];
count: number;
depth: number;
private constructor() { }
private constructor(public element: T) { }
splice(index: number, deleteCount: number, treeElements: ITreeElement<T>[]): { listDeleteCount: number; listElements: ITreeListElement<T>[]; deletedNodes: TreeNode<T>[]; } {
splice(index: number, deleteCount: number, toInsert: IIterator<ITreeElement<T>>): { listDeleteCount: number; listElements: ITreeListElement<T>[]; deletedNodes: TreeNode<T>[]; } {
const listElements = [] as ITreeListElement<T>[];
const added = treeElements.map(e => TreeNode.createNode<T>(e, this.depth + 1, listElements));
const listAddCount = added.reduce((r, n) => r + n.count, 0);
const deletedNodes = this.children.splice(index, deleteCount, ...added);
const nodesToInsert = collect(map(toInsert, e => TreeNode.createNode<T>(e, this.depth + 1, listElements)));
const listAddCount = nodesToInsert.reduce((r, n) => r + n.count, 0);
const deletedNodes = this.children.splice(index, deleteCount, ...nodesToInsert);
const listDeleteCount = deletedNodes.reduce((r, n) => r + n.count, 0);
this.count += listAddCount - listDeleteCount;
......@@ -72,24 +73,31 @@ class TreeNode<T> implements ITreeListElement<T> {
}
}
function asTreeElement<T>(node: TreeNode<T>): ITreeElement<T> {
return {
element: node.element,
children: map(iter(node.children), asTreeElement)
};
}
export class TreeModel<T> {
private root = TreeNode.createRoot<T>();
private root = TreeNode.createRoot<T>(undefined);
constructor(private spliceable: ISpliceable<ITreeListElement<T>>) { }
splice(start: number[], deleteCount: number, elements: ITreeElement<T>[] = []): ITreeElement<T>[] {
splice(start: number[], deleteCount: number, toInsert: IIterator<ITreeElement<T>>): IIterator<ITreeElement<T>> {
if (start.length === 0) {
throw new Error('Invalid tree location');
}
const { parentNode, parentListIndex } = this.findParentNode(start);
const lastIndex = start[start.length - 1];
const { listDeleteCount, listElements, deletedNodes } = parentNode.splice(lastIndex, deleteCount, elements);
const { listDeleteCount, listElements, deletedNodes } = parentNode.splice(lastIndex, deleteCount, toInsert);
this.spliceable.splice(parentListIndex + lastIndex, listDeleteCount, listElements);
return deletedNodes;
return map(iter(deletedNodes), asTreeElement);
}
private findParentNode(location: number[], node: TreeNode<T> = this.root, listIndex: number = 0): { parentNode: TreeNode<T>; parentListIndex: number } {
......@@ -108,61 +116,3 @@ export class TreeModel<T> {
return this.findParentNode(rest, node.children[i], listIndex + 1);
}
}
export interface ICollapsibleTreeElement<T> {
element: T;
collapsed: boolean;
}
export class CollapsibleTreeModel<T> {
private model = new Tree<ICollapsibleTreeElement<T>>();
private collapsedElements = new Trie<number, ITreeElement<T>>();
private visibleModel: TreeModel<T>;
constructor(spliceable: ISpliceable<ITreeListElement<T>>) {
this.visibleModel = new TreeModel<T>(spliceable);
}
splice(start: number[], deleteCount: number, items: ITreeElement<ICollapsibleTreeElement<T>>[]): void {
// const elementPath = this.model.getElementPath(start);
this.model.splice(start, deleteCount, items);
// this.visibleModel.splice(start, deleteCount, items);
}
setCollapsed(location: number[], collapsed: boolean): void {
const elementPath = this.model.getElementPath(location);
const [pathToElement, collapsibleElement] = tail2(elementPath);
if (collapsibleElement.collapsed === collapsed) {
return;
}
collapsibleElement.collapsed = collapsed;
if (pathToElement.some(e => e.collapsed)) {
return;
}
if (collapsed) {
const collapsedElement: ITreeElement<T> = {
element: collapsibleElement.element,
children: []
};
const [element] = this.visibleModel.splice(location, 1, [collapsedElement]);
this.collapsedElements.set(location, element);
} else {
const expandedElement = this.collapsedElements.delete(location);
this.visibleModel.splice(location, 1, [expandedElement]);
}
// gotta reflect the state on the visibleModel
}
isCollapsed(location: number[]): boolean {
return this.model.getElement(location).collapsed;
}
}
\ No newline at end of file
......@@ -10,8 +10,43 @@ export interface IIteratorResult<T> {
readonly value: T | undefined;
}
export interface IIterator<E> {
next(): IIteratorResult<E>;
export interface IIterator<T> {
next(): IIteratorResult<T>;
}
export function iter<T>(array: T[]): IIterator<T> {
let index = 0;
return {
next(): IIteratorResult<T> {
if (index === array.length) {
return { done: true, value: undefined };
}
return { done: false, value: array[index++] };
}
};
}
export function map<T, R>(iterator: IIterator<T>, fn: (t: T) => R): IIterator<R> {
return {
next() {
const { done, value } = iterator.next();
return { done, value: done ? undefined : fn(value) };
}
};
}
export function forEach<T>(iterator: IIterator<T>, fn: (t: T) => void): void {
for (let next = iterator.next(); !next.done; next = iterator.next()) {
fn(next.value);
}
}
export function collect<T>(iterator: IIterator<T>): T[] {
const result: T[] = [];
forEach(iterator, value => result.push(value));
return result;
}
export interface INextIterator<T> {
......
......@@ -6,6 +6,7 @@
import * as assert from 'assert';
import { TreeModel, ITreeListElement } from 'vs/base/browser/ui/list/treeModel';
import { ISpliceable } from 'vs/base/browser/ui/list/splice';
import { iter } from 'vs/base/common/iterator';
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
return {
......@@ -28,11 +29,11 @@ suite('TreeModel2', () => {
const list = [] as ITreeListElement<number>[];
const model = new TreeModel<number>(toSpliceable(list));
model.splice([0], 0, [
{ element: 0, children: [] },
{ element: 1, children: [] },
{ element: 2, children: [] }
]);
model.splice([0], 0, iter([
{ element: 0, children: iter([]) },
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
assert.deepEqual(list.length, 3);
assert.deepEqual(list[0].element, 0);
......@@ -47,17 +48,17 @@ suite('TreeModel2', () => {
const list = [] as ITreeListElement<number>[];
const model = new TreeModel<number>(toSpliceable(list));
model.splice([0], 0, [
model.splice([0], 0, iter([
{
element: 0, children: [
{ element: 10, children: [] },
{ element: 11, children: [] },
{ element: 12, children: [] },
]
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: [] },
{ element: 2, children: [] }
]);
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
assert.deepEqual(list.length, 6);
assert.deepEqual(list[0].element, 0);
......@@ -78,13 +79,13 @@ suite('TreeModel2', () => {
const list = [] as ITreeListElement<number>[];
const model = new TreeModel<number>(toSpliceable(list));
model.splice([0], 0, [
{ element: 0, children: [] },
{ element: 1, children: [] },
{ element: 2, children: [] }
]);
model.splice([0], 0, iter([
{ element: 0, children: iter([]) },
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
model.splice([0], 3, []);
model.splice([0], 3, iter([]));
assert.equal(list.length, 0);
});
......@@ -93,19 +94,19 @@ suite('TreeModel2', () => {
const list = [] as ITreeListElement<number>[];
const model = new TreeModel<number>(toSpliceable(list));
model.splice([0], 0, [
model.splice([0], 0, iter([
{
element: 0, children: [
{ element: 10, children: [] },
{ element: 11, children: [] },
{ element: 12, children: [] },
]
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: [] },
{ element: 2, children: [] }
]);
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
model.splice([0, 1], 1, []);
model.splice([0, 1], 1, iter([]));
assert.deepEqual(list.length, 5, 'list has 5 elements');
assert.deepEqual(list[0].element, 0);
......@@ -124,19 +125,19 @@ suite('TreeModel2', () => {
const list = [] as ITreeListElement<number>[];
const model = new TreeModel<number>(toSpliceable(list));
model.splice([0], 0, [
model.splice([0], 0, iter([
{
element: 0, children: [
{ element: 10, children: [] },
{ element: 11, children: [] },
{ element: 12, children: [] },
]
element: 0, children: iter([
{ element: 10, children: iter([]) },
{ element: 11, children: iter([]) },
{ element: 12, children: iter([]) },
])
},
{ element: 1, children: [] },
{ element: 2, children: [] }
]);
{ element: 1, children: iter([]) },
{ element: 2, children: iter([]) }
]));
model.splice([0], 1, []);
model.splice([0], 1, iter([]));
assert.deepEqual(list.length, 2, 'list has 2 elements only');
assert.deepEqual(list[0].element, 1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册