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 getTempfile(name) {
|
||||
var path = require('path'), filepath, suffix = '', fd;
|
||||
var pathUtil = require('path'), filepath, suffix = '', fd;
|
||||
tempdir = tempdir || require('os').tmpdir();
|
||||
|
||||
while (true) {
|
||||
filepath = path.join(tempdir, name + suffix);
|
||||
filepath = pathUtil.join(tempdir, name + suffix);
|
||||
try {
|
||||
fd = fs.openSync(filepath, 'wx');
|
||||
} catch (e) {
|
||||
|
@ -662,10 +662,29 @@ function getPhCharlist(param) {
|
|||
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) {
|
||||
var res, forceNext, resCheck, limitMessage,
|
||||
matches, histInput;
|
||||
matches, histInput, args;
|
||||
function _getPhContent(param) { return getPhContent(param, options); }
|
||||
function addDisplay(text)
|
||||
{ options.display += (/[^\r\n]$/.test(options.display) ? '\n' : '') + text; }
|
||||
|
||||
options.limitSrc = options.limit;
|
||||
options.displaySrc = options.display;
|
||||
|
@ -677,14 +696,15 @@ function getValidLine(options, preCheck) {
|
|||
forceNext = false;
|
||||
limitMessage = '';
|
||||
|
||||
if (options.defaultInput && !res) { res = options.defaultInput; }
|
||||
|
||||
if (options.history) {
|
||||
if ((matches = /^\s*\!(?:\!|-1)(:p)?\s*$/.exec(res))) { // `!!` `!-1` +`:p`
|
||||
histInput = inputHistory[0] || '';
|
||||
if (matches[1]) { forceNext = true; } // only display
|
||||
else { res = histInput; } // replace input
|
||||
// Show it even if it is empty (NL only).
|
||||
options.display +=
|
||||
(/[^\n]$/.test(options.display) ? '\n' : '') + histInput + '\n';
|
||||
addDisplay(histInput + '\n');
|
||||
if (!forceNext) { // Loop may break
|
||||
options.displayOnly = true;
|
||||
_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) {
|
||||
resCheck = preCheck(res, options);
|
||||
res = resCheck.res;
|
||||
if (resCheck.forceNext) { forceNext = true; } // Don't switch to false.
|
||||
}
|
||||
|
||||
if (!forceNext) {
|
||||
if (!options.limitSrc.length ||
|
||||
isMatched(res, options.limitSrc, options.caseSensitive)) { break; }
|
||||
|
@ -707,9 +750,8 @@ function getValidLine(options, preCheck) {
|
|||
{ limitMessage = replacePlaceholder(options.limitMessage, _getPhContent); }
|
||||
}
|
||||
|
||||
options.display += (/[^\n]$/.test(options.display) ? '\n' : '') +
|
||||
(limitMessage ? limitMessage + '\n' : '') +
|
||||
replacePlaceholder(options.displaySrc + '', _getPhContent);
|
||||
addDisplay((limitMessage ? limitMessage + '\n' : '') +
|
||||
replacePlaceholder(options.displaySrc + '', _getPhContent));
|
||||
}
|
||||
return toBool(res, options);
|
||||
}
|
||||
|
@ -823,22 +865,26 @@ exports.questionNewPassword = function(query, options) {
|
|||
param === 'length' ? min + '...' + max : null;
|
||||
}
|
||||
}),
|
||||
// added: charlist, min, max, confirm
|
||||
charlist, min, max, confirm, limit, resCharlist, limitMessage, res1, res2;
|
||||
// added: charlist, min, max, confirmMessage, unmatchMessage
|
||||
charlist, min, max, confirmMessage, unmatchMessage,
|
||||
limit, resCharlist, limitMessage, res1, res2;
|
||||
options = options || {};
|
||||
|
||||
charlist = replacePlaceholder(
|
||||
options && options.charlist ? options.charlist + '' : '${!-~}', getPhCharlist);
|
||||
if (options) { min = options.min; max = options.max; }
|
||||
if (isNaN(min = parseInt(min, 10)) || typeof min !== 'number') { min = 12; }
|
||||
if (isNaN(max = parseInt(max, 10)) || typeof max !== 'number') { max = 24; }
|
||||
options.charlist ? options.charlist + '' : '${!-~}', getPhCharlist);
|
||||
if (isNaN(min = parseInt(options.min, 10)) || typeof min !== 'number') { min = 12; }
|
||||
if (isNaN(max = parseInt(options.max, 10)) || typeof max !== 'number') { max = 24; }
|
||||
limit = new RegExp('^[' + charlist.replace(/[^A-Za-z0-9_ ]/g, '\\$&') +
|
||||
']{' + min + ',' + max + '}$');
|
||||
resCharlist = array2charlist([charlist], readOptions.caseSensitive, true);
|
||||
resCharlist.text = joinChunks(resCharlist.values, resCharlist.suppressed);
|
||||
|
||||
/* jshint eqnull:true */
|
||||
confirm = options && options.confirm != null ? options.confirm :
|
||||
confirmMessage = options.confirmMessage != null ? options.confirmMessage :
|
||||
'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:true */
|
||||
|
@ -852,9 +898,8 @@ exports.questionNewPassword = function(query, options) {
|
|||
res1 = exports.question(query, readOptions);
|
||||
|
||||
readOptions.limit = [res1, ''];
|
||||
readOptions.limitMessage = 'Two passwords don\'t match.' +
|
||||
' Hit only Enter key if you want to retry from first password.';
|
||||
res2 = exports.question(confirm, readOptions);
|
||||
readOptions.limitMessage = unmatchMessage;
|
||||
res2 = exports.question(confirmMessage, readOptions);
|
||||
}
|
||||
|
||||
return res1;
|
||||
|
@ -887,38 +932,85 @@ exports.questionFloat = function(query, options) {
|
|||
exports.questionPath = function(query, options) {
|
||||
var readOptions = margeOptions({
|
||||
// -------- 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,
|
||||
cd: true
|
||||
}, options, {
|
||||
// -------- forced
|
||||
keepWhitespace: false,
|
||||
limit: function(value) {
|
||||
var stat;
|
||||
if (!fs.existsSync(value)) { return; }
|
||||
validPath = fs.realpathSync(value);
|
||||
if (options) {
|
||||
if (options.minSize || options.maxSize ||
|
||||
options.isFile || options.isDirectory) {
|
||||
stat = fs.statSync(validPath);
|
||||
if (options.minSize && stat.size < +options.minSize ||
|
||||
options.maxSize && stat.size > +options.maxSize ||
|
||||
options.isFile && !stat.isFile() ||
|
||||
options.isDirectory && !stat.isDirectory()) { return; }
|
||||
var exists, stat, res, pathUtil = require('path');
|
||||
// mkdir -p
|
||||
function mkdirParents(dirPath) {
|
||||
dirPath.split(/\/|\\/).reduce(function(parents, dir) {
|
||||
var path = pathUtil.resolve((parents += dir + pathUtil.sep));
|
||||
if (!fs.existsSync(path)) {
|
||||
fs.mkdirSync(path);
|
||||
} else if (!fs.statSync(path).isDirectory()) {
|
||||
throw new Error('Non directory already exists: ' + path);
|
||||
}
|
||||
return parents;
|
||||
}, '');
|
||||
}
|
||||
|
||||
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 (typeof options.validate === 'function' && !options.validate(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;
|
||||
},
|
||||
// trueValue, falseValue are don't work.
|
||||
phContent: function(param) {
|
||||
return param !== 'minSize' && param !== 'maxSize' ? null :
|
||||
options && options.hasOwnProperty(param) ? options[param] + '' : '';
|
||||
return param === 'error' ? error :
|
||||
param !== 'minSize' && param !== 'maxSize' ? null :
|
||||
options.hasOwnProperty(param) ? options[param] + '' : '';
|
||||
}
|
||||
}),
|
||||
// added: minSize, maxSize, isFile, isDirectory, validate
|
||||
validPath;
|
||||
// added: exists, create, minSize, maxSize, isFile, isDirectory, validate
|
||||
validPath, error = '';
|
||||
options = options || {};
|
||||
|
||||
/* jshint eqnull:true */
|
||||
if (query == null) { query = 'Input path (you can "cd" and "pwd") :'; }
|
||||
|
@ -931,6 +1023,7 @@ exports.questionPath = function(query, options) {
|
|||
exports.promptSimShell = function(options) {
|
||||
return exports.prompt(margeOptions({
|
||||
// -------- default
|
||||
hideEchoBack: false,
|
||||
history: true
|
||||
}, options, {
|
||||
// -------- 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;
|
||||
/* jshint eqnull:true */
|
||||
if (query == null) { query = 'Are you sure? :'; }
|
||||
|
@ -956,13 +1068,17 @@ exports.keyInYN = function(query, options) {
|
|||
res = exports.keyIn(query, margeOptions(options, {
|
||||
// -------- forced
|
||||
hideEchoBack: false,
|
||||
limit: options && options.strict ? 'yn' : null,
|
||||
limit: limit,
|
||||
trueValue: 'y',
|
||||
falseValue: 'n',
|
||||
caseSensitive: false
|
||||
}));
|
||||
// added: guide
|
||||
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) {
|
||||
/* jshint eqnull:true */
|
||||
|
@ -970,11 +1086,15 @@ exports.keyInPause = function(query, options) {
|
|||
/* jshint eqnull:false */
|
||||
if ((!options || options.guide !== false) && (query += ''))
|
||||
{ query = query.replace(/\s+$/, '') + ' (Hit any key)'; }
|
||||
exports.keyIn(query, margeOptions(options, {
|
||||
exports.keyIn(query, margeOptions({
|
||||
// -------- default
|
||||
limit: null
|
||||
}, options, {
|
||||
// -------- forced
|
||||
hideEchoBack: true,
|
||||
mask: ''
|
||||
}));
|
||||
// added: guide
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -989,6 +1109,7 @@ exports.keyInSelect = function(query, items, options) {
|
|||
caseSensitive: false
|
||||
// limit (by items)
|
||||
}),
|
||||
// added: guide, cancel
|
||||
keylist = '', key2i = {}, charCode = 49 /* '1' */, display = '\n';
|
||||
if (!Array.isArray(items) || items.length > 35)
|
||||
{ throw '`items` must be Array (max length: 35).'; }
|
||||
|
|
Loading…
Reference in a new issue