I am using TreeElement to develop an app but it always crash when TreeElement is focused. I make breakpoints according to the traceback and finally understand the infinite loop. (see wechaty/cli#9)
Tree.prototype.focus = function() {
this.rows.focus(); // this.rows: blessed.Widgets.ListElement
};
// if any element is focused
Element.prototype.focus = function() {
return this.screen.focused = this;
};
The callback of Screen.prototype.__defineSetter__('focused', el) will then call this.focusPush(el).
The last statement in focusPush() is this._focus(el, old), where old is the tail of array this.history.
The trigger of infinite loop lies in function Screen.prototype._focus():
Screen.prototype._focus = function(self, old) {
// Find a scrollable ancestor if we have one.
var el = self;
while (el = el.parent) {
if (el.scrollable) break;
}
// If we're in a scrollable element,
// automatically scroll to the focused element.
if (el && !el.detached) {
// NOTE: This is different from the other "visible" values - it needs the
// visible height of the scrolling element itself, not the element within
// it.
var visible = self.screen.height - el.atop - el.itop - el.abottom - el.ibottom;
if (self.rtop < el.childBase) {
el.scrollTo(self.rtop);
self.screen.render();
} else if (self.rtop + self.height - self.ibottom > el.childBase + visible) {
// Explanation for el.itop here: takes into account scrollable elements
// with borders otherwise the element gets covered by the bottom border:
el.scrollTo(self.rtop - (el.height - self.height) + el.itop, true);
self.screen.render();
}
}
// omitted
};
The initial value of el is still the ListElement inside TreeElement, and el.parent is the TreeElement.
I find the tree scrollable, so the while loop breaks with el = TreeElement, then screen.render() is likely to be called in the following if-statements.
screen.render() will make childrens of the screen to render, so the TreeElement will be rendered.
The if-statement in functioon Tree.prototype.render(), if evaluated true, will focus the ListElement again, which causes the infinite loop.
To sum up, tree.rows.focus() calls screen._focus(), screen._focus() will call screen.render() if tree.scrollable is true.
screen.render() calls tree.render(), tree.render() will call tree.rows.focus() again if tree.screen.focused === tree.rows, which causes the infinite loop.
The example/explorer.js will not cause infinite loop, I debug it and find tree.scrollable is undefined so it will not crash. But in my app I set the scrollable option.
if (this.screen.focused === this.rows) this.rows.focus();, this line really confused me.
I am using TreeElement to develop an app but it always crash when TreeElement is focused. I make breakpoints according to the traceback and finally understand the infinite loop. (see wechaty/cli#9)
The callback of
Screen.prototype.__defineSetter__('focused', el)
will then callthis.focusPush(el)
. The last statement infocusPush()
isthis._focus(el, old)
, whereold
is the tail of arraythis.history
.The trigger of infinite loop lies in function
Screen.prototype._focus()
:The initial value of
el
is still the ListElement inside TreeElement, andel.parent
is the TreeElement. I find the tree scrollable, so the while loop breaks withel = TreeElement
, thenscreen.render()
is likely to be called in the following if-statements.screen.render()
will make childrens of the screen to render, so the TreeElement will be rendered. The if-statement in functioonTree.prototype.render()
, if evaluated true, will focus the ListElement again, which causes the infinite loop.To sum up,
tree.rows.focus()
callsscreen._focus()
,screen._focus()
will callscreen.render()
iftree.scrollable
istrue
.screen.render()
callstree.render()
,tree.render()
will calltree.rows.focus()
again iftree.screen.focused === tree.rows
, which causes the infinite loop.The
example/explorer.js
will not cause infinite loop, I debug it and findtree.scrollable
isundefined
so it will not crash. But in my app I set the scrollable option.if (this.screen.focused === this.rows) this.rows.focus();
, this line really confused me.