commando.html5/node_modules/charm/index.js

306 lines
7.2 KiB
JavaScript

var tty = require('tty');
var encode = require('./lib/encode');
var Stream = require('stream').Stream;
var exports = module.exports = function () {
var input = null;
function setInput (s) {
if (input) throw new Error('multiple inputs specified')
else input = s
}
var output = null;
function setOutput (s) {
if (output) throw new Error('multiple outputs specified')
else output = s
}
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
if (arg.readable) setInput(arg)
else if (arg.stdin || arg.input) setInput(arg.stdin || arg.input)
if (arg.writable) setOutput(arg)
else if (arg.stdout || arg.output) setOutput(arg.stdout || arg.output)
}
if (input && typeof input.fd === 'number' && tty.isatty(input.fd)) {
if (process.stdin.setRawMode) {
process.stdin.setRawMode(true);
}
else tty.setRawMode(true);
}
var charm = new Charm;
if (input) {
input.pipe(charm);
}
if (output) {
charm.pipe(output);
}
charm.once('^C', process.exit);
charm.once('end', function () {
if (input) {
if (typeof input.fd === 'number' && tty.isatty(input.fd)) {
if (process.stdin.setRawMode) {
process.stdin.setRawMode(false);
}
else tty.setRawMode(false);
}
input.destroy();
}
});
return charm;
};
var Charm = exports.Charm = function Charm () {
this.writable = true;
this.readable = true;
this.pending = [];
}
Charm.prototype = new Stream;
Charm.prototype.write = function (buf) {
var self = this;
if (self.pending.length) {
var codes = extractCodes(buf);
var matched = false;
for (var i = 0; i < codes.length; i++) {
for (var j = 0; j < self.pending.length; j++) {
var cb = self.pending[j];
if (cb(codes[i])) {
matched = true;
self.pending.splice(j, 1);
break;
}
}
}
if (matched) return;
}
if (buf.length === 1) {
if (buf[0] === 3) self.emit('^C');
if (buf[0] === 4) self.emit('^D');
}
self.emit('data', buf);
return self;
};
Charm.prototype.destroy = function () {
this.end();
};
Charm.prototype.end = function (buf) {
if (buf) this.write(buf);
this.emit('end');
};
Charm.prototype.reset = function (cb) {
this.write(encode('c'));
return this;
};
Charm.prototype.position = function (x, y) {
// get/set absolute coordinates
if (typeof x === 'function') {
var cb = x;
this.pending.push(function (buf) {
if (buf[0] === 27 && buf[1] === encode.ord('[')
&& buf[buf.length-1] === encode.ord('R')) {
var pos = buf.toString()
.slice(2,-1)
.split(';')
.map(Number)
;
cb(pos[1], pos[0]);
return true;
}
});
this.write(encode('[6n'));
}
else {
this.write(encode(
'[' + Math.floor(y) + ';' + Math.floor(x) + 'f'
));
}
return this;
};
Charm.prototype.move = function (x, y) {
// set relative coordinates
var bufs = [];
if (y < 0) this.up(-y)
else if (y > 0) this.down(y)
if (x > 0) this.right(x)
else if (x < 0) this.left(-x)
return this;
};
Charm.prototype.up = function (y) {
if (y === undefined) y = 1;
this.write(encode('[' + Math.floor(y) + 'A'));
return this;
};
Charm.prototype.down = function (y) {
if (y === undefined) y = 1;
this.write(encode('[' + Math.floor(y) + 'B'));
return this;
};
Charm.prototype.right = function (x) {
if (x === undefined) x = 1;
this.write(encode('[' + Math.floor(x) + 'C'));
return this;
};
Charm.prototype.left = function (x) {
if (x === undefined) x = 1;
this.write(encode('[' + Math.floor(x) + 'D'));
return this;
};
Charm.prototype.column = function (x) {
this.write(encode('[' + Math.floor(x) + 'G'));
return this;
};
Charm.prototype.push = function (withAttributes) {
this.write(encode(withAttributes ? '7' : '[s'));
return this;
};
Charm.prototype.pop = function (withAttributes) {
this.write(encode(withAttributes ? '8' : '[u'));
return this;
};
Charm.prototype.erase = function (s) {
if (s === 'end' || s === '$') {
this.write(encode('[K'));
}
else if (s === 'start' || s === '^') {
this.write(encode('[1K'));
}
else if (s === 'line') {
this.write(encode('[2K'));
}
else if (s === 'down') {
this.write(encode('[J'));
}
else if (s === 'up') {
this.write(encode('[1J'));
}
else if (s === 'screen') {
this.write(encode('[1J'));
}
else {
this.emit('error', new Error('Unknown erase type: ' + s));
}
return this;
};
Charm.prototype.display = function (attr) {
var c = {
reset : 0,
bright : 1,
dim : 2,
underscore : 4,
blink : 5,
reverse : 7,
hidden : 8
}[attr];
if (c === undefined) {
this.emit('error', new Error('Unknown attribute: ' + attr));
}
this.write(encode('[' + c + 'm'));
return this;
};
Charm.prototype.foreground = function (color) {
if (typeof color === 'number') {
if (color < 0 || color >= 256) {
this.emit('error', new Error('Color out of range: ' + color));
}
this.write(encode('[38;5;' + color + 'm'));
}
else {
var c = {
black : 30,
red : 31,
green : 32,
yellow : 33,
blue : 34,
magenta : 35,
cyan : 36,
white : 37
}[color.toLowerCase()];
if (!c) this.emit('error', new Error('Unknown color: ' + color));
this.write(encode('[' + c + 'm'));
}
return this;
};
Charm.prototype.background = function (color) {
if (typeof color === 'number') {
if (color < 0 || color >= 256) {
this.emit('error', new Error('Color out of range: ' + color));
}
this.write(encode('[48;5;' + color + 'm'));
}
else {
var c = {
black : 40,
red : 41,
green : 42,
yellow : 43,
blue : 44,
magenta : 45,
cyan : 46,
white : 47
}[color.toLowerCase()];
if (!c) this.emit('error', new Error('Unknown color: ' + color));
this.write(encode('[' + c + 'm'));
}
return this;
};
Charm.prototype.cursor = function (visible) {
this.write(encode(visible ? '[?25h' : '[?25l'));
return this;
};
var extractCodes = exports.extractCodes = function (buf) {
var codes = [];
var start = -1;
for (var i = 0; i < buf.length; i++) {
if (buf[i] === 27) {
if (start >= 0) codes.push(buf.slice(start, i));
start = i;
}
else if (start >= 0 && i === buf.length - 1) {
codes.push(buf.slice(start));
}
}
return codes;
}