better content parsing and scrolling.

This commit is contained in:
Christopher Jeffrey 2013-06-09 20:19:32 -05:00
parent c260bb9a02
commit ee739c6e7a
1 changed files with 91 additions and 98 deletions

View File

@ -826,6 +826,19 @@ Box.prototype.render = function(stop) {
dattr = ((this.bold << 18) + (this.underline << 18)) | (this.fg << 9) | this.bg; dattr = ((this.bold << 18) + (this.underline << 18)) | (this.fg << 9) | this.bg;
attr = dattr; attr = dattr;
// Check previous line for escape codes.
if (this.childBase > 0 && this.content != null) {
var cci = ci - (this._content[this.childBase - 1].length + 1);
for (; cci < ci; cci++) {
if (this.content[cci] === '\x1b') {
if (c = /^\x1b\[(?:\d+(?:;\d+)*)?m/.exec(this.content.substring(cci))) {
attr = attrCode(c[0], attr);
cci += c[0].length - 1;
}
}
}
}
for (; yi < yl; yi++) { for (; yi < yl; yi++) {
if (!lines[yi]) break; if (!lines[yi]) break;
for (xi = this.left; xi < xl; xi++) { for (xi = this.left; xi < xl; xi++) {
@ -1265,7 +1278,12 @@ ScrollableText.prototype._scroll = ScrollableText.prototype.scroll;
ScrollableText.prototype.scroll = function(offset) { ScrollableText.prototype.scroll = function(offset) {
var base = this.childBase var base = this.childBase
, ret = this._scroll(offset) , ret = this._scroll(offset)
, diff = this.childBase - base; , cb = this.childBase
, diff = cb - base
, w
, i
, max
, t;
if (diff === 0) { if (diff === 0) {
return ret; return ret;
@ -1275,107 +1293,37 @@ ScrollableText.prototype.scroll = function(offset) {
// feeds. This allows us to take preformatted text output from other programs // feeds. This allows us to take preformatted text output from other programs
// and put it in a scrollable text box. // and put it in a scrollable text box.
if (this.content != null) { if (this.content != null) {
var cb = this.childBase w = this.width - (this.border ? 2 : 0);
, data = this.render(true) || 0 if (this.__content == null) this.__content = this.content;
, xi = data.xi if (this._content == null || this._content.width !== w) {
, xl = data.xl this._content = wrapContent(this.__content, w);
, xxl = xl - (this.border ? 1 : 0) this.content = this._content.join('\n');
, xxi
, ci = 0
, xxxi
, cci;
// XXX Temporary workaround for .render() not working while hidden.
if (!data) return ret;
if (this.contentIndex != null) {
ci = this.contentIndex;
cb = diff;
// Scroll up.
// This is confusing because we have to parse the
// text backwards if we want to be efficient instead
// of being O(ridiculous).
// TODO: Remove code duplication.
if (cb < 0) {
cb = -cb;
while (cb--) {
if (ci < 0) break;
for (xxi = xi + (this.border ? 1 : 0); xxi < xxl; xxi++) {
if (this.content[ci] === '\n' || this.content[ci] === '\r') {
ci--;
// TODO: Come up with a cleaner way of doing this:
for (xxxi = xi + (this.border ? 1 : 0); xxxi < xxl; xxxi++) {
if (this.content[ci] === '\n' || this.content[ci] === '\r') {
ci++;
break;
} else if (this.content[ci] === 'm') {
for (cci = ci - 1; cci >= 0; cci--) {
if (/[^\x1b\[\d;]/.test(this.content[cci])) {
break;
}
if (this.content[cci] === '\x1b') {
xxxi -= (ci - cci);
ci = cci;
break;
}
}
ci--;
} else {
ci--;
}
}
break;
} else if (this.content[ci] === 'm') {
for (cci = ci - 1; cci >= 0; cci--) {
if (/[^\x1b\[\d;]/.test(this.content[cci])) {
break;
}
if (this.content[cci] === '\x1b') {
xxi -= (ci - cci);
ci = cci;
break;
}
}
ci--;
} else {
ci--;
}
}
}
if (ci < 0) ci = 0;
this.contentIndex = ci;
return ret;
}
} }
// Scroll down. // Slow:
while (cb--) { // this.contentIndex = this._content.slice(0, cb).join('\n').length;
for (xxi = xi + (this.border ? 1 : 0); xxi < xxl; xxi++) { // if (cb > 0) this.contentIndex++;
if (this.content[ci] === '\n' || this.content[ci] === '\r') {
ci++; // Less slow:
break; //this.contentIndex = this._content.slice(0, cb).reduce(function(total, line) {
} else if (this.content[ci] === '\x1b') { // return total + line.length + 1;
for (; ci < this.content.length; ci++) { //}, 0);
xxi--;
if (this.content[ci] === 'm') break; // Fast:
} //for (i = 0, t = 0; i < cb; i++) {
ci++; // t += this._content[i].length + 1;
} else { //}
ci++; //this.contentIndex = t;
}
} // Faster:
if (diff > 0) {
for (i = base; i < cb; i++) this.contentIndex += this._content[i].length + 1;
} else {
for (i = base - 1; i >= cb; i--) this.contentIndex -= this._content[i].length + 1;
} }
// TODO: Parse the last few lines to see how max = this._content.length - 1 - (this.height - (this.border ? 2 : 0));
// many characters we need to subtract. if (cb > max) this.childBase = max;
if (ci >= this.content.length) {
if (this.contentIndex >= this.content.length) {
this.childBase = base;
}
ci = this.content.length;
}
this.contentIndex = ci;
} }
return ret; return ret;
@ -1677,6 +1625,51 @@ function readEditor(callback) {
}); });
} }
function wrapContent(content, width) {
var lines = content.split('\n')
, out = [];
lines.forEach(function(line) {
var total
, i
, part
, esc;
while (line.length > width) {
for (i = 0, total = 0; i < line.length; i++) {
while (line[i] === '\x1b') {
while (line[i] && line[i++] !== 'm');
}
if (!line[i]) break;
if (++total === width) break;
}
part = line.substring(0, i - 1);
esc = /\x1b[\[\d;]*$/.exec(part);
if (esc) {
part = part.slice(0, -esc[0].length);
line = line.substring(i - 1 - esc[0].length);
out.push(part);
} else {
line = line.substring(i - 1);
out.push(part);
}
}
// If only an escape code got cut off, at it to `part`.
if (/^(?:\x1b[\[\d;]*m)+$/.test(line)) {
out[out.length-1] += line;
return;
}
out.push(line);
});
out.width = width;
return out;
}
/** /**
* Constants * Constants
*/ */