/bash_completion.d/mercurial

http://github.com/brinkman83/bashrc · #! · 573 lines · 505 code · 68 blank · 0 comment · 0 complexity · b6f333bd127bc79f3db3e86b6b38ccea MD5 · raw file

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