better content parsing and scrolling.
This commit is contained in:
parent
c260bb9a02
commit
ee739c6e7a
187
lib/widget.js
187
lib/widget.js
|
@ -826,6 +826,19 @@ Box.prototype.render = function(stop) {
|
|||
dattr = ((this.bold << 18) + (this.underline << 18)) | (this.fg << 9) | this.bg;
|
||||
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++) {
|
||||
if (!lines[yi]) break;
|
||||
for (xi = this.left; xi < xl; xi++) {
|
||||
|
@ -1265,7 +1278,12 @@ ScrollableText.prototype._scroll = ScrollableText.prototype.scroll;
|
|||
ScrollableText.prototype.scroll = function(offset) {
|
||||
var base = this.childBase
|
||||
, ret = this._scroll(offset)
|
||||
, diff = this.childBase - base;
|
||||
, cb = this.childBase
|
||||
, diff = cb - base
|
||||
, w
|
||||
, i
|
||||
, max
|
||||
, t;
|
||||
|
||||
if (diff === 0) {
|
||||
return ret;
|
||||
|
@ -1275,107 +1293,37 @@ ScrollableText.prototype.scroll = function(offset) {
|
|||
// feeds. This allows us to take preformatted text output from other programs
|
||||
// and put it in a scrollable text box.
|
||||
if (this.content != null) {
|
||||
var cb = this.childBase
|
||||
, data = this.render(true) || 0
|
||||
, xi = data.xi
|
||||
, xl = data.xl
|
||||
, xxl = xl - (this.border ? 1 : 0)
|
||||
, xxi
|
||||
, ci = 0
|
||||
, xxxi
|
||||
, cci;
|
||||
w = this.width - (this.border ? 2 : 0);
|
||||
if (this.__content == null) this.__content = this.content;
|
||||
if (this._content == null || this._content.width !== w) {
|
||||
this._content = wrapContent(this.__content, w);
|
||||
this.content = this._content.join('\n');
|
||||
}
|
||||
|
||||
// XXX Temporary workaround for .render() not working while hidden.
|
||||
if (!data) return ret;
|
||||
// Slow:
|
||||
// this.contentIndex = this._content.slice(0, cb).join('\n').length;
|
||||
// if (cb > 0) this.contentIndex++;
|
||||
|
||||
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--;
|
||||
// Less slow:
|
||||
//this.contentIndex = this._content.slice(0, cb).reduce(function(total, line) {
|
||||
// return total + line.length + 1;
|
||||
//}, 0);
|
||||
|
||||
// Fast:
|
||||
//for (i = 0, t = 0; i < cb; i++) {
|
||||
// t += this._content[i].length + 1;
|
||||
//}
|
||||
//this.contentIndex = t;
|
||||
|
||||
// Faster:
|
||||
if (diff > 0) {
|
||||
for (i = base; i < cb; i++) this.contentIndex += this._content[i].length + 1;
|
||||
} 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;
|
||||
}
|
||||
for (i = base - 1; i >= cb; i--) this.contentIndex -= this._content[i].length + 1;
|
||||
}
|
||||
|
||||
// Scroll down.
|
||||
while (cb--) {
|
||||
for (xxi = xi + (this.border ? 1 : 0); xxi < xxl; xxi++) {
|
||||
if (this.content[ci] === '\n' || this.content[ci] === '\r') {
|
||||
ci++;
|
||||
break;
|
||||
} else if (this.content[ci] === '\x1b') {
|
||||
for (; ci < this.content.length; ci++) {
|
||||
xxi--;
|
||||
if (this.content[ci] === 'm') break;
|
||||
}
|
||||
ci++;
|
||||
} else {
|
||||
ci++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Parse the last few lines to see how
|
||||
// many characters we need to subtract.
|
||||
if (ci >= this.content.length) {
|
||||
if (this.contentIndex >= this.content.length) {
|
||||
this.childBase = base;
|
||||
}
|
||||
ci = this.content.length;
|
||||
}
|
||||
|
||||
this.contentIndex = ci;
|
||||
max = this._content.length - 1 - (this.height - (this.border ? 2 : 0));
|
||||
if (cb > max) this.childBase = max;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue