completion.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. const fs = require('fs')
  2. const path = require('path')
  3. // add bash completions to your
  4. // yargs-powered applications.
  5. module.exports = function (yargs, usage, command) {
  6. const self = {
  7. completionKey: 'get-yargs-completions'
  8. }
  9. // get a list of completion commands.
  10. // 'args' is the array of strings from the line to be completed
  11. self.getCompletion = function (args, done) {
  12. const completions = []
  13. const current = args.length ? args[args.length - 1] : ''
  14. const argv = yargs.parse(args, true)
  15. const aliases = yargs.parsed.aliases
  16. // a custom completion function can be provided
  17. // to completion().
  18. if (completionFunction) {
  19. if (completionFunction.length < 3) {
  20. var result = completionFunction(current, argv)
  21. // promise based completion function.
  22. if (typeof result.then === 'function') {
  23. return result.then(function (list) {
  24. process.nextTick(function () { done(list) })
  25. }).catch(function (err) {
  26. process.nextTick(function () { throw err })
  27. })
  28. }
  29. // synchronous completion function.
  30. return done(result)
  31. } else {
  32. // asynchronous completion function
  33. return completionFunction(current, argv, function (completions) {
  34. done(completions)
  35. })
  36. }
  37. }
  38. var handlers = command.getCommandHandlers()
  39. for (var i = 0, ii = args.length; i < ii; ++i) {
  40. if (handlers[args[i]] && handlers[args[i]].builder) {
  41. const builder = handlers[args[i]].builder
  42. if (typeof builder === 'function') {
  43. const y = yargs.reset()
  44. builder(y)
  45. return y.argv
  46. }
  47. }
  48. }
  49. if (!current.match(/^-/)) {
  50. usage.getCommands().forEach(function (command) {
  51. if (args.indexOf(command[0]) === -1) {
  52. completions.push(command[0])
  53. }
  54. })
  55. }
  56. if (current.match(/^-/)) {
  57. Object.keys(yargs.getOptions().key).forEach(function (key) {
  58. // If the key and its aliases aren't in 'args', add the key to 'completions'
  59. var keyAndAliases = [key].concat(aliases[key] || [])
  60. var notInArgs = keyAndAliases.every(function (val) {
  61. return args.indexOf('--' + val) === -1
  62. })
  63. if (notInArgs) {
  64. completions.push('--' + key)
  65. }
  66. })
  67. }
  68. done(completions)
  69. }
  70. // generate the completion script to add to your .bashrc.
  71. self.generateCompletionScript = function ($0) {
  72. var script = fs.readFileSync(
  73. path.resolve(__dirname, '../completion.sh.hbs'),
  74. 'utf-8'
  75. )
  76. var name = path.basename($0)
  77. // add ./to applications not yet installed as bin.
  78. if ($0.match(/\.js$/)) $0 = './' + $0
  79. script = script.replace(/{{app_name}}/g, name)
  80. return script.replace(/{{app_path}}/g, $0)
  81. }
  82. // register a function to perform your own custom
  83. // completions., this function can be either
  84. // synchrnous or asynchronous.
  85. var completionFunction = null
  86. self.registerFunction = function (fn) {
  87. completionFunction = fn
  88. }
  89. return self
  90. }