promptify
Version:
An easy-to-use prompt for Node.js.
209 lines (174 loc) • 7.67 kB
JavaScript
;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ul = require("ul"),
isWin = require("is-win"),
fs = require("fs");
var CARRIAGE_RETURN = 13;
var Promptify = function () {
/**
* Promptify
* Creates a new `Promptify`. In most of the cases,
* there will be one such instance per process.
*
* @name Promptify
* @function
* @param {Object} conf The `Promptify` config:
* @returns {Promptify} The `Promptify` instance.
*/
function Promptify(conf) {
_classCallCheck(this, Promptify);
conf = ul.merge(conf, {
sigint: true
});
this.conf = conf;
}
/**
* sync
* Synchronous version of the prompt.
*
* @name sync
* @function
* @param {String} message The message do display.
* @param {String} defMsg The default value.
* @param {Object} options An object containing the following fields:
*
* - `char` (String): The character to display when writing something. For
* example, if it's `*`, the text characters will be replaced with `*`.
* - `delimiter` (String): The delimiter between message and the value (default: `": "`).
*
* @returns {String} The result.
*/
_createClass(Promptify, [{
key: "sync",
value: function sync(message, defMsg, options) {
var insert = 0,
savedinsert = 0,
res = void 0;
if ((typeof defMsg === "undefined" ? "undefined" : _typeof(defMsg)) === "object") {
options = defMsg;
defMsg = "";
}
options = ul.merge(options, {
delimiter: ": "
});
message = message || "";
message = "" + message + options.delimiter;
var char = options.char;
var mmessageed = "char" in options;
var fd = isWin() ? process.stdin.fd : fs.openSync("/dev/tty", "rs");
var wasRaw = process.stdin.isRaw;
if (!wasRaw) {
process.stdin.setRawMode(true);
}
var buf = new Buffer.alloc(3);
var str = "",
character = void 0,
read = void 0;
if (message) {
process.stdout.write(message);
}
var cycle = 0;
var prevComplete = void 0;
while (true) {
read = fs.readSync(fd, buf, 0, 3);
if (read > 1) {
switch (buf.toString()) {
// Up/Down arrows
case "\x1B[A":
case "\x1B[B":
process.stdout.write("\x1B[2K\x1B[0G" + message + str);
break;
// Left arrow
case "\x1B[D":
if (mmessageed) break;
var before = insert;
insert = --insert < 0 ? 0 : insert;
if (before - insert) process.stdout.write("\x1B[1D");
break;
// Right arrow
case "\x1B[C":
if (mmessageed) break;
insert = ++insert > str.length ? str.length : insert;
process.stdout.write("\x1B[" + (insert + message.length + 1) + 'G');
break;
default:
if (buf.toString()) {
str = str + buf.toString();
str = str.replace(/\0/g, '');
insert = str.length;
process.stdout.write("\x1B[2K\x1B[0G" + message + str);
process.stdout.write("\x1B[" + (insert + message.length + 1) + 'G');
buf = new Buffer(3);
break;
}
}
continue;
}
// if it is not a control character seq, assume only one character is read
character = buf[read - 1];
// catch a ^C and return null
if (character == 3) {
process.stdout.write('^C\n');
fs.closeSync(fd);
if (this.conf.sigint) process.exit(130);
process.stdin.setRawMode(wasRaw);
return null;
}
if (character == CARRIAGE_RETURN) {
fs.closeSync(fd);
break;
}
if (character == 127 || process.platform == 'win32' && character == 8) {
//backspace
if (!insert) continue;
str = str.slice(0, insert - 1) + str.slice(insert);
insert--;
process.stdout.write("\x1B[2D");
} else {
if (character < 32 || character > 126) continue;
str = str.slice(0, insert) + String.fromCharCode(character) + str.slice(insert);
insert++;
};
if (mmessageed) {
process.stdout.write("\x1B[2K\x1B[0G" + message + Array(str.length + 1).join(char));
} else {
process.stdout.write("\x1B[s");
if (insert == str.length) {
process.stdout.write("\x1B[2K\x1B[0G" + message + str);
} else {
if (message) {
process.stdout.write("\x1B[2K\x1B[0G" + message + str);
} else {
process.stdout.write("\x1B[2K\x1B[0G" + str + "\x1B[" + (str.length - insert) + 'D');
}
}
process.stdout.write("\x1B[u");
process.stdout.write("\x1B[1C");
}
}
process.stdout.write('\n');
process.stdin.setRawMode(wasRaw);
return str || defMsg || '';
}
}]);
return Promptify;
}();
var _ = null;
/**
* promptify
* Prompt a message to the user. The arguments are passed to the `sync` method.
*
* @name promptify
* @function
*/
module.exports = function () {
var _ref;
if (!process.stdin.isTTY) {
return;
}
_ = _ || new Promptify();
return (_ref = _).sync.apply(_ref, arguments);
};
module.exports.Promptify = Promptify;