diff options
author | Nathan Rajlich <nathan@tootallnate.net> | 2012-03-27 02:21:25 +0400 |
---|---|---|
committer | Nathan Rajlich <nathan@tootallnate.net> | 2012-03-27 02:21:25 +0400 |
commit | aad12d0b265c9b06ae029d6ee168849260a91dd6 (patch) | |
tree | 7aa1deffdfc5216b50beb4c43eaf09088643a67b /doc | |
parent | ab518ae50e480b5ffe01bdaaabd8c652200d1d55 (diff) |
readline: migrate ansi/vt100 logic from tty to readline
The overall goal here is to make readline more interoperable with other node
Streams like say a net.Socket instance, in "terminal" mode.
See #2922 for all the details.
Closes #2922.
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api/readline.markdown | 71 | ||||
-rw-r--r-- | doc/api/repl.markdown | 69 | ||||
-rw-r--r-- | doc/api/tty.markdown | 74 |
3 files changed, 163 insertions, 51 deletions
diff --git a/doc/api/readline.markdown b/doc/api/readline.markdown index 66615485a21..e707a271fa3 100644 --- a/doc/api/readline.markdown +++ b/doc/api/readline.markdown @@ -3,7 +3,7 @@ Stability: 3 - Stable To use this module, do `require('readline')`. Readline allows reading of a -stream (such as STDIN) on a line-by-line basis. +stream (such as `process.stdin`) on a line-by-line basis. Note that once you've invoked this module, your node program will not terminate until you've paused the interface. Here's how to allow your @@ -11,35 +11,69 @@ program to gracefully pause: var rl = require('readline'); - var i = rl.createInterface(process.stdin, process.stdout, null); - i.question("What do you think of node.js?", function(answer) { + var i = rl.createInterface({ + input: process.stdin, + output: process.stdout + }); + + i.question("What do you think of node.js? ", function(answer) { // TODO: Log the answer in a database - console.log("Thank you for your valuable feedback."); + console.log("Thank you for your valuable feedback:", answer); i.pause(); }); -## rl.createInterface(input, output, completer) +## rl.createInterface(options) + +Creates a readline `Interface` instance. Accepts an "options" Object that takes +the following values: + + - `input` - the readable stream to listen to (Required). + + - `output` - the writable stream to write readline data to (Required). + + - `completer` - an optional function that is used for Tab autocompletion. See + below for an example of using this. + + - `terminal` - pass `true` if the `input` and `output` streams should be treated + like a TTY, and have ANSI/VT100 escape codes written to it. Defaults to + checking `isTTY` on the `output` stream upon instantiation. + +The `completer` function is given a the current line entered by the user, and +is supposed to return an Array with 2 entries: -Takes two streams and creates a readline interface. The `completer` function -is used for autocompletion. When given a substring, it returns `[[substr1, -substr2, ...], originalsubstring]`. + 1. An Array with matching entries for the completion. + + 2. The substring that was used for the matching. + +Which ends up looking something like: +`[[substr1, substr2, ...], originalsubstring]`. Also `completer` can be run in async mode if it accepts two arguments: - function completer(linePartial, callback) { - callback(null, [['123'], linePartial]); - } + function completer(linePartial, callback) { + callback(null, [['123'], linePartial]); + } `createInterface` is commonly used with `process.stdin` and `process.stdout` in order to accept user input: - var readline = require('readline'), - rl = readline.createInterface(process.stdin, process.stdout); + var readline = require('readline'); + var rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + +Once you have a readline instance, you most commonly listen for the `"line"` event. + +If `terminal` is `true` for this instance then the `output` stream will get the +best compatability if it defines an `output.columns` property, and fires +a `"resize"` event on the `output` if/when the columns ever change +(`process.stdout` does this automatically when it is a TTY). ## Class: Interface -The class that represents a readline interface with a stdin and stdout +The class that represents a readline interface with an input and output stream. ### rl.setPrompt(prompt, length) @@ -72,18 +106,17 @@ Example usage: ### rl.pause() -Pauses the readline `in` stream, allowing it to be resumed later if needed. +Pauses the readline `input` stream, allowing it to be resumed later if needed. ### rl.resume() -Resumes the readline `in` stream. +Resumes the readline `input` stream. ### rl.write() -Writes to tty. +Writes to `output` stream. -This will also resume the `in` stream used with `createInterface` if it has -been paused. +This will also resume the `input` stream if it has been paused. ### Event: 'line' diff --git a/doc/api/repl.markdown b/doc/api/repl.markdown index 60a5b72ab77..c61c5751b73 100644 --- a/doc/api/repl.markdown +++ b/doc/api/repl.markdown @@ -1,8 +1,8 @@ # REPL -A Read-Eval-Print-Loop (REPL) is available both as a standalone program and easily -includable in other programs. REPL provides a way to interactively run -JavaScript and see the results. It can be used for debugging, testing, or +A Read-Eval-Print-Loop (REPL) is available both as a standalone program and +easily includable in other programs. The REPL provides a way to interactively +run JavaScript and see the results. It can be used for debugging, testing, or just trying things out. By executing `node` without any arguments from the command-line you will be @@ -19,26 +19,39 @@ dropped into the REPL. It has simplistic emacs line-editing. 2 3 -For advanced line-editors, start node with the environmental variable `NODE_NO_READLINE=1`. -This will start the REPL in canonical terminal settings which will allow you to use with `rlwrap`. +For advanced line-editors, start node with the environmental variable +`NODE_NO_READLINE=1`. This will start the main and debugger REPL in canonical +terminal settings which will allow you to use with `rlwrap`. For example, you could add this to your bashrc file: alias node="env NODE_NO_READLINE=1 rlwrap node" -## repl.start([prompt], [stream], [eval], [useGlobal], [ignoreUndefined]) +## repl.start(options) -Returns and starts a REPL with `prompt` as the prompt and `stream` for all I/O. -`prompt` is optional and defaults to `> `. `stream` is optional and defaults to -`process.stdin`. `eval` is optional too and defaults to async wrapper for -`eval()`. +Returns and starts a `REPLServer` instance. Accepts an "options" Object that +takes the following values: -If `useGlobal` is set to true, then the repl will use the global object, -instead of running scripts in a separate context. Defaults to `false`. + - `prompt` - the prompt and `stream` for all I/O. Defaults to `> `. -If `ignoreUndefined` is set to true, then the repl will not output return value -of command if it's `undefined`. Defaults to `false`. + - `input` - the readable stream to listen to. Defaults to `process.stdin`. + + - `output` - the writable stream to write readline data to. Defaults to + `process.stdout`. + + - `terminal` - pass `true` if the `stream` should be treated like a TTY, and + have ANSI/VT100 escape codes written to it. Defaults to checking `isTTY` + on the `output` stream upon instantiation. + + - `eval` - function that will be used to eval each given line. Defaults to + an async wrapper for `eval()`. See below for an example of a custom `eval`. + + - `useGlobal` - if set to `true`, then the repl will use the `global` object, + instead of running scripts in a separate context. Defaults to `false`. + + - `ignoreUndefined` - if set to `true`, then the repl will not output the + return value of command if it's `undefined`. Defaults to `false`. You can use your own `eval` function if it has following signature: @@ -56,16 +69,32 @@ Here is an example that starts a REPL on stdin, a Unix socket, and a TCP socket: connections = 0; - repl.start("node via stdin> "); + repl.start({ + prompt: "node via stdin> ", + input: process.stdin, + output: process.stdout + }); net.createServer(function (socket) { connections += 1; - repl.start("node via Unix socket> ", socket); + repl.start({ + prompt: "node via Unix socket> ", + input: socket, + output: socket + }).on('exit', function() { + socket.end(); + }) }).listen("/tmp/node-repl-sock"); net.createServer(function (socket) { connections += 1; - repl.start("node via TCP socket> ", socket); + repl.start({ + prompt: "node via TCP socket> ", + input: socket, + output: socket + }).on('exit', function() { + socket.end(); + }); }).listen(5001); Running this program from the command line will start a REPL on stdin. Other @@ -76,6 +105,12 @@ TCP sockets. By starting a REPL from a Unix socket-based server instead of stdin, you can connect to a long-running node process without restarting it. +For an example of running a "full-featured" (`terminal`) REPL over +a `net.Server` and `net.Socket` instance, see: https://gist.github.com/2209310 + +For an example of running a REPL instance over `curl(1)`, +see: https://gist.github.com/2053342 + ### Event: 'exit' `function () {}` diff --git a/doc/api/tty.markdown b/doc/api/tty.markdown index 21ac240ece4..54c597732bd 100644 --- a/doc/api/tty.markdown +++ b/doc/api/tty.markdown @@ -2,20 +2,18 @@ Stability: 3 - Stable -Use `require('tty')` to access this module. - -Example: - - var tty = require('tty'); - process.stdin.resume(); - tty.setRawMode(true); - process.stdin.on('keypress', function(char, key) { - if (key && key.ctrl && key.name == 'c') { - console.log('graceful exit'); - process.exit() - } - }); +The `tty` module houses the `tty.ReadStream` and `tty.WriteStream` classes. In +most cases, you will not need to use this module directly. + +When node detects that it is being run inside a TTY context, then `process.stdin` +will be a `tty.ReadStream` instance and `process.stdout` will be +a `tty.WriteStream` instance. The preferred way to check if node is being run in +a TTY context is to check `process.stdout.isTTY`: + $ node -p -e "Boolean(process.stdout.isTTY)" + true + $ node -p -e "Boolean(process.stdout.isTTY)" | cat + false ## tty.isatty(fd) @@ -26,5 +24,51 @@ terminal. ## tty.setRawMode(mode) -`mode` should be `true` or `false`. This sets the properties of the current -process's stdin fd to act either as a raw device or default. +Deprecated. Use `tty.ReadStream#setRawMode()` instead. + + +## Class: ReadStream + +A `net.Socket` subclass that represents the readable portion of a tty. In normal +circumstances, `process.stdin` will be the only `tty.ReadStream` instance in any +node program (only when `isatty(0)` is true). + +### rs.isRaw + +A `Boolean` that is initialized to `false`. It represents the current "raw" state +of the `tty.ReadStream` instance. + +### rs.setRawMode(mode) + +`mode` should be `true` or `false`. This sets the properties of the +`tty.ReadStream` to act either as a raw device or default. `isRaw` will be set +to the resulting mode. + + +## Class WriteStream + +A `net.Socket` subclass that represents the writable portion of a tty. In normal +circumstances, `process.stdout` will be the only `tty.WriteStream` instance +ever created (and only when `isatty(1)` is true). + +### ws.columns + +A `Number` that gives the number of columns the TTY currently has. This property +gets updated on "resize" events. + +### ws.rows + +A `Number` that gives the number of rows the TTY currently has. This property +gets updated on "resize" events. + +### Event: 'resize' + +`function () {}` + +Emitted by `refreshSize()` when either of the `columns` or `rows` properties +has changed. + + process.stdout.on('resize', function() { + console.log('screen size has changed!'); + console.log(process.stdout.columns + 'x' + process.stdout.rows); + }); |