add multiple screen docs and telnet server example.
This commit is contained in:
parent
b068a8d036
commit
90c441a329
131
README.md
131
README.md
|
@ -188,6 +188,8 @@ screen.render();
|
|||
- [Poisitioning](#positioning)
|
||||
- [Rendering](#rendering)
|
||||
- [Artificial Cursors](#artificial-cursors)
|
||||
- [Multiple Screens](#multiple-screens)
|
||||
- [Server Side Usage](#server-side-usage)
|
||||
|
||||
### Notes
|
||||
|
||||
|
@ -2120,6 +2122,135 @@ var screen = blessed.screen({
|
|||
```
|
||||
|
||||
|
||||
#### Multiple Screens
|
||||
|
||||
Blessed supports the ability to create multiple screens. This may not seem
|
||||
useful at first, but if you're writing a program that serves terminal
|
||||
interfaces over http, telnet, or any other protocol, this can be very useful.
|
||||
|
||||
##### Server Side Usage
|
||||
|
||||
A simple telnet server might look like this (see examples/blessed-telnet.js for
|
||||
a full example):
|
||||
|
||||
``` js
|
||||
telnet.createServer(function(client) {
|
||||
client.do.transmit_binary();
|
||||
client.do.terminal_type();
|
||||
client.do.window_size();
|
||||
|
||||
client.on('terminal type', function(data) {
|
||||
// https://tools.ietf.org/html/rfc884
|
||||
if (data.command === 'sb' && data.buf[3] === 1) {
|
||||
var TERM = data.buf.slice(4, -2).toString('ascii');
|
||||
screen.program.terminal = TERM;
|
||||
screen.program.tput.terminal = TERM;
|
||||
screen.program.tput.setup();
|
||||
screen.render();
|
||||
}
|
||||
});
|
||||
|
||||
client.on('window size', function(data) {
|
||||
if (data.command === 'sb') {
|
||||
client.columns = data.columns;
|
||||
client.rows = data.rows;
|
||||
client.emit('resize');
|
||||
}
|
||||
});
|
||||
|
||||
// Make the client look like a tty:
|
||||
client.setRawMode = function(mode) {
|
||||
client.isRaw = mode;
|
||||
if (!client.writable) return;
|
||||
if (mode) {
|
||||
client.do.suppress_go_ahead();
|
||||
client.will.suppress_go_ahead();
|
||||
client.will.echo();
|
||||
} else {
|
||||
client.dont.suppress_go_ahead();
|
||||
client.wont.suppress_go_ahead();
|
||||
client.wont.echo();
|
||||
}
|
||||
};
|
||||
client.isTTY = true;
|
||||
client.isRaw = false;
|
||||
client.columns = 80;
|
||||
client.rows = 24;
|
||||
|
||||
var screen = blessed.screen({
|
||||
smartCSR: true,
|
||||
input: client,
|
||||
output: client,
|
||||
term: 'xterm-256color'
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
if (!screen.destroyed) {
|
||||
screen.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
screen.key(['C-c', 'q'], function(ch, key) {
|
||||
screen.destroy();
|
||||
});
|
||||
|
||||
screen.on('destroy', function() {
|
||||
if (client.writable) {
|
||||
client.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
screen.data.main = blessed.box({
|
||||
parent: screen,
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
width: '80%',
|
||||
height: '90%',
|
||||
border: 'line',
|
||||
content: 'Welcome to my server. Here is your own private session.'
|
||||
});
|
||||
|
||||
screen.render();
|
||||
}).listen(2300);
|
||||
```
|
||||
|
||||
Once you've written something similar and started it, you can simply telnet
|
||||
into your blessed app:
|
||||
|
||||
``` bash
|
||||
$ telnet localhost 2300
|
||||
```
|
||||
|
||||
Creating a netcat server would also work as long as you disable line buffering
|
||||
and terminal echo on the commandline via `stty`:
|
||||
`$ stty -icanon -echo; ncat localhost 3000; stty icanon echo`
|
||||
|
||||
Creating a streaming http 1.1 server than runs in the terminal is possible by
|
||||
curling it with special arguments: `$ curl -sSNT. localhost:8080`.
|
||||
|
||||
There are currently no examples of netcat/nc/ncat or http->curl servers yet.
|
||||
|
||||
---
|
||||
|
||||
The `blessed.screen` constructor can accept `input`, `output`, and `term`
|
||||
arguments to aid with this. The multiple screens will be managed internally by
|
||||
blessed. The programmer just has to keep track of the references, however, to
|
||||
avoid ambiguity, it's possible to explicitly dictate which screen a node is
|
||||
part of by using the `screen` option when creating an element.
|
||||
|
||||
The `screen.destroy()` method is also crucial: this will clean up all event
|
||||
listeners the screen has bound and make sure it stops listening on the event
|
||||
loop. Make absolutely certain to remember to clean up your screens once you're
|
||||
done with them.
|
||||
|
||||
A tricky part is making sure to include the ability for the client to send the
|
||||
TERM which is reset on the serverside, and the terminal size, which is should
|
||||
also be reset on the serverside. Both of these capabilities are demonstrated
|
||||
above.
|
||||
|
||||
For a working example of a blessed telnet server, see
|
||||
`examples/blessed-telnet.js`.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* blessed-telnet.js
|
||||
* https://github.com/chjj/blessed
|
||||
* Copyright (c) 2013-2015, Christopher Jeffrey (MIT License)
|
||||
* A blessed telnet server.
|
||||
* See: https://github.com/TooTallNate/node-telnet
|
||||
*/
|
||||
|
||||
process.title = 'blessed-telnet';
|
||||
|
||||
var fs = require('fs');
|
||||
var blessed = require('blessed');
|
||||
var telnet = require('telnet');
|
||||
|
||||
var server = telnet.createServer(function(client) {
|
||||
client.do.transmit_binary();
|
||||
client.do.terminal_type();
|
||||
client.do.window_size();
|
||||
|
||||
client.on('terminal type', function(data) {
|
||||
// https://tools.ietf.org/html/rfc884
|
||||
if (data.command === 'sb' && data.buf[3] === 1) {
|
||||
var TERM = data.buf.slice(4, -2).toString('ascii');
|
||||
screen.program.terminal = TERM;
|
||||
screen.program.tput.terminal = TERM;
|
||||
screen.program.tput.setup();
|
||||
screen.render();
|
||||
}
|
||||
});
|
||||
|
||||
client.on('window size', function(data) {
|
||||
if (data.command === 'sb') {
|
||||
client.columns = data.columns;
|
||||
client.rows = data.rows;
|
||||
client.emit('resize');
|
||||
}
|
||||
});
|
||||
|
||||
// Make the client look like a tty:
|
||||
client.setRawMode = function(mode) {
|
||||
client.isRaw = mode;
|
||||
if (!client.writable) return;
|
||||
if (mode) {
|
||||
client.do.suppress_go_ahead();
|
||||
client.will.suppress_go_ahead();
|
||||
client.will.echo();
|
||||
} else {
|
||||
client.dont.suppress_go_ahead();
|
||||
client.wont.suppress_go_ahead();
|
||||
client.wont.echo();
|
||||
}
|
||||
};
|
||||
client.isTTY = true;
|
||||
client.isRaw = false;
|
||||
client.columns = 80;
|
||||
client.rows = 24;
|
||||
|
||||
var screen = blessed.screen({
|
||||
smartCSR: true,
|
||||
input: client,
|
||||
output: client,
|
||||
term: 'xterm-256color'
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
if (!screen.destroyed) {
|
||||
screen.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
screen.key(['C-c', 'q'], function(ch, key) {
|
||||
screen.destroy();
|
||||
});
|
||||
|
||||
screen.on('destroy', function() {
|
||||
if (client.writable) {
|
||||
client.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
if (test === 'widget-simple') {
|
||||
return simpleTest(screen);
|
||||
}
|
||||
|
||||
loadTest(screen, test);
|
||||
});
|
||||
|
||||
function simpleTest(screen) {
|
||||
screen.data.main = blessed.box({
|
||||
parent: screen,
|
||||
width: '80%',
|
||||
height: '90%',
|
||||
border: 'line',
|
||||
content: 'Welcome to my server. Here is your own private session.',
|
||||
style: {
|
||||
bg: 'red'
|
||||
}
|
||||
});
|
||||
|
||||
screen.key('i', function() {
|
||||
screen.data.main.style.bg = 'blue';
|
||||
screen.render();
|
||||
});
|
||||
|
||||
screen.render();
|
||||
}
|
||||
|
||||
var test = 'widget-' + (process.argv[2] || 'shadow');
|
||||
if (test === 'widget-png') process.argv.length = 2;
|
||||
|
||||
function loadTest(screen, name) {
|
||||
var Screen = blessed.screen;
|
||||
var key = screen.key;
|
||||
blessed.screen = function() { return screen; };
|
||||
screen.key = function(keys) {
|
||||
keys = [].concat(keys)
|
||||
if (~keys.indexOf('q') || ~keys.indexOf('C-c') || ~keys.indexOf('escape')) {
|
||||
return;
|
||||
}
|
||||
return key.apply(screen, arguments);
|
||||
};
|
||||
var path = require.resolve('../test/' + name);
|
||||
delete require.cache[path];
|
||||
require('../test/' + name);
|
||||
blessed.screen = Screen;
|
||||
screen.key = key;
|
||||
}
|
||||
|
||||
server.listen(2300);
|
||||
console.log('Listening on 2300...');
|
Loading…
Reference in New Issue