work on adding back_color_erase handling, acs optimization, and other stuff ncurses usually handles.

This commit is contained in:
Christopher Jeffrey 2013-07-21 21:00:13 -05:00
parent de79656b04
commit 00e680d413
3 changed files with 243 additions and 3 deletions

View File

@ -1105,6 +1105,63 @@ Program.prototype.response = function(name, text, callback) {
return this.write(text);
};
Program.prototype._wrapCursor = function(nl) {
if (this.tput) {
//if (this.tput.bools.eat_newline_glitch) {
// return;
//}
if (this.tput.bools.auto_right_margin) {
this.x = 0;
this.y++;
return;
}
this.x--;
return;
}
this.x = 0;
this.y++;
};
// TODO: Make a private write for all of the methods here
// which does not call _parseChar. Make public write call
// _parseChar.
Program.prototype._parseChar = function(text, attr) {
for (var i = 0; i < text.length; i++) {
var cs = false;
while (text[i] === '\x1b') {
i++;
if (text[i] === '[' || text === ']') {
cs = true;
continue;
}
if (cs && (text[i] === ';' || (text[i] >= '0' && text[i] <= '9'))) {
continue;
}
if (text[i] === '\\' && text[i + 1] === '\x1b') i++;
i++;
cs = false;
break;
}
if (text[i] === '\n') {
if (this.tput
&& this.tput.bools.eat_newline_glitch
&& this.x >= this.cols) {
;
} else {
this.x = 0;
this.y++;
}
} else if (text[i] === '\r') {
this.x = 0;
} else {
this.x++;
if (this.x >= this.width) {
this._wrapCursor();
}
}
}
};
Program.prototype.write =
Program.prototype.echo = function(text, attr) {
// if (this.output === process.stdout) {
@ -1261,6 +1318,9 @@ Program.prototype.return = function() {
Program.prototype.nel =
Program.prototype.newline =
Program.prototype.feed = function() {
if (this.tput && this.tput.bools.eat_newline_glitch && this.x >= this.width) {
return;
}
this.x = 0;
this.y++;
this._ncoords();

View File

@ -677,6 +677,64 @@ Screen.prototype.deleteLine = function(n, y, top, bottom) {
}
};
// This is how ncurses does it.
// Scroll down (up cursor-wise).
// This will only work for top line deletion as opposed to arbitrary lines.
Screen.prototype.insertLineNC = function(n, y, top, bottom) {
if (!this.tput
|| !this.tput.strings.change_scroll_region
|| !this.tput.strings.delete_line
|| !this.tput.strings.insert_line) return;
if (y !== top) return this.insertLine.apply(this, arguments);
this.program.sc();
this.program.csr(top, bottom);
this.program.cup(top, 0);
this.program.dl(n);
this.program.csr(0, this.height - 1);
// this.program.cup(top, 0);
this.program.rc();
var j = bottom + 1;
while (n--) {
this.lines.splice(j, 0, this.blankLine());
this.lines.splice(y, 1);
this.olines.splice(j, 0, this.blankLine());
this.olines.splice(y, 1);
}
};
// This is how ncurses does it.
// Scroll up (down cursor-wise).
// This will only work for bottom line deletion as opposed to arbitrary lines.
Screen.prototype.deleteLineNC = function(n, y, top, bottom) {
if (!this.tput
|| !this.tput.strings.change_scroll_region
|| !this.tput.strings.delete_line
|| !this.tput.strings.insert_line) return;
if (y !== bottom) return this.deleteLine.apply(this, arguments);
this.program.sc();
this.program.csr(top, bottom);
this.program.cup(bottom, 0);
this.program.write(Array(n + 1).join('\n'));
this.program.csr(0, this.height - 1);
// this.program.cup(bottom - 1, 0);
this.program.rc();
var j = bottom + 1;
while (n--) {
this.lines.splice(j, 0, this.blankLine());
this.lines.splice(y, 1);
this.olines.splice(j, 0, this.blankLine());
this.olines.splice(y, 1);
}
};
Screen.prototype.insertBottom = function(top, bottom) {
return this.deleteLine(1, top, top, bottom);
};
@ -768,12 +826,18 @@ Screen.prototype.draw = function(start, end) {
, attr
, fg
, bg
, flags;
, flags
, acs
, bc;
var lx = -1
, ly = -1
, o;
var bcx = -1
, bcy = -1
, bca = -1;
// var cx = this.program.x
// , cy = this.program.y
// , ch = this.program.cursorHidden;
@ -797,6 +861,65 @@ Screen.prototype.draw = function(start, end) {
data = line[x][0];
ch = line[x][1];
// Take advantage of xterm's back_color_erase
// feature by using a lookahead.
if (this.tput.bools.back_color_erase && ch === ' ' && line[x + 1]) {
var ne = false
, cl = true;
for (var xi = x; xi < this.cols; xi++) {
if (line[xi][0] !== data || line[xi][1] !== ' ') {
cl = false;
break;
}
if (line[xi][0] !== o[xi][0] || line[xi][1] !== o[xi][1]) {
ne = true;
}
}
if (cl && ne) {
if (data !== attr) {
out += this.codeAttr(data);
attr = data;
}
out += this.tput.el(0);
for (var xi = x; xi < this.cols; xi++) {
o[xi][0] = data;
o[xi][1] = ' ';
}
break;
}
// comment the break in the first xi loop above for this to work.
// if (!ne) {
// attr = data;
// break;
// }
}
// Take advantage of xterm's back_color_erase feature.
// Stop spitting out so many damn spaces.
if (0) if (this.tput.bools.back_color_erase) {
if (ch === ' ' && (bca === -1 || bca === data)) {
if (bcy === -1) {
bcx = x;
bcy = y;
bca = data;
}
//ch = '';
} else if (bcy !== -1) {
// If it's more than ten spaces, just EL and jump forward.
// Might break things since it could alter the output buffer.
// out += x - bcx > 10
// ? this.tput.el(0) + this.tput.cuf(x - bcx)
// : Array((x - bcx) + 1).join(' ');
out += Array((x - bcx) + 1).join(' ');
bcx = -1, bcy = -1, bca = -1;
}
}
// Optimize by comparing the real output
// buffer to the pending output buffer.
if (data === o[x][0] && ch === o[x][1]) {
if (lx === -1) {
lx = x;
@ -890,6 +1013,7 @@ Screen.prototype.draw = function(start, end) {
}
}
/*
// Attempt to use ACS for supported characters.
// This is not ideal, but it's how ncurses works.
// There are a lot of terminals that support ACS
@ -929,15 +1053,50 @@ Screen.prototype.draw = function(start, end) {
// ch = this.tput.utoa[ch] || '?';
// }
}
*/
if (this.tput.strings.enter_alt_charset_mode) {
if (!this.tput.brokenACS || !this.tput.unicode) {
if (this.tput.acscr[ch]) {
if (acs) {
ch = this.tput.acscr[ch];
} else {
ch = this.tput.smacs()
+ this.tput.acscr[ch]
acs = true;
}
} else if (acs) {
ch = this.tput.rmacs() + ch;
acs = false;
}
}
} else {
// if (this.program.term('sun') && ch > '~') {
// if (this.tput.numbers.U8 !== 1 && ch > '~') {
if (this.tput.numbers.U8 !== 1 && this.utoa[ch]) {
ch = this.tput.utoa[ch] || '?';
}
}
if (0) if (bcy !== -1) ch = '';
out += ch;
attr = data;
}
if (0) if (bcy !== -1) {
out += this.tput.el(0);
bcx = -1, bcy = -1, bca = -1;
}
if (attr !== this.dattr) {
out += '\x1b[m';
}
//if (this.tput.bools.back_color_erase && out && lx === -1) {
// out = this._replaceSpaces(out);
//}
if (this.tput) {
if (out) this.program.write(this.tput.cup(y, 0) + out);
} else {
@ -951,6 +1110,27 @@ Screen.prototype.draw = function(start, end) {
this.program.restoreCursor();
};
Screen.prototype._replaceSpaces = function(out) {
if (!this._sr) this._sr = this._spaceReplacer.bind(this);
return out.replace(/ {5,}/g, this._sr);
};
Screen.prototype._spaceReplacer = function(ch) {
return this.tput.el(0) + this.tput.cuf(ch.length);
};
Screen.prototype._replaceSpaces = function(out) {
if (!this._sr) this._sr = this._spaceReplacer.bind(this);
// / +(?=(?:\x1b\[m)?(?:\x1b\[[\d;]*H|$))/g,
return out.replace(
/ {5,}(?=(?:\x1b\[[\d;]*m)*(?:\x1b\[[\d;]*H|$))/g,
this._sr);
};
Screen.prototype._spaceReplacer = function(ch) {
return this.tput.el(0);
};
Screen.prototype._reduceColor = function(col) {
if (this.tput) {
if (col >= 16 && this.tput.colors <= 16) {
@ -1633,7 +1813,7 @@ Element.prototype._focus = function() {
, visible = el.height - el.iheight;
if (ryi < el.childBase) {
el.scrollTo(ryi - 0);
el.scrollTo(ryi);
this.screen.render();
} else if (ryi >= el.childBase + visible) {
el.scrollTo(ryi);

View File

@ -12,7 +12,7 @@ var form = blessed.form({
height: 12,
bg: 'green',
content: 'foobar',
border: {
border_: {
type: 'ch',
ch: ' ',
style: { inverse: true }