UNPKG

3.98 kBJavaScriptView Raw
1'use strict'
2const path = require('path')
3
4// add bash completions to your
5// yargs-powered applications.
6module.exports = function completion (yargs, usage, command) {
7 const self = {
8 completionKey: 'get-yargs-completions'
9 }
10
11 const zshShell = (process.env.SHELL && process.env.SHELL.indexOf('zsh') !== -1) ||
12 (process.env.ZSH_NAME && process.env.ZSH_NAME.indexOf('zsh') !== -1)
13 // get a list of completion commands.
14 // 'args' is the array of strings from the line to be completed
15 self.getCompletion = function getCompletion (args, done) {
16 const completions = []
17 const current = args.length ? args[args.length - 1] : ''
18 const argv = yargs.parse(args, true)
19 const aliases = yargs.parsed.aliases
20 const parentCommands = yargs.getContext().commands
21
22 // a custom completion function can be provided
23 // to completion().
24 if (completionFunction) {
25 if (completionFunction.length < 3) {
26 const result = completionFunction(current, argv)
27
28 // promise based completion function.
29 if (typeof result.then === 'function') {
30 return result.then((list) => {
31 process.nextTick(() => { done(list) })
32 }).catch((err) => {
33 process.nextTick(() => { throw err })
34 })
35 }
36
37 // synchronous completion function.
38 return done(result)
39 } else {
40 // asynchronous completion function
41 return completionFunction(current, argv, (completions) => {
42 done(completions)
43 })
44 }
45 }
46
47 const handlers = command.getCommandHandlers()
48 for (let i = 0, ii = args.length; i < ii; ++i) {
49 if (handlers[args[i]] && handlers[args[i]].builder) {
50 const builder = handlers[args[i]].builder
51 if (typeof builder === 'function') {
52 const y = yargs.reset()
53 builder(y)
54 return y.argv
55 }
56 }
57 }
58
59 if (!current.match(/^-/) && parentCommands[parentCommands.length - 1] !== current) {
60 usage.getCommands().forEach((usageCommand) => {
61 const commandName = command.parseCommand(usageCommand[0]).cmd
62 if (args.indexOf(commandName) === -1) {
63 if (!zshShell) {
64 completions.push(commandName)
65 } else {
66 const desc = usageCommand[1] || ''
67 completions.push(commandName.replace(/:/g, '\\:') + ':' + desc)
68 }
69 }
70 })
71 }
72
73 if (current.match(/^-/) || (current === '' && completions.length === 0)) {
74 const descs = usage.getDescriptions()
75 Object.keys(yargs.getOptions().key).forEach((key) => {
76 // If the key and its aliases aren't in 'args', add the key to 'completions'
77 const keyAndAliases = [key].concat(aliases[key] || [])
78 const notInArgs = keyAndAliases.every(val => args.indexOf(`--${val}`) === -1)
79 if (notInArgs) {
80 if (!zshShell) {
81 completions.push(`--${key}`)
82 } else {
83 const desc = descs[key] || ''
84 completions.push(`--${key.replace(/:/g, '\\:')}:${desc.replace('__yargsString__:', '')}`)
85 }
86 }
87 })
88 }
89
90 done(completions)
91 }
92
93 // generate the completion script to add to your .bashrc.
94 self.generateCompletionScript = function generateCompletionScript ($0, cmd) {
95 const templates = require('./completion-templates')
96 let script = zshShell ? templates.completionZshTemplate : templates.completionShTemplate
97 const name = path.basename($0)
98
99 // add ./to applications not yet installed as bin.
100 if ($0.match(/\.js$/)) $0 = `./${$0}`
101
102 script = script.replace(/{{app_name}}/g, name)
103 script = script.replace(/{{completion_command}}/g, cmd)
104 return script.replace(/{{app_path}}/g, $0)
105 }
106
107 // register a function to perform your own custom
108 // completions., this function can be either
109 // synchrnous or asynchronous.
110 let completionFunction = null
111 self.registerFunction = (fn) => {
112 completionFunction = fn
113 }
114
115 return self
116}