_hub 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #compdef hub
  2. # Zsh will source this file when attempting to autoload the "_hub" function,
  3. # typically on the first attempt to complete the hub command. We define two new
  4. # setup helper routines (one for the zsh-distributed version, one for the
  5. # git-distributed, bash-based version). Then we redefine the "_hub" function to
  6. # call "_git" after some other interception.
  7. #
  8. # This is pretty fragile, if you think about it. Any number of implementation
  9. # changes in the "_git" scripts could cause problems down the road. It would be
  10. # better if the stock git completions were just a bit more permissive about how
  11. # it allowed third-party commands to be added.
  12. (( $+functions[__hub_setup_zsh_fns] )) ||
  13. __hub_setup_zsh_fns () {
  14. (( $+functions[_git-alias] )) ||
  15. _git-alias () {
  16. _arguments \
  17. '-s[output shell script suitable for eval]' \
  18. '1::shell:(zsh bash csh)'
  19. }
  20. (( $+functions[_git-browse] )) ||
  21. _git-browse () {
  22. _arguments \
  23. '-u[output the URL]' \
  24. '2::subpage:(wiki commits issues)'
  25. }
  26. (( $+functions[_git-compare] )) ||
  27. _git-compare () {
  28. _arguments \
  29. '-u[output the URL]' \
  30. ':[start...]end range:'
  31. }
  32. (( $+functions[_git-create] )) ||
  33. _git-create () {
  34. _arguments \
  35. '::name (REPOSITORY or ORGANIZATION/REPOSITORY):' \
  36. '-p[make repository private]' \
  37. '-d[description]:description' \
  38. '-h[home page]:repository home page URL:_urls'
  39. }
  40. (( $+functions[_git-fork] )) ||
  41. _git-fork () {
  42. _arguments \
  43. '--no-remote[do not add a remote for the new fork]'
  44. }
  45. (( $+functions[_git-pull-request] )) ||
  46. _git-pull-request () {
  47. _arguments \
  48. '-f[force (skip check for local commits)]' \
  49. '-b[base]:base ("branch", "owner\:branch", "owner/repo\:branch"):' \
  50. '-h[head]:head ("branch", "owner\:branch", "owner/repo\:branch"):' \
  51. - set1 \
  52. '-m[message]' \
  53. '-F[file]' \
  54. '--no-edit[use first commit message for pull request title/description]' \
  55. '-a[user]' \
  56. '-M[milestone]' \
  57. '-l[labels]' \
  58. - set2 \
  59. '-i[issue]:issue number:' \
  60. - set3 \
  61. '::issue-url:_urls'
  62. }
  63. # stash the "real" command for later
  64. functions[_hub_orig_git_commands]=$functions[_git_commands]
  65. # Replace it with our own wrapper.
  66. declare -f _git_commands >& /dev/null && unfunction _git_commands
  67. _git_commands () {
  68. local ret=1
  69. # call the original routine
  70. _call_function ret _hub_orig_git_commands
  71. # Effectively "append" our hub commands to the behavior of the original
  72. # _git_commands function. Using this wrapper function approach ensures
  73. # that we only offer the user the hub subcommands when the user is
  74. # actually trying to complete subcommands.
  75. hub_commands=(
  76. alias:'show shell instructions for wrapping git'
  77. pull-request:'open a pull request on GitHub'
  78. pr:'list or checkout a GitHub pull request'
  79. issue:'list or create a GitHub issue'
  80. release:'list or create a GitHub release'
  81. fork:'fork origin repo on GitHub'
  82. create:'create new repo on GitHub for the current project'
  83. delete:'delete a GitHub repo'
  84. browse:'browse the project on GitHub'
  85. compare:'open GitHub compare view'
  86. ci-status:'show status of GitHub checks for a commit'
  87. sync:'update local branches from upstream'
  88. )
  89. _describe -t hub-commands 'hub command' hub_commands && ret=0
  90. return ret
  91. }
  92. }
  93. (( $+functions[__hub_setup_bash_fns] )) ||
  94. __hub_setup_bash_fns () {
  95. # TODO more bash-style fns needed here to complete subcommand args. They take
  96. # the form "_git_CMD" where "CMD" is something like "pull-request".
  97. # Duplicate and rename the 'list_all_commands' function
  98. eval "$(declare -f __git_list_all_commands | \
  99. sed 's/__git_list_all_commands/__git_list_all_commands_without_hub/')"
  100. # Wrap the 'list_all_commands' function with extra hub commands
  101. __git_list_all_commands() {
  102. cat <<-EOF
  103. alias
  104. pull-request
  105. pr
  106. issue
  107. release
  108. fork
  109. create
  110. delete
  111. browse
  112. compare
  113. ci-status
  114. sync
  115. EOF
  116. __git_list_all_commands_without_hub
  117. }
  118. # Ensure cached commands are cleared
  119. __git_all_commands=""
  120. }
  121. # redefine _hub to a much smaller function in the steady state
  122. _hub () {
  123. # only attempt to intercept the normal "_git" helper functions once
  124. (( $+__hub_func_replacement_done )) ||
  125. () {
  126. # At this stage in the shell's execution the "_git" function has not yet
  127. # been autoloaded, so the "_git_commands" or "__git_list_all_commands"
  128. # functions will not be defined. Call it now (with a bogus no-op service
  129. # to prevent premature completion) so that we can wrap them.
  130. if declare -f _git >& /dev/null ; then
  131. _hub_noop () { __hub_zsh_provided=1 } # zsh-provided will call this one
  132. __hub_noop_main () { __hub_git_provided=1 } # git-provided will call this one
  133. local service=hub_noop
  134. _git
  135. unfunction _hub_noop
  136. unfunction __hub_noop_main
  137. service=git
  138. fi
  139. if (( $__hub_zsh_provided )) ; then
  140. __hub_setup_zsh_fns
  141. elif (( $__hub_git_provided )) ; then
  142. __hub_setup_bash_fns
  143. fi
  144. __hub_func_replacement_done=1
  145. }
  146. # Now perform the actual completion, allowing the "_git" function to call our
  147. # replacement "_git_commands" function as needed. Both versions expect
  148. # service=git or they will call nonexistent routines or end up in an infinite
  149. # loop.
  150. service=git
  151. declare -f _git >& /dev/null && _git
  152. }
  153. # make sure we actually attempt to complete on the first "tab" from the user
  154. _hub