未验证 提交 e0667816 编写于 作者: J Joao Moreno

fixes #81393

上级 9bc1083d
......@@ -225,18 +225,14 @@ interface Collection<T> {
class EventCollection<T> implements Collection<T> {
private disposables = new DisposableStore();
readonly onDidChange: Event<T[]>;
get elements(): T[] {
return this._elements;
}
constructor(readonly onDidChange: Event<T[]>, private _elements: T[] = []) {
onDidChange(e => this._elements = e, null, this.disposables);
}
dispose() {
this.disposables.dispose();
constructor(onDidChange: Event<T[]>, private _elements: T[] = []) {
this.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements);
}
}
......@@ -249,7 +245,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
private renderedNodes = new Map<ITreeNode<T, TFilterData>, IRenderData<TTemplateData>>();
private indent: number = TreeRenderer.DefaultIndent;
private _renderIndentGuides: RenderIndentGuides = RenderIndentGuides.None;
private shouldRenderIndentGuides: boolean = false;
private renderedIndentGuides = new SetMap<ITreeNode<T, TFilterData>, HTMLDivElement>();
private activeIndentNodes = new Set<ITreeNode<T, TFilterData>>();
private indentGuidesDisposable: IDisposable = Disposable.None;
......@@ -279,19 +275,18 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
if (typeof options.renderIndentGuides !== 'undefined') {
const renderIndentGuides = options.renderIndentGuides;
const shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None;
if (renderIndentGuides !== this._renderIndentGuides) {
this._renderIndentGuides = renderIndentGuides;
if (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) {
this.shouldRenderIndentGuides = shouldRenderIndentGuides;
this.indentGuidesDisposable.dispose();
if (renderIndentGuides) {
if (shouldRenderIndentGuides) {
const disposables = new DisposableStore();
this.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables);
this.indentGuidesDisposable = disposables;
this._onDidChangeActiveNodes(this.activeNodes.elements);
} else {
this.indentGuidesDisposable.dispose();
}
}
}
......@@ -384,7 +379,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
clearNode(templateData.indent);
templateData.indentGuidesDisposable.dispose();
if (this._renderIndentGuides === RenderIndentGuides.None) {
if (!this.shouldRenderIndentGuides) {
return;
}
......@@ -424,7 +419,7 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
}
private _onDidChangeActiveNodes(nodes: ITreeNode<T, TFilterData>[]): void {
if (this._renderIndentGuides === RenderIndentGuides.None) {
if (!this.shouldRenderIndentGuides) {
return;
}
......@@ -1001,7 +996,6 @@ class Trait<T> {
insertedNodes.forEach(node => dfs(node, insertedNodesVisitor));
const nodes: ITreeNode<T, any>[] = [];
let silent = true;
for (const node of this.nodes) {
const id = this.identityProvider.getId(node.element).toString();
......@@ -1014,13 +1008,11 @@ class Trait<T> {
if (insertedNode) {
nodes.push(insertedNode);
} else {
silent = false;
}
}
}
this._set(nodes, silent);
this._set(nodes, true);
}
private createNodeSet(): Set<ITreeNode<T, any>> {
......@@ -1228,9 +1220,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const treeDelegate = new ComposedTreeDelegate<T, ITreeNode<T, TFilterData>>(delegate);
const onDidChangeCollapseStateRelay = new Relay<ICollapseStateChangeEvent<T, TFilterData>>();
const onDidChangeActiveNodes = new Emitter<ITreeNode<T, TFilterData>[]>();
const onDidChangeActiveNodes = new Relay<ITreeNode<T, TFilterData>[]>();
const activeNodes = new EventCollection(onDidChangeActiveNodes.event);
this.disposables.push(activeNodes);
this.renderers = renderers.map(r => new TreeRenderer<T, TFilterData, TRef, any>(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, _options));
this.disposables.push(...this.renderers);
......@@ -1250,24 +1241,32 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model = this.createModel(user, this.view, _options);
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
this.model.onDidSplice(e => {
const onDidModelSplice = Event.forEach(this.model.onDidSplice, e => {
this.eventBufferer.bufferEvents(() => {
this.focus.onDidModelSplice(e);
this.selection.onDidModelSplice(e);
});
});
const set = new Set<ITreeNode<T, TFilterData>>();
for (const node of this.focus.getNodes()) {
set.add(node);
}
// Active nodes can change when the model changes or when focus or selection change.
// We debouce it with 0 delay since these events may fire in the same stack and we only
// want to run this once. It also doesn't matter if it runs on the next tick since it's only
// a nice to have UI feature.
onDidChangeActiveNodes.input = Event.chain(Event.any<any>(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange))
.debounce(() => null, 0)
.map(() => {
const set = new Set<ITreeNode<T, TFilterData>>();
for (const node of this.focus.getNodes()) {
set.add(node);
}
for (const node of this.selection.getNodes()) {
set.add(node);
}
for (const node of this.selection.getNodes()) {
set.add(node);
}
onDidChangeActiveNodes.fire(fromSet(set));
}, null, this.disposables);
return fromSet(set);
}).event;
if (_options.keyboardSupport !== false) {
const onKeyDown = Event.chain(this.view.onKeyDown)
......
......@@ -271,6 +271,8 @@ export namespace Event {
filter(fn: (e: T) => boolean): IChainableEvent<T>;
reduce<R>(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent<R>;
latch(): IChainableEvent<T>;
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<R>;
on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
}
......@@ -299,6 +301,12 @@ export namespace Event {
return new ChainableEvent(latch(this.event));
}
debounce(merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<T>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay?: number, leading?: boolean, leakWarningThreshold?: number): IChainableEvent<R>;
debounce<R>(merge: (last: R | undefined, event: T) => R, delay: number = 100, leading = false, leakWarningThreshold?: number): IChainableEvent<R> {
return new ChainableEvent(debounce(this.event, merge, delay, leading, leakWarningThreshold));
}
on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[] | DisposableStore) {
return this.event(listener, thisArgs, disposables);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册