Add: defaultInput
, Utility Methods
This commit is contained in:
parent
b8e194e743
commit
69ce4ab6c2
1 changed files with 161 additions and 40 deletions
|
@ -273,11 +273,11 @@ function readlineExt(options) {
|
||||||
function _execFileSync(options, execOptions) {
|
function _execFileSync(options, execOptions) {
|
||||||
|
|
||||||
function getTempfile(name) {
|
function getTempfile(name) {
|
||||||
var path = require('path'), filepath, suffix = '', fd;
|
var pathUtil = require('path'), filepath, suffix = '', fd;
|
||||||
tempdir = tempdir || require('os').tmpdir();
|
tempdir = tempdir || require('os').tmpdir();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
filepath = path.join(tempdir, name + suffix);
|
filepath = pathUtil.join(tempdir, name + suffix);
|
||||||
try {
|
try {
|
||||||
fd = fs.openSync(filepath, 'wx');
|
fd = fs.openSync(filepath, 'wx');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -662,10 +662,29 @@ function getPhCharlist(param) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cmd "arg" " a r g " 'a"r"g' "a""rg" "arg
|
||||||
|
function parseCL(cl) {
|
||||||
|
var reToken = new RegExp(/(\s*)(?:("|')(.*?)(?:\2|$)|(\S+))/g), matches,
|
||||||
|
taken = '', args = [], part;
|
||||||
|
cl = cl.trim();
|
||||||
|
while ((matches = reToken.exec(cl))) {
|
||||||
|
part = matches[3] || matches[4];
|
||||||
|
if (matches[1] && taken) {
|
||||||
|
args.push(taken);
|
||||||
|
taken = '';
|
||||||
|
}
|
||||||
|
taken += part;
|
||||||
|
}
|
||||||
|
if (taken) { args.push(taken); }
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
function getValidLine(options, preCheck) {
|
function getValidLine(options, preCheck) {
|
||||||
var res, forceNext, resCheck, limitMessage,
|
var res, forceNext, resCheck, limitMessage,
|
||||||
matches, histInput;
|
matches, histInput, args;
|
||||||
function _getPhContent(param) { return getPhContent(param, options); }
|
function _getPhContent(param) { return getPhContent(param, options); }
|
||||||
|
function addDisplay(text)
|
||||||
|
{ options.display += (/[^\r\n]$/.test(options.display) ? '\n' : '') + text; }
|
||||||
|
|
||||||
options.limitSrc = options.limit;
|
options.limitSrc = options.limit;
|
||||||
options.displaySrc = options.display;
|
options.displaySrc = options.display;
|
||||||
|
@ -677,14 +696,15 @@ function getValidLine(options, preCheck) {
|
||||||
forceNext = false;
|
forceNext = false;
|
||||||
limitMessage = '';
|
limitMessage = '';
|
||||||
|
|
||||||
|
if (options.defaultInput && !res) { res = options.defaultInput; }
|
||||||
|
|
||||||
if (options.history) {
|
if (options.history) {
|
||||||
if ((matches = /^\s*\!(?:\!|-1)(:p)?\s*$/.exec(res))) { // `!!` `!-1` +`:p`
|
if ((matches = /^\s*\!(?:\!|-1)(:p)?\s*$/.exec(res))) { // `!!` `!-1` +`:p`
|
||||||
histInput = inputHistory[0] || '';
|
histInput = inputHistory[0] || '';
|
||||||
if (matches[1]) { forceNext = true; } // only display
|
if (matches[1]) { forceNext = true; } // only display
|
||||||
else { res = histInput; } // replace input
|
else { res = histInput; } // replace input
|
||||||
// Show it even if it is empty (NL only).
|
// Show it even if it is empty (NL only).
|
||||||
options.display +=
|
addDisplay(histInput + '\n');
|
||||||
(/[^\n]$/.test(options.display) ? '\n' : '') + histInput + '\n';
|
|
||||||
if (!forceNext) { // Loop may break
|
if (!forceNext) { // Loop may break
|
||||||
options.displayOnly = true;
|
options.displayOnly = true;
|
||||||
_readlineSync(options);
|
_readlineSync(options);
|
||||||
|
@ -695,11 +715,34 @@ function getValidLine(options, preCheck) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.cd && res) {
|
||||||
|
args = parseCL(res);
|
||||||
|
switch (args[0].toLowerCase()) {
|
||||||
|
case 'cd':
|
||||||
|
if (args[1]) {
|
||||||
|
try {
|
||||||
|
process.chdir(args[1].trim() === '~' ? (
|
||||||
|
IS_WIN ? (process.env.HOMEDRIVE || '') + (process.env.HOMEPATH || '') :
|
||||||
|
process.env.HOME || '') : args[1]);
|
||||||
|
} catch (e) {
|
||||||
|
addDisplay(e + '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forceNext = true;
|
||||||
|
break;
|
||||||
|
case 'pwd':
|
||||||
|
addDisplay(process.cwd());
|
||||||
|
forceNext = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (preCheck) {
|
if (preCheck) {
|
||||||
resCheck = preCheck(res, options);
|
resCheck = preCheck(res, options);
|
||||||
res = resCheck.res;
|
res = resCheck.res;
|
||||||
if (resCheck.forceNext) { forceNext = true; } // Don't switch to false.
|
if (resCheck.forceNext) { forceNext = true; } // Don't switch to false.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forceNext) {
|
if (!forceNext) {
|
||||||
if (!options.limitSrc.length ||
|
if (!options.limitSrc.length ||
|
||||||
isMatched(res, options.limitSrc, options.caseSensitive)) { break; }
|
isMatched(res, options.limitSrc, options.caseSensitive)) { break; }
|
||||||
|
@ -707,9 +750,8 @@ function getValidLine(options, preCheck) {
|
||||||
{ limitMessage = replacePlaceholder(options.limitMessage, _getPhContent); }
|
{ limitMessage = replacePlaceholder(options.limitMessage, _getPhContent); }
|
||||||
}
|
}
|
||||||
|
|
||||||
options.display += (/[^\n]$/.test(options.display) ? '\n' : '') +
|
addDisplay((limitMessage ? limitMessage + '\n' : '') +
|
||||||
(limitMessage ? limitMessage + '\n' : '') +
|
replacePlaceholder(options.displaySrc + '', _getPhContent));
|
||||||
replacePlaceholder(options.displaySrc + '', _getPhContent);
|
|
||||||
}
|
}
|
||||||
return toBool(res, options);
|
return toBool(res, options);
|
||||||
}
|
}
|
||||||
|
@ -823,22 +865,26 @@ exports.questionNewPassword = function(query, options) {
|
||||||
param === 'length' ? min + '...' + max : null;
|
param === 'length' ? min + '...' + max : null;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// added: charlist, min, max, confirm
|
// added: charlist, min, max, confirmMessage, unmatchMessage
|
||||||
charlist, min, max, confirm, limit, resCharlist, limitMessage, res1, res2;
|
charlist, min, max, confirmMessage, unmatchMessage,
|
||||||
|
limit, resCharlist, limitMessage, res1, res2;
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
charlist = replacePlaceholder(
|
charlist = replacePlaceholder(
|
||||||
options && options.charlist ? options.charlist + '' : '${!-~}', getPhCharlist);
|
options.charlist ? options.charlist + '' : '${!-~}', getPhCharlist);
|
||||||
if (options) { min = options.min; max = options.max; }
|
if (isNaN(min = parseInt(options.min, 10)) || typeof min !== 'number') { min = 12; }
|
||||||
if (isNaN(min = parseInt(min, 10)) || typeof min !== 'number') { min = 12; }
|
if (isNaN(max = parseInt(options.max, 10)) || typeof max !== 'number') { max = 24; }
|
||||||
if (isNaN(max = parseInt(max, 10)) || typeof max !== 'number') { max = 24; }
|
|
||||||
limit = new RegExp('^[' + charlist.replace(/[^A-Za-z0-9_ ]/g, '\\$&') +
|
limit = new RegExp('^[' + charlist.replace(/[^A-Za-z0-9_ ]/g, '\\$&') +
|
||||||
']{' + min + ',' + max + '}$');
|
']{' + min + ',' + max + '}$');
|
||||||
resCharlist = array2charlist([charlist], readOptions.caseSensitive, true);
|
resCharlist = array2charlist([charlist], readOptions.caseSensitive, true);
|
||||||
resCharlist.text = joinChunks(resCharlist.values, resCharlist.suppressed);
|
resCharlist.text = joinChunks(resCharlist.values, resCharlist.suppressed);
|
||||||
|
|
||||||
/* jshint eqnull:true */
|
/* jshint eqnull:true */
|
||||||
confirm = options && options.confirm != null ? options.confirm :
|
confirmMessage = options.confirmMessage != null ? options.confirmMessage :
|
||||||
'Reinput same one to confirm it :';
|
'Reinput same one to confirm it :';
|
||||||
|
unmatchMessage = options.unmatchMessage != null ? options.unmatchMessage :
|
||||||
|
'It differs from first one.' +
|
||||||
|
' Hit only Enter key if you want to retry from first one.';
|
||||||
/* jshint eqnull:false */
|
/* jshint eqnull:false */
|
||||||
|
|
||||||
/* jshint eqnull:true */
|
/* jshint eqnull:true */
|
||||||
|
@ -852,9 +898,8 @@ exports.questionNewPassword = function(query, options) {
|
||||||
res1 = exports.question(query, readOptions);
|
res1 = exports.question(query, readOptions);
|
||||||
|
|
||||||
readOptions.limit = [res1, ''];
|
readOptions.limit = [res1, ''];
|
||||||
readOptions.limitMessage = 'Two passwords don\'t match.' +
|
readOptions.limitMessage = unmatchMessage;
|
||||||
' Hit only Enter key if you want to retry from first password.';
|
res2 = exports.question(confirmMessage, readOptions);
|
||||||
res2 = exports.question(confirm, readOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res1;
|
return res1;
|
||||||
|
@ -887,38 +932,85 @@ exports.questionFloat = function(query, options) {
|
||||||
exports.questionPath = function(query, options) {
|
exports.questionPath = function(query, options) {
|
||||||
var readOptions = margeOptions({
|
var readOptions = margeOptions({
|
||||||
// -------- default
|
// -------- default
|
||||||
limitMessage: 'Input valid path, please.${( Min:)minSize}${( Max:)maxSize}',
|
hideEchoBack: false,
|
||||||
|
limitMessage: '${error(\n)}Input valid path, please.' +
|
||||||
|
'${( Min:)minSize}${( Max:)maxSize}',
|
||||||
history: true,
|
history: true,
|
||||||
cd: true
|
cd: true
|
||||||
}, options, {
|
}, options, {
|
||||||
// -------- forced
|
// -------- forced
|
||||||
keepWhitespace: false,
|
keepWhitespace: false,
|
||||||
limit: function(value) {
|
limit: function(value) {
|
||||||
var stat;
|
var exists, stat, res, pathUtil = require('path');
|
||||||
if (!fs.existsSync(value)) { return; }
|
// mkdir -p
|
||||||
validPath = fs.realpathSync(value);
|
function mkdirParents(dirPath) {
|
||||||
if (options) {
|
dirPath.split(/\/|\\/).reduce(function(parents, dir) {
|
||||||
if (options.minSize || options.maxSize ||
|
var path = pathUtil.resolve((parents += dir + pathUtil.sep));
|
||||||
options.isFile || options.isDirectory) {
|
if (!fs.existsSync(path)) {
|
||||||
stat = fs.statSync(validPath);
|
fs.mkdirSync(path);
|
||||||
if (options.minSize && stat.size < +options.minSize ||
|
} else if (!fs.statSync(path).isDirectory()) {
|
||||||
options.maxSize && stat.size > +options.maxSize ||
|
throw new Error('Non directory already exists: ' + path);
|
||||||
options.isFile && !stat.isFile() ||
|
|
||||||
options.isDirectory && !stat.isDirectory()) { return; }
|
|
||||||
}
|
}
|
||||||
if (typeof options.validate === 'function' && !options.validate(validPath))
|
return parents;
|
||||||
{ return; }
|
}, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
exists = fs.existsSync(value);
|
||||||
|
validPath = exists ? fs.realpathSync(value) : pathUtil.resolve(value);
|
||||||
|
// options.exists default: true, not-bool: no-check
|
||||||
|
if (!options.hasOwnProperty('exists') && !exists ||
|
||||||
|
typeof options.exists === 'boolean' && options.exists !== exists) {
|
||||||
|
error = (exists ? 'Already exists' : 'No such file or directory') +
|
||||||
|
': ' + validPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!exists && options.create) {
|
||||||
|
if (options.isDirectory) {
|
||||||
|
mkdirParents(validPath);
|
||||||
|
} else {
|
||||||
|
mkdirParents(pathUtil.dirname(validPath));
|
||||||
|
fs.closeSync(fs.openSync(validPath, 'w')); // touch
|
||||||
|
}
|
||||||
|
validPath = fs.realpathSync(validPath);
|
||||||
|
}
|
||||||
|
if (exists && (options.minSize || options.maxSize ||
|
||||||
|
options.isFile || options.isDirectory)) {
|
||||||
|
stat = fs.statSync(validPath);
|
||||||
|
// type check first (directory has zero size)
|
||||||
|
if (options.isFile && !stat.isFile()) {
|
||||||
|
error = 'Not file: ' + validPath;
|
||||||
|
return;
|
||||||
|
} else if (options.isDirectory && !stat.isDirectory()) {
|
||||||
|
error = 'Not directory: ' + validPath;
|
||||||
|
return;
|
||||||
|
} else if (options.minSize && stat.size < +options.minSize ||
|
||||||
|
options.maxSize && stat.size > +options.maxSize) {
|
||||||
|
error = 'Size ' + stat.size +' is out of range: ' + validPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof options.validate === 'function' &&
|
||||||
|
(res = options.validate(validPath)) !== true) {
|
||||||
|
error = res + '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
error = e + '';
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
// trueValue, falseValue are don't work.
|
// trueValue, falseValue are don't work.
|
||||||
phContent: function(param) {
|
phContent: function(param) {
|
||||||
return param !== 'minSize' && param !== 'maxSize' ? null :
|
return param === 'error' ? error :
|
||||||
options && options.hasOwnProperty(param) ? options[param] + '' : '';
|
param !== 'minSize' && param !== 'maxSize' ? null :
|
||||||
|
options.hasOwnProperty(param) ? options[param] + '' : '';
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// added: minSize, maxSize, isFile, isDirectory, validate
|
// added: exists, create, minSize, maxSize, isFile, isDirectory, validate
|
||||||
validPath;
|
validPath, error = '';
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
/* jshint eqnull:true */
|
/* jshint eqnull:true */
|
||||||
if (query == null) { query = 'Input path (you can "cd" and "pwd") :'; }
|
if (query == null) { query = 'Input path (you can "cd" and "pwd") :'; }
|
||||||
|
@ -931,6 +1023,7 @@ exports.questionPath = function(query, options) {
|
||||||
exports.promptSimShell = function(options) {
|
exports.promptSimShell = function(options) {
|
||||||
return exports.prompt(margeOptions({
|
return exports.prompt(margeOptions({
|
||||||
// -------- default
|
// -------- default
|
||||||
|
hideEchoBack: false,
|
||||||
history: true
|
history: true
|
||||||
}, options, {
|
}, options, {
|
||||||
// -------- forced
|
// -------- forced
|
||||||
|
@ -946,7 +1039,26 @@ exports.promptSimShell = function(options) {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.keyInYN = function(query, options) {
|
exports.promptCL = function(options) {
|
||||||
|
return exports.prompt(margeOptions({
|
||||||
|
// -------- default
|
||||||
|
hideEchoBack: false,
|
||||||
|
history: true
|
||||||
|
}, options, {
|
||||||
|
// -------- forced
|
||||||
|
prompt: (function() {
|
||||||
|
return IS_WIN ?
|
||||||
|
'${cwd}>' :
|
||||||
|
// 'user@host:cwd$ '
|
||||||
|
(process.env.USER || '') +
|
||||||
|
(process.env.HOSTNAME ?
|
||||||
|
'@' + process.env.HOSTNAME.replace(/\..*$/, '') : '') +
|
||||||
|
':${cwdHome}$ ';
|
||||||
|
})()
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
function _keyInYN(query, options, limit) {
|
||||||
var res;
|
var res;
|
||||||
/* jshint eqnull:true */
|
/* jshint eqnull:true */
|
||||||
if (query == null) { query = 'Are you sure? :'; }
|
if (query == null) { query = 'Are you sure? :'; }
|
||||||
|
@ -956,13 +1068,17 @@ exports.keyInYN = function(query, options) {
|
||||||
res = exports.keyIn(query, margeOptions(options, {
|
res = exports.keyIn(query, margeOptions(options, {
|
||||||
// -------- forced
|
// -------- forced
|
||||||
hideEchoBack: false,
|
hideEchoBack: false,
|
||||||
limit: options && options.strict ? 'yn' : null,
|
limit: limit,
|
||||||
trueValue: 'y',
|
trueValue: 'y',
|
||||||
falseValue: 'n',
|
falseValue: 'n',
|
||||||
caseSensitive: false
|
caseSensitive: false
|
||||||
}));
|
}));
|
||||||
|
// added: guide
|
||||||
return typeof res === 'boolean' ? res : '';
|
return typeof res === 'boolean' ? res : '';
|
||||||
};
|
}
|
||||||
|
exports.keyInYN = function(query, options) { return _keyInYN(query, options); };
|
||||||
|
exports.keyInYNStrict = function(query, options)
|
||||||
|
{ return _keyInYN(query, options, 'yn'); };
|
||||||
|
|
||||||
exports.keyInPause = function(query, options) {
|
exports.keyInPause = function(query, options) {
|
||||||
/* jshint eqnull:true */
|
/* jshint eqnull:true */
|
||||||
|
@ -970,11 +1086,15 @@ exports.keyInPause = function(query, options) {
|
||||||
/* jshint eqnull:false */
|
/* jshint eqnull:false */
|
||||||
if ((!options || options.guide !== false) && (query += ''))
|
if ((!options || options.guide !== false) && (query += ''))
|
||||||
{ query = query.replace(/\s+$/, '') + ' (Hit any key)'; }
|
{ query = query.replace(/\s+$/, '') + ' (Hit any key)'; }
|
||||||
exports.keyIn(query, margeOptions(options, {
|
exports.keyIn(query, margeOptions({
|
||||||
|
// -------- default
|
||||||
|
limit: null
|
||||||
|
}, options, {
|
||||||
// -------- forced
|
// -------- forced
|
||||||
hideEchoBack: true,
|
hideEchoBack: true,
|
||||||
mask: ''
|
mask: ''
|
||||||
}));
|
}));
|
||||||
|
// added: guide
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -989,6 +1109,7 @@ exports.keyInSelect = function(query, items, options) {
|
||||||
caseSensitive: false
|
caseSensitive: false
|
||||||
// limit (by items)
|
// limit (by items)
|
||||||
}),
|
}),
|
||||||
|
// added: guide, cancel
|
||||||
keylist = '', key2i = {}, charCode = 49 /* '1' */, display = '\n';
|
keylist = '', key2i = {}, charCode = 49 /* '1' */, display = '\n';
|
||||||
if (!Array.isArray(items) || items.length > 35)
|
if (!Array.isArray(items) || items.length > 35)
|
||||||
{ throw '`items` must be Array (max length: 35).'; }
|
{ throw '`items` must be Array (max length: 35).'; }
|
||||||
|
|
Loading…
Reference in a new issue