diff --git a/lib/commands/new_project.js b/lib/commands/new_project.js index 8d172a29d..61abe5e15 100644 --- a/lib/commands/new_project.js +++ b/lib/commands/new_project.js @@ -88,7 +88,7 @@ function _promptUser(projName, stage, s3Bucket, region, notificationEmail, awsPr // Prompt: region - initial region for this stage prompts.properties.region = { description: JawsCLI.promptList( - 'Which AWS Region would you like to start with (enter a number): ', + 'Which AWS Region would you like to start with: ', regions, regions[0]).yellow, message: 'Please enter a valid region in the list', diff --git a/lib/utils/cli.js b/lib/utils/cli.js index 5a0b307ca..b1a85005b 100644 --- a/lib/utils/cli.js +++ b/lib/utils/cli.js @@ -1,4 +1,4 @@ -'use strict'; +// 'use strict'; /** * JAWS Services: CLI @@ -18,14 +18,16 @@ var Promise = require('bluebird'), Promise.promisifyAll(fs); +var JawsCLI = {}; + /** * Prompt */ -module.exports.prompt = function() { - prompt.start(); - prompt.delimiter = ""; - prompt.message = "JAWS: "; - return prompt; +module.exports.prompt = JawsCLI.prompt = function() { + prompt.start(); + prompt.delimiter = ''; + prompt.message = 'JAWS: '; + return prompt; }; /** @@ -34,11 +36,11 @@ module.exports.prompt = function() { * @param choices * @returns {*} */ -module.exports.promptList = function(message, choices, defaultChoice) { +module.exports.promptList = JawsCLI.promptList = function(message, choices, defaultChoice) { message = message + '('.white + defaultChoice + ')'.white + os.EOL; - for (var i = 0;i < choices.length;i++) { + for (var i = 0; i < choices.length; i++) { message = message + ' - ' + choices[i].toString().yellow @@ -48,10 +50,147 @@ module.exports.promptList = function(message, choices, defaultChoice) { return message; }; +/** + * Prompt CheckList + * + * @param message + * @param choices + * @param spacer + * + * Accepts array: {key: '1: ', key2: '(deployed) ', value: 'a great choice!'} + * Or: {spacer: true} + * + * @returns {Promise} + */ +module.exports.promptChecklist = JawsCLI.promptChecklist = function(message, choices, spacer) { + return new Promise(function(resolve, reject) { + + // Log Message + console.log('JAWS: ' + chalk.yellow(message)); + + var state = { + choices: choices, + index: 1, + lines: 0, + }; + + // Add Done and Cancel to choices + state.choices.push( + { spacer: true }, + { action: 'Done'}); + + var keypress = require('keypress'); + keypress(process.stdin); + + process.stdin.on('keypress', function (ch, key) { + if (key && key.ctrl && key.name == 'c') { + process.stdin.pause(); + } else if (key.name == 'up' && state.index > 1) { + if (state.choices[state.index - 2].spacer) { + state.index = state.index - 2; + } else { + state.index = state.index - 1; + } + return _render(); + } else if (key.name == 'down' && state.index < state.choices.length) { + if (state.choices[state.index].spacer) { + state.index = state.index + 2; + } else { + state.index = state.index + 1; + } + return _render(); + } else if (key.name == 'return') { + if (state.choices[state.index - 1].action && state.choices[state.index - 1].action.toLowerCase() === 'done') { + return _close(); + } else { + state.choices[state.index - 1].toggled = state.choices[state.index - 1].toggled ? false : true; + return _render(); + } + } + }); + + process.stdin.setRawMode(true); + process.stdin.resume(); + + // Initial Render + _render(); + + // Render function + function _render() { + + // Clear Rendering + for (var i = 1; i < state.lines; i++) { + process.stdout.moveCursor(0, -1); + process.stdout.clearLine(); + } + + // Reset line count + state.lines = 1; + + // Render Line + for (var i = 0; i < state.choices.length; i++) { + var choice = state.choices[i], + line = ''; + + // Increment line count + state.lines++; + + // Select Arrow + var arrow = i === (state.index - 1) ? ' > ' : ' '; + + // Render Choice + if (choice.value) { + // Line - Key + if (choice.key) line = line + choice.key; + // Line - Key2 + if (choice.key2) line = line + choice.key2; + // Line - Line + line = line + choice.value; + // Add toggled style + if (choice.toggled) { + line = chalk.yellow(line); + } + // Add line break + line = line + os.EOL; + } + + // Render Spacer + if (choice.spacer) { + line = (spacer ? spacer : ' ') + os.EOL; + } + + // Render Action + if (choice.action) { + line = choice.action + os.EOL; + } + + // TODO: Add custom word wrap after measuring terminal width. Re-count lines. + + // Render + process.stdout.write(arrow + line); + } + } + + // Close function + function _close() { + + process.stdin.pause(); + + // Clean Choices + for (var i = 0; i < state.choices.length; i++) { + if (state.choices[i].spacer) state.choices.splice(i, 1); + if (state.choices[i].action) state.choices.splice(i, 1); + } + + return resolve(state.choices); + } + }); +}; + /** * ASCII */ -module.exports.ascii = function() { +module.exports.ascii = JawsCLI.ascii = function() { var art = ''; art = art + ' ____ _____ __ __ _________ ' + os.EOL; @@ -60,7 +199,7 @@ module.exports.ascii = function() { art = art + ' /\\__| / | \\ / / \\ ' + os.EOL; art = art + ' \\________\\____|__ /\\__/\\__/ /_________/ v' + packageJson.version + os.EOL; art = art + '' + os.EOL; - art = art + ' *** The Server-less Framework *** ' + os.EOL; + art = art + ' *** The Server-Less Framework *** ' + os.EOL; console.log(chalk.yellow(art)); }; @@ -68,15 +207,15 @@ module.exports.ascii = function() { /** * Spinner */ -module.exports.spinner = function(message) { +module.exports.spinner = JawsCLI.spinner = function(message) { var spinner = new Spinner('JAWS: ' + chalk.yellow('%s ' + message)); spinner.setSpinnerString('|/-\\'); return spinner; -} +}; /** * Log */ -module.exports.log = function(message) { +module.exports.log = JawsCLI.log = function(message) { console.log('JAWS: ' + chalk.yellow(message)); -} +}; diff --git a/package.json b/package.json index a5d4b37b5..5bbf0aba1 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "insert-module-globals": "^6.5.2", "jaws-api-gateway-client": "0.11.0", "mkdirp-then": "^1.1.0", + "keypress": "^0.2.1", "moment": "^2.10.6", "node-uuid": "^1.4.2", "node-zip": "^1.1.0",