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 _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; } 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)) if (!exists && options.create) {
{ return; } 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).'; }