hub.zsh_completion 5.1 KB
Newer Older
D
Dave Goodell 已提交
1 2 3 4 5 6 7
#compdef hub

# Zsh will source this file when attempting to autoload the "_hub" function,
# typically on the first attempt to complete the hub command.  We define two new
# setup helper routines (one for the zsh-distributed version, one for the
# git-distributed, bash-based version).  Then we redefine the "_hub" function to
# call "_git" after some other interception.
8
#
D
Dave Goodell 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
# This is pretty fragile, if you think about it.  Any number of implementation
# changes in the "_git" scripts could cause problems down the road.  It would be
# better if the stock git completions were just a bit more permissive about how
# it allowed third-party commands to be added.

(( $+functions[__hub_setup_zsh_fns] )) ||
__hub_setup_zsh_fns () {
  (( $+functions[_git-alias] )) ||
  _git-alias () {
    _arguments \
      '-s[output shell script suitable for eval]' \
      '1::shell:(zsh bash csh)'
  }

  (( $+functions[_git-browse] )) ||
  _git-browse () {
    _arguments \
26 27
      '-u[output the URL]' \
      '2::subpage:(wiki commits issues)'
D
Dave Goodell 已提交
28 29 30 31 32
  }

  (( $+functions[_git-compare] )) ||
  _git-compare () {
    _arguments \
33
      '-u[output the URL]' \
D
Dave Goodell 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
      ':[start...]end range:'
  }

  (( $+functions[_git-create] )) ||
  _git-create () {
    _arguments \
      '::name (REPOSITORY or ORGANIZATION/REPOSITORY):' \
      '-p[make repository private]' \
      '-d[description]:description' \
      '-h[home page]:repository home page URL:_urls'
  }

  (( $+functions[_git-fork] )) ||
  _git-fork () {
    _arguments \
      '--no-remote[do not add a remote for the new fork]'
  }

  (( $+functions[_git-pull-request] )) ||
  _git-pull-request () {
    _arguments \
      '-f[force (skip check for local commits)]' \
      '-b[base]:base ("branch", "owner\:branch", "owner/repo\:branch"):' \
      '-h[head]:head ("branch", "owner\:branch", "owner/repo\:branch"):' \
      - set1 \
59 60
        '-m[message]' \
        '-F[file]' \
D
Dave Goodell 已提交
61
      - set2 \
62
        '-i[issue]:issue number:' \
D
Dave Goodell 已提交
63
      - set3 \
64
        '::issue-url:_urls'
D
Dave Goodell 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  }

  # stash the "real" command for later
  functions[_hub_orig_git_commands]=$functions[_git_commands]

  # Replace it with our own wrapper.
  declare -f _git_commands >& /dev/null && unfunction _git_commands
  _git_commands () {
    local ret=1
    # call the original routine
    _call_function ret _hub_orig_git_commands

    # Effectively "append" our hub commands to the behavior of the original
    # _git_commands function.  Using this wrapper function approach ensures
    # that we only offer the user the hub subcommands when the user is
    # actually trying to complete subcommands.
    hub_commands=(
      alias:'show shell instructions for wrapping git'
      pull-request:'open a pull request on GitHub'
      fork:'fork origin repo on GitHub'
      create:'create new repo on GitHub for the current project'
      browse:'browse the project on GitHub'
      compare:'open GitHub compare view'
88
      ci-status:'lookup commit in GitHub Status API'
D
Dave Goodell 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    )
    _describe -t hub-commands 'hub command' hub_commands && ret=0

    return ret
  }
}

(( $+functions[__hub_setup_bash_fns] )) ||
__hub_setup_bash_fns () {
  # TODO more bash-style fns needed here to complete subcommand args.  They take
  # the form "_git_CMD" where "CMD" is something like "pull-request".

  # Duplicate and rename the 'list_all_commands' function
  eval "$(declare -f __git_list_all_commands | \
        sed 's/__git_list_all_commands/__git_list_all_commands_without_hub/')"

  # Wrap the 'list_all_commands' function with extra hub commands
  __git_list_all_commands() {
    cat <<-EOF
alias
pull-request
fork
create
browse
compare
114
ci-status
D
Dave Goodell 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
EOF
    __git_list_all_commands_without_hub
  }

  # Ensure cached commands are cleared
  __git_all_commands=""
}

# redefine _hub to a much smaller function in the steady state
_hub () {
  # only attempt to intercept the normal "_git" helper functions once
  (( $+__hub_func_replacement_done )) ||
    () {
      # At this stage in the shell's execution the "_git" function has not yet
      # been autoloaded, so the "_git_commands" or "__git_list_all_commands"
      # functions will not be defined.  Call it now (with a bogus no-op service
      # to prevent premature completion) so that we can wrap them.
      if declare -f _git >& /dev/null ; then
        _hub_noop () { __hub_zsh_provided=1 }       # zsh-provided will call this one
        __hub_noop_main () { __hub_git_provided=1 } # git-provided will call this one
        local service=hub_noop
        _git
        unfunction _hub_noop
        unfunction __hub_noop_main
        service=git
      fi

      if (( $__hub_zsh_provided )) ; then
        __hub_setup_zsh_fns
      elif (( $__hub_git_provided )) ; then
        __hub_setup_bash_fns
      fi

      __hub_func_replacement_done=1
    }

  # Now perform the actual completion, allowing the "_git" function to call our
  # replacement "_git_commands" function as needed.  Both versions expect
  # service=git or they will call nonexistent routines or end up in an infinite
  # loop.
  service=git
  declare -f _git >& /dev/null && _git
}

# make sure we actually attempt to complete on the first "tab" from the user
_hub