diff --git a/lib/readline-sync.js b/lib/readline-sync.js index aac2394..da7bcdf 100644 --- a/lib/readline-sync.js +++ b/lib/readline-sync.js @@ -35,7 +35,8 @@ var print: void 0, history: true, cd: false, - phContent: void 0 + phContent: void 0, + preCheck: void 0 }, fdR = 'none', fdW, ttyR, isRawMode = false, @@ -494,6 +495,7 @@ function margeOptions() { // ================ function case 'print': // * * case 'phContent': // * + case 'preCheck': // * options[optionName] = typeof value === 'function' ? value : void 0; break; // ================ other @@ -662,14 +664,14 @@ function getPhCharlist(param) { return text; } -// cmd "arg" " a r g " 'a"r"g' "a""rg" "arg -function parseCL(cl) { +// 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) { + part = matches[3] || matches[4] || ''; + if (matches[1]) { args.push(taken); taken = ''; } @@ -679,9 +681,17 @@ function parseCL(cl) { return args; } -function getValidLine(options, preCheck) { - var res, forceNext, resCheck, limitMessage, - matches, histInput, args; +function toBool(res, options) { + return ( + (options.trueValue.length && + isMatched(res, options.trueValue, options.caseSensitive)) ? true : + (options.falseValue.length && + isMatched(res, options.falseValue, options.caseSensitive)) ? false : res); +} + +function getValidLine(options) { + var res, forceNext, limitMessage, + matches, histInput, args, resCheck; function _getPhContent(param) { return getPhContent(param, options); } function addDisplay(text) { options.display += (/[^\r\n]$/.test(options.display) ? '\n' : '') + text; } @@ -715,8 +725,8 @@ function getValidLine(options, preCheck) { } } - if (options.cd && res) { - args = parseCL(res); + if (!forceNext && options.cd && res) { + args = parseCl(res); switch (args[0].toLowerCase()) { case 'cd': if (args[1]) { @@ -737,8 +747,8 @@ function getValidLine(options, preCheck) { } } - if (preCheck) { - resCheck = preCheck(res, options); + if (!forceNext && options.preCheck) { + resCheck = options.preCheck(res, options); res = resCheck.res; if (resCheck.forceNext) { forceNext = true; } // Don't switch to false. } @@ -756,14 +766,6 @@ function getValidLine(options, preCheck) { return toBool(res, options); } -function toBool(res, options) { - return ( - (options.trueValue.length && - isMatched(res, options.trueValue, options.caseSensitive)) ? true : - (options.falseValue.length && - isMatched(res, options.falseValue, options.caseSensitive)) ? false : res); -} - // for dev exports._DBG_set_useExt = function(val) { _DBG_useExt = val; }; exports._DBG_set_checkOptions = function(val) { _DBG_checkOptions = val; }; @@ -1020,26 +1022,97 @@ exports.questionPath = function(query, options) { return validPath; }; -exports.promptSimShell = function(options) { - return exports.prompt(margeOptions({ +// props: preCheck, args, hRes, limit +function getClHandler(commandHandler, options) { + var clHandler = {}, hIndex = {}; + if (typeof commandHandler === 'object') { + Object.keys(commandHandler).forEach(function(cmd) { + if (typeof commandHandler[cmd] === 'function') { + hIndex[options.caseSensitive ? cmd : cmd.toLowerCase()] = commandHandler[cmd]; + } + }); + clHandler.preCheck = function(res) { + var cmdKey; + clHandler.args = parseCl(res); + cmdKey = clHandler.args[0] || ''; + if (!options.caseSensitive) { cmdKey = cmdKey.toLowerCase(); } + clHandler.hRes = + hIndex.hasOwnProperty(cmdKey) ? + hIndex[cmdKey].apply(res, clHandler.args.slice(1)) : + hIndex.hasOwnProperty('_') ? hIndex._.apply(res, clHandler.args) : null; + return {res: res, forceNext: false}; + }; + if (!hIndex.hasOwnProperty('_')) { + clHandler.limit = function() { // It's called after preCheck. + var cmdKey = clHandler.args[0] || ''; + if (!options.caseSensitive) { cmdKey = cmdKey.toLowerCase(); } + return hIndex.hasOwnProperty(cmdKey); + }; + } + } else { + clHandler.preCheck = function(res) { + clHandler.args = parseCl(res); + clHandler.hRes = typeof commandHandler === 'function' ? + commandHandler.apply(res, clHandler.args) : null; + return {res: res, forceNext: false}; + }; + } + return clHandler; +} + +exports.promptCL = function(commandHandler, options) { + var readOptions = margeOptions({ // -------- default hideEchoBack: false, + limitMessage: 'Requested command is not available.', + caseSensitive: false, history: true - }, options, { + }, options), // -------- forced - prompt: (function() { - return IS_WIN ? - '${cwd}>' : - // 'user@host:cwd$ ' - (process.env.USER || '') + - (process.env.HOSTNAME ? - '@' + process.env.HOSTNAME.replace(/\..*$/, '') : '') + - ':${cwdHome}$ '; - })() - })); + // trueValue, falseValue are don't work. + // preCheck, limit (by clHandler) + clHandler = getClHandler(commandHandler, readOptions); + readOptions.limit = clHandler.limit; + readOptions.preCheck = clHandler.preCheck; + exports.prompt(readOptions); + return clHandler.args; }; -exports.promptCL = function(options) { +exports.promptLoop = function(inputHandler, options) { + var readOptions = margeOptions({ + // -------- default + hideEchoBack: false, + trueValue: null, + falseValue: null, + caseSensitive: false, + history: true + }, options); + while (true) { if (inputHandler(exports.prompt(readOptions))) { break; } } + return; +}; + +exports.promptCLLoop = function(commandHandler, options) { + var readOptions = margeOptions({ + // -------- default + hideEchoBack: false, + limitMessage: 'Requested command is not available.', + caseSensitive: false, + history: true + }, options), + // -------- forced + // trueValue, falseValue are don't work. + // preCheck, limit (by clHandler) + clHandler = getClHandler(commandHandler, readOptions); + readOptions.limit = clHandler.limit; + readOptions.preCheck = clHandler.preCheck; + while (true) { + exports.prompt(readOptions); + if (clHandler.hRes) { break; } + } + return; +}; + +exports.promptSimShell = function(options) { return exports.prompt(margeOptions({ // -------- default hideEchoBack: false, @@ -1098,7 +1171,7 @@ exports.keyInPause = function(query, options) { return; }; -exports.keyInSelect = function(query, items, options) { +exports.keyInSelect = function(items, query, options) { var readOptions = margeOptions({ // -------- default hideEchoBack: false