2 const fs = require('fs')
3 const path = require('path')
5 // add bash completions to your
6 // yargs-powered applications.
7 module.exports = function completion (yargs, usage, command) {
9 completionKey: 'get-yargs-completions'
12 // get a list of completion commands.
13 // 'args' is the array of strings from the line to be completed
14 self.getCompletion = function getCompletion (args, done) {
15 const completions = []
16 const current = args.length ? args[args.length - 1] : ''
17 const argv = yargs.parse(args, true)
18 const aliases = yargs.parsed.aliases
20 // a custom completion function can be provided
22 if (completionFunction) {
23 if (completionFunction.length < 3) {
24 const result = completionFunction(current, argv)
26 // promise based completion function.
27 if (typeof result.then === 'function') {
28 return result.then((list) => {
29 process.nextTick(() => { done(list) })
31 process.nextTick(() => { throw err })
35 // synchronous completion function.
38 // asynchronous completion function
39 return completionFunction(current, argv, (completions) => {
45 const handlers = command.getCommandHandlers()
46 for (let i = 0, ii = args.length; i < ii; ++i) {
47 if (handlers[args[i]] && handlers[args[i]].builder) {
48 const builder = handlers[args[i]].builder
49 if (typeof builder === 'function') {
50 const y = yargs.reset()
57 if (!current.match(/^-/)) {
58 usage.getCommands().forEach((usageCommand) => {
59 const commandName = command.parseCommand(usageCommand[0]).cmd
60 if (args.indexOf(commandName) === -1) {
61 completions.push(commandName)
66 if (current.match(/^-/)) {
67 Object.keys(yargs.getOptions().key).forEach((key) => {
68 // If the key and its aliases aren't in 'args', add the key to 'completions'
69 const keyAndAliases = [key].concat(aliases[key] || [])
70 const notInArgs = keyAndAliases.every(val => args.indexOf(`--${val}`) === -1)
72 completions.push(`--${key}`)
80 // generate the completion script to add to your .bashrc.
81 self.generateCompletionScript = function generateCompletionScript ($0, cmd) {
82 let script = fs.readFileSync(
83 path.resolve(__dirname, '../completion.sh.hbs'),
86 const name = path.basename($0)
88 // add ./to applications not yet installed as bin.
89 if ($0.match(/\.js$/)) $0 = `./${$0}`
91 script = script.replace(/{{app_name}}/g, name)
92 script = script.replace(/{{completion_command}}/g, cmd)
93 return script.replace(/{{app_path}}/g, $0)
96 // register a function to perform your own custom
97 // completions., this function can be either
98 // synchrnous or asynchronous.
99 let completionFunction = null
100 self.registerFunction = (fn) => {
101 completionFunction = fn