diff options
author | isaacs <i@izs.me> | 2012-01-13 20:33:27 +0400 |
---|---|---|
committer | isaacs <i@izs.me> | 2012-01-13 20:41:06 +0400 |
commit | c18fe966ddbeb66c8a9b9aa8ab4899166e6986f5 (patch) | |
tree | 8650e7575caff9d05e04352b78669dd81d21230d /node_modules/read | |
parent | b7ff884870958221eb52c5a600c101fab4c26781 (diff) |
check in node_modules
Diffstat (limited to 'node_modules/read')
-rw-r--r-- | node_modules/read/README.md | 43 | ||||
-rw-r--r-- | node_modules/read/lib/read.js | 151 | ||||
-rw-r--r-- | node_modules/read/package.json | 16 |
3 files changed, 210 insertions, 0 deletions
diff --git a/node_modules/read/README.md b/node_modules/read/README.md new file mode 100644 index 000000000..9913b4df0 --- /dev/null +++ b/node_modules/read/README.md @@ -0,0 +1,43 @@ +For reading user input from stdin. + +## USAGE + +```javascript +var read = require("read") +read(options, callback) +``` + +The callback gets called with either the user input, or the default +specified, or an error, in the traditional `callback(error, result)` +node style. + +## OPTIONS + +Every option is optional. + +* `prompt` What to write to stdout before reading input. +* `silent` Don't echo the output as the user types it. +* `num` Max number of chars to read from terminal. +* `delim` The char that means we're done. Default: `"\n"` +* `timeout` Number of ms to wait for user input before giving up. +* `default` The default value if the user enters nothing. + +If silent is true, or num is set, or delim is something other than +`"\n"`, then read will set raw mode, and read character by character. + +At this time, backspace and arrow keys are not supported in raw mode. +It's probably not too hard to add support for this, perhaps using node's +built-in readline module. + +## CONTRIBUTING + +Patches welcome. + +## BUGS + +In node 0.6.0 through 0.6.5, you must explicitly call +`process.stdin.destroy()` or `process.exit()` when you know that your +program is done reading, or else it will keep the event loop running +forever. + +See: <https://github.com/joyent/node/issues/2257> diff --git a/node_modules/read/lib/read.js b/node_modules/read/lib/read.js new file mode 100644 index 000000000..246044bcd --- /dev/null +++ b/node_modules/read/lib/read.js @@ -0,0 +1,151 @@ + +module.exports = read + +var buffer = "" + , tty = require("tty") + , StringDecoder = require("string_decoder").StringDecoder + +function read (opts, cb) { + if (!cb) cb = opts, opts = {} + + var p = opts.prompt || "" + , def = opts.default + , silent = opts.silent + , timeout = opts.timeout + , num = opts.num || null + , delim = opts.delim || "\n" + + if (p && def) p += "("+(silent ? "<default hidden>" : def)+") " + + // switching into raw mode is a little bit painful. + // avoid if possible. + var r = silent || num || delim !== "\n" ? rawRead : normalRead + + if (timeout) { + cb = (function (cb) { + var called = false + var t = setTimeout(function () { + tty.setRawMode(false) + process.stdout.write("\n") + if (def) done(null, def) + else done(new Error("timeout")) + }, timeout) + + function done (er, data) { + clearTimeout(t) + if (called) return + // stop reading! + stdin.pause() + called = true + cb(er, data) + } + + return done + })(cb) + } + + if (p && !process.stdout.write(p)) { + process.stdout.on("drain", function D () { + process.stdout.removeListener("drain", D) + r(def, timeout, delim, silent, num, cb) + }) + } else { + process.nextTick(function () { + r(def, timeout, delim, silent, num, cb) + }) + } +} + +function normalRead (def, timeout, delim, silent, num, cb) { + var stdin = process.openStdin() + , val = "" + , decoder = new StringDecoder("utf8") + + stdin.resume() + stdin.on("error", cb) + stdin.on("data", function D (chunk) { + // get the characters that are completed. + val += buffer + decoder.write(chunk) + buffer = "" + + // \r has no place here. + // XXX But what if \r is the delim or something dumb like that? + // Meh. If anyone complains about this, deal with it. + val = val.replace(/\r/g, "") + + // TODO Make delim configurable + if (val.indexOf(delim) !== -1) { + // pluck off any delims at the beginning. + if (val !== delim) { + var i, l + for (i = 0, l = val.length; i < l; i ++) { + if (val.charAt(i) !== delim) break + } + if (i !== 0) val = val.substr(i) + } + + // buffer whatever might have come *after* the delimter + var delimIndex = val.indexOf(delim) + if (delimIndex !== -1) { + buffer = val.substr(delimIndex) + val = val.substr(0, delimIndex) + } else { + buffer = "" + } + + stdin.pause() + stdin.removeListener("data", D) + stdin.removeListener("error", cb) + + // read(1) trims + val = val.trim() || def + cb(null, val) + } + }) +} + +function rawRead (def, timeout, delim, silent, num, cb) { + var stdin = process.openStdin() + , val = "" + , decoder = new StringDecoder + + tty.setRawMode(true) + stdin.resume() + stdin.on("error", cb) + stdin.on("data", function D (c) { + // \r is my enemy. + c = decoder.write(c).replace(/\r/g, "\n") + + switch (c) { + case "": // probably just a \r that was ignored. + break + + case "\u0004": // EOF + case delim: + tty.setRawMode(false) + stdin.removeListener("data", D) + stdin.removeListener("error", cb) + val = val.trim() || def + process.stdout.write("\n") + stdin.pause() + return cb(null, val) + + case "\u0003": case "\0": // ^C or other signal abort + tty.setRawMode(false) + stdin.removeListener("data", D) + stdin.removeListener("error", cb) + stdin.pause() + return cb(new Error("cancelled")) + break + + default: // just a normal char + val += buffer + c + buffer = "" + if (!silent) process.stdout.write(c) + + // explicitly process a delim if we have enough chars. + if (num && val.length >= num) D(delim) + break + } + }) +} diff --git a/node_modules/read/package.json b/node_modules/read/package.json new file mode 100644 index 000000000..bc05577aa --- /dev/null +++ b/node_modules/read/package.json @@ -0,0 +1,16 @@ +{ + "name": "read", + "version": "0.0.1", + "main": "lib/read.js", + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.6" + }, + "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)", + "description": "read(1) for node programs", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/read.git" + } +} |