refactor. clean up. more colors.
This commit is contained in:
parent
04f4145524
commit
1428b7137b
391
lib/program.js
391
lib/program.js
|
@ -44,36 +44,38 @@ Program.prototype.term = function(is) {
|
|||
};
|
||||
|
||||
Program.prototype.listen = function() {
|
||||
if (!this.input.isTTY || !this.output.isTTY) return;
|
||||
if (!this.input.isTTY || !this.output.isTTY) {
|
||||
return;
|
||||
}
|
||||
|
||||
var readline = require('readline')
|
||||
, self = this;
|
||||
|
||||
this._raw = true;
|
||||
if (!this.input.isRaw) {
|
||||
this.input.setRawMode(true);
|
||||
|
||||
this.input.setRawMode(true);
|
||||
|
||||
this.input.on('keypress', function(ch, key) {
|
||||
key = key || 0;
|
||||
if (key.ctrl && key.name === 'c') {
|
||||
if (process.listeners('SIGINT').length) {
|
||||
process.emit('SIGINT');
|
||||
this.input.on('keypress', function(ch, key) {
|
||||
key = key || 0;
|
||||
if (key.ctrl && key.name === 'c') {
|
||||
if (process.listeners('SIGINT').length) {
|
||||
process.emit('SIGINT');
|
||||
}
|
||||
if (self.listeners('SIGINT').length) {
|
||||
self.emit('SIGINT');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self.listeners('SIGINT').length) {
|
||||
self.emit('SIGINT');
|
||||
}
|
||||
return;
|
||||
}
|
||||
self.emit('keypress', ch, key);
|
||||
});
|
||||
self.emit('keypress', ch, key);
|
||||
});
|
||||
|
||||
this.input.on('data', function(data) {
|
||||
self.emit('data', data);
|
||||
});
|
||||
this.input.on('data', function(data) {
|
||||
self.emit('data', data);
|
||||
});
|
||||
|
||||
readline.emitKeypressEvents(this.input);
|
||||
readline.emitKeypressEvents(this.input);
|
||||
|
||||
this.input.resume();
|
||||
this.input.resume();
|
||||
}
|
||||
|
||||
this.output.on('resize', function() {
|
||||
self.cols = self.output.columns;
|
||||
|
@ -81,18 +83,15 @@ Program.prototype.listen = function() {
|
|||
self.emit('resize');
|
||||
});
|
||||
|
||||
// this.getCursor(function(err, cursor) {
|
||||
// if (err) return;
|
||||
// self.x = cursor.x;
|
||||
// self.y = cursor.y;
|
||||
// });
|
||||
|
||||
this.on('newListener', function fn(type) {
|
||||
if (type === 'mouse') {
|
||||
self.removeListener('newListener', fn);
|
||||
self.bindMouse();
|
||||
}
|
||||
});
|
||||
|
||||
// self.bindMouse();
|
||||
// self.bindResponse();
|
||||
};
|
||||
|
||||
// XTerm mouse events
|
||||
|
@ -142,7 +141,7 @@ Program.prototype._bindMouse = function(s) {
|
|||
}
|
||||
|
||||
// XTerm / X10
|
||||
if (parts = /^\x1b\[M([\x00\u0020-\xffff]{3})/.exec(s)) {
|
||||
if (parts = /^\x1b\[M([\x00\u0020-\uffff]{3})/.exec(s)) {
|
||||
var b = parts[1].charCodeAt(0)
|
||||
, x = parts[1].charCodeAt(1)
|
||||
, y = parts[1].charCodeAt(2)
|
||||
|
@ -352,6 +351,7 @@ Program.prototype._bindMouse = function(s) {
|
|||
}
|
||||
};
|
||||
|
||||
// All possible responses from the terminal
|
||||
Program.prototype.bindResponse = function() {
|
||||
this.on('data', this._bindResponse.bind(this));
|
||||
this.bindResponse = function() {};
|
||||
|
@ -435,33 +435,18 @@ Program.prototype._bindResponse = function(s) {
|
|||
: 'unavailable'
|
||||
});
|
||||
}
|
||||
|
||||
return this.emit('response', {
|
||||
error: 'Unhandled: ' + JSON.stringify(parts)
|
||||
});
|
||||
}
|
||||
|
||||
// CSI Ps n Device Status Report (DSR).
|
||||
// Ps = 5 -> Status Report. Result (``OK'') is
|
||||
// CSI 0 n
|
||||
// Ps = 6 -> Report Cursor Position (CPR) [row;column].
|
||||
// Result is
|
||||
// CSI r ; c R
|
||||
// CSI ? Ps n
|
||||
// Device Status Report (DSR, DEC-specific).
|
||||
// Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
|
||||
// ? r ; c R (assumes page is zero).
|
||||
// Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
|
||||
// or CSI ? 1 1 n (not ready).
|
||||
// Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
|
||||
// or CSI ? 2 1 n (locked).
|
||||
// Ps = 2 6 -> Report Keyboard status as
|
||||
// CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
|
||||
// The last two parameters apply to VT400 & up, and denote key-
|
||||
// board ready and LK01 respectively.
|
||||
// Ps = 5 3 -> Report Locator status as
|
||||
// CSI ? 5 3 n Locator available, if compiled-in, or
|
||||
// CSI ? 5 0 n No Locator, if not.
|
||||
|
||||
// CSI Ps n Device Status Report (DSR).
|
||||
// Ps = 6 -> Report Cursor Position (CPR) [row;column].
|
||||
// Result is
|
||||
// CSI r ; c R
|
||||
// CSI ? Ps n
|
||||
// Device Status Report (DSR, DEC-specific).
|
||||
// Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
|
||||
// ? r ; c R (assumes page is zero).
|
||||
if (parts = /^\x1b\[(\?)?(\d+);(\d+)R/.exec(s)) {
|
||||
|
@ -534,6 +519,10 @@ Program.prototype._bindResponse = function(s) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this.emit('response', {
|
||||
error: 'Unhandled: ' + JSON.stringify(parts)
|
||||
});
|
||||
}
|
||||
|
||||
// CSI Ps ; Ps ; Ps t
|
||||
|
@ -557,14 +546,19 @@ Program.prototype._bindResponse = function(s) {
|
|||
windowTitle: parts[2]
|
||||
});
|
||||
}
|
||||
|
||||
return this.emit('response', {
|
||||
error: 'Unhandled: ' + JSON.stringify(parts)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Program.prototype.receive = function(text, callback) {
|
||||
var listeners = this.listeners('keypress')
|
||||
, bak = listeners.slice();
|
||||
, bak = listeners.slice()
|
||||
, self = this;
|
||||
|
||||
if (!this._raw) {
|
||||
if (!this.input.isRaw) {
|
||||
throw new Error('Input must be raw.');
|
||||
}
|
||||
|
||||
|
@ -575,26 +569,53 @@ Program.prototype.receive = function(text, callback) {
|
|||
text = null;
|
||||
}
|
||||
|
||||
this.input.once('data', function(data) {
|
||||
listeners.push.apply(listeners, bak);
|
||||
if (typeof data !== 'string') {
|
||||
data = data.toString('utf8');
|
||||
}
|
||||
return callback(null, data);
|
||||
});
|
||||
return process.nextTick(function() {
|
||||
self.input.once('data', function(data) {
|
||||
listeners.push.apply(listeners, bak);
|
||||
if (typeof data !== 'string') {
|
||||
data = data.toString('utf8');
|
||||
}
|
||||
return callback(null, data);
|
||||
});
|
||||
|
||||
if (text) this.write(text);
|
||||
if (text) self.write(text);
|
||||
});
|
||||
};
|
||||
|
||||
Program.prototype.receive_ = function(text, callback) {
|
||||
var listeners = this.listeners('keypress')
|
||||
, bak = listeners.slice()
|
||||
, self = this;
|
||||
|
||||
if (!this.input.isRaw) {
|
||||
throw new Error('Input must be raw.');
|
||||
}
|
||||
|
||||
listeners.length = 0;
|
||||
|
||||
if (!callback) {
|
||||
callback = text;
|
||||
text = null;
|
||||
}
|
||||
|
||||
return process.nextTick(function() {
|
||||
self.input.once('data', function(data) {
|
||||
listeners.push.apply(listeners, bak);
|
||||
self.once('response', function(event) {
|
||||
return callback(null, event[Object.keys(event)[0]]);
|
||||
});
|
||||
self._bindResponse(data);
|
||||
});
|
||||
|
||||
if (text) self.write(text);
|
||||
});
|
||||
};
|
||||
|
||||
Program.prototype.write =
|
||||
Program.prototype.echo = function(text, attr) {
|
||||
if (attr) {
|
||||
this.attr(attr, true);
|
||||
this.write(text);
|
||||
this.attr(attr, false);
|
||||
return;
|
||||
}
|
||||
return this.output.write(text);
|
||||
return attr
|
||||
? this.output.write(this.text(text, attr))
|
||||
: this.output.write(text);
|
||||
};
|
||||
|
||||
Program.prototype.setx = function(x) {
|
||||
|
@ -1041,6 +1062,25 @@ Program.prototype.eraseInLine = function(param) {
|
|||
Program.prototype.sgr =
|
||||
Program.prototype.attr =
|
||||
Program.prototype.charAttributes = function(param, val) {
|
||||
return this.write(this._attr(param, val));
|
||||
};
|
||||
|
||||
Program.prototype.text = function(text, attr) {
|
||||
return this._attr(attr, true) + text + this._attr(attr, false);
|
||||
};
|
||||
|
||||
Program.prototype._attr = function(param, val) {
|
||||
var self = this
|
||||
, parts = param.split(/\s*[,;]\s*/)
|
||||
, out = '';
|
||||
|
||||
if (parts.length > 1) {
|
||||
parts.forEach(function(part) {
|
||||
out += self._attr(part, val);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
if (param.indexOf('no ') === 0) {
|
||||
param = param.substring(3);
|
||||
val = false;
|
||||
|
@ -1048,118 +1088,233 @@ Program.prototype.charAttributes = function(param, val) {
|
|||
param = param.substring(1);
|
||||
val = false;
|
||||
}
|
||||
|
||||
switch (param) {
|
||||
// attributes
|
||||
case 'normal':
|
||||
return this.write('\x1b[m');
|
||||
return '\x1b[m';
|
||||
case 'bold':
|
||||
return val === false
|
||||
? this.write('\x1b[22m')
|
||||
: this.write('\x1b[1m');
|
||||
? '\x1b[22m'
|
||||
: '\x1b[1m';
|
||||
case 'underlined':
|
||||
return val === false
|
||||
? this.write('\x1b[24m')
|
||||
: this.write('\x1b[4m');
|
||||
? '\x1b[24m'
|
||||
: '\x1b[4m';
|
||||
case 'blink':
|
||||
return val === false
|
||||
? this.write('\x1b[25m')
|
||||
: this.write('\x1b[5m');
|
||||
? '\x1b[25m'
|
||||
: '\x1b[5m';
|
||||
case 'inverse':
|
||||
return val === false
|
||||
? this.write('\x1b[27m')
|
||||
: this.write('\x1b[7m');
|
||||
? '\x1b[27m'
|
||||
: '\x1b[7m';
|
||||
break;
|
||||
case 'invisible':
|
||||
return val === false
|
||||
? this.write('\x1b[28m')
|
||||
: this.write('\x1b[8m');
|
||||
? '\x1b[28m'
|
||||
: '\x1b[8m';
|
||||
case 'invisible':
|
||||
return val === false
|
||||
? this.write('\x1b[28m')
|
||||
: this.write('\x1b[8m');
|
||||
? '\x1b[28m'
|
||||
: '\x1b[8m';
|
||||
|
||||
// 8-color foreground
|
||||
case 'black fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[30m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[30m';
|
||||
case 'red fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[31m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[31m';
|
||||
case 'green fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[32m');
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[32m';
|
||||
case 'yellow fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[33m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[33m';
|
||||
case 'blue fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[34m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[34m';
|
||||
case 'magenta fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[35m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[35m';
|
||||
case 'cyan fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[36m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[36m';
|
||||
case 'white fg':
|
||||
return val === false
|
||||
? this.write('\x1b[39m')
|
||||
: this.write('\x1b[37m');
|
||||
? '\x1b[39m'
|
||||
: '\x1b[37m';
|
||||
case 'default fg':
|
||||
return this.write('\x1b[39m');
|
||||
return '\x1b[39m';
|
||||
|
||||
// 8-color background
|
||||
case 'black bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[40m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[40m';
|
||||
case 'red bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[41m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[41m';
|
||||
case 'green bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[42m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[42m';
|
||||
case 'yellow bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[43m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[43m';
|
||||
case 'blue bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[44m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[44m';
|
||||
case 'magenta bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[45m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[45m';
|
||||
case 'cyan bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[46m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[46m';
|
||||
case 'white bg':
|
||||
return val === false
|
||||
? this.write('\x1b[49m')
|
||||
: this.write('\x1b[47m');
|
||||
? '\x1b[49m'
|
||||
: '\x1b[47m';
|
||||
case 'default bg':
|
||||
return this.write('\x1b[49m');
|
||||
return '\x1b[49m';
|
||||
|
||||
// 16-color foreground
|
||||
case 'light black fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[90m';
|
||||
case 'light red fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[91m';
|
||||
case 'light green fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[92m';
|
||||
case 'light yellow fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[93m';
|
||||
case 'light blue fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[94m';
|
||||
case 'light magenta fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[95m';
|
||||
case 'light cyan fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[96m';
|
||||
case 'light white fg':
|
||||
return val === false
|
||||
? '\x1b[39m'
|
||||
: '\x1b[97m';
|
||||
|
||||
// 16-color background
|
||||
case 'light black bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[100m';
|
||||
case 'light red bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[101m';
|
||||
case 'light green bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[102m';
|
||||
case 'light yellow bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[103m';
|
||||
case 'light blue bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[104m';
|
||||
case 'light magenta bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[105m';
|
||||
case 'light cyan bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[106m';
|
||||
case 'light white bg':
|
||||
return val === false
|
||||
? '\x1b[49m'
|
||||
: '\x1b[107m';
|
||||
|
||||
// non-16-color rxvt default fg and bg
|
||||
case 'default fg bg':
|
||||
if (this.term('rxvt')) {
|
||||
return '\x1b[100m';
|
||||
}
|
||||
return this._attr('default fg') + this._attr('default bg');
|
||||
|
||||
default:
|
||||
return this.write('\x1b[' + param + 'm');
|
||||
// 256-color fg and bg
|
||||
var m = /^(\d+) (fg|bg)$/.exec(param);
|
||||
if (m) {
|
||||
var color = +m[1] - 1;
|
||||
|
||||
if (val === false) {
|
||||
return this._attr('default ' + m[2]);
|
||||
}
|
||||
|
||||
if (color < 16) {
|
||||
if (m[2] === 'fg') {
|
||||
if (color < 8) {
|
||||
color += 30;
|
||||
} else if (color < 16) {
|
||||
color += 90;
|
||||
}
|
||||
} else if (m[2] === 'bg') {
|
||||
if (color < 8) {
|
||||
color += 40;
|
||||
} else if (color < 16) {
|
||||
color += 100;
|
||||
}
|
||||
}
|
||||
return '\x1b[' + color + 'm';
|
||||
}
|
||||
|
||||
if (m[2] === 'fg') {
|
||||
return '\x1b[38;5;' + color + 'm';
|
||||
}
|
||||
|
||||
if (m[2] === 'bg') {
|
||||
return '\x1b[48;5;' + color + 'm';
|
||||
}
|
||||
}
|
||||
return '\x1b[' + param + 'm';
|
||||
}
|
||||
};
|
||||
|
||||
Program.prototype.fg =
|
||||
Program.prototype.setForeground = function(color, val) {
|
||||
return this.attr(color + ' fg', val);
|
||||
color = color.split(/\s*[,;]\s*/).join(' fg, ') + ' fg';
|
||||
return this.attr(color, val);
|
||||
};
|
||||
|
||||
Program.prototype.bg =
|
||||
Program.prototype.setBackground = function(color, val) {
|
||||
return this.attr(color + ' bg', val);
|
||||
color = color.split(/\s*[,;]\s*/).join(' bg, ') + ' bg';
|
||||
return this.attr(color, val);
|
||||
};
|
||||
|
||||
// CSI Ps n Device Status Report (DSR).
|
||||
|
|
Loading…
Reference in New Issue