On Yargs Autocompletion
Yargs provides some rather nice autocompletion for commands and flags with some minimal setup, but I wanted autocompletion of positional arguments for one of the commands in the CLI clipboard manager I'm making. This clipboard manager (cb
) basically does one thing: let's me quickly save the contents of my clipboard, and retrieve them by name.
So, I want to be able to type my getter command cb get
, and to have autocomplete pulling from the list of clips stored by the clipboard manager.
I found the docs on this a bit confusing, so decided to write up my experience.
How to use Yarg's default completion
This is fairly easy. Add a call to .completion()
in your yargs...argv
chain:
var argv = require('yargs/yargs')(process.argv.slice(2)).completion().argv;
Then run ./your-script.js completion >> ~/.bashrc
to output a completion script to ~/.bashrc
. Change to .bash_profile
if you prefer. After this, don't forget to source .bashrc
.
How to add custom completion, but still leverage the defaults
This was a bit tricky. As it turns out, there are three different ways that you can interact with the completion
method, and only one supports using the defaults along with custom completion (source):
- 2 args = synchronous function or Promise function, can't call default
- 3 args = callback function, can't call default
- 4 args = callback function, can call default
So, going with the 4 arg option, I wound up with something like this:
.completion('completion', function (current, argv, completionFilter, done) {
if (argv._.includes('g') || argv._.includes('get')) {
completionFilter(() => {
const clipKeys = Object.keys(JSON.parse(fs.readFileSync(clipsPath)));
done(clipKeys);
});
} else {
completionFilter();
}
})
I tried using current == 'get
in the condition, instead of checking for strings in argv
, but it didn't work. I'm not really sure what you're supposed to do with current
. The completion filter is used in the docs to literally filter out the defaults, which it accepts as an argument, but that wasn't what I wanted. So, instead I parsed my JSON clips file and passed the keys to done
.
It works quite nicely. The rest of the setup is the same as for the defaults. Simply run
./your-script.js completion >> ~/.bashrc
source ~/.bashrc
But don't forget to remove your previous completion script from ~/.bashrc
before running them.