Skip to content

Commit

Permalink
multiple: improved completion for choices
Browse files Browse the repository at this point in the history
feat(completion): choices will now work for all possible aliases of an option and not just the default long option
fix(completion): fix for completions that contain non-leading hyphens
fix(completion): changed the check for option arguments to match options that begin with '-', instead of '--', to include short options
  • Loading branch information
gmahomarf committed Dec 29, 2021
1 parent b951a7d commit 30edd50
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 10 deletions.
32 changes: 22 additions & 10 deletions lib/completion.ts
Expand Up @@ -153,21 +153,33 @@ export class Completion implements CompletionInstance {
let previousArg = args[args.length - 1];
let filter = '';
// use second to last argument if the last one is not an option starting with --
if (!previousArg.startsWith('--') && args.length > 1) {
if (!previousArg.startsWith('-') && args.length > 1) {
filter = previousArg; // use last arg as filter for choices
previousArg = args[args.length - 2];
}
if (!previousArg.startsWith('--')) return; // still no valid arg, abort
const previousArgKey = previousArg.replace(/-/g, '');
if (!previousArg.startsWith('-')) return; // still no valid arg, abort
const previousArgKey = previousArg.replace(/^-+/, '');

const options = this.yargs.getOptions();
if (
Object.keys(options.key).some(key => key === previousArgKey) &&
Array.isArray(options.choices[previousArgKey])
) {
return options.choices[previousArgKey].filter(
choice => !filter || choice.startsWith(filter)
);

const possibleAliases = [
previousArgKey,
...(this.yargs.getAliases()[previousArgKey] || []),
];
let choices: string[] | undefined;
// Find choices across all possible aliases
for (const possibleAlias of possibleAliases) {
if (
Object.prototype.hasOwnProperty.call(options.key, possibleAlias) &&
Array.isArray(options.choices[possibleAlias])
) {
choices = options.choices[possibleAlias];
break;
}
}

if (choices) {
return choices.filter(choice => !filter || choice.startsWith(filter));
}
}

Expand Down
80 changes: 80 additions & 0 deletions test/completion.cjs
Expand Up @@ -373,6 +373,86 @@ describe('Completion', () => {
r.logs.should.not.include('banana');
r.logs.should.not.include('pear');
});

it('completes choices if previous option or one of its aliases requires a choice', () => {
process.env.SHELL = '/bin/bash';
const r = checkUsage(() => {
return yargs([
'./completion',
'--get-yargs-completions',
'./completion',
'-f',
])
.options({
fruit: {
alias: ['f', 'not-a-vegetable'],
describe: 'fruit option',
choices: ['apple', 'banana', 'pear'],
},
amount: {describe: 'amount', type: 'number'},
})
.completion('completion', false).argv;
});

r.logs.should.have.length(3);
r.logs.should.include('apple');
r.logs.should.include('banana');
r.logs.should.include('pear');
});

it('completes choices if previous option or one of its aliases requires a choice and space has been entered', () => {
process.env.SHELL = '/bin/bash';
const r = checkUsage(() => {
return yargs([
'./completion',
'--get-yargs-completions',
'./completion',
'--not-a-vegetable',
'',
])
.options({
fruit: {
alias: ['f', 'not-a-vegetable'],
describe: 'fruit option',
choices: ['apple', 'banana', 'pear'],
},
amount: {describe: 'amount', type: 'number'},
})
.completion('completion', false).argv;
});

r.logs.should.have.length(3);
r.logs.should.include('apple');
r.logs.should.include('banana');
r.logs.should.include('pear');
});

it('completes choices if previous option or one of its aliases requires a choice and a partial choice has been entered', () => {
process.env.SHELL = '/bin/bash';
const r = checkUsage(() => {
return yargs([
'./completion',
'--get-yargs-completions',
'./completion',
'-f',
'ap',
])
.options({
fruit: {
alias: 'f',
describe: 'fruit option',
choices: ['apple', 'banana', 'pear'],
},
amount: {describe: 'amount', type: 'number'},
})
.completion('completion', false).argv;
});

r.logs.should.have.length(1);
r.logs.should.include('apple');
r.logs.should.not.include('banana');
r.logs.should.not.include('pear');
});
});

describe('generateCompletionScript()', () => {
Expand Down

0 comments on commit 30edd50

Please sign in to comment.