coa 0.4.1 → 1.0.3

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.
@@ -1,158 +0,0 @@
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.all([compls, opt._comp(opts)])
141
- .spread (c, o) ->
142
- c.concat o.map (v) -> (optPrefix or '') + v
143
-
144
- # TODO: complete on args values (context aware, custom completion?)
145
-
146
- # custom completion on cmds
147
- if cmd._comp
148
- compls = Q.all([compls, cmd._comp(opts)])
149
- .spread (c, o) ->
150
- c.concat o
151
-
152
- # TODO: context aware custom completion on cmds, opts and args
153
- # (can depend on already entered values, especially options)
154
-
155
- Q.when compls, (compls) ->
156
- console.error 'partialWord: %s', opts.partialWord
157
- console.error 'compls: %j', compls
158
- compls.filter (c) -> c.indexOf(opts.partialWord) is 0
package/src/index.coffee DELETED
@@ -1,5 +0,0 @@
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;
package/src/opt.coffee DELETED
@@ -1,243 +0,0 @@
1
- fs = require 'fs'
2
- Q = require 'q'
3
- Color = require('./color').Color
4
- Cmd = require('./cmd').Cmd
5
-
6
- ###*
7
- Option
8
-
9
- Named entity. Options may have short and long keys for use from command line.
10
- @namespace
11
- @class Presents option
12
- ###
13
- exports.Opt = class Opt
14
-
15
- ###*
16
- @constructs
17
- @param {COA.Cmd} cmd parent command
18
- ###
19
- constructor: (@_cmd) -> @_cmd._opts.push @
20
-
21
- ###*
22
- Set a canonical option identifier to be used anywhere in the API.
23
- @param {String} _name option name
24
- @returns {COA.Opt} this instance (for chainability)
25
- ###
26
- name: (@_name) -> @
27
-
28
- ###*
29
- Set a long description for option to be used anywhere in text messages.
30
- @param {String} _title option title
31
- @returns {COA.Opt} this instance (for chainability)
32
- ###
33
- title: Cmd::title
34
-
35
- ###*
36
- Set a short key for option to be used with one hyphen from command line.
37
- @param {String} _short
38
- @returns {COA.Opt} this instance (for chainability)
39
- ###
40
- short: (@_short) -> @_cmd._optsByKey['-' + _short] = @
41
-
42
- ###*
43
- Set a short key for option to be used with double hyphens from command line.
44
- @param {String} _long
45
- @returns {COA.Opt} this instance (for chainability)
46
- ###
47
- long: (@_long) -> @_cmd._optsByKey['--' + _long] = @
48
-
49
- ###*
50
- Make an option boolean, i.e. option without value.
51
- @returns {COA.Opt} this instance (for chainability)
52
- ###
53
- flag: () ->
54
- @_flag = true
55
- @
56
-
57
- ###*
58
- Makes an option accepts multiple values.
59
- Otherwise, the value will be used by the latter passed.
60
- @returns {COA.Opt} this instance (for chainability)
61
- ###
62
- arr: ->
63
- @_arr = true
64
- @
65
-
66
- ###*
67
- Makes an option required.
68
- @returns {COA.Opt} this instance (for chainability)
69
- ###
70
- req: ->
71
- @_req = true
72
- @
73
-
74
- ###*
75
- Makes an option to act as a command,
76
- i.e. program will exit just after option action.
77
- @returns {COA.Opt} this instance (for chainability)
78
- ###
79
- only: ->
80
- @_only = true
81
- @
82
-
83
- ###*
84
- Set a validation (or value) function for option.
85
- Value from command line passes through before becoming available from API.
86
- Using for validation and convertion simple types to any values.
87
- @param {Function} _val validating function,
88
- invoked in the context of option instance
89
- and has one parameter with value from command line
90
- @returns {COA.Opt} this instance (for chainability)
91
- ###
92
- val: (@_val) -> @
93
-
94
- ###*
95
- Set a default value for option.
96
- Default value passed through validation function as ordinary value.
97
- @param {Object} _def
98
- @returns {COA.Opt} this instance (for chainability)
99
- ###
100
- def: (@_def) -> @
101
-
102
- ###*
103
- Make option value inputting stream.
104
- It's add useful validation and shortcut for STDIN.
105
- @returns {COA.Opt} this instance (for chainability)
106
- ###
107
- input: ->
108
- # XXX: hack to workaround a bug in node 0.6.x,
109
- # see https://github.com/joyent/node/issues/2130
110
- process.stdin.pause();
111
-
112
- @
113
- .def(process.stdin)
114
- .val (v) ->
115
- if typeof v is 'string'
116
- if v is '-'
117
- process.stdin
118
- else
119
- s = fs.createReadStream v, { encoding: 'utf8' }
120
- s.pause()
121
- s
122
- else v
123
-
124
- ###*
125
- Make option value outputing stream.
126
- It's add useful validation and shortcut for STDOUT.
127
- @returns {COA.Opt} this instance (for chainability)
128
- ###
129
- output: ->
130
- @
131
- .def(process.stdout)
132
- .val (v) ->
133
- if typeof v is 'string'
134
- if v is '-'
135
- process.stdout
136
- else
137
- fs.createWriteStream v, { encoding: 'utf8' }
138
- else v
139
-
140
- ###*
141
- Add action for current option command.
142
- This action is performed if the current option
143
- is present in parsed options (with any value).
144
- @param {Function} act action function,
145
- invoked in the context of command instance
146
- and has the parameters:
147
- - {Object} opts parsed options
148
- - {Array} args parsed arguments
149
- - {Object} res actions result accumulator
150
- It can return rejected promise by Cmd.reject (in case of error)
151
- or any other value treated as result.
152
- @returns {COA.Opt} this instance (for chainability)
153
- ###
154
- act: (act) ->
155
- opt = @
156
- name = @_name
157
- @_cmd.act (opts) ->
158
- if name of opts
159
- res = act.apply @, arguments
160
- if opt._only
161
- Q.when res, (res) =>
162
- @reject {
163
- toString: -> res.toString()
164
- exitCode: 0
165
- }
166
- else
167
- res
168
- @
169
-
170
- ###*
171
- Set custom additional completion for current option.
172
- @param {Function} completion generation function,
173
- invoked in the context of option instance.
174
- Accepts parameters:
175
- - {Object} opts completion options
176
- It can return promise or any other value treated as result.
177
- @returns {COA.Opt} this instance (for chainability)
178
- ###
179
- comp: Cmd::comp
180
-
181
- _saveVal: (opts, val) ->
182
- if @_val then val = @_val val
183
- if @_arr
184
- (opts[@_name] or= []).push val
185
- else
186
- opts[@_name] = val
187
- val
188
-
189
- _parse: (argv, opts) ->
190
- @_saveVal(
191
- opts,
192
- if @_flag
193
- true
194
- else
195
- argv.shift()
196
- )
197
-
198
- _checkParsed: (opts, args) -> not opts.hasOwnProperty @_name
199
-
200
- _usage: ->
201
- res = []
202
- nameStr = @_name.toUpperCase()
203
-
204
- if @_short
205
- res.push '-', Color 'lgreen', @_short
206
- unless @_flag then res.push ' ' + nameStr
207
- res.push ', '
208
-
209
- if @_long
210
- res.push '--', Color 'green', @_long
211
- unless @_flag then res.push '=' + nameStr
212
-
213
- res.push ' : ', @_title
214
-
215
- if @_req then res.push ' ', Color('lred', '(required)')
216
-
217
- res.join ''
218
-
219
- _requiredText: -> 'Missing required option:\n ' + @_usage()
220
-
221
- ###*
222
- Return rejected promise with error code.
223
- Use in .val() for return with error.
224
- @param {Object} reject reason
225
- You can customize toString() method and exitCode property
226
- of reason object.
227
- @returns {Q.promise} rejected promise
228
- ###
229
- reject: Cmd::reject
230
-
231
- ###*
232
- Finish chain for current option and return parent command instance.
233
- @returns {COA.Cmd} parent command
234
- ###
235
- end: Cmd::end
236
-
237
- ###*
238
- Apply function with arguments in context of option instance.
239
- @param {Function} fn
240
- @param {Array} args
241
- @returns {COA.Opt} this instance (for chainability)
242
- ###
243
- apply: Cmd::apply
package/src/shell.coffee DELETED
@@ -1,10 +0,0 @@
1
- exports.unescape = (w) ->
2
- w = if w.charAt(0) is '"'
3
- w.replace(/^"|([^\\])"$/g, '$1')
4
- else
5
- w.replace(/\\ /g, ' ')
6
- w.replace(/\\("|'|\$|`|\\)/g, '$1')
7
-
8
- exports.escape = (w) ->
9
- w = w.replace(/(["'$`\\])/g,'\\$1')
10
- if w.match(/\s+/) then '"' + w + '"' else w