mirror of
https://github.com/nodejs/node.git
synced 2025-05-14 22:56:41 +00:00

Conflicts: ChangeLog Makefile deps/npm/AUTHORS deps/npm/html/api/bin.html deps/npm/html/api/bugs.html deps/npm/html/api/commands.html deps/npm/html/api/config.html deps/npm/html/api/deprecate.html deps/npm/html/api/docs.html deps/npm/html/api/edit.html deps/npm/html/api/explore.html deps/npm/html/api/help-search.html deps/npm/html/api/init.html deps/npm/html/api/install.html deps/npm/html/api/link.html deps/npm/html/api/load.html deps/npm/html/api/ls.html deps/npm/html/api/npm.html deps/npm/html/api/outdated.html deps/npm/html/api/owner.html deps/npm/html/api/pack.html deps/npm/html/api/prefix.html deps/npm/html/api/prune.html deps/npm/html/api/publish.html deps/npm/html/api/rebuild.html deps/npm/html/api/restart.html deps/npm/html/api/root.html deps/npm/html/api/run-script.html deps/npm/html/api/search.html deps/npm/html/api/shrinkwrap.html deps/npm/html/api/start.html deps/npm/html/api/stop.html deps/npm/html/api/submodule.html deps/npm/html/api/tag.html deps/npm/html/api/test.html deps/npm/html/api/uninstall.html deps/npm/html/api/unpublish.html deps/npm/html/api/update.html deps/npm/html/api/version.html deps/npm/html/api/view.html deps/npm/html/api/whoami.html deps/npm/html/doc/README.html deps/npm/html/doc/adduser.html deps/npm/html/doc/bin.html deps/npm/html/doc/bugs.html deps/npm/html/doc/build.html deps/npm/html/doc/bundle.html deps/npm/html/doc/cache.html deps/npm/html/doc/changelog.html deps/npm/html/doc/coding-style.html deps/npm/html/doc/completion.html deps/npm/html/doc/config.html deps/npm/html/doc/deprecate.html deps/npm/html/doc/developers.html deps/npm/html/doc/disputes.html deps/npm/html/doc/docs.html deps/npm/html/doc/edit.html deps/npm/html/doc/explore.html deps/npm/html/doc/faq.html deps/npm/html/doc/folders.html deps/npm/html/doc/help-search.html deps/npm/html/doc/help.html deps/npm/html/doc/index.html deps/npm/html/doc/init.html deps/npm/html/doc/install.html deps/npm/html/doc/json.html deps/npm/html/doc/link.html deps/npm/html/doc/list.html deps/npm/html/doc/npm.html deps/npm/html/doc/outdated.html deps/npm/html/doc/owner.html deps/npm/html/doc/pack.html deps/npm/html/doc/prefix.html deps/npm/html/doc/prune.html deps/npm/html/doc/publish.html deps/npm/html/doc/rebuild.html deps/npm/html/doc/registry.html deps/npm/html/doc/removing-npm.html deps/npm/html/doc/restart.html deps/npm/html/doc/root.html deps/npm/html/doc/run-script.html deps/npm/html/doc/scripts.html deps/npm/html/doc/search.html deps/npm/html/doc/semver.html deps/npm/html/doc/shrinkwrap.html deps/npm/html/doc/star.html deps/npm/html/doc/start.html deps/npm/html/doc/stop.html deps/npm/html/doc/submodule.html deps/npm/html/doc/tag.html deps/npm/html/doc/test.html deps/npm/html/doc/uninstall.html deps/npm/html/doc/unpublish.html deps/npm/html/doc/update.html deps/npm/html/doc/version.html deps/npm/html/doc/view.html deps/npm/html/doc/whoami.html deps/npm/man/man1/npm.1 deps/npm/man/man3/npm.3 deps/npm/package.json doc/api/url.markdown lib/http.js src/node_version.h test/simple/test-fs-sync-fd-leak.js
152 lines
3.7 KiB
JavaScript
152 lines
3.7 KiB
JavaScript
|
|
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
|
|
}
|
|
})
|
|
}
|