coa 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.npmignore +6 -0
  2. package/.nyc_output/1f2a0db5a6d6559149db56d397f47cfc.json +1 -0
  3. package/.nyc_output/75b82d38f2186df930141082076e11c6.json +1 -0
  4. package/.travis.yml +9 -0
  5. package/GNUmakefile +34 -0
  6. package/README.md +1 -19
  7. package/coverage/base.css +212 -0
  8. package/coverage/coa/index.html +93 -0
  9. package/coverage/coa/index.js.html +68 -0
  10. package/coverage/coa/lib/arg.js.html +239 -0
  11. package/coverage/coa/lib/cmd.js.html +1556 -0
  12. package/coverage/coa/lib/coaobject.js.html +365 -0
  13. package/coverage/coa/lib/coaparam.js.html +440 -0
  14. package/coverage/coa/lib/color.js.html +131 -0
  15. package/coverage/coa/lib/completion.js.html +593 -0
  16. package/coverage/coa/lib/index.html +197 -0
  17. package/coverage/coa/lib/index.js.html +107 -0
  18. package/coverage/coa/lib/opt.js.html +524 -0
  19. package/coverage/coa/lib/shell.js.html +107 -0
  20. package/coverage/index.html +106 -0
  21. package/coverage/prettify.css +1 -0
  22. package/coverage/prettify.js +1 -0
  23. package/coverage/sort-arrow-sprite.png +0 -0
  24. package/coverage/sorter.js +158 -0
  25. package/index.js +1 -1
  26. package/lib/arg.js +161 -44
  27. package/lib/cmd.js +547 -434
  28. package/lib/color.js +22 -19
  29. package/lib/completion.js +119 -161
  30. package/lib/index.js +10 -14
  31. package/lib/opt.js +313 -130
  32. package/lib/shell.js +13 -13
  33. package/package.json +14 -19
  34. package/qq.js +17 -0
  35. package/src/arg.coffee +130 -0
  36. package/src/cmd.coffee +456 -0
  37. package/src/color.coffee +25 -0
  38. package/src/completion.coffee +156 -0
  39. package/src/index.coffee +5 -0
  40. package/src/opt.coffee +243 -0
  41. package/src/shell.coffee +10 -0
  42. package/test/coa.js +496 -0
  43. package/test/mocha.opts +2 -0
  44. package/test/shell-test.js +60 -0
  45. package/tests/api-h.js +9 -0
  46. package/tests/h.js +6 -0
  47. package/LICENSE +0 -21
  48. package/lib/coaobject.js +0 -100
  49. package/lib/coaparam.js +0 -125
package/src/cmd.coffee ADDED
@@ -0,0 +1,456 @@
1
+ UTIL = require 'util'
2
+ PATH = require 'path'
3
+ Color = require('./color').Color
4
+ Q = require('q')
5
+
6
+ #inspect = require('eyes').inspector { maxLength: 99999, stream: process.stderr }
7
+
8
+ ###*
9
+ Command
10
+
11
+ Top level entity. Commands may have options and arguments.
12
+ @namespace
13
+ @class Presents command
14
+ ###
15
+ exports.Cmd = class Cmd
16
+
17
+ ###*
18
+ @constructs
19
+ @param {COA.Cmd} [cmd] parent command
20
+ ###
21
+ constructor: (cmd) ->
22
+ if this not instanceof Cmd
23
+ return new Cmd cmd
24
+
25
+ @_parent cmd
26
+
27
+ @_cmds = []
28
+ @_cmdsByName = {}
29
+
30
+ @_opts = []
31
+ @_optsByKey = {}
32
+
33
+ @_args = []
34
+
35
+ @_ext = false
36
+
37
+ @get: (propertyName, func) ->
38
+ Object.defineProperty @::, propertyName,
39
+ configurable: true
40
+ enumerable: true
41
+ get: func
42
+
43
+ ###*
44
+ Returns object containing all its subcommands as methods
45
+ to use from other programs.
46
+ @returns {Object}
47
+ ###
48
+ @get 'api', () ->
49
+ if not @_api
50
+ @_api = => @invoke.apply @, arguments
51
+ for c of @_cmdsByName
52
+ do (c) =>
53
+ @_api[c] = @_cmdsByName[c].api
54
+ @_api
55
+
56
+ _parent: (cmd) ->
57
+ @_cmd = cmd or this
58
+ if cmd
59
+ cmd._cmds.push @
60
+ if @_name then @_cmd._cmdsByName[@_name] = @
61
+ @
62
+
63
+ ###*
64
+ Set a canonical command identifier to be used anywhere in the API.
65
+ @param {String} _name command name
66
+ @returns {COA.Cmd} this instance (for chainability)
67
+ ###
68
+ name: (@_name) ->
69
+ if @_cmd isnt @ then @_cmd._cmdsByName[_name] = @
70
+ @
71
+
72
+ ###*
73
+ Set a long description for command to be used anywhere in text messages.
74
+ @param {String} _title command title
75
+ @returns {COA.Cmd} this instance (for chainability)
76
+ ###
77
+ title: (@_title) -> @
78
+
79
+ ###*
80
+ Create new or add existing subcommand for current command.
81
+ @param {COA.Cmd} [cmd] existing command instance
82
+ @returns {COA.Cmd} new subcommand instance
83
+ ###
84
+ cmd: (cmd) ->
85
+ if cmd then cmd._parent @
86
+ else new Cmd @
87
+
88
+ ###*
89
+ Create option for current command.
90
+ @returns {COA.Opt} new option instance
91
+ ###
92
+ opt: -> new (require('./opt').Opt) @
93
+
94
+ ###*
95
+ Create argument for current command.
96
+ @returns {COA.Opt} new argument instance
97
+ ###
98
+ arg: -> new (require('./arg').Arg) @
99
+
100
+ ###*
101
+ Add (or set) action for current command.
102
+ @param {Function} act action function,
103
+ invoked in the context of command instance
104
+ and has the parameters:
105
+ - {Object} opts parsed options
106
+ - {Array} args parsed arguments
107
+ - {Object} res actions result accumulator
108
+ It can return rejected promise by Cmd.reject (in case of error)
109
+ or any other value treated as result.
110
+ @param {Boolean} [force=false] flag for set action instead add to existings
111
+ @returns {COA.Cmd} this instance (for chainability)
112
+ ###
113
+ act: (act, force) ->
114
+ return @ unless act
115
+
116
+ if not force and @_act
117
+ @_act.push act
118
+ else
119
+ @_act = [act]
120
+
121
+ @
122
+
123
+ ###*
124
+ Set custom additional completion for current command.
125
+ @param {Function} completion generation function,
126
+ invoked in the context of command instance.
127
+ Accepts parameters:
128
+ - {Object} opts completion options
129
+ It can return promise or any other value treated as result.
130
+ @returns {COA.Cmd} this instance (for chainability)
131
+ ###
132
+ comp: (@_comp) -> @
133
+
134
+ ###*
135
+ Apply function with arguments in context of command instance.
136
+ @param {Function} fn
137
+ @param {Array} args
138
+ @returns {COA.Cmd} this instance (for chainability)
139
+ ###
140
+ apply: (fn, args...) ->
141
+ fn.apply this, args
142
+ @
143
+
144
+ ###*
145
+ Make command "helpful", i.e. add -h --help flags for print usage.
146
+ @returns {COA.Cmd} this instance (for chainability)
147
+ ###
148
+ helpful: ->
149
+ @opt()
150
+ .name('help').title('Help')
151
+ .short('h').long('help')
152
+ .flag()
153
+ .only()
154
+ .act ->
155
+ return @usage()
156
+ .end()
157
+
158
+ ###*
159
+ Adds shell completion to command, adds "completion" subcommand,
160
+ that makes all the magic.
161
+ Must be called only on root command.
162
+ @returns {COA.Cmd} this instance (for chainability)
163
+ ###
164
+ completable: ->
165
+ @cmd()
166
+ .name('completion')
167
+ .apply(require './completion')
168
+ .end()
169
+
170
+ ###*
171
+ Allow command to be extendable by external node.js modules.
172
+ @param {String} [pattern] Pattern of node.js module to find subcommands at.
173
+ @returns {COA.Cmd} this instance (for chainability)
174
+ ###
175
+ extendable: (pattern) ->
176
+ @_ext = pattern or true
177
+ @
178
+
179
+ _exit: (msg, code) ->
180
+ process.once 'exit', ->
181
+ if msg then console.error msg
182
+ process.exit code or 0
183
+
184
+ ###*
185
+ Build full usage text for current command instance.
186
+ @returns {String} usage text
187
+ ###
188
+ usage: ->
189
+ res = []
190
+
191
+ if @_title then res.push @_fullTitle()
192
+
193
+ res.push('', 'Usage:')
194
+
195
+ if @_cmds.length then res.push(['', '',
196
+ Color('lred', @_fullName()),
197
+ Color('lblue', 'COMMAND'),
198
+ Color('lgreen', '[OPTIONS]'),
199
+ Color('lpurple', '[ARGS]')].join ' ')
200
+
201
+ if @_opts.length + @_args.length then res.push(['', '',
202
+ Color('lred', @_fullName()),
203
+ Color('lgreen', '[OPTIONS]'),
204
+ Color('lpurple', '[ARGS]')].join ' ')
205
+
206
+ res.push(
207
+ @_usages(@_cmds, 'Commands'),
208
+ @_usages(@_opts, 'Options'),
209
+ @_usages(@_args, 'Arguments'))
210
+
211
+ res.join '\n'
212
+
213
+ _usage: ->
214
+ Color('lblue', @_name) + ' : ' + @_title
215
+
216
+ _usages: (os, title) ->
217
+ unless os.length then return
218
+ res = ['', title + ':']
219
+ for o in os
220
+ res.push ' ' + o._usage()
221
+ res.join '\n'
222
+
223
+ _fullTitle: ->
224
+ (if @_cmd is this then '' else @_cmd._fullTitle() + '\n') + @_title
225
+
226
+ _fullName: ->
227
+ (if this._cmd is this then '' else @_cmd._fullName() + ' ') + PATH.basename(@_name)
228
+
229
+ _ejectOpt: (opts, opt) ->
230
+ if (pos = opts.indexOf(opt)) >= 0
231
+ if opts[pos]._arr
232
+ opts[pos]
233
+ else
234
+ opts.splice(pos, 1)[0]
235
+
236
+ _checkRequired: (opts, args) ->
237
+ if not (@_opts.filter (o) -> o._only and o._name of opts).length
238
+ all = @_opts.concat @_args
239
+ while i = all.shift()
240
+ if i._req and i._checkParsed opts, args
241
+ return @reject i._requiredText()
242
+
243
+ _parseCmd: (argv, unparsed = []) ->
244
+ argv = argv.concat()
245
+ optSeen = false
246
+ while i = argv.shift()
247
+ if not i.indexOf '-'
248
+ optSeen = true
249
+ if not optSeen and /^\w[\w-_]*$/.test(i)
250
+ cmd = @_cmdsByName[i]
251
+
252
+ if not cmd and @_ext
253
+ # construct package name to require
254
+ if typeof @_ext is 'string'
255
+ if ~@_ext.indexOf('%s')
256
+ # use formatted string
257
+ pkg = UTIL.format(@_ext, i)
258
+ else
259
+ # just append subcommand name to the prefix
260
+ pkg = @_ext + i
261
+ else if @_ext is true
262
+ # use default scheme: <command>-<subcommand>-<subcommand> and so on
263
+ pkg = i
264
+ c = @
265
+ loop
266
+ pkg = c._name + '-' + pkg
267
+ if c._cmd is c then break
268
+ c = c._cmd
269
+
270
+ try
271
+ cmdDesc = require(pkg)
272
+ catch e
273
+
274
+ if cmdDesc
275
+ if typeof cmdDesc == 'function'
276
+ # set create subcommand, set its name and apply imported function
277
+ @cmd()
278
+ .name(i)
279
+ .apply(cmdDesc)
280
+ .end()
281
+ else if typeof cmdDesc == 'object'
282
+ # register subcommand
283
+ @cmd(cmdDesc)
284
+ # set command name
285
+ cmdDesc.name(i)
286
+ else
287
+ throw new Error 'Error: Unsupported command declaration type, ' +
288
+ 'should be function or COA.Cmd() object'
289
+ cmd = @_cmdsByName[i]
290
+ if cmd
291
+ return cmd._parseCmd argv, unparsed
292
+
293
+ unparsed.push i
294
+
295
+ { cmd: @, argv: unparsed }
296
+
297
+ _parseOptsAndArgs: (argv) ->
298
+ opts = {}
299
+ args = {}
300
+
301
+ nonParsedOpts = @_opts.concat()
302
+ nonParsedArgs = @_args.concat()
303
+
304
+ while i = argv.shift()
305
+ # opt
306
+ if i isnt '--' and not i.indexOf '-'
307
+
308
+ if m = i.match /^(--\w[\w-_]*)=(.*)$/
309
+ i = m[1]
310
+
311
+ # suppress 'unknown argument' error for flag options with values
312
+ if not @_optsByKey[i]._flag
313
+ argv.unshift m[2]
314
+
315
+ if opt = @_ejectOpt nonParsedOpts, @_optsByKey[i]
316
+ if Q.isRejected(res = opt._parse argv, opts)
317
+ return res
318
+ else
319
+ return @reject "Unknown option: #{ i }"
320
+
321
+ # arg
322
+ else
323
+ if i is '--'
324
+ i = argv.splice(0)
325
+
326
+ i = if Array.isArray(i) then i else [i]
327
+
328
+ while a = i.shift()
329
+ if arg = nonParsedArgs.shift()
330
+ if arg._arr then nonParsedArgs.unshift arg
331
+ if Q.isRejected(res = arg._parse a, args)
332
+ return res
333
+ else
334
+ return @reject "Unknown argument: #{ a }"
335
+
336
+ # set defaults
337
+ {
338
+ opts: @_setDefaults(opts, nonParsedOpts),
339
+ args: @_setDefaults(args, nonParsedArgs)
340
+ }
341
+
342
+ _setDefaults: (params, desc) ->
343
+ for i in desc
344
+ if i._name not of params and '_def' of i
345
+ i._saveVal params, i._def
346
+ params
347
+
348
+ _processParams: (params, desc) ->
349
+ notExists = []
350
+ for i in desc
351
+ n = i._name
352
+ if n not of params
353
+ notExists.push i
354
+ continue
355
+
356
+ vals = params[n]
357
+ delete params[n]
358
+ if not Array.isArray vals
359
+ vals = [vals]
360
+
361
+ for v in vals
362
+ if Q.isRejected(res = i._saveVal(params, v))
363
+ return res
364
+
365
+ # set defaults
366
+ @_setDefaults params, notExists
367
+
368
+ _parseArr: (argv) ->
369
+ Q.when @_parseCmd(argv), (p) ->
370
+ Q.when p.cmd._parseOptsAndArgs(p.argv), (r) ->
371
+ { cmd: p.cmd, opts: r.opts, args: r.args }
372
+
373
+ _do: (input) ->
374
+ Q.when input, (input) =>
375
+ cmd = input.cmd
376
+ [@_checkRequired].concat(cmd._act or []).reduce(
377
+ (res, act) ->
378
+ Q.when res, (res) ->
379
+ act.call(
380
+ cmd
381
+ input.opts
382
+ input.args
383
+ res)
384
+ undefined
385
+ )
386
+
387
+ ###*
388
+ Parse arguments from simple format like NodeJS process.argv
389
+ and run ahead current program, i.e. call process.exit when all actions done.
390
+ @param {Array} argv
391
+ @returns {COA.Cmd} this instance (for chainability)
392
+ ###
393
+ run: (argv = process.argv.slice(2)) ->
394
+ cb = (code) => (res) =>
395
+ if res
396
+ @_exit res.stack ? res.toString(), res.exitCode ? code
397
+ else
398
+ @_exit()
399
+ Q.when(@do(argv), cb(0), cb(1)).done()
400
+ @
401
+
402
+ ###*
403
+ Convenient function to run command from tests.
404
+ @param {Array} argv
405
+ @returns {Q.Promise}
406
+ ###
407
+ do: (argv) ->
408
+ @_do(@_parseArr argv || [])
409
+
410
+ ###*
411
+ Invoke specified (or current) command using provided
412
+ options and arguments.
413
+ @param {String|Array} cmds subcommand to invoke (optional)
414
+ @param {Object} opts command options (optional)
415
+ @param {Object} args command arguments (optional)
416
+ @returns {Q.Promise}
417
+ ###
418
+ invoke: (cmds = [], opts = {}, args = {}) ->
419
+ if typeof cmds == 'string'
420
+ cmds = cmds.split(' ')
421
+
422
+ if arguments.length < 3
423
+ if not Array.isArray cmds
424
+ args = opts
425
+ opts = cmds
426
+ cmds = []
427
+
428
+ Q.when @_parseCmd(cmds), (p) =>
429
+ if p.argv.length
430
+ return @reject "Unknown command: " + cmds.join ' '
431
+
432
+ Q.all([@_processParams(opts, @_opts), @_processParams(args, @_args)])
433
+ .spread (opts, args) =>
434
+ @_do({ cmd: p.cmd, opts: opts, args: args })
435
+ # catch fails from .only() options
436
+ .fail (res) =>
437
+ if res and res.exitCode is 0
438
+ res.toString()
439
+ else
440
+ @reject(res)
441
+
442
+ ###*
443
+ Return reject of actions results promise with error code.
444
+ Use in .act() for return with error.
445
+ @param {Object} reject reason
446
+ You can customize toString() method and exitCode property
447
+ of reason object.
448
+ @returns {Q.promise} rejected promise
449
+ ###
450
+ reject: (reason) -> Q.reject(reason)
451
+
452
+ ###*
453
+ Finish chain for current subcommand and return parent command instance.
454
+ @returns {COA.Cmd} parent command
455
+ ###
456
+ end: -> @_cmd
@@ -0,0 +1,25 @@
1
+ colors =
2
+ black: '30'
3
+ dgray: '1;30'
4
+ red: '31'
5
+ lred: '1;31'
6
+ green: '32'
7
+ lgreen: '1;32'
8
+ brown: '33'
9
+ yellow: '1;33'
10
+ blue: '34'
11
+ lblue: '1;34'
12
+ purple: '35'
13
+ lpurple: '1;35'
14
+ cyan: '36'
15
+ lcyan: '1;36'
16
+ lgray: '37'
17
+ white: '1;37'
18
+
19
+ exports.Color = (c, str) ->
20
+ # Use \x1B instead of \033 because of CoffeeScript 1.3.x compilation error
21
+ [
22
+ '\x1B[', colors[c], 'm'
23
+ str
24
+ '\x1B[m'
25
+ ].join ''
@@ -0,0 +1,156 @@
1
+ ###*
2
+ Most of the code adopted from the npm package shell completion code.
3
+ See https://github.com/isaacs/npm/blob/master/lib/completion.js
4
+ ###
5
+
6
+ Q = require 'q'
7
+ escape = require('./shell').escape
8
+ unescape = require('./shell').unescape
9
+
10
+ module.exports = ->
11
+ @title('Shell completion')
12
+ .helpful()
13
+ .arg()
14
+ .name('raw')
15
+ .title('Completion words')
16
+ .arr()
17
+ .end()
18
+ .act (opts, args) ->
19
+ if process.platform == 'win32'
20
+ e = new Error 'shell completion not supported on windows'
21
+ e.code = 'ENOTSUP'
22
+ e.errno = require('constants').ENOTSUP
23
+ return @reject(e)
24
+
25
+ # if the COMP_* isn't in the env, then just dump the script
26
+ if !process.env.COMP_CWORD? or !process.env.COMP_LINE? or !process.env.COMP_POINT?
27
+ return dumpScript(@_cmd._name)
28
+
29
+ console.error 'COMP_LINE: %s', process.env.COMP_LINE
30
+ console.error 'COMP_CWORD: %s', process.env.COMP_CWORD
31
+ console.error 'COMP_POINT: %s', process.env.COMP_POINT
32
+ console.error 'args: %j', args.raw
33
+
34
+ # completion opts
35
+ opts = getOpts args.raw
36
+
37
+ # cmd
38
+ { cmd, argv } = @_cmd._parseCmd opts.partialWords
39
+ Q.when complete(cmd, opts), (compls) ->
40
+ console.error 'filtered: %j', compls
41
+ console.log compls.map(escape).join('\n')
42
+
43
+
44
+ dumpScript = (name) ->
45
+ fs = require 'fs'
46
+ path = require 'path'
47
+ defer = Q.defer()
48
+
49
+ fs.readFile path.resolve(__dirname, 'completion.sh'), 'utf8', (err, d) ->
50
+ if err then return defer.reject err
51
+ d = d.replace(/{{cmd}}/g, path.basename name).replace(/^\#\!.*?\n/, '')
52
+
53
+ onError = (err) ->
54
+ # Darwin is a real dick sometimes.
55
+ #
56
+ # This is necessary because the "source" or "." program in
57
+ # bash on OS X closes its file argument before reading
58
+ # from it, meaning that you get exactly 1 write, which will
59
+ # work most of the time, and will always raise an EPIPE.
60
+ #
61
+ # Really, one should not be tossing away EPIPE errors, or any
62
+ # errors, so casually. But, without this, `. <(cmd completion)`
63
+ # can never ever work on OS X.
64
+ if err.errno == require('constants').EPIPE
65
+ process.stdout.removeListener 'error', onError
66
+ defer.resolve()
67
+ else
68
+ defer.reject(err)
69
+
70
+ process.stdout.on 'error', onError
71
+ process.stdout.write d, -> defer.resolve()
72
+
73
+ defer.promise
74
+
75
+
76
+ getOpts = (argv) ->
77
+ # get the partial line and partial word, if the point isn't at the end
78
+ # ie, tabbing at: cmd foo b|ar
79
+ line = process.env.COMP_LINE
80
+ w = +process.env.COMP_CWORD
81
+ point = +process.env.COMP_POINT
82
+ words = argv.map unescape
83
+ word = words[w]
84
+ partialLine = line.substr 0, point
85
+ partialWords = words.slice 0, w
86
+
87
+ # figure out where in that last word the point is
88
+ partialWord = argv[w] or ''
89
+ i = partialWord.length
90
+ while partialWord.substr(0, i) isnt partialLine.substr(-1 * i) and i > 0
91
+ i--
92
+ partialWord = unescape partialWord.substr 0, i
93
+ if partialWord then partialWords.push partialWord
94
+
95
+ {
96
+ line: line
97
+ w: w
98
+ point: point
99
+ words: words
100
+ word: word
101
+ partialLine: partialLine
102
+ partialWords: partialWords
103
+ partialWord: partialWord
104
+ }
105
+
106
+
107
+ complete = (cmd, opts) ->
108
+ compls = []
109
+
110
+ # complete on cmds
111
+ if opts.partialWord.indexOf('-')
112
+ compls = Object.keys(cmd._cmdsByName)
113
+ # Complete on required opts without '-' in last partial word
114
+ # (if required not already specified)
115
+ #
116
+ # Commented out because of uselessness:
117
+ # -b, --block suggest results in '-' on cmd line;
118
+ # next completion suggest all options, because of '-'
119
+ #.concat Object.keys(cmd._optsByKey).filter (v) -> cmd._optsByKey[v]._req
120
+ else
121
+ # complete on opt values: --opt=| case
122
+ if m = opts.partialWord.match /^(--\w[\w-_]*)=(.*)$/
123
+ optWord = m[1]
124
+ optPrefix = optWord + '='
125
+ else
126
+ # complete on opts
127
+ # don't complete on opts in case of --opt=val completion
128
+ # TODO: don't complete on opts in case of unknown arg after commands
129
+ # TODO: complete only on opts with arr() or not already used
130
+ # TODO: complete only on full opts?
131
+ compls = Object.keys cmd._optsByKey
132
+
133
+ # complete on opt values: next arg case
134
+ if not (o = opts.partialWords[opts.w - 1]).indexOf '-'
135
+ optWord = o
136
+
137
+ # complete on opt values: completion
138
+ if optWord and opt = cmd._optsByKey[optWord]
139
+ if not opt._flag and opt._comp
140
+ compls = Q.join compls, Q.when opt._comp(opts), (c, o) ->
141
+ c.concat o.map (v) -> (optPrefix or '') + v
142
+
143
+ # TODO: complete on args values (context aware, custom completion?)
144
+
145
+ # custom completion on cmds
146
+ if cmd._comp
147
+ compls = Q.join compls, Q.when(cmd._comp(opts)), (c, o) ->
148
+ c.concat o
149
+
150
+ # TODO: context aware custom completion on cmds, opts and args
151
+ # (can depend on already entered values, especially options)
152
+
153
+ Q.when compls, (compls) ->
154
+ console.error 'partialWord: %s', opts.partialWord
155
+ console.error 'compls: %j', compls
156
+ compls.filter (c) -> c.indexOf(opts.partialWord) is 0
@@ -0,0 +1,5 @@
1
+ exports.Cmd = require('./cmd').Cmd
2
+ exports.Opt = require('./cmd').Opt
3
+ exports.Arg = require('./cmd').Arg
4
+ exports.shell = require('./shell')
5
+ exports.require = require;