coa 0.4.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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