Add bash completion script for TopGit
[topgit/kirr.git] / contrib / tg-completion.bash
blob35eabe9f7cdcdd1e336f09c0d62a8a3fc6c15b61
2 # bash completion support for TopGit.
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.
10 # The contained completion routines provide support for completing:
12 # *) local and remote branch names
13 # *) local and remote tag names
14 # *) .git/remotes file names
15 # *) git 'subcommands'
16 # *) tree paths within 'ref:path/to/file' expressions
17 # *) common --long-options
19 # To use these routines:
21 # 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
22 # 2) Added the following line to your .bashrc:
23 # source ~/.git-completion.sh
25 # 3) You may want to make sure the git executable is available
26 # in your PATH before this script is sourced, as some caching
27 # is performed while the script loads. If git isn't found
28 # at source time then all lookups will be done on demand,
29 # which may be slightly slower.
31 # 4) Consider changing your PS1 to also show the current branch:
32 # PS1='[\u@\h \W$(__tg_ps1 " (%s)")]\$ '
34 # The argument to __tg_ps1 will be displayed only if you
35 # are currently in a git repository. The %s token will be
37 case "$COMP_WORDBREAKS" in
38 *:*) : great ;;
39 *) COMP_WORDBREAKS="$COMP_WORDBREAKS:"
40 esac
42 ### {{{ Utilities
44 __tgdir ()
46 if [ -z "$1" ]; then
47 if [ -n "$__tg_dir" ]; then
48 echo "$__tg_dir"
49 elif [ -d .git ]; then
50 echo .git
51 else
52 git rev-parse --git-dir 2>/dev/null
54 elif [ -d "$1/.git" ]; then
55 echo "$1/.git"
56 else
57 echo "$1"
61 __tgcomp_1 ()
63 local c IFS=' '$'\t'$'\n'
64 for c in $1; do
65 case "$c$2" in
66 --*=*) printf %s$'\n' "$c$2" ;;
67 *.) printf %s$'\n' "$c$2" ;;
68 *) printf %s$'\n' "$c$2 " ;;
69 esac
70 done
73 __tgcomp ()
75 local cur="${COMP_WORDS[COMP_CWORD]}"
76 if [ $# -gt 2 ]; then
77 cur="$3"
79 case "$cur" in
80 --*=)
81 COMPREPLY=()
84 local IFS=$'\n'
85 COMPREPLY=($(compgen -P "$2" \
86 -W "$(__tgcomp_1 "$1" "$4")" \
87 -- "$cur"))
89 esac
92 __tg_heads ()
94 local cmd i is_hash=y dir="$(__tgdir "$1")"
95 if [ -d "$dir" ]; then
96 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
97 refs/heads
98 return
100 for i in $(git ls-remote "$1" 2>/dev/null); do
101 case "$is_hash,$i" in
102 y,*) is_hash=n ;;
103 n,*^{}) is_hash=y ;;
104 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
105 n,*) is_hash=y; echo "$i" ;;
106 esac
107 done
110 __tg_refs ()
112 local cmd i is_hash=y dir="$(__tgdir "$1")"
113 if [ -d "$dir" ]; then
114 if [ -e "$dir/HEAD" ]; then echo HEAD; fi
115 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
116 refs/tags refs/heads refs/remotes
117 return
119 for i in $(git ls-remote "$dir" 2>/dev/null); do
120 case "$is_hash,$i" in
121 y,*) is_hash=n ;;
122 n,*^{}) is_hash=y ;;
123 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
124 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
125 n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
126 n,*) is_hash=y; echo "$i" ;;
127 esac
128 done
131 __tg_refs2 ()
133 local i
134 for i in $(__tg_refs "$1"); do
135 echo "$i:$i"
136 done
139 __tg_refs_remotes ()
141 local cmd i is_hash=y
142 for i in $(git ls-remote "$1" 2>/dev/null); do
143 case "$is_hash,$i" in
144 n,refs/heads/*)
145 is_hash=y
146 echo "$i:refs/remotes/$1/${i#refs/heads/}"
148 y,*) is_hash=n ;;
149 n,*^{}) is_hash=y ;;
150 n,refs/tags/*) is_hash=y;;
151 n,*) is_hash=y; ;;
152 esac
153 done
156 __tg_remotes ()
158 local i ngoff IFS=$'\n' d="$(__tgdir)"
159 shopt -q nullglob || ngoff=1
160 shopt -s nullglob
161 for i in "$d/remotes"/*; do
162 echo ${i#$d/remotes/}
163 done
164 [ "$ngoff" ] && shopt -u nullglob
165 for i in $(git --git-dir="$d" config --list); do
166 case "$i" in
167 remote.*.url=*)
168 i="${i#remote.}"
169 echo "${i/.url=*/}"
171 esac
172 done
175 __tg_complete_revlist ()
177 local pfx cur="${COMP_WORDS[COMP_CWORD]}"
178 case "$cur" in
179 *...*)
180 pfx="${cur%...*}..."
181 cur="${cur#*...}"
182 __tgcomp "$(__tg_refs)" "$pfx" "$cur"
184 *..*)
185 pfx="${cur%..*}.."
186 cur="${cur#*..}"
187 __tgcomp "$(__tg_refs)" "$pfx" "$cur"
190 __tgcomp "$(__tg_refs)"
192 esac
195 __tg_topics ()
197 tg summary | cut -f 2
200 __tg_commands ()
202 if [ -n "$__tg_all_commandlist" ]; then
203 echo "$__tg_all_commandlist"
204 return
206 local i IFS=" "$'\n'
207 for i in $(tg help | sed -n 's/^Usage:.*(\(.*\)).*/\1/p' | tr '|' ' ')
209 case $i in
210 *--*) : helper pattern;;
211 *) echo $i;;
212 esac
213 done
215 __tg_all_commandlist=
216 __tg_all_commandlist="$(__tg_commands 2>/dev/null)"
218 __tg_complete_arg ()
220 if [ $COMP_CWORD -gt 2 ] && [ "${COMP_WORDS[$COMP_CWORD - 1]}" = "$1" ]; then
221 return 0
223 return 1
226 ### }}}
227 ### {{{ Commands
229 _tg_create ()
231 local cmd="$1"
232 local cur="${COMP_WORDS[COMP_CWORD]}"
234 # Name must be the first arg after the create command
235 if [ $((cmd + 1)) = $COMP_CWORD ]; then
236 __tgcomp "$(__tg_topics)"
237 return
240 __tg_complete_arg "-r" && {
241 __tgcomp "$(__tg_remotes)"
242 return
245 case "$cur" in
247 __tgcomp "
252 __tgcomp "$(__tg_refs)"
253 esac
256 _tg_delete ()
258 local cur="${COMP_WORDS[COMP_CWORD]}"
260 case "$cur" in
262 __tgcomp "
267 __tgcomp "$(__tg_topics)"
268 esac
271 _tg_export ()
273 local cur="${COMP_WORDS[COMP_CWORD]}"
275 __tg_complete_arg "--collapse" && {
276 __tgcomp "$(__tg_heads)"
277 return
280 __tg_complete_arg "--quilt" && {
281 return
284 case "$cur" in
286 __tgcomp "
287 --collapse
288 --quilt
290 esac
293 _tg_help ()
295 local cur="${COMP_WORDS[COMP_CWORD]}"
296 case "$cur" in
298 COMPREPLY=()
299 return
301 esac
302 __tgcomp "$(__tg_commands)"
305 _tg_import ()
307 local cur="${COMP_WORDS[COMP_CWORD]}"
309 __tg_complete_arg "-p" && {
310 COMPREPLY=()
311 return
314 case "$cur" in
316 __tgcomp "
321 __tg_complete_revlist
322 esac
325 _tg_info ()
327 local cur="${COMP_WORDS[COMP_CWORD]}"
329 case "$cur" in
331 __tgcomp "$(__tg_topics)"
332 esac
335 _tg_mail ()
337 local cur="${COMP_WORDS[COMP_CWORD]}"
339 case "$cur" in
341 __tgcomp "$(__tg_topics)"
342 esac
345 _tg_patch ()
347 local cur="${COMP_WORDS[COMP_CWORD]}"
349 case "$cur" in
351 __tgcomp "$(__tg_topics)"
352 esac
355 _tg_remote ()
357 local cur="${COMP_WORDS[COMP_CWORD]}"
359 case "$cur" in
361 __tgcomp "$(__tg_remotes)"
362 esac
365 _tg_summary ()
367 COMPREPLY=()
370 _tg_update ()
372 COMPREPLY=()
375 ### }}}
376 ### {{{ tg completion
378 _tg ()
380 local i c=1 command __tg_dir
382 while [ $c -lt $COMP_CWORD ]; do
383 i="${COMP_WORDS[c]}"
384 case "$i" in
385 -r)
386 c=$((++c))
387 if [ $c -lt $COMP_CWORD ]; then
388 __tgcomp "$(__tg_remotes)"
389 return
392 -h|--help) command="help"; break ;;
393 *) command="$i"; break ;;
394 esac
395 c=$((++c))
396 done
398 if [ -z "$command" ]; then
399 case "${COMP_WORDS[COMP_CWORD]}" in
400 -*) __tgcomp "
403 --help
406 *) __tgcomp "$(__tg_commands)" ;;
407 esac
408 return
411 case "$command" in
412 create) _tg_create "$c" ;;
413 delete) _tg_delete ;;
414 export) _tg_export ;;
415 help) _tg_help ;;
416 import) _tg_import ;;
417 info) _tg_info ;;
418 mail) _tg_mail ;;
419 patch) _tg_patch ;;
420 remote) _tg_remote ;;
421 summary) _tg_summary ;;
422 update) _tg_update ;;
423 *) COMPREPLY=() ;;
424 esac
427 ### }}}
429 __tgcomp "$(__tg_refs top-bases)"
430 complete -o default -o nospace -F _tg tg
432 # The following are necessary only for Cygwin, and only are needed
433 # when the user has tab-completed the executable name and consequently
434 # included the '.exe' suffix.
436 if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
437 complete -o default -o nospace -F _tg tg.exe