From b4c4bf644bc3ce65c646f54267df78d1bfabf9b1 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 21 Mar 2022 10:17:07 +0100 Subject: [PATCH 1/2] fix(completion): don't show positional args choices with option choices Previously, when both positional arguments and options has choices, during autocompletion we displayed both at the same time. --- lib/completion.ts | 13 ++++++++++--- test/completion.cjs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/completion.ts b/lib/completion.ts index 42f4c2d49..7cfe28111 100644 --- a/lib/completion.ts +++ b/lib/completion.ts @@ -158,6 +158,14 @@ export class Completion implements CompletionInstance { argv: Arguments, current: string ) { + if ( + current === '' && + completions.length > 0 && + this.previousArgHasChoices(args) + ) { + return; + } + const positionalKeys = this.yargs.getGroups()[this.usage.getPositionalGroupName()] || []; const offset = Math.max( @@ -165,13 +173,12 @@ export class Completion implements CompletionInstance { this.yargs.getInternalMethods().getContext().commands.length + /* name of the script is first param */ 1 ); - const positionalValues = argv._.slice(offset); - - const positionalKey = positionalKeys[positionalValues.length - 1]; + const positionalKey = positionalKeys[argv._.length - offset - 1]; if (!positionalKey) { return; } + const choices = this.yargs.getOptions().choices[positionalKey] || []; for (const choice of choices) { if (choice.startsWith(current)) { diff --git a/test/completion.cjs b/test/completion.cjs index 6dc6868ee..9c5e032a2 100644 --- a/test/completion.cjs +++ b/test/completion.cjs @@ -426,6 +426,36 @@ describe('Completion', () => { r.logs.should.include('--amount'); }); + it('options choices should not be display with positional choices', () => { + process.env.SHELL = '/bin/bash'; + const r = checkUsage( + () => + yargs([ + ...firstArguments, + './completion', + 'cmd', + 'apple', + '--foo', + '', + ]) + .help(false) + .version(false) + .command('cmd [fruit]', 'command', subYargs => { + subYargs + .positional('fruit', {choices: ['apple', 'banana', 'pear']}) + .options('foo', { + choices: ['bar', 'buz'], + }) + .options({amount: {describe: 'amount', type: 'number'}}); + }).argv + ); + + r.logs.should.have.length(2); + r.logs.should.include('bar'); + r.logs.should.include('buz'); + r.logs.should.not.include('apple'); + }); + it('completes choices for positional with prefix', () => { process.env.SHELL = '/bin/bash'; const r = checkUsage( From 904772cb58de9b96f48ddc71a06044f14089b67e Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Mon, 21 Mar 2022 16:05:24 +0100 Subject: [PATCH 2/2] fix(completions): escape colon in completion choices This is similar to the code in `completeOptionKey` --- lib/completion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/completion.ts b/lib/completion.ts index 7cfe28111..c93405bcc 100644 --- a/lib/completion.ts +++ b/lib/completion.ts @@ -147,7 +147,7 @@ export class Completion implements CompletionInstance { if (this.previousArgHasChoices(args)) { const choices = this.getPreviousArgChoices(args); if (choices && choices.length > 0) { - completions.push(...choices); + completions.push(...choices.map(c => c.replace(/:/g, '\\:'))); } } } @@ -182,7 +182,7 @@ export class Completion implements CompletionInstance { const choices = this.yargs.getOptions().choices[positionalKey] || []; for (const choice of choices) { if (choice.startsWith(current)) { - completions.push(choice); + completions.push(choice.replace(/:/g, '\\:')); } } }