##// END OF EJS Templates
bash_completion: completion for commands provided by extensions...
Alexis S. L. Carvalho -
r2041:077a2da7 default
parent child Browse files
Show More
@@ -1,189 +1,385
1 # bash completion for the Mercurial distributed SCM
2
3 # Docs:
4 #
5 # If you source this file from your .bashrc, bash should be able to
6 # complete a command line that uses hg with all the available commands
7 # and options and sometimes even arguments.
8 #
9 # Mercurial allows you to define additional commands through extensions.
10 # Bash should be able to automatically figure out the name of these new
11 # commands and their options. If you also want to tell it how to
12 # complete non-option arguments, see below for how to define an
13 # _hg_cmd_foo function.
14 #
15 #
16 # Notes about completion for specific commands:
17 #
18 # - the completion function for the email command from the patchbomb
19 # extension will try to call _hg_emails to get a list of e-mail
20 # addresses. It's up to the user to define this function. For
21 # example, put the addresses of the lists that you usually patchbomb
22 # in ~/.patchbomb-to and the addresses that you usually use to send
23 # the patchbombs in ~/.patchbomb-from and use something like this:
24 #
25 # _hg_emails()
26 # {
27 # if [ -r ~/.patchbomb-$1 ]; then
28 # cat ~/.patchbomb-$1
29 # fi
30 # }
31 #
32 #
33 # Writing completion functions for additional commands:
34 #
35 # If it exists, the function _hg_cmd_foo will be called without
36 # arguments to generate the completion candidates for the hg command
37 # "foo".
38 #
39 # In addition to the regular completion variables provided by bash,
40 # the following variables are also set:
41 # - $hg - the hg program being used (e.g. /usr/bin/hg)
42 # - $cmd - the name of the hg command being completed
43 # - $cmd_index - the index of $cmd in $COMP_WORDS
44 # - $cur - the current argument being completed
45 # - $prev - the argument before $cur
46 # - $global_args - "|"-separated list of global options that accept
47 # an argument (e.g. '--cwd|-R|--repository')
48 # - $canonical - 1 if we canonicalized $cmd before calling the function
49 # 0 otherwise
50 #
51
1 52 shopt -s extglob
2 53
3 54 _hg_commands()
4 55 {
5 56 local commands
6 57 commands="$("$hg" debugcomplete "$cur" 2>/dev/null)" || commands=""
7 58 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur"))
8 59 }
9 60
10 61 _hg_paths()
11 62 {
12 63 local paths="$("$hg" paths 2>/dev/null | sed -e 's/ = .*$//')"
13 64 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur"))
14 65 }
15 66
16 67 _hg_repos()
17 68 {
18 69 local i
19 70 for i in $(compgen -d -- "$cur"); do
20 71 test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
21 72 done
22 73 }
23 74
24 75 _hg_status()
25 76 {
26 77 local files="$("$hg" status -n$1 . 2>/dev/null)"
27 78 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
28 79 }
29 80
30 81 _hg_tags()
31 82 {
32 83 local tags="$("$hg" tags -q 2>/dev/null)"
33 84 local IFS=$'\n'
34 85 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur"))
35 86 }
36 87
37 88 # this is "kind of" ugly...
38 89 _hg_count_non_option()
39 90 {
40 91 local i count=0
41 92 local filters="$1"
42 93
43 94 for ((i=1; $i<=$COMP_CWORD; i++)); do
44 95 if [[ "${COMP_WORDS[i]}" != -* ]]; then
45 96 if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then
46 97 continue
47 98 fi
48 99 count=$(($count + 1))
49 100 fi
50 101 done
51 102
52 103 echo $(($count - 1))
53 104 }
54 105
55 106 _hg()
56 107 {
57 local cur prev cmd opts i
108 local cur prev cmd cmd_index opts i
58 109 # global options that receive an argument
59 110 local global_args='--cwd|-R|--repository'
60 111 local hg="$1"
61 112
62 113 COMPREPLY=()
63 114 cur="$2"
64 115 prev="$3"
65 116
66 117 # searching for the command
67 118 # (first non-option argument that doesn't follow a global option that
68 119 # receives an argument)
69 120 for ((i=1; $i<=$COMP_CWORD; i++)); do
70 121 if [[ ${COMP_WORDS[i]} != -* ]]; then
71 122 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
72 123 cmd="${COMP_WORDS[i]}"
124 cmd_index=$i
73 125 break
74 126 fi
75 127 fi
76 128 done
77 129
78 130 if [[ "$cur" == -* ]]; then
79 131 opts=$("$hg" debugcomplete --options "$cmd" 2>/dev/null)
80 132
81 133 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur"))
82 134 return
83 135 fi
84 136
85 137 # global options
86 138 case "$prev" in
87 139 -R|--repository)
88 140 _hg_repos
89 141 return
90 142 ;;
91 143 --cwd)
92 144 # Stick with default bash completion
93 145 return
94 146 ;;
95 147 esac
96 148
97 149 if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then
98 150 _hg_commands
99 151 return
100 152 fi
101 153
102 154 # try to generate completion candidates for whatever command the user typed
103 155 local help
104 156 local canonical=0
105 157 if _hg_command_specific; then
106 158 return
107 159 fi
108 160
109 161 # canonicalize the command name and try again
110 162 help=$("$hg" help "$cmd" 2>/dev/null)
111 163 if [ $? -ne 0 ]; then
112 164 # Probably either the command doesn't exist or it's ambiguous
113 165 return
114 166 fi
115 167 cmd=${help#hg }
116 168 cmd=${cmd%%[$' \n']*}
117 169 canonical=1
118 170 _hg_command_specific
119 171 }
120 172
121 173 _hg_command_specific()
122 174 {
175 if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then
176 "_hg_cmd_$cmd"
177 return 0
178 fi
179
123 180 if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" == --rev ]; then
124 181 if [ $canonical = 1 ]; then
125 182 _hg_tags
126 183 return 0
127 184 elif [[ status != "$cmd"* ]]; then
128 185 _hg_tags
129 186 return 0
130 187 else
131 188 return 1
132 189 fi
133 190 fi
134 191
135 192 case "$cmd" in
136 193 help)
137 194 _hg_commands
138 195 ;;
139 196 export|manifest|update)
140 197 _hg_tags
141 198 ;;
142 199 pull|push|outgoing|incoming)
143 200 _hg_paths
144 201 _hg_repos
145 202 ;;
146 203 paths)
147 204 _hg_paths
148 205 ;;
149 206 add)
150 207 _hg_status "u"
151 208 ;;
152 209 commit)
153 210 _hg_status "mar"
154 211 ;;
155 212 remove)
156 213 _hg_status "d"
157 214 ;;
158 215 forget)
159 216 _hg_status "a"
160 217 ;;
161 218 diff)
162 219 _hg_status "mar"
163 220 ;;
164 221 revert)
165 222 _hg_status "mard"
166 223 ;;
167 224 clone)
168 225 local count=$(_hg_count_non_option)
169 226 if [ $count = 1 ]; then
170 227 _hg_paths
171 228 fi
172 229 _hg_repos
173 230 ;;
174 231 debugindex|debugindexdot)
175 232 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur"))
176 233 ;;
177 234 debugdata)
178 235 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur"))
179 236 ;;
180 237 *)
181 238 return 1
182 239 ;;
183 240 esac
184 241
185 242 return 0
186 243 }
187 244
188 245 complete -o bashdefault -o default -F _hg hg 2>/dev/null \
189 246 || complete -o default -F _hg hg
247
248
249 # Completion for commands provided by extensions
250
251 # mq
252 _hg_ext_mq_patchlist()
253 {
254 local patches=$("$hg" $1 2>/dev/null)
255 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur"))
256 }
257
258 _hg_ext_mq_queues()
259 {
260 local root=$("$hg" root 2>/dev/null)
261 local n
262 for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do
263 # I think we're usually not interested in the regular "patches" queue
264 # so just filter it.
265 if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then
266 COMPREPLY=(${COMPREPLY[@]:-} "$n")
267 fi
268 done
269 }
270
271 _hg_cmd_qpop()
272 {
273 if [[ "$prev" = @(-n|--name) ]]; then
274 _hg_ext_mq_queues
275 return
276 fi
277 _hg_ext_mq_patchlist qapplied
278 }
279
280 _hg_cmd_qpush()
281 {
282 if [[ "$prev" = @(-n|--name) ]]; then
283 _hg_ext_mq_queues
284 return
285 fi
286 _hg_ext_mq_patchlist qunapplied
287 }
288
289 _hg_cmd_qdelete()
290 {
291 _hg_ext_mq_patchlist qseries
292 }
293
294 _hg_cmd_qsave()
295 {
296 if [[ "$prev" = @(-n|--name) ]]; then
297 _hg_ext_mq_queues
298 return
299 fi
300 }
301
302 _hg_cmd_strip()
303 {
304 _hg_tags
305 }
306
307 _hg_cmd_qcommit()
308 {
309 local root=$("$hg" root 2>/dev/null)
310 # this is run in a sub-shell, so we can't use _hg_status
311 local files=$(cd "$root/.hg/patches" 2>/dev/null &&
312 "$hg" status -nmar 2>/dev/null)
313 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
314 }
315
316
317 # hbisect
318 _hg_cmd_bisect()
319 {
320 local i subcmd
321
322 # find the sub-command
323 for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
324 if [[ ${COMP_WORDS[i]} != -* ]]; then
325 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
326 subcmd="${COMP_WORDS[i]}"
327 break
328 fi
329 fi
330 done
331
332 if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then
333 COMPREPLY=(${COMPREPLY[@]:-}
334 $(compgen -W 'bad good help init next reset' -- "$cur"))
335 return
336 fi
337
338 case "$subcmd" in
339 good|bad)
340 _hg_tags
341 ;;
342 esac
343
344 return
345 }
346
347
348 # patchbomb
349 _hg_cmd_email()
350 {
351 case "$prev" in
352 -c|--cc|-t|--to|-f|--from)
353 # we need an e-mail address. let the user provide a function
354 # to get them
355 if [ "$(type -t _hg_emails)" = function ]; then
356 local arg=to
357 if [[ "$prev" == @(-f|--from) ]]; then
358 arg=from
359 fi
360 local addresses=$(_hg_emails $arg)
361 COMPREPLY=(${COMPREPLY[@]:-}
362 $(compgen -W '$addresses' -- "$cur"))
363 fi
364 return
365 ;;
366 -m|--mbox)
367 # fallback to standard filename completion
368 return
369 ;;
370 -s|--subject)
371 # free form string
372 return
373 ;;
374 esac
375
376 _hg_tags
377 return
378 }
379
380
381 # gpg
382 _hg_cmd_sign()
383 {
384 _hg_tags
385 }
General Comments 0
You need to be logged in to leave comments. Login now