##// END OF EJS Templates
bash_completion: fix issue with subdirectories not being completed...
Sean Farley -
r20126:25cb1d96 default
parent child Browse files
Show More
@@ -1,597 +1,615 b''
1 1 # bash completion for the Mercurial distributed SCM -*- sh -*-
2 2
3 3 # Docs:
4 4 #
5 5 # If you source this file from your .bashrc, bash should be able to
6 6 # complete a command line that uses hg with all the available commands
7 7 # and options and sometimes even arguments.
8 8 #
9 9 # Mercurial allows you to define additional commands through extensions.
10 10 # Bash should be able to automatically figure out the name of these new
11 11 # commands and their options. See below for how to define _hg_opt_foo
12 12 # and _hg_cmd_foo functions to fine-tune the completion for option and
13 13 # non-option arguments, respectively.
14 14 #
15 15 #
16 16 # Notes about completion for specific commands:
17 17 #
18 18 # - the completion function for the email command from the patchbomb
19 19 # extension will try to call _hg_emails to get a list of e-mail
20 20 # addresses. It's up to the user to define this function. For
21 21 # example, put the addresses of the lists that you usually patchbomb
22 22 # in ~/.patchbomb-to and the addresses that you usually use to send
23 23 # the patchbombs in ~/.patchbomb-from and use something like this:
24 24 #
25 25 # _hg_emails()
26 26 # {
27 27 # if [ -r ~/.patchbomb-$1 ]; then
28 28 # cat ~/.patchbomb-$1
29 29 # fi
30 30 # }
31 31 #
32 32 #
33 33 # Writing completion functions for additional commands:
34 34 #
35 35 # If it exists, the function _hg_cmd_foo will be called without
36 36 # arguments to generate the completion candidates for the hg command
37 37 # "foo". If the command receives some arguments that aren't options
38 38 # even though they start with a "-", you can define a function called
39 39 # _hg_opt_foo to generate the completion candidates. If _hg_opt_foo
40 40 # doesn't return 0, regular completion for options is attempted.
41 41 #
42 42 # In addition to the regular completion variables provided by bash,
43 43 # the following variables are also set:
44 44 # - $hg - the hg program being used (e.g. /usr/bin/hg)
45 45 # - $cmd - the name of the hg command being completed
46 46 # - $cmd_index - the index of $cmd in $COMP_WORDS
47 47 # - $cur - the current argument being completed
48 48 # - $prev - the argument before $cur
49 49 # - $global_args - "|"-separated list of global options that accept
50 50 # an argument (e.g. '--cwd|-R|--repository')
51 51 # - $canonical - 1 if we canonicalized $cmd before calling the function
52 52 # 0 otherwise
53 53 #
54 54
55 55 shopt -s extglob
56 56
57 57 _hg_cmd()
58 58 {
59 59 HGPLAIN=1 "$hg" "$@" 2>/dev/null
60 60 }
61 61
62 62 _hg_commands()
63 63 {
64 64 local commands
65 65 commands="$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete "$cur")" || commands=""
66 66 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur"))
67 67 }
68 68
69 69 _hg_paths()
70 70 {
71 71 local paths="$(_hg_cmd paths -q)"
72 72 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur"))
73 73 }
74 74
75 75 _hg_repos()
76 76 {
77 77 local i
78 78 for i in $(compgen -d -- "$cur"); do
79 79 test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
80 80 done
81 81 }
82 82
83 83 _hg_debugpathcomplete()
84 84 {
85 85 local files="$(_hg_cmd debugpathcomplete $1 "$cur")"
86 86 local IFS=$'\n'
87 compopt -o filenames 2>/dev/null
88 87 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
89 88 }
90 89
91 90 _hg_status()
92 91 {
93 92 local files="$(_hg_cmd status -n$1 "glob:$cur**")"
94 93 local IFS=$'\n'
95 compopt -o filenames 2>/dev/null
96 94 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
97 95 }
98 96
99 97 _hg_bookmarks()
100 98 {
101 99 local bookmarks="$(_hg_cmd bookmarks -q)"
102 100 local IFS=$'\n'
103 101 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$bookmarks' -- "$cur"))
104 102 }
105 103
106 104 _hg_labels()
107 105 {
108 106 local labels="$(_hg_cmd debuglabelcomplete "$cur")"
109 107 local IFS=$'\n'
110 108 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$labels' -- "$cur"))
111 109 }
112 110
113 111 # this is "kind of" ugly...
114 112 _hg_count_non_option()
115 113 {
116 114 local i count=0
117 115 local filters="$1"
118 116
119 117 for ((i=1; $i<=$COMP_CWORD; i++)); do
120 118 if [[ "${COMP_WORDS[i]}" != -* ]]; then
121 119 if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then
122 120 continue
123 121 fi
124 122 count=$(($count + 1))
125 123 fi
126 124 done
127 125
128 126 echo $(($count - 1))
129 127 }
130 128
129 _hg_fix_wordlist()
130 {
131 local LASTCHAR=' '
132 if [ ${#COMPREPLY[@]} = 1 ]; then
133 [ -d "$COMPREPLY" ] && LASTCHAR=/
134 COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
135 else
136 for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
137 [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
138 done
139 fi
140 }
141
131 142 _hg()
132 143 {
133 144 local cur prev cmd cmd_index opts i aliashg
134 145 # global options that receive an argument
135 146 local global_args='--cwd|-R|--repository'
136 147 local hg="$1"
137 148 local canonical=0
138 149
139 150 aliashg=$(alias $hg 2>/dev/null)
140 151 if [[ -n "$aliashg" ]]; then
141 152 aliashg=${aliashg#"alias $hg='"}
142 153 aliashg=${aliashg%"'"}
143 154 hg=$aliashg
144 155 fi
145 156
146 157 COMPREPLY=()
147 158 cur="$2"
148 159 prev="$3"
149 160
150 161 # searching for the command
151 162 # (first non-option argument that doesn't follow a global option that
152 163 # receives an argument)
153 164 for ((i=1; $i<=$COMP_CWORD; i++)); do
154 165 if [[ ${COMP_WORDS[i]} != -* ]]; then
155 166 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
156 167 cmd="${COMP_WORDS[i]}"
157 168 cmd_index=$i
158 169 break
159 170 fi
160 171 fi
161 172 done
162 173
163 174 if [[ "$cur" == -* ]]; then
164 175 if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then
176 _hg_fix_wordlist
165 177 return
166 178 fi
167 179
168 180 opts=$(_hg_cmd debugcomplete --options "$cmd")
169 181
170 182 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur"))
183 _hg_fix_wordlist
171 184 return
172 185 fi
173 186
174 187 # global options
175 188 case "$prev" in
176 189 -R|--repository)
177 190 _hg_paths
178 191 _hg_repos
192 _hg_fix_wordlist
179 193 return
180 194 ;;
181 195 --cwd)
182 196 # Stick with default bash completion
197 _hg_fix_wordlist
183 198 return
184 199 ;;
185 200 esac
186 201
187 202 if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then
188 203 _hg_commands
204 _hg_fix_wordlist
189 205 return
190 206 fi
191 207
192 208 # try to generate completion candidates for whatever command the user typed
193 209 local help
194 210 if _hg_command_specific; then
211 _hg_fix_wordlist
195 212 return
196 213 fi
197 214
198 215 # canonicalize the command name and try again
199 216 help=$(_hg_cmd help "$cmd")
200 217 if [ $? -ne 0 ]; then
201 218 # Probably either the command doesn't exist or it's ambiguous
202 219 return
203 220 fi
204 221 cmd=${help#hg }
205 222 cmd=${cmd%%[$' \n']*}
206 223 canonical=1
207 224 _hg_command_specific
225 _hg_fix_wordlist
208 226 }
209 227
210 228 _hg_command_specific()
211 229 {
212 230 if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then
213 231 "_hg_cmd_$cmd"
214 232 return 0
215 233 fi
216 234
217 235 if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" == --rev ]; then
218 236 if [ $canonical = 1 ]; then
219 237 _hg_labels
220 238 return 0
221 239 elif [[ status != "$cmd"* ]]; then
222 240 _hg_labels
223 241 return 0
224 242 else
225 243 return 1
226 244 fi
227 245 fi
228 246
229 247 local aliascmd=$(_hg_cmd showconfig alias.$cmd | awk '{print $1}')
230 248 [ -n "$aliascmd" ] && cmd=$aliascmd
231 249
232 250 case "$cmd" in
233 251 help)
234 252 _hg_commands
235 253 ;;
236 254 export)
237 255 if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then
238 256 return 0
239 257 fi
240 258 _hg_labels
241 259 ;;
242 260 manifest|update|up|checkout|co)
243 261 _hg_labels
244 262 ;;
245 263 pull|push|outgoing|incoming)
246 264 _hg_paths
247 265 _hg_repos
248 266 ;;
249 267 paths)
250 268 _hg_paths
251 269 ;;
252 270 add)
253 271 _hg_status "u"
254 272 ;;
255 273 merge)
256 274 _hg_labels
257 275 ;;
258 276 commit|ci|record)
259 277 _hg_status "mar"
260 278 ;;
261 279 remove|rm)
262 280 _hg_debugpathcomplete -n
263 281 ;;
264 282 forget)
265 283 _hg_debugpathcomplete -fa
266 284 ;;
267 285 diff)
268 286 _hg_status "mar"
269 287 ;;
270 288 revert)
271 289 _hg_debugpathcomplete
272 290 ;;
273 291 clone)
274 292 local count=$(_hg_count_non_option)
275 293 if [ $count = 1 ]; then
276 294 _hg_paths
277 295 fi
278 296 _hg_repos
279 297 ;;
280 298 debugindex|debugindexdot)
281 299 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur"))
282 300 ;;
283 301 debugdata)
284 302 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur"))
285 303 ;;
286 304 *)
287 305 return 1
288 306 ;;
289 307 esac
290 308
291 309 return 0
292 310 }
293 311
294 complete -o bashdefault -o default -F _hg hg \
295 || complete -o default -F _hg hg
312 complete -o bashdefault -o default -o nospace -F _hg hg \
313 || complete -o default -o nospace -F _hg hg
296 314
297 315
298 316 # Completion for commands provided by extensions
299 317
300 318 # bookmarks
301 319 _hg_cmd_bookmarks()
302 320 {
303 321 if [[ "$prev" = @(-d|--delete|-m|--rename) ]]; then
304 322 _hg_bookmarks
305 323 return
306 324 fi
307 325 }
308 326
309 327 # mq
310 328 _hg_ext_mq_patchlist()
311 329 {
312 330 local patches
313 331 patches=$(_hg_cmd $1)
314 332 if [ $? -eq 0 ] && [ "$patches" ]; then
315 333 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur"))
316 334 return 0
317 335 fi
318 336 return 1
319 337 }
320 338
321 339 _hg_ext_mq_queues()
322 340 {
323 341 local root=$(_hg_cmd root)
324 342 local n
325 343 for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do
326 344 # I think we're usually not interested in the regular "patches" queue
327 345 # so just filter it.
328 346 if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then
329 347 COMPREPLY=(${COMPREPLY[@]:-} "$n")
330 348 fi
331 349 done
332 350 }
333 351
334 352 _hg_cmd_qpop()
335 353 {
336 354 if [[ "$prev" = @(-n|--name) ]]; then
337 355 _hg_ext_mq_queues
338 356 return
339 357 fi
340 358 _hg_ext_mq_patchlist qapplied
341 359 }
342 360
343 361 _hg_cmd_qpush()
344 362 {
345 363 if [[ "$prev" = @(-n|--name) ]]; then
346 364 _hg_ext_mq_queues
347 365 return
348 366 fi
349 367 _hg_ext_mq_patchlist qunapplied
350 368 }
351 369
352 370 _hg_cmd_qgoto()
353 371 {
354 372 if [[ "$prev" = @(-n|--name) ]]; then
355 373 _hg_ext_mq_queues
356 374 return
357 375 fi
358 376 _hg_ext_mq_patchlist qseries
359 377 }
360 378
361 379 _hg_cmd_qdelete()
362 380 {
363 381 local qcmd=qunapplied
364 382 if [[ "$prev" = @(-r|--rev) ]]; then
365 383 qcmd=qapplied
366 384 fi
367 385 _hg_ext_mq_patchlist $qcmd
368 386 }
369 387
370 388 _hg_cmd_qfinish()
371 389 {
372 390 if [[ "$prev" = @(-a|--applied) ]]; then
373 391 return
374 392 fi
375 393 _hg_ext_mq_patchlist qapplied
376 394 }
377 395
378 396 _hg_cmd_qsave()
379 397 {
380 398 if [[ "$prev" = @(-n|--name) ]]; then
381 399 _hg_ext_mq_queues
382 400 return
383 401 fi
384 402 }
385 403
386 404 _hg_cmd_rebase() {
387 405 if [[ "$prev" = @(-s|--source|-d|--dest|-b|--base|-r|--rev) ]]; then
388 406 _hg_labels
389 407 return
390 408 fi
391 409 }
392 410
393 411 _hg_cmd_strip()
394 412 {
395 413 _hg_labels
396 414 }
397 415
398 416 _hg_cmd_qcommit()
399 417 {
400 418 local root=$(_hg_cmd root)
401 419 # this is run in a sub-shell, so we can't use _hg_status
402 420 local files=$(cd "$root/.hg/patches" && _hg_cmd status -nmar)
403 421 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
404 422 }
405 423
406 424 _hg_cmd_qfold()
407 425 {
408 426 _hg_ext_mq_patchlist qunapplied
409 427 }
410 428
411 429 _hg_cmd_qrename()
412 430 {
413 431 _hg_ext_mq_patchlist qseries
414 432 }
415 433
416 434 _hg_cmd_qheader()
417 435 {
418 436 _hg_ext_mq_patchlist qseries
419 437 }
420 438
421 439 _hg_cmd_qclone()
422 440 {
423 441 local count=$(_hg_count_non_option)
424 442 if [ $count = 1 ]; then
425 443 _hg_paths
426 444 fi
427 445 _hg_repos
428 446 }
429 447
430 448 _hg_ext_mq_guards()
431 449 {
432 450 _hg_cmd qselect --series | sed -e 's/^.//'
433 451 }
434 452
435 453 _hg_cmd_qselect()
436 454 {
437 455 local guards=$(_hg_ext_mq_guards)
438 456 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur"))
439 457 }
440 458
441 459 _hg_cmd_qguard()
442 460 {
443 461 local prefix=''
444 462
445 463 if [[ "$cur" == +* ]]; then
446 464 prefix=+
447 465 elif [[ "$cur" == -* ]]; then
448 466 prefix=-
449 467 fi
450 468 local ncur=${cur#[-+]}
451 469
452 470 if ! [ "$prefix" ]; then
453 471 _hg_ext_mq_patchlist qseries
454 472 return
455 473 fi
456 474
457 475 local guards=$(_hg_ext_mq_guards)
458 476 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur"))
459 477 }
460 478
461 479 _hg_opt_qguard()
462 480 {
463 481 local i
464 482 for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
465 483 if [[ ${COMP_WORDS[i]} != -* ]]; then
466 484 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
467 485 _hg_cmd_qguard
468 486 return 0
469 487 fi
470 488 elif [ "${COMP_WORDS[i]}" = -- ]; then
471 489 _hg_cmd_qguard
472 490 return 0
473 491 fi
474 492 done
475 493 return 1
476 494 }
477 495
478 496 _hg_cmd_qqueue()
479 497 {
480 498 local q
481 499 local queues
482 500 local opts="--list --create --rename --delete --purge"
483 501
484 502 queues=$( _hg_cmd qqueue --quiet )
485 503
486 504 COMPREPLY=( $( compgen -W "${opts} ${queues}" "${cur}" ) )
487 505 }
488 506
489 507
490 508 # hbisect
491 509 _hg_cmd_bisect()
492 510 {
493 511 local i subcmd
494 512
495 513 # find the sub-command
496 514 for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
497 515 if [[ ${COMP_WORDS[i]} != -* ]]; then
498 516 if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
499 517 subcmd="${COMP_WORDS[i]}"
500 518 break
501 519 fi
502 520 fi
503 521 done
504 522
505 523 if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then
506 524 COMPREPLY=(${COMPREPLY[@]:-}
507 525 $(compgen -W 'bad good help init next reset' -- "$cur"))
508 526 return
509 527 fi
510 528
511 529 case "$subcmd" in
512 530 good|bad)
513 531 _hg_labels
514 532 ;;
515 533 esac
516 534
517 535 return
518 536 }
519 537
520 538
521 539 # patchbomb
522 540 _hg_cmd_email()
523 541 {
524 542 case "$prev" in
525 543 -c|--cc|-t|--to|-f|--from|--bcc)
526 544 # we need an e-mail address. let the user provide a function
527 545 # to get them
528 546 if [ "$(type -t _hg_emails)" = function ]; then
529 547 local arg=to
530 548 if [[ "$prev" == @(-f|--from) ]]; then
531 549 arg=from
532 550 fi
533 551 local addresses=$(_hg_emails $arg)
534 552 COMPREPLY=(${COMPREPLY[@]:-}
535 553 $(compgen -W '$addresses' -- "$cur"))
536 554 fi
537 555 return
538 556 ;;
539 557 -m|--mbox)
540 558 # fallback to standard filename completion
541 559 return
542 560 ;;
543 561 -s|--subject)
544 562 # free form string
545 563 return
546 564 ;;
547 565 esac
548 566
549 567 _hg_labels
550 568 return
551 569 }
552 570
553 571
554 572 # gpg
555 573 _hg_cmd_sign()
556 574 {
557 575 _hg_labels
558 576 }
559 577
560 578
561 579 # transplant
562 580 _hg_cmd_transplant()
563 581 {
564 582 case "$prev" in
565 583 -s|--source)
566 584 _hg_paths
567 585 _hg_repos
568 586 return
569 587 ;;
570 588 --filter)
571 589 # standard filename completion
572 590 return
573 591 ;;
574 592 esac
575 593
576 594 # all other transplant options values and command parameters are revisions
577 595 _hg_labels
578 596 return
579 597 }
580 598
581 599 # shelve
582 600 _hg_shelves()
583 601 {
584 602 local shelves="$(_hg_cmd unshelve -l .)"
585 603 local IFS=$'\n'
586 604 COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur"))
587 605 }
588 606
589 607 _hg_cmd_shelve()
590 608 {
591 609 _hg_status "mard"
592 610 }
593 611
594 612 _hg_cmd_unshelve()
595 613 {
596 614 _hg_shelves
597 615 }
General Comments 0
You need to be logged in to leave comments. Login now