Security update to Drupal 8.4.6
[yaffs-website] / node_modules / dashdash / etc / dashdash.bash_completion.in
1 #!/bin/bash
2 #
3 # Bash completion generated for '{{name}}' at {{date}}.
4 #
5 # The original template lives here:
6 # https://github.com/trentm/node-dashdash/blob/master/etc/dashdash.bash_completion.in
7 #
8
9 #
10 # Copyright 2016 Trent Mick
11 # Copyright 2016 Joyent, Inc.
12 #
13 #
14 # A generic Bash completion driver script.
15 #
16 # This is meant to provide a re-usable chunk of Bash to use for
17 # "etc/bash_completion.d/" files for individual tools. Only the "Configuration"
18 # section with tool-specific info need differ. Features:
19 #
20 # - support for short and long opts
21 # - support for knowing which options take arguments
22 # - support for subcommands (e.g. 'git log <TAB>' to show just options for the
23 #   log subcommand)
24 # - does the right thing with "--" to stop options
25 # - custom optarg and arg types for custom completions
26 # - (TODO) support for shells other than Bash (tcsh, zsh, fish?, etc.)
27 #
28 #
29 # Examples/design:
30 #
31 # 1. Bash "default" completion. By default Bash's 'complete -o default' is
32 #    enabled. That means when there are no completions (e.g. if no opts match
33 #    the current word), then you'll get Bash's default completion. Most notably
34 #    that means you get filename completion. E.g.:
35 #       $ tool ./<TAB>
36 #       $ tool READ<TAB>
37 #
38 # 2. all opts and subcmds:
39 #       $ tool <TAB>
40 #       $ tool -v <TAB>     # assuming '-v' doesn't take an arg
41 #       $ tool -<TAB>       # matching opts
42 #       $ git lo<TAB>       # matching subcmds
43 #
44 #    Long opt completions are given *without* the '=', i.e. we prefer space
45 #    separated because that's easier for good completions.
46 #
47 # 3. long opt arg with '='
48 #       $ tool --file=<TAB>
49 #       $ tool --file=./d<TAB>
50 #    We maintain the "--file=" prefix. Limitation: With the attached prefix
51 #    the 'complete -o filenames' doesn't know to do dirname '/' suffixing. Meh.
52 #
53 # 4. envvars:
54 #       $ tool $<TAB>
55 #       $ tool $P<TAB>
56 #    Limitation: Currently only getting exported vars, so we miss "PS1" and
57 #    others.
58 #
59 # 5. Defer to other completion in a subshell:
60 #       $ tool --file $(cat ./<TAB>
61 #    We get this from 'complete -o default ...'.
62 #
63 # 6. Custom completion types from a provided bash function.
64 #       $ tool --profile <TAB>        # complete available "profiles"
65 #
66 #
67 # Dev Notes:
68 # - compgen notes, from http://unix.stackexchange.com/questions/151118/understand-compgen-builtin-command
69 # - https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
70 #
71
72
73 # Debugging this completion:
74 #   1. Uncomment the "_{{name}}_log_file=..." line.
75 #   2. 'tail -f /var/tmp/dashdash-completion.log' in one terminal.
76 #   3. Re-source this bash completion file.
77 #_{{name}}_log=/var/tmp/dashdash-completion.log
78
79 function _{{name}}_completer {
80
81     # ---- cmd definition
82
83     {{spec}}
84
85
86     # ---- locals
87
88     declare -a argv
89
90
91     # ---- support functions
92
93     function trace {
94         [[ -n "$_{{name}}_log" ]] && echo "$*" >&2
95     }
96
97     function _dashdash_complete {
98         local idx context
99         idx=$1
100         context=$2
101
102         local shortopts longopts optargs subcmds allsubcmds argtypes
103         shortopts="$(eval "echo \${cmd${context}_shortopts}")"
104         longopts="$(eval "echo \${cmd${context}_longopts}")"
105         optargs="$(eval "echo \${cmd${context}_optargs}")"
106         subcmds="$(eval "echo \${cmd${context}_subcmds}")"
107         allsubcmds="$(eval "echo \${cmd${context}_allsubcmds}")"
108         IFS=', ' read -r -a argtypes <<< "$(eval "echo \${cmd${context}_argtypes}")"
109
110         trace ""
111         trace "_dashdash_complete(idx=$idx, context=$context)"
112         trace "  shortopts: $shortopts"
113         trace "  longopts: $longopts"
114         trace "  optargs: $optargs"
115         trace "  subcmds: $subcmds"
116         trace "  allsubcmds: $allsubcmds"
117
118         # Get 'state' of option parsing at this COMP_POINT.
119         # Copying "dashdash.js#parse()" behaviour here.
120         local state=
121         local nargs=0
122         local i=$idx
123         local argtype
124         local optname
125         local prefix
126         local word
127         local dashdashseen=
128         while [[ $i -lt $len && $i -le $COMP_CWORD ]]; do
129             argtype=
130             optname=
131             prefix=
132             word=
133
134             arg=${argv[$i]}
135             trace "  consider argv[$i]: '$arg'"
136
137             if [[ "$arg" == "--" && $i -lt $COMP_CWORD ]]; then
138                 trace "    dashdash seen"
139                 dashdashseen=yes
140                 state=arg
141                 word=$arg
142             elif [[ -z "$dashdashseen" && "${arg:0:2}" == "--" ]]; then
143                 arg=${arg:2}
144                 if [[ "$arg" == *"="* ]]; then
145                     optname=${arg%%=*}
146                     val=${arg##*=}
147                     trace "    long opt: optname='$optname' val='$val'"
148                     state=arg
149                     argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
150                     word=$val
151                     prefix="--$optname="
152                 else
153                     optname=$arg
154                     val=
155                     trace "    long opt: optname='$optname'"
156                     state=longopt
157                     word=--$optname
158
159                     if [[ "$optargs" == *"-$optname="* && $i -lt $COMP_CWORD ]]; then
160                         i=$(( $i + 1 ))
161                         state=arg
162                         argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
163                         word=${argv[$i]}
164                         trace "    takes arg (consume argv[$i], word='$word')"
165                     fi
166                 fi
167             elif [[ -z "$dashdashseen" && "${arg:0:1}" == "-" ]]; then
168                 trace "    short opt group"
169                 state=shortopt
170                 word=$arg
171
172                 local j=1
173                 while [[ $j -lt ${#arg} ]]; do
174                     optname=${arg:$j:1}
175                     trace "    consider index $j: optname '$optname'"
176
177                     if [[ "$optargs" == *"-$optname="* ]]; then
178                         argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
179                         if [[ $(( $j + 1 )) -lt ${#arg} ]]; then
180                             state=arg
181                             word=${arg:$(( $j + 1 ))}
182                             trace "      takes arg (rest of this arg, word='$word', argtype='$argtype')"
183                         elif [[ $i -lt $COMP_CWORD ]]; then
184                             state=arg
185                             i=$(( $i + 1 ))
186                             word=${argv[$i]}
187                             trace "    takes arg (word='$word', argtype='$argtype')"
188                         fi
189                         break
190                     fi
191
192                     j=$(( $j + 1 ))
193                 done
194             elif [[ $i -lt $COMP_CWORD && -n "$arg" ]] && $(echo "$allsubcmds" | grep -w "$arg" >/dev/null); then
195                 trace "    complete subcmd: recurse _dashdash_complete"
196                 _dashdash_complete $(( $i + 1 )) "${context}__${arg/-/_}"
197                 return
198             else
199                 trace "    not an opt or a complete subcmd"
200                 state=arg
201                 word=$arg
202                 nargs=$(( $nargs + 1 ))
203                 if [[ ${#argtypes[@]} -gt 0 ]]; then
204                     argtype="${argtypes[$(( $nargs - 1 ))]}"
205                     if [[ -z "$argtype" ]]; then
206                         # If we have more args than argtypes, we use the
207                         # last type.
208                         argtype="${argtypes[@]: -1:1}"
209                     fi
210                 fi
211             fi
212
213             trace "    state=$state prefix='$prefix' word='$word'"
214             i=$(( $i + 1 ))
215         done
216
217         trace "  parsed: state=$state optname='$optname' argtype='$argtype' prefix='$prefix' word='$word' dashdashseen=$dashdashseen"
218         local compgen_opts=
219         if [[ -n "$prefix" ]]; then
220             compgen_opts="$compgen_opts -P $prefix"
221         fi
222
223         case $state in
224         shortopt)
225             compgen $compgen_opts -W "$shortopts $longopts" -- "$word"
226             ;;
227         longopt)
228             compgen $compgen_opts -W "$longopts" -- "$word"
229             ;;
230         arg)
231             # If we don't know what completion to do, then emit nothing. We
232             # expect that we are running with:
233             #       complete -o default ...
234             # where "default" means: "Use Readline's default completion if
235             # the compspec generates no matches." This gives us the good filename
236             # completion, completion in subshells/backticks.
237             #
238             # We cannot support an argtype="directory" because
239             #       compgen -S '/' -A directory -- "$word"
240             # doesn't give a satisfying result. It doesn't stop at the trailing '/'
241             # so you cannot descend into dirs.
242             if [[ "${word:0:1}" == '$' ]]; then
243                 # By default, Bash will complete '$<TAB>' to all envvars. Apparently
244                 # 'complete -o default' does *not* give us that. The following
245                 # gets *close* to the same completions: '-A export' misses envvars
246                 # like "PS1".
247                 trace "  completing envvars"
248                 compgen $compgen_opts -P '$' -A export -- "${word:1}"
249             elif [[ -z "$argtype" ]]; then
250                 # Only include opts in completions if $word is not empty.
251                 # This is to avoid completing the leading '-', which foils
252                 # using 'default' completion.
253                 if [[ -n "$dashdashseen" ]]; then
254                     trace "  completing subcmds, if any (no argtype, dashdash seen)"
255                     compgen $compgen_opts -W "$subcmds" -- "$word"
256                 elif [[ -z "$word" ]]; then
257                     trace "  completing subcmds, if any (no argtype, empty word)"
258                     compgen $compgen_opts -W "$subcmds" -- "$word"
259                 else
260                     trace "  completing opts & subcmds (no argtype)"
261                     compgen $compgen_opts -W "$shortopts $longopts $subcmds" -- "$word"
262                 fi
263             elif [[ $argtype == "none" ]]; then
264                 # We want *no* completions, i.e. some way to get the active
265                 # 'complete -o default' to not do filename completion.
266                 trace "  completing 'none' (hack to imply no completions)"
267                 echo "##-no-completion- -results-##"
268             elif [[ $argtype == "file" ]]; then
269                 # 'complete -o default' gives the best filename completion, at least
270                 # on Mac.
271                 trace "  completing 'file' (let 'complete -o default' handle it)"
272                 echo ""
273             elif ! type complete_$argtype 2>/dev/null >/dev/null; then
274                 trace "  completing '$argtype' (fallback to default b/c complete_$argtype is unknown)"
275                 echo ""
276             else
277                 trace "  completing custom '$argtype'"
278                 completions=$(complete_$argtype "$word")
279                 if [[ -z "$completions" ]]; then
280                     trace "  no custom '$argtype' completions"
281                     # These are in ascii and "dictionary" order so they sort
282                     # correctly.
283                     echo "##-no-completion- -results-##"
284                 else
285                     echo $completions
286                 fi
287             fi
288             ;;
289         *)
290             trace "  unknown state: $state"
291             ;;
292         esac
293     }
294
295
296     trace ""
297     trace "-- $(date)"
298     #trace "\$IFS: '$IFS'"
299     #trace "\$@: '$@'"
300     #trace "COMP_WORDBREAKS: '$COMP_WORDBREAKS'"
301     trace "COMP_CWORD: '$COMP_CWORD'"
302     trace "COMP_LINE: '$COMP_LINE'"
303     trace "COMP_POINT: $COMP_POINT"
304
305     # Guard against negative COMP_CWORD. This is a Bash bug at least on
306     # Mac 10.10.4's bash. See
307     # <https://lists.gnu.org/archive/html/bug-bash/2009-07/msg00125.html>.
308     if [[ $COMP_CWORD -lt 0 ]]; then
309         trace "abort on negative COMP_CWORD"
310         exit 1;
311     fi
312
313     # I don't know how to do array manip on argv vars,
314     # so copy over to argv array to work on them.
315     shift   # the leading '--'
316     i=0
317     len=$#
318     while [[ $# -gt 0 ]]; do
319         argv[$i]=$1
320         shift;
321         i=$(( $i + 1 ))
322     done
323     trace "argv: '${argv[@]}'"
324     trace "argv[COMP_CWORD-1]: '${argv[$(( $COMP_CWORD - 1 ))]}'"
325     trace "argv[COMP_CWORD]: '${argv[$COMP_CWORD]}'"
326     trace "argv len: '$len'"
327
328     _dashdash_complete 1 ""
329 }
330
331
332 # ---- mainline
333
334 # Note: This if-block to help work with 'compdef' and 'compctl' is
335 # adapted from 'npm completion'.
336 if type complete &>/dev/null; then
337     function _{{name}}_completion {
338         local _log_file=/dev/null
339         [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
340         COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
341             COMP_LINE="$COMP_LINE" \
342             COMP_POINT="$COMP_POINT" \
343             _{{name}}_completer -- "${COMP_WORDS[@]}" \
344             2>$_log_file)) || return $?
345     }
346     complete -o default -F _{{name}}_completion {{name}}
347 elif type compdef &>/dev/null; then
348     function _{{name}}_completion {
349         local _log_file=/dev/null
350         [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
351         compadd -- $(COMP_CWORD=$((CURRENT-1)) \
352             COMP_LINE=$BUFFER \
353             COMP_POINT=0 \
354             _{{name}}_completer -- "${words[@]}" \
355             2>$_log_file)
356     }
357     compdef _{{name}}_completion {{name}}
358 elif type compctl &>/dev/null; then
359     function _{{name}}_completion {
360         local cword line point words si
361         read -Ac words
362         read -cn cword
363         let cword-=1
364         read -l line
365         read -ln point
366         local _log_file=/dev/null
367         [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
368         reply=($(COMP_CWORD="$cword" \
369             COMP_LINE="$line" \
370             COMP_POINT="$point" \
371             _{{name}}_completer -- "${words[@]}" \
372             2>$_log_file)) || return $?
373     }
374     compctl -K _{{name}}_completion {{name}}
375 fi
376
377
378 ##
379 ## This is a Bash completion file for the '{{name}}' command. You can install
380 ## with either:
381 ##
382 ##     cp FILE /usr/local/etc/bash_completion.d/{{name}}   # Mac
383 ##     cp FILE /etc/bash_completion.d/{{name}}             # Linux
384 ##
385 ## or:
386 ##
387 ##     cp FILE > ~/.{{name}}.completion
388 ##     echo "source ~/.{{name}}.completion" >> ~/.bashrc
389 ##