readme. example. fixes. response codes.

This commit is contained in:
Christopher Jeffrey 2013-01-29 23:26:27 -06:00
parent 0b62eabfce
commit f03d84bb7b
3 changed files with 343 additions and 28 deletions

View File

@ -3,7 +3,9 @@
A curses-like library for node.js.
As of right now, it does not read all terminfo. It was designed for one
terminal's terminfo: **xterm**.
terminal's terminfo: **xterm**, but if you understand the differences between
the three popular vt100-based terminals (xterm, screen, rxvt), you should be
able to use it for any terminal.
I want this library to eventually become a high-level library for terminal
widgets.
@ -11,52 +13,74 @@ widgets.
## Example Usage
``` js
var Program = require('blessed')
, program = new Program;
var blessed = require('blessed')
, program = blessed();
program.on('key', function(ch, key) {
if (key.ctrl && key.name === 'c') {
console.log('This would have been SIGINT!');
program.on('keypress', function(ch, key) {
if (key.name === 'q') {
program.clear();
program.disableMouse();
program.showCursor();
program.normalBuffer();
process.exit(0);
}
});
program.setMouse({ normalMouse: true });
program.on('mouse', function(data) {
console.log('Mouse event received:');
console.log(data.button, data.x, data.y);
if (data.action === 'mouseup') return;
program.move(1, program.rows);
program.eraseInLine('right');
if (data.action === 'wheelup') {
program.write('Mouse wheel up at: ' + data.x + ', ' + data.y);
} else if (data.action === 'wheeldown') {
program.write('Mouse wheel down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'left') {
program.write('Left button down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'right') {
program.write('Right button down at: ' + data.x + ', ' + data.y);
} else {
program.write('Mouse at: ' + data.x + ', ' + data.y);
}
program.move(data.x, data.y);
program.bg('red');
program.write(' ');
program.bg('!red');
});
program.on('focus', function() {
program.move(1, program.rows);
program.write('Gained focus.');
});
program.on('blur', function() {
program.move(1, program.rows);
program.write('Lost focus.');
});
program.alternateBuffer();
program.enableMouse();
program.hideCursor();
program.clear();
program.bg('white');
program.move(1, 1);
program.bg('black');
program.write('Hello world', 'blue fg');
program.setx(1);
program.setx((program.cols / 2 | 0) - 4);
program.down(5);
program.write('Hi again!');
program.bg('!white');
program.bg('!black');
program.feed();
program.getCursor(function(err, data) {
if (!err) {
console.log('Cursor is at: %s, %s.', data.x, data.y);
program.write('Cursor is at: ' + data.x + ', ' + data.y + '.');
program.feed();
}
program.charset('SCLD');
program.write('abcdefghijklmnopqrstuvwxyz0123456789');
program.charset('US');
program.setx(0);
setTimeout(function() {
program.eraseInLine('right');
setTimeout(function() {
program.clear();
program.normalBuffer();
program.setMouse({ normalMouse: false });
}, 2000);
}, 2000);
program.setx(1);
});
```

77
example/index.js Normal file
View File

@ -0,0 +1,77 @@
/**
* Example Program for Blessed
* Copyright (c) 2013, Christopher Jeffrey (MIT License).
* https://github.com/chjj/blessed
*/
var blessed = require('blessed')
, program = blessed();
process.title = 'blessed';
program.on('keypress', function(ch, key) {
if (key.name === 'q') {
program.clear();
program.disableMouse();
program.showCursor();
program.normalBuffer();
process.exit(0);
}
});
program.on('mouse', function(data) {
if (data.action === 'mouseup') return;
program.move(1, program.rows);
program.eraseInLine('right');
if (data.action === 'wheelup') {
program.write('Mouse wheel up at: ' + data.x + ', ' + data.y);
} else if (data.action === 'wheeldown') {
program.write('Mouse wheel down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'left') {
program.write('Left button down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'right') {
program.write('Right button down at: ' + data.x + ', ' + data.y);
} else {
program.write('Mouse at: ' + data.x + ', ' + data.y);
}
program.move(data.x, data.y);
program.bg('red');
program.write(' ');
program.bg('!red');
});
program.on('focus', function() {
program.move(1, program.rows);
program.write('Gained focus.');
});
program.on('blur', function() {
program.move(1, program.rows);
program.write('Lost focus.');
});
program.alternateBuffer();
program.enableMouse();
program.hideCursor();
program.clear();
program.move(1, 1);
program.bg('black');
program.write('Hello world', 'blue fg');
program.setx((program.cols / 2 | 0) - 4);
program.down(5);
program.write('Hi again!');
program.bg('!black');
program.feed();
program.getCursor(function(err, data) {
if (!err) {
program.write('Cursor is at: ' + data.x + ', ' + data.y + '.');
program.feed();
}
program.charset('SCLD');
program.write('abcdefghijklmnopqrstuvwxyz0123456789');
program.charset('US');
program.setx(1);
});

View File

@ -15,6 +15,10 @@ var EventEmitter = require('events').EventEmitter;
*/
function Program(input, output) {
if (!(this instanceof Program)) {
return new Program(input, output);
}
var self = this;
EventEmitter.call(this);
@ -348,6 +352,214 @@ Program.prototype._bindMouse = function(s) {
}
};
Program.prototype.bindResponse = function() {
this.on('data', this._bindResponse.bind(this));
this.bindResponse = function() {};
};
Program.prototype._bindResponse = function(s) {
var self = this;
// FROM: node/lib/readline.js
var ch
, key = {
name: undefined,
ctrl: false,
meta: false,
shift: false
}
, parts;
if (Buffer.isBuffer(s)) {
if (s[0] > 127 && s[1] === undefined) {
s[0] -= 128;
s = '\x1b' + s.toString('utf-8');
} else {
s = s.toString('utf-8');
}
}
// CSI Ps n Device Status Report (DSR).
// Ps = 5 -> Status Report. Result (``OK'') is
// CSI 0 n
// CSI ? Ps n
// Device Status Report (DSR, DEC-specific).
// 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.
if (parts = /^\x1b\[(\?)?(\d+)(?:;(\d+);(\d+);(\d+))?n/.exec(s)) {
if (!parts[1] && parts[2] === '0' && !parts[3]) {
return this.emit('response', {
deviceStatus: 'OK'
});
}
if (parts[1] && (parts[2] === '10' || parts[2] === '11') && !parts[3]) {
return this.emit('response', {
printerStatus: parts[2] === '10'
? 'ready'
: 'not ready'
});
}
if (parts[1] && (parts[2] === '20' || parts[2] === '21') && !parts[3]) {
return this.emit('response', {
UDKStatus: parts[2] === '20'
? 'unlocked'
: 'locked'
});
}
if (parts[1]
&& parts[2] === '27'
&& parts[3] === '1'
&& parts[4] === '0'
&& parts[5] === '0') {
return this.emit('response', {
keyboardStatus: 'OK'
});
}
if (parts[1] && (parts[2] === '53' || parts[2] === '50') && !parts[3]) {
return this.emit('response', {
locator: parts[2] === '53'
? 'available'
: 'unavailable'
});
}
}
// 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.
// Ps = 6 -> Report Cursor Position (CPR) [row;column].
// Result is
// CSI r ; c R
// 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)) {
return this.emit('response', {
cursor: {
x: +parts[3],
y: +parts[2],
page: !parts[1] ? undefined : 0
}
});
}
// CSI Ps ; Ps ; Ps t
// Window manipulation (from dtterm, as well as extensions).
// These controls may be disabled using the allowWindowOps
// resource. Valid values for the first (and any additional
// parameters) are:
// Ps = 1 1 -> Report xterm window state. If the xterm window
// is open (non-iconified), it returns CSI 1 t . If the xterm
// window is iconified, it returns CSI 2 t .
// Ps = 1 3 -> Report xterm window position. Result is CSI 3
// ; x ; y t
// Ps = 1 4 -> Report xterm window in pixels. Result is CSI
// 4 ; height ; width t
// Ps = 1 8 -> Report the size of the text area in characters.
// Result is CSI 8 ; height ; width t
// Ps = 1 9 -> Report the size of the screen in characters.
// Result is CSI 9 ; height ; width t
if (parts = /^\x1b\[(\d+)(?:;(\d+);(\d+))?t/.exec(s)) {
if ((parts[1] === '1' || parts[1] === '2') && !parts[2]) {
return this.emit('response', {
windowState: parts[1] === '1'
? 'non-iconified'
: 'iconified'
});
}
if (parts[1] === '3' && parts[2]) {
return this.emit('response', {
windowPosition: {
x: +parts[2],
y: +parts[3]
}
});
}
if (parts[1] === '4' && parts[2]) {
return this.emit('response', {
windowSizePixels: {
height: +parts[2],
width: +parts[3]
}
});
}
if (parts[1] === '8' && parts[2]) {
return this.emit('response', {
textAreaSizeCharacters: {
height: +parts[2],
width: +parts[3]
}
});
}
if (parts[1] === '9' && parts[2]) {
return this.emit('response', {
screenSizeCharacters: {
height: +parts[2],
width: +parts[3]
}
});
}
}
// CSI Ps ; Ps ; Ps t
// Window manipulation (from dtterm, as well as extensions).
// These controls may be disabled using the allowWindowOps
// resource. Valid values for the first (and any additional
// parameters) are:
// Ps = 2 0 -> Report xterm window's icon label. Result is
// OSC L label ST
// Ps = 2 1 -> Report xterm window's title. Result is OSC l
// label ST
if (parts = /^\x1b\](l|L)([^\x07\x1b]*)(?:\x07|\\\x1b)/.exec(s)) {
if (parts[1] === 'L') {
return this.emit('response', {
windowIconLabel: parts[2]
});
}
if (parts[1] === 'l') {
return this.emit('response', {
windowTitle: parts[2]
});
}
}
};
Program.prototype.receive = function(text, callback) {
var listeners = this.listeners('keypress')
, bak = listeners.slice();
@ -386,8 +598,8 @@ Program.prototype.echo = function(text, attr) {
};
Program.prototype.setx = function(x) {
// return this.cursorCharAbsolute(x);
return this.charPosAbsolute(x);
return this.cursorCharAbsolute(x);
// return this.charPosAbsolute(x);
};
Program.prototype.sety = function(y) {
@ -2058,4 +2270,6 @@ Program.prototype.deleteColumns = function() {
* Expose
*/
module.exports = Program;
exports = Program;
exports.Program = Program;
module.exports = exports;