mirror of
https://github.com/embarklabs/neo-blessed.git
synced 2025-01-10 19:16:20 +00:00
fix terminfo if/else. detect features.
This commit is contained in:
parent
342ed23b66
commit
363bc44caa
@ -54,8 +54,6 @@ function Program(options) {
|
||||
|
||||
this.terminal = options.terminal || process.env.TERM || 'xterm';
|
||||
|
||||
this.unicode = this.detectUnicode();
|
||||
|
||||
// if (!Program.global) {
|
||||
// Program._write = process.stdout.write;
|
||||
// process.stdout.write = function() {};
|
||||
@ -783,42 +781,6 @@ Program.prototype._bindResponse = function(s) {
|
||||
}
|
||||
};
|
||||
|
||||
// Not as foolproof as I'd like it to be.
|
||||
Program.prototype.detectUnicode = function() {
|
||||
var LANG = process.env.LANG
|
||||
+ ':' + process.env.LANGUAGE
|
||||
+ ':' + process.env.LC_ALL
|
||||
+ ':' + process.env.LC_CTYPE;
|
||||
|
||||
return /utf-?8/i.test(LANG);
|
||||
};
|
||||
|
||||
// Could do something goofy like this:
|
||||
Program.prototype.detectUnicode_ = function(callback) {
|
||||
var out = String.fromCharCode((0x1b << 8) | '['.charCodeAt(0)) + 'c'
|
||||
, done;
|
||||
|
||||
this.once('response', function(data) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
if (data.deviceAttributes) {
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
|
||||
this.write(out);
|
||||
|
||||
this.cub(2);
|
||||
this.write(' ');
|
||||
this.cub(2);
|
||||
|
||||
setTimeout(function() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
return callback(null, true);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
Program.prototype.receive = function(text, callback) {
|
||||
var listeners = (this._events && this._events['keypress']) || []
|
||||
, bak = listeners.slice()
|
||||
|
191
lib/tput.js
191
lib/tput.js
@ -65,6 +65,8 @@ function Tput(options) {
|
||||
}
|
||||
this._useXtermI();
|
||||
}
|
||||
|
||||
this.detectFeatures();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -477,7 +479,7 @@ Tput.prototype.compile = function(info, inject) {
|
||||
if (self.debug) {
|
||||
console.log('Compiling %s: %s', key, JSON.stringify(info.all[key]));
|
||||
}
|
||||
info.methods[key] = self._compile(info.all[key]);
|
||||
info.methods[key] = self._compile(info.all[key], key);
|
||||
});
|
||||
});
|
||||
|
||||
@ -536,8 +538,10 @@ Tput.prototype.inject = function(info) {
|
||||
this.strings = info.strings;
|
||||
};
|
||||
|
||||
Tput.prototype._compile = function(val) {
|
||||
var self = this;
|
||||
Tput.prototype._compile = function(val, key) {
|
||||
var self = this
|
||||
, _val = val
|
||||
, _key = key;
|
||||
|
||||
switch (typeof val) {
|
||||
case 'boolean':
|
||||
@ -563,7 +567,8 @@ Tput.prototype._compile = function(val) {
|
||||
, i
|
||||
, v
|
||||
|
||||
var then
|
||||
var fi
|
||||
, then
|
||||
, els
|
||||
, end;
|
||||
|
||||
@ -902,15 +907,17 @@ Tput.prototype._compile = function(val) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if/then/else/end
|
||||
// Terminfo does elseif's like
|
||||
// this: %?[expr]%t...%e[expr]%t...%;
|
||||
if (read(/^%e/)) {
|
||||
fi = val.indexOf('%?');
|
||||
then = val.indexOf('%t');
|
||||
els = val.indexOf('%e');
|
||||
end = val.indexOf('%;');
|
||||
// Terminfo does elseif's like
|
||||
// this: %?[expr]%t...%e[expr]%t...%;
|
||||
// if (then < end && then < els) {
|
||||
// if (then !== -1 && then < end && then < els) {
|
||||
if (then !== -1 && then < end && (els !== -1 && then < els)) {
|
||||
if (then !== -1 && then < end
|
||||
&& (fi === -1 || then < fi)
|
||||
&& (els === -1 || then < els)) {
|
||||
stmt('} else if (');
|
||||
} else {
|
||||
stmt('} else {');
|
||||
@ -1002,11 +1009,21 @@ Tput.prototype._compile = function(val) {
|
||||
process.stdout.write(v + '\n');
|
||||
}
|
||||
|
||||
// Possibly do:
|
||||
// if (code.indexOf('return ') === 0) {
|
||||
// return new Function('', code)();
|
||||
// }
|
||||
|
||||
try {
|
||||
return this.printf
|
||||
? new Function('sprintf, params', code).bind(null, sprintf)
|
||||
: new Function('params', code);
|
||||
} catch (e) {
|
||||
console.error('');
|
||||
console.error('Error on `' + _key + '`:');
|
||||
console.error(JSON.stringify(_val));
|
||||
console.error('');
|
||||
console.error(code.replace(/(,|;)/g, '$1\n'));
|
||||
e.stack = e.stack.replace(/\x1b/g, '\\x1b');
|
||||
throw e;
|
||||
}
|
||||
@ -1261,6 +1278,122 @@ Tput.prototype.compileTermcap = function(info, inject) {
|
||||
return this.compile(info, inject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect Features / Quirks
|
||||
*/
|
||||
|
||||
Tput.prototype.detectFeatures = function() {
|
||||
this.unicode = this.detectUnicode();
|
||||
this.brokenACS = this.detectBrokenACS();
|
||||
this.PCRomSet = this.detectPCRomSet();
|
||||
|
||||
this.magicCookie = this.detectMagicCookie();
|
||||
this.padding = this.detectPadding();
|
||||
this.setbuf = this.detectSetbuf();
|
||||
|
||||
this.parseACS();
|
||||
};
|
||||
|
||||
Tput.prototype.detectUnicode = function() {
|
||||
var LANG = process.env.LANG
|
||||
+ ':' + process.env.LANGUAGE
|
||||
+ ':' + process.env.LC_ALL
|
||||
+ ':' + process.env.LC_CTYPE;
|
||||
|
||||
return /utf-?8/i.test(LANG);
|
||||
};
|
||||
|
||||
// For some reason TERM=linux has smacs/rmacs, but it maps to `^[[11m`
|
||||
// and it does not switch to the DEC SCLD character set. What the hell?
|
||||
// xterm: \x1b(0, screen: \x0e, linux: \x1b[11m (doesn't work)
|
||||
// `man console_codes` says:
|
||||
// 11 select null mapping, set display control flag, reset tog‐
|
||||
// gle meta flag (ECMA-48 says "first alternate font").
|
||||
// See ncurses:
|
||||
// ~/ncurses/ncurses/tinfo/lib_acs.c
|
||||
// ~/ncurses/ncurses/tinfo/tinfo_driver.c
|
||||
// ~/ncurses/ncurses/tinfo/lib_setup.c
|
||||
Tput.prototype.detectBrokenACS = function() {
|
||||
// ncurses-compatible env variable.
|
||||
if (process.env.NCURSES_NO_UTF8_ACS != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An extended terminfo number.
|
||||
if (this.numbers['U8'] !== -1) {
|
||||
return !!this.numbers['U8'];
|
||||
}
|
||||
|
||||
// The linux console is just broken for some reason.
|
||||
if (this.term === 'linux') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// screen termcap is bugged?
|
||||
if (this.term.indexOf('screen') == 0
|
||||
&& process.env.TERMCAP
|
||||
&& ~process.env.TERMCAP.indexOf('screen')
|
||||
&& ~process.env.TERMCAP.indexOf('hhII00')) {
|
||||
if (~this.strings.enter_alt_charset_mode.indexOf('\016')
|
||||
|| ~this.strings.enter_alt_charset_mode.indexOf('\017')
|
||||
|| ~this.strings.set_attributes.indexOf('\016')
|
||||
|| ~this.strings.set_attributes.indexOf('\017')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Apparently the Linux console does not support ACS,
|
||||
// but it does support the PC ROM character set.
|
||||
// See: ~/ncurses/ncurses/tinfo/lib_acs.c
|
||||
Tput.prototype.detectPCRomSet = function() {
|
||||
var str = this.strings;
|
||||
if (str.enter_pc_charset_mode === str.enter_alt_charset_mode
|
||||
&& str.exit_pc_charset_mode === str.exit_alt_charset_mode) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Tput.prototype.detectMagicCookie = function() {
|
||||
return process.env.NCURSES_NO_MAGIC_COOKIE == null;
|
||||
};
|
||||
|
||||
Tput.prototype.detectPadding = function() {
|
||||
return process.env.NCURSES_NO_PADDING == null;
|
||||
};
|
||||
|
||||
Tput.prototype.detectSetbuf = function() {
|
||||
return process.env.NCURSES_NO_SETBUF == null;
|
||||
};
|
||||
|
||||
Tput.prototype.parseACS = function() {
|
||||
var self = this;
|
||||
|
||||
this.acsc = {};
|
||||
this.acscr = {};
|
||||
|
||||
if (this.PCRomSet) {
|
||||
;
|
||||
}
|
||||
|
||||
// See: ~/ncurses/ncurses/tinfo/lib_acs.c: L208
|
||||
Object.keys(acsc).forEach(function(ch) {
|
||||
var acs_chars = self.strings.acs_chars || ''
|
||||
, i = acs_chars.indexOf(ch)
|
||||
, next = acs_chars[i + 1];
|
||||
|
||||
if (!next || i === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.acsc[ch] = acsc[next];
|
||||
self.acscr[acsc[next]] = ch;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
@ -1987,6 +2120,46 @@ Tput.strings = [
|
||||
'box_chars_1'
|
||||
];
|
||||
|
||||
// DEC Special Character and Line Drawing Set.
|
||||
// Taken from tty.js.
|
||||
var acsc = { // (0
|
||||
'`': '\u25c6', // '◆'
|
||||
'a': '\u2592', // '▒'
|
||||
'b': '\u0009', // '\t'
|
||||
'c': '\u000c', // '\f'
|
||||
'd': '\u000d', // '\r'
|
||||
'e': '\u000a', // '\n'
|
||||
'f': '\u00b0', // '°'
|
||||
'g': '\u00b1', // '±'
|
||||
'h': '\u2424', // '\u2424' (NL)
|
||||
'i': '\u000b', // '\v'
|
||||
'j': '\u2518', // '┘'
|
||||
'k': '\u2510', // '┐'
|
||||
'l': '\u250c', // '┌'
|
||||
'm': '\u2514', // '└'
|
||||
'n': '\u253c', // '┼'
|
||||
'o': '\u23ba', // '⎺'
|
||||
'p': '\u23bb', // '⎻'
|
||||
'q': '\u2500', // '─'
|
||||
'r': '\u23bc', // '⎼'
|
||||
's': '\u23bd', // '⎽'
|
||||
't': '\u251c', // '├'
|
||||
'u': '\u2524', // '┤'
|
||||
'v': '\u2534', // '┴'
|
||||
'w': '\u252c', // '┬'
|
||||
'x': '\u2502', // '│'
|
||||
'y': '\u2264', // '≤'
|
||||
'z': '\u2265', // '≥'
|
||||
'{': '\u03c0', // 'π'
|
||||
'|': '\u2260', // '≠'
|
||||
'}': '\u00a3', // '£'
|
||||
'~': '\u00b7' // '·'
|
||||
};
|
||||
|
||||
// ['b', 'c', 'd', 'e', 'h', 'i'].forEach(function(ch) {
|
||||
// delete acsc[ch];
|
||||
// });
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
@ -766,14 +766,16 @@ Screen.prototype.draw = function(start, end) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.program.unicode && this.tput
|
||||
&& this.tput.strings.enter_alt_charset_mode && SCLD[ch]
|
||||
&& this.tput.strings.enter_alt_charset_mode !== '\x1b[11m') {
|
||||
// TODO: Possibly do not check for unicode above.
|
||||
// For some reason TERM=linux has smacs/rmacs, but it maps to `^[[11m`
|
||||
// and it does not switch to the DEC SCLD character set. What the hell?
|
||||
// xterm: \x1b(0, screen: \x0e
|
||||
ch = this.tput.smacs() + SCLD[ch] + this.tput.rmacs();
|
||||
// Attempt to use ACS for supported characters.
|
||||
// XXX We may not want to check tput.unicode here.
|
||||
if (this.tput
|
||||
&& this.tput.strings.enter_alt_charset_mode
|
||||
&& this.tput.acscr[ch]
|
||||
&& !this.tput.brokenACS
|
||||
&& !this.tput.unicode) {
|
||||
ch = this.tput.smacs()
|
||||
+ this.tput.acscr[ch]
|
||||
+ this.tput.rmacs();
|
||||
}
|
||||
|
||||
out += ch;
|
||||
@ -4084,48 +4086,6 @@ function sattr(obj, fg, bg) {
|
||||
| bg;
|
||||
}
|
||||
|
||||
// DEC Special Character and Line Drawing Set.
|
||||
// Taken from tty.js.
|
||||
var SCLD = { // (0
|
||||
'`': '\u25c6', // '◆'
|
||||
'a': '\u2592', // '▒'
|
||||
// 'b': '\u0009', // '\t'
|
||||
// 'c': '\u000c', // '\f'
|
||||
// 'd': '\u000d', // '\r'
|
||||
// 'e': '\u000a', // '\n'
|
||||
'f': '\u00b0', // '°'
|
||||
'g': '\u00b1', // '±'
|
||||
'h': '\u2424', // '\u2424' (NL)
|
||||
// 'i': '\u000b', // '\v'
|
||||
'j': '\u2518', // '┘'
|
||||
'k': '\u2510', // '┐'
|
||||
'l': '\u250c', // '┌'
|
||||
'm': '\u2514', // '└'
|
||||
'n': '\u253c', // '┼'
|
||||
'o': '\u23ba', // '⎺'
|
||||
'p': '\u23bb', // '⎻'
|
||||
'q': '\u2500', // '─'
|
||||
'r': '\u23bc', // '⎼'
|
||||
's': '\u23bd', // '⎽'
|
||||
't': '\u251c', // '├'
|
||||
'u': '\u2524', // '┤'
|
||||
'v': '\u2534', // '┴'
|
||||
'w': '\u252c', // '┬'
|
||||
'x': '\u2502', // '│'
|
||||
'y': '\u2264', // '≤'
|
||||
'z': '\u2265', // '≥'
|
||||
'{': '\u03c0', // 'π'
|
||||
'|': '\u2260', // '≠'
|
||||
'}': '\u00a3', // '£'
|
||||
'~': '\u00b7' // '·'
|
||||
};
|
||||
|
||||
Object.keys(SCLD).forEach(function(key) {
|
||||
var val = SCLD[key];
|
||||
delete SCLD[key];
|
||||
SCLD[val] = key;
|
||||
});
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
@ -92,6 +92,9 @@ var tput = Tput({
|
||||
|
||||
console.log('Max colors: %d.', tput.colors);
|
||||
|
||||
// console.log(tput.strings.acs_chars.split('').map(function(ch) { return ch.charCodeAt(0); }));
|
||||
// console.log(JSON.stringify(tput.strings.acs_chars));
|
||||
|
||||
// process.stdout.write(Tput.sprintf('%-10s\n', 'hello'));
|
||||
|
||||
// tput._compile('%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m');
|
||||
|
Loading…
x
Reference in New Issue
Block a user