chiark / gitweb /
Compile regexp just once
[stgit] / contrib / stgit-completion.bash
1 # bash completion support for StGIT                        -*- shell-script -*-
2 #
3 # Copyright (C) 2006, Karl Hasselström <kha@treskal.com>
4 # Based on git-completion.sh
5 #
6 # To use these routines:
7 #
8 #    1. Copy this file to somewhere (e.g. ~/.stgit-completion.bash).
9 #
10 #    2. Add the following line to your .bashrc:
11 #         . ~/.stgit-completion.bash
12
13 _stg_commands="
14     add
15     applied
16     assimilate
17     branch
18     delete
19     diff
20     clean
21     clone
22     commit
23     cp
24     export
25     files
26     float
27     fold
28     goto
29     hide
30     id
31     import
32     init
33     log
34     mail
35     new
36     patches
37     pick
38     pop
39     pull
40     push
41     rebase
42     refresh
43     rename
44     resolved
45     rm
46     series
47     show
48     sink
49     status
50     sync
51     top
52     unapplied
53     uncommit
54     unhide
55 "
56
57 # The path to .git, or empty if we're not in a repository.
58 _gitdir ()
59 {
60     echo "$(git rev-parse --git-dir 2>/dev/null)"
61 }
62
63 # Name of the current branch, or empty if there isn't one.
64 _current_branch ()
65 {
66     local b=$(git symbolic-ref HEAD 2>/dev/null)
67     echo ${b#refs/heads/}
68 }
69
70 # List of all applied patches.
71 _applied_patches ()
72 {
73     local g=$(_gitdir)
74     [ "$g" ] && cat "$g/patches/$(_current_branch)/applied"
75 }
76
77 # List of all unapplied patches.
78 _unapplied_patches ()
79 {
80     local g=$(_gitdir)
81     [ "$g" ] && cat "$g/patches/$(_current_branch)/unapplied"
82 }
83
84 # List of all applied patches.
85 _hidden_patches ()
86 {
87     local g=$(_gitdir)
88     [ "$g" ] && cat "$g/patches/$(_current_branch)/hidden"
89 }
90
91 # List of all patches.
92 _all_patches ()
93 {
94     local b=$(_current_branch)
95     local g=$(_gitdir)
96     [ "$g" ] && cat "$g/patches/$b/applied" "$g/patches/$b/unapplied"
97 }
98
99 # List of all patches except the current patch.
100 _all_other_patches ()
101 {
102     local b=$(_current_branch)
103     local g=$(_gitdir)
104     [ "$g" ] && cat "$g/patches/$b/applied" "$g/patches/$b/unapplied" \
105         | grep -v "^$(cat $g/patches/$b/current 2> /dev/null)$"
106 }
107
108 _all_branches ()
109 {
110     local g=$(_gitdir)
111     [ "$g" ] && (cd $g/patches/ && echo *)
112 }
113
114 _conflicting_files ()
115 {
116     local g=$(_gitdir)
117     [ "$g" ] && stg status --conflict
118 }
119
120 _dirty_files ()
121 {
122     local g=$(_gitdir)
123     [ "$g" ] && stg status --modified --new --deleted
124 }
125
126 _unknown_files ()
127 {
128     local g=$(_gitdir)
129     [ "$g" ] && stg status --unknown
130 }
131
132 _known_files ()
133 {
134     local g=$(_gitdir)
135     [ "$g" ] && git ls-files
136 }
137
138 # List the command options
139 _cmd_options ()
140 {
141     stg $1 --help 2>/dev/null | grep -e " --[A-Za-z]" | sed -e "s/.*\(--[^ =]\+\).*/\1/"
142 }
143
144 # Generate completions for patches and patch ranges from the given
145 # patch list function, and options from the given list.
146 _complete_patch_range ()
147 {
148     local patchlist="$1" options="$2"
149     local pfx cur="${COMP_WORDS[COMP_CWORD]}"
150     case "$cur" in
151         *..*)
152             pfx="${cur%..*}.."
153             cur="${cur#*..}"
154             COMPREPLY=($(compgen -P "$pfx" -W "$($patchlist)" -- "$cur"))
155             ;;
156         *)
157             COMPREPLY=($(compgen -W "$options $($patchlist)" -- "$cur"))
158             ;;
159     esac
160 }
161
162 _complete_patch_range_options ()
163 {
164     local patchlist="$1" options="$2" patch_options="$3"
165     local prev="${COMP_WORDS[COMP_CWORD-1]}"
166     local cur="${COMP_WORDS[COMP_CWORD]}"
167     local popt
168     for popt in $patch_options; do
169         if [ $prev == $popt ]; then
170             _complete_patch_range $patchlist
171             return
172         fi
173     done
174     COMPREPLY=($(compgen -W "$options" -- "$cur"))
175 }
176
177 _complete_branch ()
178 {
179      COMPREPLY=($(compgen -W "$(_cmd_options $1) $($2)" -- "${COMP_WORDS[COMP_CWORD]}"))
180 }
181
182 # Generate completions for options from the given list.
183 _complete_options ()
184 {
185     local options="$1"
186     COMPREPLY=($(compgen -W "$options" -- "${COMP_WORDS[COMP_CWORD]}"))
187 }
188
189 _complete_files ()
190 {
191     COMPREPLY=($(compgen -W "$(_cmd_options $1) $2" -- "${COMP_WORDS[COMP_CWORD]}"))
192 }
193
194 _stg_common ()
195 {
196     _complete_options "$(_cmd_options $1)"
197 }
198
199 _stg_patches ()
200 {
201     _complete_patch_range "$2" "$(_cmd_options $1)"
202 }
203
204 _stg_patches_options ()
205 {
206     _complete_patch_range_options "$2" "$(_cmd_options $1)" "$3"
207 }
208
209 _stg_help ()
210 {
211     _complete_options "$_stg_commands"
212 }
213
214 _stg ()
215 {
216     local i c=1 command
217
218     while [ $c -lt $COMP_CWORD ]; do
219         if [ $c == 1 ]; then
220             command="${COMP_WORDS[c]}"
221         fi
222         c=$((++c))
223     done
224
225     # Complete name of subcommand.
226     if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
227         COMPREPLY=($(compgen \
228             -W "--help --version copyright help $_stg_commands" \
229             -- "${COMP_WORDS[COMP_CWORD]}"))
230         return;
231     fi
232
233     # Complete arguments to subcommands.
234     case "$command" in
235         # generic commands
236         help)   _stg_help ;;
237         # repository commands
238         id)     _stg_patches $command _all_patches ;;
239         # stack commands
240         float)  _stg_patches $command _all_patches ;;
241         goto)   _stg_patches $command _all_other_patches ;;
242         hide)   _stg_patches $command _unapplied_patches ;;
243         pop)    _stg_patches $command _applied_patches ;;
244         push)   _stg_patches $command _unapplied_patches ;;
245         series) _stg_patches $command _all_patches ;;
246         sink)   _stg_patches $command _all_patches ;;
247         unhide) _stg_patches $command _hidden_patches ;;
248         # patch commands
249         delete) _stg_patches $command _all_patches ;;
250         export) _stg_patches $command _applied_patches ;;
251         files)  _stg_patches $command _all_patches ;;
252         log)    _stg_patches $command _all_patches ;;
253         mail)   _stg_patches $command _all_patches ;;
254         pick)   _stg_patches $command _unapplied_patches ;;
255 #       refresh)_stg_patches_options $command _applied_patches "-p --patch" ;;
256         refresh) _complete_files $command "$(_dirty_files)" ;;
257         rename) _stg_patches $command _all_patches ;;
258         show)   _stg_patches $command _all_patches ;;
259         sync)   _stg_patches $command _applied_patches ;;
260         # working-copy commands
261         diff)   _stg_patches_options $command _applied_patches "-r --range" ;;
262         resolved) _complete_files $command "$(_conflicting_files)" ;;
263         add)    _complete_files $command "$(_unknown_files)" ;;
264 #       rm)     _complete_files $command "$(_known_files)" ;;
265         # commands that usually raher accept branches
266         branch) _complete_branch $command _all_branches ;;
267         rebase) _complete_branch $command _all_branches ;;
268         # all the other commands
269         *)      _stg_common $command ;;
270     esac
271 }
272
273 complete -o default -F _stg stg