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.term = options.term || process.env.TERM;
this.data = null;
this.info = {};
this.methods = null;
this.termcap = null;
this.debug = options.debug;
this.padding = options.padding;
this.extended = options.extended;
this.printf = options.printf;
this.termcap = options.termcap;
try {
if (options.termcap) {
this.readTermcap();
if (this.termcap) {
this.compileTermcap();
} else {
this.readTerminfo();
this.compile();
this.compileTerminfo();
}
} catch (e) {
this.fallback();
}
}
Tput.prototype.fallback = function() {
delete this.term;
delete this.data;
delete this.info;
delete this.methods;
delete this.termcap;
this.term = 'vt102';
this.readTermcap(Tput.vt102);
this.compileTermcap();
};
}
}
Tput.prototype.readTerminfo = function() {
// if (this.data) return;
/**
* Terminfo
*/
Tput.prototype.readTerminfo = function(data) {
if (!data) {
var file = path.resolve(
'/usr/share/terminfo',
path.basename(this.term[0]),
path.basename(this.term)
);
this.data = fs.readFileSync(file);
this.info = this.parseTerminfo(this.data);
return this.info;
data = fs.readFileSync(file);
}
return this.parseTerminfo(data);
};
/**
@ -200,10 +185,10 @@ Tput.prototype.parseTerminfo = function(data) {
l = data.length;
if (i < l - 1) {
var extended = this.parseExtended(data.slice(i));
// info.header.extended = extended.header;
['bools', 'numbers', 'strings'].forEach(function(key) {
merge(info[key], extended[key]);
});
// info.extendedHexer = extended.header;
}
}
@ -387,78 +372,86 @@ Tput.prototype.parseExtended = function(data) {
return info;
};
Tput.prototype.compileTerminfo = function() {
return this.compile.apply(this, arguments);
};
/**
* Compiler - terminfo cap->javascript
*/
Tput.prototype.compile = function(key) {
var self = this
, info = this.info;
Tput.prototype.compile = function(info, inject) {
var self = this;
if (arguments.length === 0) {
info = this.readTerminfo();
}
if (!info) {
throw new Error('Terminal not found.');
}
if (this.debug) {
console.log(this.info);
console.log(info);
}
this.methods = {};
this.info.all = {};
info.all = {};
info.methods = {};
Object.keys(info.bools).forEach(function(key) {
info.all[key] = info.bools[key];
});
Object.keys(info.numbers).forEach(function(key) {
info.all[key] = info.numbers[key];
});
Object.keys(info.strings).forEach(function(key) {
info.all[key] = info.strings[key];
});
Object.keys(info.all).forEach(function(key) {
['bools', 'numbers', 'strings'].forEach(function(type) {
Object.keys(info[type]).forEach(function(key) {
info.all[key] = info[type][key];
if (self.debug) {
console.log('Compiling %s: %s', key, JSON.stringify(info.all[key]));
}
self.methods[key] = self._compile(info.all[key]);
info.methods[key] = self._compile(info.all[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) {
if (self.methods[key] == null) self.methods[key] = -1;
if (info.methods[key] == null) info.methods[key] = -1;
});
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];
if (alias) {
if (!alias) return;
if (!Array.isArray(alias)) alias = [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.
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 (typeof self.methods[key] !== 'function') {
self[key] = self.methods[key];
if (inject !== false) {
this.inject(info);
}
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;
}
self[key] = function() {
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.
// $ man termcap
if (this.options.termcap) {
if (this.termcap) {
// %r Single parameter capability
if (read(/^%r/)) {
expr('()');
@ -991,19 +984,13 @@ Tput.prototype._parsePadding = function(code, print, done) {
*/
Tput.prototype.readTermcap = function(data) {
// if (this.termcap) return;
this.termcap = {};
this.termcap.data = data
var data = data
|| process.env.TERMCAP
|| tryRead('/etc/termcap')
|| Tput.vt102;
this.termcap.terms = this.parseTermcap(this.termcap.data);
this.termcap.info = this.termcap.terms[this.term];
return this.termcap;
var terms = this.parseTermcap(data);
return terms[this.term];
};
/**
@ -1092,15 +1079,18 @@ Tput.prototype.parseTermcap = function(data) {
* man termcap
*/
Tput.prototype.translateTermcap = function() {
Tput.prototype.translateTermcap = function(info) {
var self = this
, info = this.termcap.info
, out = {};
if (!info) {
throw new Error('Terminal not found.');
}
if (this.debug) {
console.log(info);
}
['name', 'names', 'desc'].forEach(function(key) {
out[key] = info[key];
});
@ -1112,13 +1102,15 @@ Tput.prototype.translateTermcap = function() {
Object.keys(alias).forEach(function(key) {
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);
});
return out;
})();
// Translate termcap cap names to terminfo cap names.
// e.g. `up` -> `cursor_up`
['bools', 'numbers', 'strings'].forEach(function(key) {
out[key] = {};
Object.keys(info[key]).forEach(function(cap) {
@ -1131,9 +1123,14 @@ Tput.prototype.translateTermcap = function() {
return out;
};
Tput.prototype.compileTermcap = function() {
this.info = this.translateTermcap();
this.compile();
Tput.prototype.compileTermcap = function(info) {
if (arguments.length === 0) {
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);
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) {
return Array.isArray(Tput.alias[key])
? Tput.alias[key][0]
@ -1306,10 +1304,13 @@ Object.keys(Tput.alias).forEach(function(key) {
var alias = Tput.alias[key]
, tcap = alias[1];
alias.name = key;
alias.terminfo = alias[0];
alias.termcap = alias[1];
if (!tcap) return;
if (~Tput._vec.indexOf(tcap)) {
alias.termcap = tcap;
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');
/**
* Fallback Termcap
* Fallback Termcap Entry
*/
Tput.vt102 = ''