From ed8b600b98e434dbe6d966df371dfde08016222f Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 27 May 2016 10:59:50 -0700 Subject: [PATCH] doc: general improvements to readline.md copy PR-URL: https://github.com/nodejs/node/pull/7022 Reviewed-By: Benjamin Gruenbaum --- doc/api/readline.md | 530 +++++++++++++++++++++++++------------------- 1 file changed, 298 insertions(+), 232 deletions(-) diff --git a/doc/api/readline.md b/doc/api/readline.md index fb4681f177..9003d4d2eb 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -2,12 +2,14 @@ Stability: 2 - Stable -To use this module, do `require('readline')`. Readline allows reading of a -stream (such as [`process.stdin`][]) on a line-by-line basis. +The `readline` module provides an interface for reading data from a [Readable][] +stream (such as [`process.stdin`]) one line at a time. It can be accessed using: -Note that once you've invoked this module, your Node.js program will not -terminate until you've closed the interface. Here's how to allow your -program to gracefully exit: +```js +const readline = require('readline'); +``` + +The following simple example illustrates the basic use of the `readline` module. ```js const readline = require('readline'); @@ -25,138 +27,57 @@ rl.question('What do you think of Node.js? ', (answer) => { }); ``` +*Note* Once this code is invoked, the Node.js application will not +terminate until the `readline.Interface` is closed because the interface +waits for data to be received on the `input` stream. + ## Class: Interface -The class that represents a readline interface with an input and output -stream. - -### rl.close() - - -Closes the `Interface` instance, relinquishing control on the `input` and -`output` streams. The `'close'` event will also be emitted. - -### rl.pause() - - -Pauses the readline `input` stream, allowing it to be resumed later if needed. - -Note that this doesn't immediately pause the stream of events. Several events may -be emitted after calling `pause`, including `line`. - -### rl.prompt([preserveCursor]) - - -Readies readline for input from the user, putting the current `setPrompt` -options on a new line, giving the user a new spot to write. Set `preserveCursor` -to `true` to prevent the cursor placement being reset to `0`. - -This will also resume the `input` stream used with `createInterface` if it has -been paused. - -If `output` is set to `null` or `undefined` when calling `createInterface`, the -prompt is not written. - -### rl.question(query, callback) - - -Prepends the prompt with `query` and invokes `callback` with the user's -response. Displays the query to the user, and then invokes `callback` -with the user's response after it has been typed. - -This will also resume the `input` stream used with `createInterface` if -it has been paused. - -If `output` is set to `null` or `undefined` when calling `createInterface`, -nothing is displayed. - -Example usage: - -```js -rl.question('What is your favorite food?', (answer) => { - console.log(`Oh, so your favorite food is ${answer}`); -}); -``` - -### rl.resume() - - -Resumes the readline `input` stream. - -### rl.setPrompt(prompt) - - -Sets the prompt, for example when you run `node` on the command line, you see -`> `, which is Node.js's prompt. - -### rl.write(data[, key]) - - -Writes `data` to `output` stream, unless `output` is set to `null` or -`undefined` when calling `createInterface`. `key` is an object literal to -represent a key sequence; available if the terminal is a TTY. - -This will also resume the `input` stream if it has been paused. - -Example: - -```js -rl.write('Delete me!'); -// Simulate ctrl+u to delete the line written previously -rl.write(null, {ctrl: true, name: 'u'}); -``` - -## Events +Instances of the `readline.Interface` class are constructed using the +`readline.createInterface()` method. Every instance is associated with a +single `input` [Readable][] stream and a single `output` [Writable][] stream. +The `output` stream is used to print prompts for user input that arrives on, +and is read from, the `input` stream. ### Event: 'close' -`function () {}` +The `'close'` event is emitted when one of the following occur: -Emitted when `close()` is called. +* The `rl.close()` method is called and the `readline.Interface` instance has + relinquished control over the `input` and `output` streams; +* The `input` stream receives its `'end'` event; +* The `input` stream receives `-D` to signal end-of-transmission (EOT); +* The `input` stream receives `-C` to signal `SIGINT` and there is no + `SIGINT` event listener registered on the `readline.Interface` instance. -Also emitted when the `input` stream receives its `'end'` event. The `Interface` -instance should be considered "finished" once this is emitted. For example, when -the `input` stream receives `^D`, respectively known as `EOT`. +The listener function is called without passing any arguments. -This event is also called if there is no `SIGINT` event listener present when -the `input` stream receives a `^C`, respectively known as `SIGINT`. +The `readline.Interface` instance should be considered to be "finished" once +the `'close'` event is emitted. ### Event: 'line' -`function (line) {}` +The `'line'` event is emitted whenever the `input` stream receives an +end-of-line input (`\n`, `\r`, or `\r\n`). This usually occurs when the user +presses the ``, or `` keys. -Emitted whenever the `input` stream receives an end of line (`\n`, `\r`, or -`\r\n`), usually received when the user hits enter, or return. This is a good -hook to listen for user input. +The listener function is called with a string containing the single line of +received input. -Example of listening for `'line'`: +For example: ```js -rl.on('line', (cmd) => { - console.log(`You just typed: ${cmd}`); +rl.on('line', (input) => { + console.log(`Received: ${input}`); }); ``` @@ -165,14 +86,15 @@ rl.on('line', (cmd) => { added: v0.7.5 --> -`function () {}` +The `'pause'` event is emitted when one of the following occur: -Emitted whenever the `input` stream is paused. +* The `input` stream is paused. +* The `input` stream is not paused and receives the `SIGCONT` event. (See + events `SIGTSTP` and `SIGCONT`) -Also emitted whenever the `input` stream is not paused and receives the -`SIGCONT` event. (See events `SIGTSTP` and `SIGCONT`) +The listener function is called without passing any arguments. -Example of listening for `'pause'`: +For example: ```js rl.on('pause', () => { @@ -185,11 +107,9 @@ rl.on('pause', () => { added: v0.7.5 --> -`function () {}` +The `'resume'` event is emitted whenever the `input` stream is resumed. -Emitted whenever the `input` stream is resumed. - -Example of listening for `'resume'`: +The listener function is called without passing any arguments. ```js rl.on('resume', () => { @@ -202,16 +122,16 @@ rl.on('resume', () => { added: v0.7.5 --> -`function () {}` +The `'SIGCONT'` event is emitted when a Node.js process previously moved into +the background using `-Z` (i.e. `SIGTSTP`) is then brought back to the +foreground using `fg(1)`. -**This does not work on Windows.** +If the `input` stream was paused *before* the `SIGSTP` request, this event will +not be emitted. -Emitted whenever the `input` stream is sent to the background with `^Z`, -respectively known as `SIGTSTP`, and then continued with `fg(1)`. This event -only emits if the stream was not paused before sending the program to the -background. +The listener function is invoked without passing any arguments. -Example of listening for `SIGCONT`: +For example: ```js rl.on('SIGCONT', () => { @@ -220,18 +140,21 @@ rl.on('SIGCONT', () => { }); ``` +*Note*: The `'SIGCONT'` event is _not_ supported on Windows. + ### Event: 'SIGINT' -`function () {}` +The `'SIGINT'` event is emitted whenever the `input` stream receives a +`-C` input, known typically as `SIGINT`. If there are no `'SIGINT'` event +listeners registered when the `input` stream receives a `SIGINT`, the `'pause'` +event will be emitted. -Emitted whenever the `input` stream receives a `^C`, respectively known as -`SIGINT`. If there is no `SIGINT` event listener present when the `input` -stream receives a `SIGINT`, `pause` will be triggered. +The listener function is invoked without passing any arguments. -Example of listening for `SIGINT`: +For example: ```js rl.on('SIGINT', () => { @@ -246,21 +169,20 @@ rl.on('SIGINT', () => { added: v0.7.5 --> -`function () {}` +The `'SIGTSPT'` event is emitted when the `input` stream receives a `-Z` +input, typically known as `SIGTSTP`. If there are no `SIGTSTP` event listeners +registered when the `input` stream receives a `SIGTSTP`, the Node.js process +will be sent to the background. -**This does not work on Windows.** +When the program is resumed using `fg(1)`, the `'pause'` and `SIGCONT` events +will be emitted. These can be used to resume the `input` stream. -Emitted whenever the `input` stream receives a `^Z`, respectively known as -`SIGTSTP`. If there is no `SIGTSTP` event listener present when the `input` -stream receives a `SIGTSTP`, the program will be sent to the background. +The `'pause'` and `'SIGCONT'` events will not be emitted if the `input` was +paused before the process was sent to the background. -When the program is resumed with `fg`, the `'pause'` and `SIGCONT` events will be -emitted. You can use either to resume the stream. +The listener function is invoked without passing any arguments. -The `'pause'` and `SIGCONT` events will not be triggered if the stream was paused -before the program was sent to the background. - -Example of listening for `SIGTSTP`: +For example: ```js rl.on('SIGTSTP', () => { @@ -270,50 +192,123 @@ rl.on('SIGTSTP', () => { }); ``` -## Example: Tiny CLI +*Note*: The `'SIGTSTP'` event is _not_ supported on Windows. -Here's an example of how to use all these together to craft a tiny command -line interface: +### rl.close() + -```js -const readline = require('readline'); -const rl = readline.createInterface(process.stdin, process.stdout); +The `rl.close()` method closes the `readline.Interface` instance and +relinquishes control over the `input` and `output` streams. When called, +the `'close'` event will be emitted. +Closes the `Interface` instance, relinquishing control on the `input` and +`output` streams. The `'close'` event will also be emitted. -rl.setPrompt('OHAI> '); -rl.prompt(); +### rl.pause() + -rl.on('line', (line) => { - switch(line.trim()) { - case 'hello': - console.log('world!'); - break; - default: - console.log('Say what? I might have heard `' + line.trim() + '`'); - break; - } - rl.prompt(); -}).on('close', () => { - console.log('Have a great day!'); - process.exit(0); +The `rl.pause()` method pauses the `input` stream, allowing it to be resumed +later if necessary. + +Calling `rl.pause()` does not immediately pause other events (including +`'line'`) from being emitted by the `readline.Interface` instance. + +### rl.prompt([preserveCursor]) + + +* `preserveCursor` {boolean} If `true`, prevents the cursor placement from + being reset to `0`. + +The `rl.prompt()` method writes the `readline.Interface` instances configured +`prompt` to a new line in `output` in order to provide a user with a new +location at which to provide input. + +When called, `rl.prompt()` will resume the `input` stream if it has been +paused. + +If the `readline.Interface` was created with `output` set to `null` or +`undefined` the prompt is not written. + +### rl.question(query, callback) + + +* `query` {String} A statement or query to write to `output`, prepended to the + prompt. +* `callback` {Function} A callback function that is invoked with the user's + input in response to the `query`. + +The `rl.question()` method displays the `query` by writing it to the `output`, +waits for user input to be provided on `input`, then invokes the `callback` +function passing the provided input as the first argument. + +When called, `rl.question()` will resume the `input` stream if it has been +paused. + +If the `readline.Interface` was created with `output` set to `null` or +`undefined` the `query` is not written. + +Example usage: + +```js +rl.question('What is your favorite food?', (answer) => { + console.log(`Oh, so your favorite food is ${answer}`); }); ``` -## Example: Read File Stream Line-by-Line +### rl.resume() + -A common case for `readline`'s `input` option is to pass a filesystem readable -stream to it. This is how one could craft line-by-line parsing of a file: +The `rl.resume()` method resumes the `input` stream if it has been paused. -```js -const readline = require('readline'); -const fs = require('fs'); +### rl.setPrompt(prompt) + -const rl = readline.createInterface({ - input: fs.createReadStream('sample.txt') -}); +* `prompt` {String} -rl.on('line', (line) => { - console.log('Line from file:', line); -}); +The `rl.setPrompt()` method sets the prompt that will be written to `output` +whenever `rl.prompt()` is called. + +### rl.write(data[, key]) + + +* `data` {String} +* `key` {Object} + * `ctrl` {boolean} `true` to indicate the `` key. + * `meta` {boolean} `true` to indicate the `` key. + * `shift` {boolean} `true` to indicate the `` key. + * `name` {String} The name of the a key. + +The `rl.write()` method will write either `data` or a key sequence identified +by `key` to the `output`. The `key` argument is supported only if `output` is +a [TTY][] text terminal. + +If `key` is specified, `data` is ignored. + +When called, `rl.write()` will resume the `input` stream if it has been +paused. + +If the `readline.Interface` was created with `output` set to `null` or +`undefined` the `data` and `key` are not written. + +For example: + +```js +rl.write('Delete this!'); +// Simulate Ctrl+u to delete the line written previously +rl.write(null, {ctrl: true, name: 'u'}); ``` ## readline.clearLine(stream, dir) @@ -321,55 +316,80 @@ rl.on('line', (line) => { added: v0.7.7 --> -Clears current line of given TTY stream in a specified direction. -`dir` should have one of following values: +* `stream` {Writable} +* `dir` {number} + * `-1` - to the left from cursor + * `1` - to the right from cursor + * `0` - the entire line + +The `readline.clearLine()` method clears current line of given [TTY][] stream +in a specified direction identified by `dir`. -* `-1` - to the left from cursor -* `1` - to the right from cursor -* `0` - the entire line ## readline.clearScreenDown(stream) -Clears the screen from the current position of the cursor down. +* `stream` {Writable} + +The `readline.clearScreenDown()` method clears the given [TTY][] stream from +the current position of the cursor down. ## readline.createInterface(options) -Creates a readline `Interface` instance. Accepts an `options` Object that takes -the following values: +* `options` {Object} + * `input` {Readable} The [Readable][] stream to listen to. This option is + *required*. + * `output` {Writable} The [Writable][] stream to write readline data to. + * `completer` {Function} An optional function used for Tab autocompletion. + * `terminal` {boolean} `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. + * `historySize` {number} maximum number of history lines retained. To disable + the history set this value to `0`. Defaults to `30`. This option makes sense + only if `terminal` is set to `true` by the user or by an internal `output` + check, otherwise the history caching mechanism is not initialized at all. - - `input` - the readable stream to listen to (Required). +The `readline.createInterface()` method creates a new `readline.Interface` +instance. - - `output` - the writable stream to write readline data to (Optional). +For example: - - `completer` - an optional function that is used for Tab autocompletion. See - below for an example of using this. +```js +const readline = require('readline'); +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); +``` - - `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. +Once the `readline.Interface` instance is created, the most common case is to +listen for the `'line'` event: - - `historySize` - maximum number of history lines retained. To disable the - history set this value to `0`. Defaults to `30`. This option makes sense - only if `terminal` is set to `true` by the user or by an internal `output` - check, otherwise the history caching mechanism is not initialized at all. +```js +rl.on('line', (line) => { + console.log(`Received: ${line}`); +}); +``` -The `completer` function is given the current line entered by the user, and -is supposed to return an Array with 2 entries: +If `terminal` is `true` for this instance then the `output` stream will get +the best compatibility if it defines an `output.columns` property and emits +a `'resize'` event on the `output` if or when the columns ever change +([`process.stdout`][] does this automatically when it is a TTY). - 1. An Array with matching entries for the completion. +### Use of the `completer` Function - 2. The substring that was used for the matching. +When called, the `completer` function is provided the current line entered by +the user, and is expected to return an Array with 2 entries: -Which ends up looking something like: -`[[substr1, substr2, ...], originalsubstring]`. +* An Array with matching entries for the completion. +* The substring that was used for the matching. -Example: +For instance: `[[substr1, substr2, ...], originalsubstring]`. ```js function completer(line) { @@ -380,7 +400,8 @@ function completer(line) { } ``` -Also `completer` can be run in async mode if it accepts two arguments: +The `completer` function can be called asynchronously if it accepts two +arguments: ```js function completer(linePartial, callback) { @@ -388,49 +409,38 @@ function completer(linePartial, callback) { } ``` -`createInterface` is commonly used with [`process.stdin`][] and -[`process.stdout`][] in order to accept user input: - -```js -const readline = require('readline'); -const 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 compatibility 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). - ## readline.cursorTo(stream, x, y) -Move cursor to the specified position in a given TTY stream. +* `stream` {Writable} +* `x` {number} +* `y` {number} + +The `readline.cursorTo()` method moves cursor to the specified position in a +given [TTY][] `stream`. ## readline.emitKeypressEvents(stream[, interface]) -Causes `stream` to begin emitting `'keypress'` events corresponding to its -input. +* `stream` {Readable} +* `interface` {readline.Interface} + +The `readline.emitKeypressEvents()` method causes the given [Writable][] +`stream` to begin emitting `'keypress'` events corresponding to received input. + Optionally, `interface` specifies a `readline.Interface` instance for which autocompletion is disabled when copy-pasted input is detected. -Note that the stream, if it is a TTY, needs to be in raw mode: +If the `stream` is a [TTY][], then it must be in raw mode. + ```js readline.emitKeypressEvents(process.stdin); -if (process.stdin.isTTY) { - // might not be a TTY if spawned from another node process +if (process.stdin.isTTY) process.stdin.setRawMode(true); -} ``` ## readline.moveCursor(stream, dx, dy) @@ -438,7 +448,63 @@ if (process.stdin.isTTY) { added: v0.7.7 --> -Move cursor relative to it's current position in a given TTY stream. +* `stream` {Writable} +* `dx` {number} +* `dy` {Number} + +The `readline.moveCursor()` method moves the cursor *relative* to its current +position in a given [TTY][] `stream`. + + +## Example: Tiny CLI + +The following example illustrates the use of `readline.Interface` class to +implement a small command-line interface: + +```js +const readline = require('readline'); +const rl = readline.createInterface(process.stdin, process.stdout); + +rl.setPrompt('OHAI> '); +rl.prompt(); + +rl.on('line', (line) => { + switch(line.trim()) { + case 'hello': + console.log('world!'); + break; + default: + console.log(`Say what? I might have heard '${line.trim()}'`); + break; + } + rl.prompt(); +}).on('close', () => { + console.log('Have a great day!'); + process.exit(0); +}); +``` + +## Example: Read File Stream Line-by-Line + +A common use case for `readline` is to consume input from a filesystem +[Readable][] stream one line at a time, as illustrated in the following +example: + +```js +const readline = require('readline'); +const fs = require('fs'); + +const rl = readline.createInterface({ + input: fs.createReadStream('sample.txt') +}); + +rl.on('line', (line) => { + console.log('Line from file:', line); +}); +``` [`process.stdin`]: process.html#process_process_stdin [`process.stdout`]: process.html#process_process_stdout +[Writable]: stream.html +[Readable]: stream.html +[TTY]: tty.html