Add: defaultInput, Utility Methods

This commit is contained in:
anseki 2015-04-16 19:08:04 +09:00
parent b8e194e743
commit 69ce4ab6c2

View file

@ -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);
}
if (typeof options.validate === 'function' && !options.validate(validPath))
{ return; }
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 (!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).'; }