From a26b17e4205832a768a46467d2234c964174b59c Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 20 Jun 2015 09:28:43 -0700 Subject: [PATCH 1/3] Enable completion of options for commands --- index.js | 20 ++++++------ lib/completion.js | 7 +++++ test/completion.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 9382fef45..86e95889a 100644 --- a/index.js +++ b/index.js @@ -433,16 +433,6 @@ function Argv (processArgs, cwd) { } } - // if there's a handler associated with a - // command defer processing to it. - var handlerKeys = Object.keys(self.getCommandHandlers()) - for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) { - if (~argv._.indexOf(command)) { - self.getCommandHandlers()[command](self.reset()) - return self.argv - } - } - // we must run completions first, a user might // want to complete the --help or --version option. if (completionOpt in argv) { @@ -460,6 +450,16 @@ function Argv (processArgs, cwd) { return } + // if there's a handler associated with a + // command defer processing to it. + var handlerKeys = Object.keys(self.getCommandHandlers()) + for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) { + if (~argv._.indexOf(command)) { + self.getCommandHandlers()[command](self.reset()) + return self.argv + } + } + Object.keys(argv).forEach(function (key) { if (key === helpOpt && argv[key]) { self.showHelp('log') diff --git a/lib/completion.js b/lib/completion.js index 1024381b4..33e9b75e8 100644 --- a/lib/completion.js +++ b/lib/completion.js @@ -29,6 +29,13 @@ module.exports = function (yargs, usage) { } } + var handlers = yargs.getCommandHandlers() + for (var i = 0, ii = previous.length; i < ii; ++i) { + if (handlers[previous[i]]) { + return handlers[previous[i]](yargs.reset()) + } + } + if (!current.match(/^-/)) { usage.getCommands().forEach(function (command) { if (previous.indexOf(command[0]) === -1) { diff --git a/test/completion.js b/test/completion.js index 1f43fb38a..8d30dd143 100644 --- a/test/completion.js +++ b/test/completion.js @@ -43,6 +43,82 @@ describe('Completion', function () { r.logs.should.not.include('apple') }) + it('completes options for a command', function () { + var r = checkUsage(function () { + try { + return yargs(['--get-yargs-completions']) + .command('foo', 'foo command', function (subYargs) { + subYargs.options({ + bar: { + describe: 'bar option' + } + }) + .help('help') + .completion() + .argv + }) + .completion() + .argv + } catch (e) { + console.log(e.message) + } + }, ['./completion', '--get-yargs-completions', 'foo', '--b']) + + r.logs.should.have.length(2) + r.logs.should.include('--bar') + r.logs.should.include('--help') + }) + + it('completes options for the correct command', function () { + var r = checkUsage(function () { + try { + return yargs(['--get-yargs-completions']) + .command('cmd1', 'first command', function (subYargs) { + subYargs.options({ + opt1: { + describe: 'first option' + } + }) + .completion() + .argv + }) + .command('cmd2', 'second command', function (subYargs) { + subYargs.options({ + opt2: { + describe: 'second option' + } + }) + .completion() + .argv + }) + .completion() + .argv + } catch (e) { + console.log(e.message) + } + }, ['./completion', '--get-yargs-completions', 'cmd2', '--o']) + + r.logs.should.have.length(1) + r.logs.should.include('--opt2') + }) + + it('works if command has no options', function () { + var r = checkUsage(function () { + try { + return yargs(['--get-yargs-completions']) + .command('foo', 'foo command', function (subYargs) { + subYargs.completion().argv + }) + .completion() + .argv + } catch (e) { + console.log(e.message) + } + }, ['./completion', '--get-yargs-completions', 'foo', '--b']) + + r.logs.should.have.length(0) + }) + it("returns arguments as completion suggestion, if next contains '-'", function () { var r = checkUsage(function () { return yargs(['--get-yargs-completions']) From bb4ffd8d7249644de2a80dd90c497d7492e85f00 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 22 Jun 2015 22:09:57 -0700 Subject: [PATCH 2/3] a couple slight tweaks to @tschaub's completion fixes --- index.js | 33 +++++++++++++++------------------ test/completion.js | 37 +++++++------------------------------ 2 files changed, 22 insertions(+), 48 deletions(-) diff --git a/index.js b/index.js index 86e95889a..9bdb77c7d 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,6 @@ function Argv (processArgs, cwd) { strict = false helpOpt = null versionOpt = null - completionOpt = null commandHandlers = {} self.parsed = false @@ -352,7 +351,6 @@ function Argv (processArgs, cwd) { return usage.help() } - var completionOpt = null var completionCommand = null self.completion = function (cmd, desc, fn) { // a function to execute when generating @@ -365,7 +363,6 @@ function Argv (processArgs, cwd) { // register the completion command. completionCommand = cmd || 'completion' - completionOpt = completion.completionKey self.command(completionCommand, desc || 'generate bash completion script') // a function can be provided @@ -420,13 +417,23 @@ function Argv (processArgs, cwd) { // are two passes through the parser. If completion // is being performed short-circuit on the first pass. if (completionCommand && - (process.argv.join(' ')).indexOf(completionOpt) !== -1 && - !argv[completionOpt]) { + (process.argv.join(' ')).indexOf(completion.completionKey) !== -1 && + !argv[completion.completionKey]) { return argv } + // if there's a handler associated with a + // command defer processing to it. + var handlerKeys = Object.keys(self.getCommandHandlers()) + for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) { + if (~argv._.indexOf(command)) { + self.getCommandHandlers()[command](self.reset()) + return self.argv + } + } + // generate a completion script for adding to ~/.bashrc. - if (completionCommand && ~argv._.indexOf(completionCommand) && !argv[completionOpt]) { + if (completionCommand && ~argv._.indexOf(completionCommand) && !argv[completion.completionKey]) { self.showCompletionScript() if (exitProcess) { process.exit(0) @@ -435,7 +442,7 @@ function Argv (processArgs, cwd) { // we must run completions first, a user might // want to complete the --help or --version option. - if (completionOpt in argv) { + if (completion.completionKey in argv) { // we allow for asynchronous completions, // e.g., loading in a list of commands from an API. completion.getCompletion(function (completions) { @@ -450,16 +457,6 @@ function Argv (processArgs, cwd) { return } - // if there's a handler associated with a - // command defer processing to it. - var handlerKeys = Object.keys(self.getCommandHandlers()) - for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) { - if (~argv._.indexOf(command)) { - self.getCommandHandlers()[command](self.reset()) - return self.argv - } - } - Object.keys(argv).forEach(function (key) { if (key === helpOpt && argv[key]) { self.showHelp('log') @@ -476,7 +473,7 @@ function Argv (processArgs, cwd) { // if we're executed via bash completion, don't // bother with validation. - if (!argv[completionOpt]) { + if (!argv[completion.completionKey]) { validation.nonOptionCount(argv) validation.missingArgumentValue(argv) validation.requiredArguments(argv) diff --git a/test/completion.js b/test/completion.js index 8d30dd143..ecf02a3b4 100644 --- a/test/completion.js +++ b/test/completion.js @@ -1,8 +1,9 @@ /* global describe, it, beforeEach */ - var checkUsage = require('./helpers/utils').checkOutput var yargs = require('../') +require('chai').should() + describe('Completion', function () { beforeEach(function () { yargs.reset() @@ -11,15 +12,11 @@ describe('Completion', function () { describe('default completion behavior', function () { it('it returns a list of commands as completion suggestions', function () { var r = checkUsage(function () { - try { - return yargs(['--get-yargs-completions']) + return yargs(['--get-yargs-completions']) .command('foo', 'bar') .command('apple', 'banana') .completion() .argv - } catch (e) { - console.log(e.message) - } }, ['./completion', '--get-yargs-completions', '']) r.logs.should.include('apple') @@ -28,15 +25,10 @@ describe('Completion', function () { it('avoids repeating already included commands', function () { var r = checkUsage(function () { - try { - return yargs(['--get-yargs-completions']) + return yargs(['--get-yargs-completions']) .command('foo', 'bar') .command('apple', 'banana') - .completion() .argv - } catch (e) { - console.log(e.message) - } }, ['./completion', '--get-yargs-completions', 'apple']) r.logs.should.include('foo') @@ -45,8 +37,7 @@ describe('Completion', function () { it('completes options for a command', function () { var r = checkUsage(function () { - try { - return yargs(['--get-yargs-completions']) + return yargs(['--get-yargs-completions']) .command('foo', 'foo command', function (subYargs) { subYargs.options({ bar: { @@ -54,14 +45,10 @@ describe('Completion', function () { } }) .help('help') - .completion() .argv }) .completion() .argv - } catch (e) { - console.log(e.message) - } }, ['./completion', '--get-yargs-completions', 'foo', '--b']) r.logs.should.have.length(2) @@ -71,15 +58,13 @@ describe('Completion', function () { it('completes options for the correct command', function () { var r = checkUsage(function () { - try { - return yargs(['--get-yargs-completions']) + return yargs(['--get-yargs-completions']) .command('cmd1', 'first command', function (subYargs) { subYargs.options({ opt1: { describe: 'first option' } }) - .completion() .argv }) .command('cmd2', 'second command', function (subYargs) { @@ -88,14 +73,10 @@ describe('Completion', function () { describe: 'second option' } }) - .completion() .argv }) .completion() .argv - } catch (e) { - console.log(e.message) - } }, ['./completion', '--get-yargs-completions', 'cmd2', '--o']) r.logs.should.have.length(1) @@ -104,16 +85,12 @@ describe('Completion', function () { it('works if command has no options', function () { var r = checkUsage(function () { - try { - return yargs(['--get-yargs-completions']) + return yargs(['--get-yargs-completions']) .command('foo', 'foo command', function (subYargs) { subYargs.completion().argv }) .completion() .argv - } catch (e) { - console.log(e.message) - } }, ['./completion', '--get-yargs-completions', 'foo', '--b']) r.logs.should.have.length(0) From f7b9c9ebca7121f41e37fd248a3dd77335d8ac56 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Mon, 22 Jun 2015 22:13:49 -0700 Subject: [PATCH 3/3] update standard --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e17151f41..933ccafea 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "hashish": "0.0.4", "mocha": "^2.2.1", "nyc": "^2.2.1", - "standard": "^4.2.1" + "standard": "^4.3.2" }, "scripts": { "test": "standard && nyc mocha --check-leaks && nyc report",