]>
Commit | Line | Data |
---|---|---|
bb70624e JA |
1 | # |
2 | # Completion examples | |
3 | # | |
4 | ||
5 | # | |
6 | # This encapsulates the default bash completion code | |
7 | # call with the word to be completed as $1 | |
8 | # | |
9 | # Since programmable completion does not use the bash default completions | |
10 | # or the readline default of filename completion when the compspec does | |
11 | # not generate any matches, this may be used as a `last resort' in a | |
12 | # completion function to mimic the default bash completion behavior. | |
13 | # | |
14 | _bash_def_completion () | |
15 | { | |
16 | local h t | |
17 | COMPREPLY=() | |
18 | ||
19 | # command substitution | |
20 | if [[ "$1" == \$\(* ]]; then | |
21 | t=${1#??} | |
22 | COMPREPLY=( $(compgen -c -P '$(' $t) ) | |
23 | fi | |
24 | # variables with a leading `${' | |
25 | if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$\{* ]]; then | |
26 | t=${1#??} | |
27 | COMPREPLY=( $(compgen -v -P '${' -S '}' $t) ) | |
28 | fi | |
29 | # variables with a leading `$' | |
30 | if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$* ]]; then | |
31 | t=${1#?} | |
32 | COMPREPLY=( $(compgen -v -P '$' $t ) ) | |
33 | fi | |
34 | # username expansion | |
35 | if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == ~* ]] && [[ "$1" != */* ]]; then | |
36 | t=${1#?} | |
37 | COMPREPLY=( $( compgen -u -P '~' $t ) ) | |
38 | fi | |
39 | # hostname | |
40 | if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == *@* ]]; then | |
41 | h=${1%%@*} | |
42 | t=${1#*@} | |
43 | COMPREPLY=( $( compgen -A hostname -P "${h}@" $t ) ) | |
44 | fi | |
45 | # glob pattern | |
46 | if [ ${#COMPREPLY[@]} -eq 0 ]; then | |
47 | # sh-style glob pattern | |
48 | if [[ $1 == *[*?[]* ]]; then | |
49 | COMPREPLY=( $( compgen -G "$1" ) ) | |
50 | # ksh-style extended glob pattern - must be complete | |
51 | elif shopt -q extglob && [[ $1 == *[?*+\!@]\(*\)* ]]; then | |
52 | COMPREPLY=( $( compgen -G "$1" ) ) | |
53 | fi | |
54 | fi | |
55 | ||
56 | # final default is filename completion | |
57 | if [ ${#COMPREPLY[@]} -eq 0 ]; then | |
58 | COMPREPLY=( $(compgen -f "$1" ) ) | |
59 | fi | |
60 | } | |
61 | ||
62 | # | |
63 | # Return 1 if $1 appears to contain a redirection operator. Handles backslash | |
64 | # quoting (barely). | |
65 | # | |
66 | _redir_op() | |
67 | { | |
68 | case "$1" in | |
69 | *\\'[\<\>]'*) return 1;; | |
70 | *[\<\>]*) return 0;; | |
71 | *) return 1;; | |
72 | esac | |
73 | } | |
74 | ||
75 | ||
76 | # _redir_test tests the current word ($1) and the previous word ($2) for | |
77 | # redirection operators and does filename completion on the current word | |
78 | # if either one contains a redirection operator | |
79 | _redir_test() | |
80 | { | |
81 | if _redir_op "$1" ; then | |
82 | COMPREPLY=( $( compgen -f "$1" ) ) | |
83 | return 0 | |
84 | elif _redir_op "$2" ; then | |
85 | COMPREPLY=( $( compgen -f "$1" ) ) | |
86 | return 0 | |
87 | fi | |
88 | return 1 | |
89 | } | |
90 | ||
91 | # optional, but without this you can't use extended glob patterns | |
92 | shopt -s extglob | |
93 | ||
94 | # | |
95 | # Easy ones for the shell builtins | |
96 | # | |
97 | # nothing for: alias, break, continue, dirs, echo, eval, exit, getopts, | |
98 | # let, logout, popd, printf, pwd, return, shift, suspend, test, times, | |
99 | # umask | |
100 | # | |
101 | ||
102 | complete -f -- . source | |
103 | complete -A enabled builtin | |
104 | complete -d cd | |
105 | ||
106 | # this isn't exactly right yet -- needs to skip shell functions and | |
107 | # do $PATH lookup (or do compgen -c and filter out matches that also | |
108 | # appear in compgen -A function) | |
109 | complete -c command | |
110 | ||
111 | # could add -S '=', but that currently screws up because readline appends | |
112 | # a space unconditionally | |
113 | ||
114 | complete -v export local readonly | |
115 | complete -A helptopic help # currently same as builtins | |
116 | ||
117 | complete -d pushd | |
118 | ||
119 | complete -A shopt shopt | |
120 | ||
121 | complete -c type | |
122 | ||
123 | complete -a unalias | |
124 | complete -v unset | |
125 | ||
126 | # | |
127 | # Job control builtins: fg, bg, disown, kill, wait | |
128 | # kill not done yet | |
129 | # | |
130 | ||
131 | complete -A stopped -P '%' bg | |
132 | complete -j -P '%' fg jobs disown | |
133 | ||
134 | # this is not quite right at this point | |
135 | ||
136 | _wait_func () | |
137 | { | |
138 | local cur | |
139 | cur=${COMP_WORDS[COMP_CWORD]} | |
140 | ||
141 | case "$cur" in | |
142 | %*) COMPREPLY=( $(compgen -A running -P '%' ${cur#?} ) ) ;; | |
143 | [0-9]*) COMPREPLY=( $(jobs -p | grep ^${cur}) ) ;; | |
144 | *) COMPREPLY=( $(compgen -A running -P '%') $(jobs -p) ) | |
145 | ;; | |
146 | esac | |
147 | } | |
148 | complete -F _wait_func wait | |
149 | ||
150 | # | |
151 | # more complicated things, several as yet unimplemented | |
152 | # | |
153 | ||
154 | #complete -F _bind_func bind | |
155 | ||
156 | _declare_func() | |
157 | { | |
158 | local cur prev nflag opts | |
159 | ||
160 | cur=${COMP_WORDS[COMP_CWORD]} | |
161 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
162 | ||
163 | COMPREPLY=() | |
164 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
165 | COMPREPLY=(-a -f -F -i -r -x -p) | |
166 | return 0; | |
167 | fi | |
168 | if [[ $cur == '+' ]]; then | |
169 | COMPREPLY=(+i +x) | |
170 | return 0; | |
171 | fi | |
172 | if [[ $prev == '-p' ]]; then | |
173 | COMPREPLY=( $(compgen -v $cur) ) | |
174 | return 0; | |
175 | fi | |
176 | return 1 | |
177 | } | |
178 | complete -F _declare_func declare typeset | |
179 | ||
180 | _enable_func() | |
181 | { | |
182 | local cur prev nflag opts | |
183 | ||
184 | cur=${COMP_WORDS[COMP_CWORD]} | |
185 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
186 | ||
187 | COMPREPLY=() | |
188 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
189 | COMPREPLY=(-a -d -f -n -p -s) | |
190 | return 0; | |
191 | fi | |
192 | if [[ $prev == '-f' ]]; then | |
193 | COMPREPLY=( $( compgen -f $cur ) ) | |
194 | return 0; | |
195 | fi | |
196 | for opts in "${COMP_WORDS[@]}" ; do | |
197 | if [[ $opts == -*n* ]]; then nflag=1; fi | |
198 | done | |
199 | ||
200 | if [ -z "$nflag" ] ; then | |
201 | COMPREPLY=( $( compgen -A enabled $cur ) ) | |
202 | else | |
203 | COMPREPLY=( $( compgen -A disabled $cur ) ) | |
204 | fi | |
205 | return 0; | |
206 | } | |
207 | complete -F _enable_func enable | |
208 | ||
209 | _exec_func() | |
210 | { | |
211 | local cur prev | |
212 | ||
213 | cur=${COMP_WORDS[COMP_CWORD]} | |
214 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
215 | ||
216 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
217 | COMPREPLY=(-a -c -l) | |
218 | return 0; | |
219 | fi | |
220 | if [[ $prev != -*a* ]]; then | |
221 | COMPREPLY=( $( compgen -c $cur ) ) | |
222 | return 0 | |
223 | fi | |
224 | return 1; | |
225 | } | |
226 | complete -F _exec_func exec | |
227 | ||
228 | _fc_func() | |
229 | { | |
230 | local cur prev | |
231 | ||
232 | cur=${COMP_WORDS[COMP_CWORD]} | |
233 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
234 | ||
235 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
236 | COMPREPLY=(-e -n -l -r -s) | |
237 | return 0; | |
238 | fi | |
239 | if [[ $prev == -*e ]]; then | |
240 | COMPREPLY=( $(compgen -c $cur) ) | |
241 | return 0 | |
242 | fi | |
243 | return 1 | |
244 | } | |
245 | complete -F _fc_func fc | |
246 | ||
247 | _hash_func() | |
248 | { | |
249 | local cur prev | |
250 | ||
251 | cur=${COMP_WORDS[COMP_CWORD]} | |
252 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
253 | ||
254 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
255 | COMPREPLY=(-p -r) | |
256 | return 0; | |
257 | fi | |
258 | ||
259 | if [[ $prev == '-p' ]]; then | |
260 | COMPREPLY=( $( compgen -f $cur ) ) | |
261 | return 0; | |
262 | fi | |
263 | COMPREPLY=( $( compgen -c $cur ) ) | |
264 | return 0 | |
265 | } | |
266 | complete -F _hash_func hash | |
267 | ||
268 | _history_func() | |
269 | { | |
270 | local cur prev | |
271 | ||
272 | cur=${COMP_WORDS[COMP_CWORD]} | |
273 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
274 | ||
275 | COMPREPLY=() | |
276 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
277 | COMPREPLY=(-a -c -d -n -r -w -p -s) | |
278 | return 0; | |
279 | fi | |
280 | if [[ $prev == -[anrw] ]]; then | |
281 | COMPREPLY=( $( compgen -f $cur ) ) | |
282 | fi | |
283 | return 0 | |
284 | } | |
285 | complete -F _history_func history | |
286 | ||
287 | #complete -F _read_func read | |
288 | ||
289 | _set_func () | |
290 | { | |
291 | local cur prev | |
292 | ||
293 | cur=${COMP_WORDS[COMP_CWORD]} | |
294 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
295 | ||
296 | COMPREPLY=() | |
297 | ||
298 | _redir_test "$cur" "$prev" && return 0; | |
299 | ||
300 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
301 | COMPREPLY=(-a -b -e -f -k -m -n -o -p -t -u -v -x -B -C -H -P --) | |
302 | return 0; | |
303 | fi | |
304 | if [[ $cur == '+' ]]; then | |
305 | COMPREPLY=(+a +b +e +f +k +m +n +o +p +t +u +v +x +B +C +H +P) | |
306 | return 0; | |
307 | fi | |
308 | if [[ $prev == [+-]o ]]; then | |
309 | COMPREPLY=( $(compgen -A setopt $cur) ) | |
310 | return 0; | |
311 | fi | |
312 | return 1; | |
313 | } | |
314 | complete -F _set_func set | |
315 | ||
316 | _trap_func () | |
317 | { | |
318 | local cur | |
319 | cur=${COMP_WORDS[COMP_CWORD]} | |
320 | ||
321 | if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then | |
322 | COMPREPLY=(-l -p) | |
323 | return 0; | |
324 | fi | |
325 | COMPREPLY=( $( compgen -A signal ${cur}) ) | |
326 | return 0 | |
327 | } | |
328 | complete -F _trap_func trap | |
329 | ||
330 | # | |
331 | # meta-completion (completion for complete/compgen) | |
332 | # | |
333 | _complete_meta_func() | |
334 | { | |
335 | local cur prev cmd | |
336 | COMPREPLY=() | |
337 | ||
338 | cmd=$1 | |
339 | ||
340 | cur=${COMP_WORDS[COMP_CWORD]} | |
341 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
342 | ||
343 | _redir_test "$cur" "$prev" && return 0; | |
344 | ||
345 | if (( $COMP_CWORD <= 1 )) || [[ "$cur" == '-' ]]; then | |
346 | case "$cmd" in | |
347 | complete) COMPREPLY=(-a -b -c -d -e -f -j -k -v -u -r -p -A -G -W -P -S -X -F -C);; | |
348 | compgen) COMPREPLY=(-a -b -c -d -e -f -j -k -v -u -A -G -W -P -S -X -F -C);; | |
349 | esac | |
350 | return 0 | |
351 | fi | |
352 | ||
353 | if [[ $prev == -A ]]; then | |
354 | COMPREPLY=(alias arrayvar binding builtin command directory \ | |
28ef6c31 | 355 | disabled enabled export file 'function' helptopic hostname job keyword \ |
bb70624e JA |
356 | running setopt shopt signal stopped variable) |
357 | return 0 | |
358 | elif [[ $prev == -F ]]; then | |
359 | COMPREPLY=( $( compgen -A function $cur ) ) | |
360 | elif [[ $prev == -C ]]; then | |
361 | COMPREPLY=( $( compgen -c $cur ) ) | |
362 | else | |
363 | COMPREPLY=( $( compgen -c $cur ) ) | |
364 | fi | |
365 | return 0 | |
366 | } | |
367 | complete -F _complete_meta_func complete compgen | |
368 | ||
369 | # | |
370 | # some completions for shell reserved words | |
371 | # | |
372 | #complete -c -k time do if then else elif '{' | |
373 | ||
374 | # | |
375 | # external commands | |
376 | # | |
377 | ||
378 | complete -e printenv | |
379 | ||
380 | complete -c nohup exec nice eval trace truss strace sotruss gdb | |
381 | ||
382 | _make_targets () | |
383 | { | |
384 | local mdef makef gcmd cur prev i | |
385 | ||
386 | COMPREPLY=() | |
387 | cur=${COMP_WORDS[COMP_CWORD]} | |
388 | prev=${COMP_WORDS[COMP_CWORD-1]} | |
389 | ||
390 | # if prev argument is -f, return possible filename completions. | |
391 | # we could be a little smarter here and return matches against | |
392 | # `makefile Makefile *.mk', whatever exists | |
393 | case "$prev" in | |
394 | -*f) COMPREPLY=( $(compgen -f $cur ) ); return 0;; | |
395 | esac | |
396 | ||
397 | # if we want an option, return the possible posix options | |
398 | case "$cur" in | |
399 | -) COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;; | |
400 | esac | |
401 | ||
402 | # make reads `makefile' before `Makefile' | |
28ef6c31 JA |
403 | # GNU make reads `GNUmakefile' before all other makefiles, but we |
404 | # check that we're completing `gmake' before checking for it | |
405 | if [ -f GNUmakefile ] && [ ${COMP_WORDS[0]} == gmake ]; then | |
406 | mdef=GNUmakefile | |
407 | elif [ -f makefile ]; then | |
bb70624e JA |
408 | mdef=makefile |
409 | elif [ -f Makefile ]; then | |
410 | mdef=Makefile | |
411 | else | |
412 | mdef=*.mk # local convention | |
413 | fi | |
414 | ||
415 | # before we scan for targets, see if a makefile name was specified | |
416 | # with -f | |
417 | for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do | |
418 | if [[ ${COMP_WORDS[i]} == -*f ]]; then | |
419 | eval makef=${COMP_WORDS[i+1]} # eval for tilde expansion | |
420 | break | |
421 | fi | |
422 | done | |
423 | ||
424 | [ -z "$makef" ] && makef=$mdef | |
425 | ||
426 | # if we have a partial word to complete, restrict completions to | |
427 | # matches of that word | |
428 | if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi | |
429 | ||
430 | # if we don't want to use *.mk, we can take out the cat and use | |
431 | # test -f $makef and input redirection | |
432 | COMPREPLY=( $(cat $makef 2>/dev/null | awk 'BEGIN {FS=":"} /^[^.# ][^=]*:/ {print $1}' | tr -s ' ' '\012' | sort -u | eval $gcmd ) ) | |
433 | } | |
434 | complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake | |
435 | ||
436 | _umount_func () | |
437 | { | |
438 | COMPREPLY=( $(mount | awk '{print $1}') ) | |
439 | } | |
440 | complete -F _umount_func umount | |
441 | ||
442 | _configure_func () | |
443 | { | |
444 | case "$2" in | |
445 | -*) ;; | |
446 | *) return ;; | |
447 | esac | |
448 | ||
449 | case "$1" in | |
450 | \~*) eval cmd=$1 ;; | |
451 | *) cmd="$1" ;; | |
452 | esac | |
453 | ||
454 | COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) ) | |
455 | } | |
456 | complete -F _configure_func configure | |
457 | ||
458 | complete -W '"${GROUPS[@]}"' newgrp | |
459 | ||
460 | complete -f chown ln more cat | |
461 | complete -d mkdir rmdir | |
462 | complete -f strip | |
463 | ||
464 | complete -f -X '*.gz' gzip | |
28ef6c31 | 465 | complete -f -X '*.bz2' bzip2 |
bb70624e JA |
466 | complete -f -X '*.Z' compress |
467 | complete -f -X '!*.+(gz|tgz|Gz)' gunzip gzcat zcat zmore | |
468 | complete -f -X '!*.Z' uncompress zmore zcat | |
28ef6c31 JA |
469 | complete -f -X '!*.bz2' bunzip2 |
470 | complete -f -X '!*.zip' unzip | |
471 | complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|JPEG|bmp)' xv | |
bb70624e JA |
472 | |
473 | complete -f -X '!*.pl' perl perl5 | |
474 | ||
475 | complete -A hostname rsh telnet rlogin ftp ping xping host traceroute nslookup | |
476 | complete -A hostname rxterm rxterm3 rxvt2 | |
477 | ||
478 | complete -u su | |
479 | ||
480 | complete -f -X '!*.+(ps|PS)' gs gv ghostview psselect pswrap | |
28ef6c31 JA |
481 | complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype catdvi |
482 | complete -f -X '!*.+(pdf|PDF)' acroread4 | |
bb70624e JA |
483 | complete -f -X '!*.texi*' makeinfo texi2dvi texi2html |
484 | complete -f -X '!*.+(tex|TEX)' tex latex slitex | |
485 | ||
28ef6c31 JA |
486 | complete -f -X '!*.+(mp3|MP3)' mpg123 |
487 | complete -f -X '!*.+(htm|html)' links w3m lynx | |
488 | ||
bb70624e JA |
489 | # |
490 | # other possibilities, left as exercises | |
491 | # | |
492 | #complete -F _find_func find | |
493 | #complete -F _man_func man | |
494 | #complete -F _stty_func stty |