chiark / gitweb /
tg-mail: accept -i/-w
[topgit.git] / contrib / tg-completion.bash
1 #
2 # bash completion support for TopGit.
3 #
4 # Copyright (C) 2008 Jonas Fonseca <fonseca@diku.dk>
5 # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
6 # Based git's git-completion.sh: http://repo.or.cz/w/git/fastimport.git
7 # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
8 # Distributed under the GNU General Public License, version 2.0.
9 #
10 # To use these routines:
11 #
12 #    1) Copy this file to somewhere (e.g. ~/.tg-completion.sh).
13 #    2) Source it from your ~/.bashrc.
14 #
15 # Note: Make sure the tg script is in your PATH before you source this
16 # script, so it can properly setup cached values.
17
18 case "$COMP_WORDBREAKS" in
19 *:*) : great ;;
20 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
21 esac
22
23 ### {{{ Utilities
24
25 __tgdir ()
26 {
27         if [ -z "$1" ]; then
28                 if [ -n "$__tg_dir" ]; then
29                         echo "$__tg_dir"
30                 elif [ -d .git ]; then
31                         echo .git
32                 else
33                         git rev-parse --git-dir 2>/dev/null
34                 fi
35         elif [ -d "$1/.git" ]; then
36                 echo "$1/.git"
37         else
38                 echo "$1"
39         fi
40 }
41
42 __tgcomp_1 ()
43 {
44         local c IFS=' '$'\t'$'\n'
45         for c in $1; do
46                 case "$c$2" in
47                 --*=*) printf %s$'\n' "$c$2" ;;
48                 *.)    printf %s$'\n' "$c$2" ;;
49                 *)     printf %s$'\n' "$c$2 " ;;
50                 esac
51         done
52 }
53
54 __tgcomp ()
55 {
56         local cur="${COMP_WORDS[COMP_CWORD]}"
57         if [ $# -gt 2 ]; then
58                 cur="$3"
59         fi
60         case "$cur" in
61         --*=)
62                 COMPREPLY=()
63                 ;;
64         *)
65                 local IFS=$'\n'
66                 COMPREPLY=($(compgen -P "$2" \
67                         -W "$(__tgcomp_1 "$1" "$4")" \
68                         -- "$cur"))
69                 ;;
70         esac
71 }
72
73 __tg_heads ()
74 {
75         local cmd i is_hash=y dir="$(__tgdir "$1")"
76         if [ -d "$dir" ]; then
77                 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
78                         refs/heads
79                 return
80         fi
81         for i in $(git ls-remote "$1" 2>/dev/null); do
82                 case "$is_hash,$i" in
83                 y,*) is_hash=n ;;
84                 n,*^{}) is_hash=y ;;
85                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
86                 n,*) is_hash=y; echo "$i" ;;
87                 esac
88         done
89 }
90
91 __tg_refs ()
92 {
93         local cmd i is_hash=y dir="$(__tgdir "$1")"
94         if [ -d "$dir" ]; then
95                 if [ -e "$dir/HEAD" ]; then echo HEAD; fi
96                 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
97                         refs/tags refs/heads refs/remotes
98                 return
99         fi
100         for i in $(git ls-remote "$dir" 2>/dev/null); do
101                 case "$is_hash,$i" in
102                 y,*) is_hash=n ;;
103                 n,*^{}) is_hash=y ;;
104                 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
105                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
106                 n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
107                 n,*) is_hash=y; echo "$i" ;;
108                 esac
109         done
110 }
111
112 __tg_refs2 ()
113 {
114         local i
115         for i in $(__tg_refs "$1"); do
116                 echo "$i:$i"
117         done
118 }
119
120 __tg_refs_remotes ()
121 {
122         local cmd i is_hash=y
123         for i in $(git ls-remote "$1" 2>/dev/null); do
124                 case "$is_hash,$i" in
125                 n,refs/heads/*)
126                         is_hash=y
127                         echo "$i:refs/remotes/$1/${i#refs/heads/}"
128                         ;;
129                 y,*) is_hash=n ;;
130                 n,*^{}) is_hash=y ;;
131                 n,refs/tags/*) is_hash=y;;
132                 n,*) is_hash=y; ;;
133                 esac
134         done
135 }
136
137 __tg_remotes ()
138 {
139         local i ngoff IFS=$'\n' d="$(__tgdir)"
140         shopt -q nullglob || ngoff=1
141         shopt -s nullglob
142         for i in "$d/remotes"/*; do
143                 echo ${i#$d/remotes/}
144         done
145         [ "$ngoff" ] && shopt -u nullglob
146         for i in $(git --git-dir="$d" config --list); do
147                 case "$i" in
148                 remote.*.url=*)
149                         i="${i#remote.}"
150                         echo "${i/.url=*/}"
151                         ;;
152                 esac
153         done
154 }
155
156 __tg_find_subcommand ()
157 {
158         local word subcommand c=1
159
160         while [ $c -lt $COMP_CWORD ]; do
161                 word="${COMP_WORDS[c]}"
162                 for subcommand in $1; do
163                         if [ "$subcommand" = "$word" ]; then
164                                 echo "$subcommand"
165                                 return
166                         fi
167                 done
168                 c=$((++c))
169         done
170 }
171
172 __tg_complete_revlist ()
173 {
174         local pfx cur="${COMP_WORDS[COMP_CWORD]}"
175         case "$cur" in
176         *...*)
177                 pfx="${cur%...*}..."
178                 cur="${cur#*...}"
179                 __tgcomp "$(__tg_refs)" "$pfx" "$cur"
180                 ;;
181         *..*)
182                 pfx="${cur%..*}.."
183                 cur="${cur#*..}"
184                 __tgcomp "$(__tg_refs)" "$pfx" "$cur"
185                 ;;
186         *)
187                 __tgcomp "$(__tg_refs)"
188                 ;;
189         esac
190 }
191
192 __tg_topics ()
193 {
194         tg summary -t
195 }
196
197 __tg_commands ()
198 {
199         if [ -n "$__tg_all_commandlist" ]; then
200                 echo "$__tg_all_commandlist"
201                 return
202         fi
203         local i IFS=" "$'\n'
204         for i in $(tg help | sed -n 's/^Usage:.*(\(.*\)).*/\1/p' | tr '|' ' ')
205         do
206                 case $i in
207                 *--*)             : helper pattern;;
208                 *) echo $i;;
209                 esac
210         done
211 }
212 __tg_all_commandlist=
213 __tg_all_commandlist="$(__tg_commands 2>/dev/null)"
214
215 __tg_complete_arg ()
216 {
217         if [ $COMP_CWORD -gt 2 ] && [ "${COMP_WORDS[$COMP_CWORD - 1]}" = "$1" ]; then
218                 return 0
219         fi
220         return 1
221 }
222
223 ### }}}
224 ### {{{ Commands
225
226 _tg_create ()
227 {
228         local cmd="$1"
229         local cur="${COMP_WORDS[COMP_CWORD]}"
230
231         # Name must be the first arg after the create command
232         if [ $((cmd + 1)) = $COMP_CWORD ]; then
233                 __tgcomp "$(__tg_topics)"
234                 return
235         fi
236
237         __tg_complete_arg "-r" && {
238                 __tgcomp "$(__tg_remotes)"
239                 return
240         }
241
242         case "$cur" in
243         -*)
244                 __tgcomp "
245                         -r
246                 "
247                 ;;
248         *)
249                 __tgcomp "$(__tg_refs)"
250         esac
251 }
252
253 _tg_delete ()
254 {
255         local cur="${COMP_WORDS[COMP_CWORD]}"
256
257         case "$cur" in
258         -*)
259                 __tgcomp "
260                         -f
261                 "
262                 ;;
263         *)
264                 __tgcomp "$(__tg_topics)"
265         esac
266 }
267
268 _tg_depend ()
269 {
270         local subcommands="add"
271         local subcommand="$(__git_find_subcommand "$subcommands")"
272         if [ -z "$subcommand" ]; then
273                 __tgcomp "$subcommands"
274                 return
275         fi
276
277         case "$subcommand" in
278         add)
279                 __tgcomp "$(__tg_refs)"
280         esac
281 }
282
283 _tg_export ()
284 {
285         local cur="${COMP_WORDS[COMP_CWORD]}"
286
287         __tg_complete_arg "--collapse" && {
288                 __tgcomp "$(__tg_heads)"
289                 return
290         }
291
292         __tg_complete_arg "--quilt" && {
293                 return
294         }
295
296         case "$cur" in
297         *)
298                 __tgcomp "
299                         --collapse
300                         --quilt
301                 "
302         esac
303 }
304
305 _tg_help ()
306 {
307         local cur="${COMP_WORDS[COMP_CWORD]}"
308         case "$cur" in
309         -*)
310                 COMPREPLY=()
311                 return
312                 ;;
313         esac
314         __tgcomp "$(__tg_commands)"
315 }
316
317 _tg_import ()
318 {
319         local cur="${COMP_WORDS[COMP_CWORD]}"
320
321         __tg_complete_arg "-p" && {
322                 COMPREPLY=()
323                 return
324         }
325
326         case "$cur" in
327         -*)
328                 __tgcomp "
329                         -p
330                 "
331                 ;;
332         *)
333                 __tg_complete_revlist
334         esac
335 }
336
337 _tg_info ()
338 {
339         local cur="${COMP_WORDS[COMP_CWORD]}"
340
341         case "$cur" in
342         *)
343                 __tgcomp "$(__tg_topics)"
344         esac
345 }
346
347 _tg_log ()
348 {
349         local cur="${COMP_WORDS[COMP_CWORD]}"
350
351         case "$cur" in
352         *)
353                 __tgcomp "$(__tg_topics)"
354         esac
355 }
356
357 _tg_mail ()
358 {
359         local cur="${COMP_WORDS[COMP_CWORD]}"
360
361         case "$cur" in
362         -*)
363                 __tgcomp "
364                         -i
365                         -w
366                         -s
367                         -r
368                 "
369                 ;;
370         *)
371                 __tgcomp "$(__tg_topics)"
372         esac
373 }
374
375 _tg_patch ()
376 {
377         local cur="${COMP_WORDS[COMP_CWORD]}"
378
379         case "$cur" in
380         -*)
381                 __tgcomp "
382                         -i
383                         -w
384                 "
385                 ;;
386         *)
387                 __tgcomp "$(__tg_topics)"
388         esac
389 }
390
391 _tg_push ()
392 {
393         local cur="${COMP_WORDS[COMP_CWORD]}"
394
395         __tg_complete_arg "-r" && {
396                 __tgcomp "$(__tg_remotes)"
397                 return
398         }
399
400         case "$cur" in
401         -*)
402                 __tgcomp "
403                         --no-deps
404                         --dry-run
405                         --tgish-only
406                         -r
407                 "
408                 ;;
409         *)
410                 __tgcomp "$(__tg_topics)"
411         esac
412 }
413
414 _tg_remote ()
415 {
416         local cur="${COMP_WORDS[COMP_CWORD]}"
417
418         case "$cur" in
419         -*)
420                 __tgcomp "
421                         --populate
422                 "
423                 ;;
424         *)
425                 __tgcomp "$(__tg_remotes)"
426         esac
427 }
428
429 _tg_summary ()
430 {
431         local cur="${COMP_WORDS[COMP_CWORD]}"
432
433         case "$cur" in
434         *)
435                 __tgcomp "
436                         --graphviz
437                         --sort
438                         --deps
439                         -t
440                         -i
441                         -w
442                 "
443         esac
444 }
445
446 _tg_update ()
447 {
448         local cur="${COMP_WORDS[COMP_CWORD]}"
449
450         case "$cur" in
451         *)
452                 __tgcomp "$(__tg_topics)"
453         esac
454 }
455
456 ### }}}
457 ### {{{ tg completion
458
459 _tg ()
460 {
461         local i c=1 command __tg_dir
462
463         while [ $c -lt $COMP_CWORD ]; do
464                 i="${COMP_WORDS[c]}"
465                 case "$i" in
466                 -r) 
467                         c=$((++c))
468                         if [ $c -lt $COMP_CWORD ]; then
469                                 __tgcomp "$(__tg_remotes)"
470                                 return
471                         fi
472                         ;;
473                 -h|--help) command="help"; break ;;
474                 *) command="$i"; break ;;
475                 esac
476                 c=$((++c))
477         done
478
479         if [ -z "$command" ]; then
480                 case "${COMP_WORDS[COMP_CWORD]}" in
481                 -*)     __tgcomp "
482                                 -r
483                                 -h
484                                 --help
485                         "
486                         ;;
487                 *)     __tgcomp "$(__tg_commands)" ;;
488                 esac
489                 return
490         fi
491
492         case "$command" in
493         create)      _tg_create "$c" ;;
494         delete)      _tg_delete ;;
495         depend)      _tg_depend ;;
496         export)      _tg_export ;;
497         files)       _tg_patch ;;
498         help)        _tg_help ;;
499         import)      _tg_import ;;
500         info)        _tg_info ;;
501         log)         _tg_log ;;
502         mail)        _tg_mail ;;
503         patch)       _tg_patch ;;
504         push)        _tg_push ;;
505         remote)      _tg_remote ;;
506         summary)     _tg_summary ;;
507         update)      _tg_update ;;
508         *)           COMPREPLY=() ;;
509         esac
510 }
511
512 ### }}}
513
514 complete -o default -o nospace -F _tg tg
515
516 # The following are necessary only for Cygwin, and only are needed
517 # when the user has tab-completed the executable name and consequently
518 # included the '.exe' suffix.
519 #
520 if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
521 complete -o default -o nospace -F _tg tg.exe
522 fi