This commit is contained in:
Christopher Jeffrey 2013-02-27 18:25:59 -06:00
parent df0aeb5005
commit d5208b758f
1 changed files with 95 additions and 94 deletions

View File

@ -33,54 +33,39 @@ function Tput(options) {
this.options = options; this.options = options;
this.term = options.term || process.env.TERM; this.term = options.term || process.env.TERM;
this.data = null;
this.info = {};
this.methods = null;
this.termcap = null;
this.debug = options.debug; this.debug = options.debug;
this.padding = options.padding; this.padding = options.padding;
this.extended = options.extended; this.extended = options.extended;
this.printf = options.printf; this.printf = options.printf;
this.termcap = options.termcap;
try { try {
if (options.termcap) { if (this.termcap) {
this.readTermcap();
this.compileTermcap(); this.compileTermcap();
} else { } else {
this.readTerminfo(); this.compileTerminfo();
this.compile();
} }
} catch (e) { } catch (e) {
this.fallback(); this.term = 'vt102';
this.compileTermcap();
} }
} }
Tput.prototype.fallback = function() { /**
delete this.term; * Terminfo
delete this.data; */
delete this.info;
delete this.methods;
delete this.termcap;
this.term = 'vt102'; Tput.prototype.readTerminfo = function(data) {
this.readTermcap(Tput.vt102); if (!data) {
this.compileTermcap(); var file = path.resolve(
}; '/usr/share/terminfo',
path.basename(this.term[0]),
Tput.prototype.readTerminfo = function() { path.basename(this.term)
// if (this.data) return; );
data = fs.readFileSync(file);
var file = path.resolve( }
'/usr/share/terminfo', return this.parseTerminfo(data);
path.basename(this.term[0]),
path.basename(this.term)
);
this.data = fs.readFileSync(file);
this.info = this.parseTerminfo(this.data);
return this.info;
}; };
/** /**
@ -200,10 +185,10 @@ Tput.prototype.parseTerminfo = function(data) {
l = data.length; l = data.length;
if (i < l - 1) { if (i < l - 1) {
var extended = this.parseExtended(data.slice(i)); var extended = this.parseExtended(data.slice(i));
// info.header.extended = extended.header;
['bools', 'numbers', 'strings'].forEach(function(key) { ['bools', 'numbers', 'strings'].forEach(function(key) {
merge(info[key], extended[key]); merge(info[key], extended[key]);
}); });
// info.extendedHexer = extended.header;
} }
} }
@ -387,78 +372,86 @@ Tput.prototype.parseExtended = function(data) {
return info; return info;
}; };
Tput.prototype.compileTerminfo = function() {
return this.compile.apply(this, arguments);
};
/** /**
* Compiler - terminfo cap->javascript * Compiler - terminfo cap->javascript
*/ */
Tput.prototype.compile = function(key) { Tput.prototype.compile = function(info, inject) {
var self = this var self = this;
, info = this.info;
if (arguments.length === 0) {
info = this.readTerminfo();
}
if (!info) { if (!info) {
throw new Error('Terminal not found.'); throw new Error('Terminal not found.');
} }
if (this.debug) { if (this.debug) {
console.log(this.info); console.log(info);
} }
this.methods = {}; info.all = {};
this.info.all = {}; info.methods = {};
Object.keys(info.bools).forEach(function(key) { ['bools', 'numbers', 'strings'].forEach(function(type) {
info.all[key] = info.bools[key]; Object.keys(info[type]).forEach(function(key) {
}); info.all[key] = info[type][key];
if (self.debug) {
Object.keys(info.numbers).forEach(function(key) { console.log('Compiling %s: %s', key, JSON.stringify(info.all[key]));
info.all[key] = info.numbers[key]; }
}); info.methods[key] = self._compile(info.all[key]);
});
Object.keys(info.strings).forEach(function(key) {
info.all[key] = info.strings[key];
});
Object.keys(info.all).forEach(function(key) {
if (self.debug) {
console.log('Compiling %s: %s', key, JSON.stringify(info.all[key]));
}
self.methods[key] = self._compile(info.all[key]);
}); });
Tput.bools.forEach(function(key) { Tput.bools.forEach(function(key) {
if (self.methods[key] == null) self.methods[key] = false; if (info.methods[key] == null) info.methods[key] = false;
}); });
Tput.numbers.forEach(function(key) { Tput.numbers.forEach(function(key) {
if (self.methods[key] == null) self.methods[key] = -1; if (info.methods[key] == null) info.methods[key] = -1;
}); });
Tput.strings.forEach(function(key) { Tput.strings.forEach(function(key) {
if (!self.methods[key]) self.methods[key] = noop; if (!info.methods[key]) info.methods[key] = noop;
}); });
Object.keys(this.methods).forEach(function(key) { Object.keys(info.methods).forEach(function(key) {
var alias = Tput.alias[key]; var alias = Tput.alias[key];
if (alias) { if (!alias) return;
if (!Array.isArray(alias)) alias = [alias]; if (!Array.isArray(alias)) alias = [alias];
alias.forEach(function(alias) { alias.forEach(function(alias) {
if (self.methods[alias] && alias !== key && alias !== 'ML') { if (info.methods[alias] && alias !== key && alias !== 'ML') {
// We can ignore `lines` and `ML` here. // We can ignore `lines` and `ML` here.
throw new Error('Alias collision: ' + key + ' -> ' + alias); throw new Error('Alias collision: ' + key + ' -> ' + alias);
} }
self.methods[alias] = self.methods[key]; info.methods[alias] = info.methods[key];
}); });
}
}); });
Object.keys(self.methods).forEach(function(key) { if (inject !== false) {
if (typeof self.methods[key] !== 'function') { this.inject(info);
self[key] = self.methods[key]; }
return info;
};
Tput.prototype.inject = function(info) {
var self = this
, methods = info.methods || info;
Object.keys(methods).forEach(function(key) {
if (typeof methods[key] !== 'function') {
self[key] = methods[key];
return; return;
} }
self[key] = function() { self[key] = function() {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
return self.methods[key].call(self, args); return methods[key].call(self, args);
}; };
}); });
}; };
@ -871,7 +864,7 @@ Tput.prototype._compile = function(val) {
// arithmetic is possible using the stack. // arithmetic is possible using the stack.
// $ man termcap // $ man termcap
if (this.options.termcap) { if (this.termcap) {
// %r Single parameter capability // %r Single parameter capability
if (read(/^%r/)) { if (read(/^%r/)) {
expr('()'); expr('()');
@ -991,19 +984,13 @@ Tput.prototype._parsePadding = function(code, print, done) {
*/ */
Tput.prototype.readTermcap = function(data) { Tput.prototype.readTermcap = function(data) {
// if (this.termcap) return; var data = data
this.termcap = {};
this.termcap.data = data
|| process.env.TERMCAP || process.env.TERMCAP
|| tryRead('/etc/termcap') || tryRead('/etc/termcap')
|| Tput.vt102; || Tput.vt102;
this.termcap.terms = this.parseTermcap(this.termcap.data); var terms = this.parseTermcap(data);
this.termcap.info = this.termcap.terms[this.term]; return terms[this.term];
return this.termcap;
}; };
/** /**
@ -1092,15 +1079,18 @@ Tput.prototype.parseTermcap = function(data) {
* man termcap * man termcap
*/ */
Tput.prototype.translateTermcap = function() { Tput.prototype.translateTermcap = function(info) {
var self = this var self = this
, info = this.termcap.info
, out = {}; , out = {};
if (!info) { if (!info) {
throw new Error('Terminal not found.'); throw new Error('Terminal not found.');
} }
if (this.debug) {
console.log(info);
}
['name', 'names', 'desc'].forEach(function(key) { ['name', 'names', 'desc'].forEach(function(key) {
out[key] = info[key]; out[key] = info[key];
}); });
@ -1112,13 +1102,15 @@ Tput.prototype.translateTermcap = function() {
Object.keys(alias).forEach(function(key) { Object.keys(alias).forEach(function(key) {
var a = alias[key].slice() var a = alias[key].slice()
, tc = a.terminfo || a.splice(1, 1)[0]; , tc = a.termcap || a.splice(1, 1)[0];
out[tc] = [key].concat(a); out[tc] = [key].concat(a);
}); });
return out; return out;
})(); })();
// Translate termcap cap names to terminfo cap names.
// e.g. `up` -> `cursor_up`
['bools', 'numbers', 'strings'].forEach(function(key) { ['bools', 'numbers', 'strings'].forEach(function(key) {
out[key] = {}; out[key] = {};
Object.keys(info[key]).forEach(function(cap) { Object.keys(info[key]).forEach(function(cap) {
@ -1131,9 +1123,14 @@ Tput.prototype.translateTermcap = function() {
return out; return out;
}; };
Tput.prototype.compileTermcap = function() { Tput.prototype.compileTermcap = function(info) {
this.info = this.translateTermcap(); if (arguments.length === 0) {
this.compile(); info = this.readTermcap();
}
info = this.translateTermcap(info);
return this.compile(info);
}; };
/** /**
@ -1291,7 +1288,8 @@ delete Tput.alias.numbers;
merge(Tput.alias, Tput.alias.strings); merge(Tput.alias, Tput.alias.strings);
delete Tput.alias.strings; delete Tput.alias.strings;
// Make sure there are no collisions between cap and tcap. // Make sure there are no collisions between terminfo names
// and termcap names. Terminfo takes precedence.
Tput._vec = Object.keys(Tput.alias).map(function(key) { Tput._vec = Object.keys(Tput.alias).map(function(key) {
return Array.isArray(Tput.alias[key]) return Array.isArray(Tput.alias[key])
? Tput.alias[key][0] ? Tput.alias[key][0]
@ -1306,10 +1304,13 @@ Object.keys(Tput.alias).forEach(function(key) {
var alias = Tput.alias[key] var alias = Tput.alias[key]
, tcap = alias[1]; , tcap = alias[1];
alias.name = key;
alias.terminfo = alias[0];
alias.termcap = alias[1];
if (!tcap) return; if (!tcap) return;
if (~Tput._vec.indexOf(tcap)) { if (~Tput._vec.indexOf(tcap)) {
alias.termcap = tcap;
alias.splice(1, 1); alias.splice(1, 1);
} }
}); });
@ -1319,7 +1320,7 @@ assert.notEqual(Tput.alias.exit_delete_mode[1], 'ed');
// assert.notEqual(Tput.alias.set_lr_margin[1], 'ML'); // assert.notEqual(Tput.alias.set_lr_margin[1], 'ML');
/** /**
* Fallback Termcap * Fallback Termcap Entry
*/ */
Tput.vt102 = '' Tput.vt102 = ''