#compdef brew
#autoload

# Brew ZSH completion function

# functions starting with __brew are helper functions that complete or list
#   various types of items.
# functions starting with _brew_ are completions for brew commands
#   this mechanism can be extended by external commands by defining a function
#   named _brew_<external-name>. See _brew_cask for an example of this.

# a list of aliased internal commands
__brew_list_aliases() {
  local -a aliases
  aliases=(
    ls list
    homepage home
    '-S' search
    up update
    ln link
    instal install
    rm uninstall
    remove uninstall
    configure diy
    abv info
    dr doctor
    '--repo' '--repository'
    environment '--env'
    '--config' config
    '-v' '--version'
  )
  echo "${aliases}"
}

__brew_formulae_or_ruby_files() {
  _alternative 'formulae::__brew_formulae' \
    'files:files:{_files -g "*.rb"}'
}

# completions remain in cache until any tap has new commits
__brew_completion_caching_policy() {
  local -a tmp

  # invalidate if cache file is missing or >=2 weeks old
  tmp=( $1(mw-2N) )
  (( $#tmp )) || return 0

  # otherwise, invalidate if latest tap index file is missing or newer than cache file
  tmp=( ${HOMEBREW_REPOSITORY:-/usr/local/Homebrew}/Library/Taps/*/*/.git/index(om[1]N) )
  [[ -z $tmp || $tmp -nt $1 ]]
}

__brew_formulae() {
  local -a list
  local comp_cachename=brew_formulae
  if ! _retrieve_cache $comp_cachename; then
    list=( $(brew search) )
    _store_cache $comp_cachename list
  fi
  _describe -t formulae 'all formulae' list
}

__brew_installed_formulae() {
  local -a formulae
  formulae=($(brew list --formula))
  _describe -t formulae 'installed formulae' formulae
}

__brew_installed_casks() {
  local -a list
  local expl
  list=( $(brew list --cask) )
  _wanted list expl 'installed casks' compadd -a list
}

__brew_outdated_formulae() {
  local -a formulae
  formulae=($(brew outdated))
  _describe -t formulae 'outdated formulae' formulae
}

__brew_installed_taps() {
  local -a taps
  taps=($(brew tap))
  _describe -t installed-taps 'installed taps' taps
}

__brew_pinned_taps() {
  local -a taps
  taps=($(brew tap --list-pinned))
  _describe -t pinned-taps 'pinned taps' taps
}

__brew_any_tap() {
  _alternative \
    'installed-taps:installed taps:__brew_installed_taps'
}

__brew_common_commands() {
  local -a commands
  commands=(
    'audit:check formulae for Homebrew coding style'
    'cat:display formula file for a formula'
    'cleanup:uninstall unused and old versions of packages'
    'commands:show a list of commands'
    'config:show homebrew and system configuration'
    'create:create a new formula'
    'deps:list dependencies of formulae'
    'desc:display a description of a formula'
    'doctor:audits your installation for common issues'
    'edit:edit a formula'
    'fetch:download formula resources to the cache'
    'formula:the path for a formula'
    'gist-logs:generate a gist of the full build logs'
    'home:visit the homepage of a formula or the brew project'
    'info:information about a formula'
    'install:install a formula'
    'reinstall:install a formula anew; re-using its current options'
    'leaves:show installed formulae that are not dependencies of another installed formula'
    'link:link a formula'
    'list:list files in a formula or not-installed formulae'
    'log:git commit log for a formula'
    'missing:check all installed formulae for missing dependencies.'
    'migrate:migrate renamed formula to new name'
    'outdated:list formulae for which a newer version is available'
    'pin:pin specified formulae'
    'postinstall:perform post_install for a given formula'
    'remove:remove a formula'
    'search:search for a formula or cask (/regex/ or string)'
    'switch:switch between different versions of a formula'
    'tap:tap a new formula repository from GitHub, or list existing taps'
    'tap-info:information about a tap'
    'test-bot:test a formula and build a bottle'
    'uninstall:uninstall a formula'
    'unlink:unlink a formula'
    'unpin:unpin specified formulae'
    'untap:remove a tapped repository'
    'update:fetch latest version of Homebrew and all formulae'
    'upgrade:upgrade outdated formulae'
    'uses:show formulae which depend on a formula'
    '--cellar:brew cellar'
    '--env:brew environment'
    '--repository:brew repository'
    '--version:version information'
    '--prefix:where brew lives on this system'
    '--cache:brew cache'
  )
  _describe -t common-commands 'common commands' commands
}

__brew_all_commands() {
  local -a list
  local comp_cachename=brew_all_commands
  if ! _retrieve_cache $comp_cachename; then
    local cache_dir=$(brew --cache)
    [[ -f $cache_dir/all_commands_list.txt ]] &&
      list=( $(<$cache_dir/all_commands_list.txt) ) ||
      list=( $(<$(brew --repo)/completions/internal_commands_list.txt) )
    list=( ${list:#*instal} ) # Exclude instal, uninstal, etc.
    _store_cache $comp_cachename list
  fi
  _describe -t all-commands 'all commands' list
}

__brew_commands() {
  # TODO remove duplicates between common and all commands
  _alternative \
    'common-commands:command:__brew_common_commands' \
    'all-commands:command:__brew_all_commands'
}

# brew --cache
# brew --cache formula
_brew___cache() {
  __brew_formulae
}

# brew --cellar
# brew --cellar formula
_brew___cellar() {
  __brew_formulae
}

# brew --env
_brew___env() {
  return 1
}

# brew --prefix
# brew --prefix formula
_brew___prefix() {
  __brew_formulae
}

# brew --repository
# brew --repository user/repo
_brew___repository() {
  __brew_any_tap
}

# brew --version
_brew___version() {
  return 1
}

# brew analytics [state]
# brew analytics (on|off)
# brew analytics regenerate-uuid
_brew_analytics() {
  _values 'analytics' \
    'off[turn off analytics]' \
    'on[turn on analytics]' \
    'regenerate-uuid[regenerate UUID used in analytics]' \
    'state[display anonymous user behaviour analytics state]'
}

# brew aspell_dictionaries
_brew_aspell_dictionaries() {
  return 1
}

# brew audit [--strict] [--online] [--new-formula] [--display-cop-names] [--display-filename] [formulae]
_brew_audit() {
  _arguments \
    '(--new-formula)--strict[run additional checks including RuboCop style checks]' \
    '(--new-formula)--online[run slower checks that require a network connection]' \
    '(--online --strict)--new-formula[check if a new formula is eligible for Homebrew. Implies --strict and --online]' \
    '--display-cop-names[include RuboCop cop name for each violation in the output]' \
    '--display-filename[prefix every line of output with the name of the file or formula being audited]' \
    '*:formula:__brew_formulae_or_ruby_files'
}

# brew bottle [--verbose] [--no-rebuild] [--keep-old] [--skip-relocation] [--root-url=root_url]
# brew bottle --merge [--no-commit] [--keep-old] [--write]
# TODO missing argument docs
_brew_bottle() {
  _arguments \
    '--keep-old' \
    - set1 \
      '--verbose' \
      '--no-rebuild' \
      '--skip-relocation' \
      '--root-url=' \
    - set2 \
      '--merge' \
      '--no-commit' \
      '--write'
}

# brew bump-formula-pr [--devel] [--dry-run] [--audit|--strict] --url=url --sha256=sha-256 formula
# brew bump-formula-pr [--devel] [--dry-run] [--audit|--strict] --tag=tag --revision=revision formula
_brew_bump_formula_pr() {
  _arguments \
      '--devel[bump the development rather than stable version]' \
      '--dry-run[print what would be done rather than doing it]' \
      '(--strict)--audit[run brew audit before opening the PR]' \
      '(--audit)--strict[run brew audit --strict before opening the PR]' \
    - set1 \
      '--url=-[new url]:url:_urls' \
      '--sha256=-[new sha256 checksum]:sha256: ' \
      ': :__brew_formulae_or_ruby_files' \
    - set2 \
      '--tag=-[new tag]: ' \
      '--revision=-[new revision]: ' \
      ': :__brew_formulae_or_ruby_files'
}

# brew bump-revision [--dry-run] [--message] formula
_brew_bump_revision() {
  _arguments \
      '--dry-run[print what would be done rather than doing it]' \
      '--message[append message to the default commit message]:message: ' \
      ': :__brew_formulae_or_ruby_files'
}

# brew cat formula
_brew_cat() {
  _arguments \
    '1:: :__brew_formulae'
}

# brew cleanup [--prune=days] [--dry-run] [-s] [formulae]
_brew_cleanup() {
  _arguments \
    '--prune=-[remove all cache files older than days]:days: ' \
    '(--dry-run,-n)'{--dry-run,-n}'[show what would be removed, but do not actually remove anything]' \
    '-s[scrub cache]' \
    '*::formula:__brew_formulae'
}

# brew command cmd
_brew_command() {
  _arguments \
    ': :__brew_all_commands'
}

# brew commands [--quiet [--include-aliases]]
_brew_commands() {
  _arguments '--quiet' && return 0
  _arguments '--include-aliases'
}

# brew config
_brew_config() {
  return 1
}

# brew create URL [--autotools|--cmake] [--no-fetch] [--set-name name] [--set-version version] [--tap user/repo]:
_brew_create() {
  _arguments \
    '(--cmake)--autotools[create a basic template for an Autotools-style build]' \
    '(--autotools)--cmake[create a basic template for a CMake-style build]' \
    '--no-fetch[don''t download URL to the cache]' \
    '--set-name:name: ' \
    '--set-version:version: ' \
    '--tap:tap:__brew_installed_taps' \
    ':url:_urls'
}

# brew deps [--1] [-n] [--union] [--full-name] [--installed] [--include-build] [--include-optional] [--skip-recommended] [--include-requirements] formulae
# brew deps --tree [--1] [filters] (formulae|--installed)
# brew deps [filters] (--installed|--all)
# The filters placeholder is any combination of options --include-build, --include-optional, and --skip-recommended as documented above.
_brew_deps() {
  _arguments \
    - formulae-deps \
      '--include-build[include \:build dependencies]' \
      '--include-optional[include \:optional dependencies]' \
      '--skip-recommended[skip \:recommended type dependencies]' \
      '--include-requirements[include requirements]' \
      '--1[only show dependencies one level down, instead of recursing]' \
      '-n[show dependencies in topological order]' \
      '--union[show the union of dependencies for formulae, instead of the intersection]' \
      '--full-name[list dependencies by their full name]' \
      '--installed[only list currently installed dependencies, or show dependencies for all installed formulae]' \
      '*:formulae:__brew_formulae' \
    - tree-deps \
      '--tree[show dependencies as a tree]' \
      '(*)--installed[show dependencies for all installed formulae]' \
      '--include-build[include \:build dependencies]' \
      '--include-optional[include \:optional dependencies]' \
      '--skip-recommended[skip \:recommended type dependencies]' \
      '--include-requirements[include requirements]' \
      '--1[only show dependencies one level down, instead of recursing]' \
      '(--installed)*:formulae:__brew_formulae' \
    - installed-all \
      '--include-build[include \:build dependencies]' \
      '--include-optional[include \:optional dependencies]' \
      '--skip-recommended[skip \:recommended type dependencies]' \
      '(--all)--installed[show dependencies for all installed formulae]' \
      '(--installed)--all[show dependencies for all available formulae]'
}

# brew desc formulae
# brew desc [-s|-n|-d] pattern
_brew_desc() {
  _arguments \
    - desc-formula \
      '*: : __brew_formulae' \
    - desc-pattern \
      '(-s -n -d)-s[search both name and description]' \
      '(-s -n -d)-n[search only name]' \
      '(-s -n -d)-d[search only description]' \
      ':pattern: '

}

# brew diy [--name=name] [--version=version]
_brew_diy() {
  _arguments \
    '--name=-:' \
    '--version=-:'
}

# brew doctor
_brew_doctor() {
  return 1
}

# brew edit
# brew edit formulae
_brew_edit() {
  _arguments \
    '*:: :__brew_formulae_or_ruby_files'
}

# brew fetch [--force] [--retry] [-v] [--devel|--HEAD] [--deps]
#   [--build-from-source|--build-bottle|--force-bottle] formulae
_brew_fetch() {
  _arguments \
    '(--force -f)'{--force,-f}'[remove previously cached version and re-fetch]' \
    '--retry[retry if a download fails or re-download if the checksum of a previously cached version no longer matches]' \
    '(--verbose -v)'{--verbose,-v}'[verbose VCS checkout]' \
    '(--HEAD)--devel[fetch devel version instead of stable]' \
    '(--devel)--HEAD[fetch HEAD version instead of stable]' \
    '--deps[also download dependencies for any listed formulae]' \
    '(--build-from-source -s --force-bottle --build-bottle)'{--build-from-source,-s}'[download the source rather than a bottle]' \
    '(--build-from-source -s --force-bottle)--build-bottle[download the source (for eventual bottling) rather than a bottle]' \
    '(--build-from-source -s --build-bottle)--force-bottle[download a bottle if it exists for the current version of OS X, even if it would not be used during installation]' \
    '*:formula:__brew_formulae'
}

# brew formula formula:
_brew_formula() {
  __brew_formulae
}

# brew gist-logs [--new-issue|-n] formula
_brew_gist_logs() {
  _arguments \
    '(--new-issue -n)'{--new-issue,-n}'[automatically create a new issue in the appropriate GitHub repository]' \
    ':formula:__brew_formulae'
}

# brew help command
_brew_help() {
  __brew_commands
}

# brew home
# brew home formula
_brew_home() {
  __brew_formulae
}

# brew info formulae
# brew info --github formula
# brew info --json=version (--all|--installed|formulae)
_brew_info() {
  _arguments \
    - formulae-opts \
      '*: :__brew_formulae' \
    - github-opts \
      '--github[open a browser to the GitHub History page for formula]' \
      ': :__brew_formulae' \
    - json-opts \
      '--json=-[print a JSON representation of formulae]:version:(v1)' \
      '(--all --installed :)--all[get information on all formulae]' \
      '(--all --installed :)--installed[get information on installed formulae]' \
      '(--all --installed)*: :__brew_formulae'
}

# brew install [--debug] [--env=std|super]
#   [--ignore-dependencies|--only-dependencies] [--include-test]
#   [--cc=compiler] [--build-from-source|--build-bottle|--force-fottle]
#   [--devel|--HEAD] [--fetch-HEAD] [--bottle-arch=architecture] [--keep-tmp] formulae
# brew install --interactive [--git] formula
_brew_install() {
  local state
  _arguments \
    - normal-install \
      '--debug[if brewing fails, open an interactive debugging session]' \
      -'-env=-[use standard or super environment]:environment:(std super)' \
      '(--only-dependencies)--ignore-dependencies[skip installing any dependencies of any kind]' \
      '(--ignore-dependencies)--only-dependencies[install the dependencies but do not install the specified formula]' \
      '--cc=-[attempt to compile using compiler]:compiler: ' \
      '(--build-from-source -s --force-bottle --build-bottle)'{--build-from-source,-s}'[compile the specified formula from source even if a bottle is provided]' \
      '(--build-from-source -s --force-bottle)--build-bottle[prepare the formula for eventual bottling during installation, skipping any post-install steps]' \
      '(--build-from-source -s --build-bottle)--force-bottle[install from a bottle if it exists for the current version of OS X, even if it would not normally be used for installation]' \
      '--include-test[install testing dependencies]' \
      '(--devel --HEAD)'{--devel,--HEAD}'[install the development / HEAD version]' \
      '--fetch-HEAD[fetch the upstream repository to detect if the HEAD installation of the formula is outdated]' \
      '--bottle-arch=-[optimise bottles for the specified architecture]:architecture: ' \
      '--keep-tmp[don''t delete temporary files created during installation]' \
      '--display-times[display installation times at end of run]' \
      '*: : __brew_formulae' \
    - interactive-install \
      '--interactive[download and patch formula, then open a shell]' \
      '--git' \
      ': : __brew_formulae'
}

# brew irb [--examples]
_brew_irb() {
  _arguments '(--examples)--examples'
}

# brew leaves
_brew_leaves() {
  return 1
}

# brew ln, link [--overwrite] [--dry-run] [--force] formulae
_brew_link() {
  _arguments \
    '--overwrite[delete files which already exist in the prefix]' \
    '(--dry-run -n)'{--dry-run,-n}'[list files that would be linked or deleted]' \
    '--force[allow keg-only formulae to be linked]' \
    '*:formula:__brew_installed_formulae'
}

# brew linkage [--test] [--reverse] formulae
_brew_linkage() {
  _arguments \
    '--test[only display missing libraries]' \
    '--reverse[print the dylib followed by the binaries which link to it]' \
    '*:formula:__brew_installed_formulae'
}

# brew list, ls [--full-name]:
# brew list, ls --unbrewed:
# brew list, ls [--versions [--multiple]] [--pinned] [formulae]:
# brew list, ls [--cask|--formula]:
_brew_list() {
  local state
  _arguments \
    - formulae \
      '--formula[list install formulae]' \
      '--full-name[print formulae with fully-qualified names]' \
      '--unbrewed[files in brew --prefix not controlled by brew]' \
      '--pinned[list all versions of pinned formulae]' \
      '--versions[list all installed versions of a formula]' \
      '--multiple[only show formulae with multiple versions installed]' \
      '*:: :__brew_installed_formulae' \
    - cask \
      '--cask[list installed Casks]' \
      '*:: :__brew_installed_casks'

}

# brew livecheck [--verbose] [--quiet] [--debug] [--full-name] [--tap user/repo]
#                [--installed] [--json] [--all] [--newer-only] formulae
_brew_livecheck() {
  _arguments \
    '--full-name[Print formulae with fully-qualified name]' \
    '--tap[Check the formulae within the given tap, specified as user/repo]' \
    '--all[Check all available formulae]' \
    '--installed[Check formulae that are currently installed]' \
    '--newer-only[Show the latest version only if it is newer than the formula]' \
    '--json[Output information in JSON format]' \
    '(--quiet,-q)'{--quiet,-q}'[Suppress warnings, do not print a progress bar for JSON output]' \
    '(--debug,-d)'{--debug,-d}'[Display any debugging information]' \
    '(--verbose,-v)'{--verbose,-v}'[Make some output more verbose]' \
    '(--help,-h)'{--help,-h}'[Show the help message]' \
    '*:: :__brew_formulae'
}

# brew log [git-log-options] formula ...:
_brew_log() {
  __brew_formulae
}

# brew man
_brew_man() {
  return 1
}

# brew migrate [--force] formulae:
_brew_migrate() {
  _arguments \
    '--force[treat installed formulae and passed formulae ike if they are from same taps and migrate them anyway]' \
    '*: :__brew_formulae'
}

# brew mirror [--test] formula-name [formula-name ...]:
# TODO missing argument docs
_brew_mirror() {
  _arguments \
    '--test' \
    '*: :__brew_formulae'
}

# brew missing [formulae]:
_brew_missing() {
  __brew_formulae
}

# brew options [--compact] (--all|--installed|formulae):
_brew_options() {
  _arguments \
    '--compact' \
    '(--all --installed :)'{--all,--installed}'[show options for all / installed formula]' \
    '(--all --installed): :__brew_formulae'
}

# brew outdated [--quiet|--verbose|--json=v1] [--fetch-HEAD] [--cask]:
_brew_outdated() {
  _arguments \
    - formulae \
      '(--quiet --verbose --json)--quiet[list only the names of outdated brews]' \
      '(--quiet --verbose --json)--verbose[display detailed version information]' \
      '(--quiet --verbose --json)--json=-[output in JSON format]:version:(v1)' \
      '--fetch-HEAD[detect if the HEAD installation of the formula is outdated]' \
    - cask \
      '--cask[list outdated Casks]' \
      '--greedy[also list Casks with auto_updates or version \:latest]'
}

# brew pin formulae:
_brew_pin() {
  __brew_formulae
}

# brew postinstall formula:
_brew_postinstall() {
  _arguments \
    '*:: :__brew_formulae'
}

# pull [--bottle] [--bump] [--clean] [--ignore-whitespace] [--resolve]
#   [--branch-okay] [--no-pbcopy] [--no-publish] patch-source [patch-source]
_brew_pull() {
  _arguments \
    '--bottle[handle bottles]' \
    '--bump[automatically reword commit message]' \
    '--clean[do not rewrite commits found in the pulled PR]' \
    '--ignore-whitespace[ignore whitespace discrepancies when applying diffs]' \
    '--resolve[allow user to resolve patches that fail to apply]' \
    '--branch-okay[do not warn on pulling branches other than master]' \
    '--no-pbcopy[do not copy anything to the system]' \
    '--no-publish[do not publish bottles to Bintray]' \
    '*:patch source: '
}

# brew pr-pull [--no-upload|--no-publish] [--dry-run] [--clean] [--branch-okay]
#   [--resolve] [--workflow] [--artifact] [--bintray-org] [--tap] pull_request
_brew_pr_pull() {
  _arguments \
    '(--no-upload)--no-publish[download the bottles, apply the bottle commit, and upload the bottles to Bintray, but don''t publish them]' \
    '(--no-publish)--no-upload[download the bottles and apply the bottle commit, but don''t upload to Bintray]' \
    '--dry-run[print what would be done rather than doing it]' \
    '--clean[do not amend the commits from pull requests]' \
    '--branch-okay[do not warn if pulling to a branch besides master (useful for testing)]' \
    '--resolve[when a patch fails to apply, leave in progress and allow user to resolve, instead of aborting]' \
    '--workflow[retrieve artifacts from the specified workflow (default: tests.yml)]' \
    '--artifact[download artifacts with the specified name (default: bottles)]' \
    '--bintray-org[upload to the specified Bintray organisation (default: homebrew)]' \
    '--tap[target repository tap (default: homebrew/core)]' \
    '*:pull_request: '
}

# brew readall [tap]:
_brew_readall() {
  __brew_installed_taps
}

# brew reinstall formulae:
# mostly copy from brew install
_brew_reinstall() {
  _arguments \
    - normal-install \
      '--debug[if brewing fails, open an interactive debugging session]' \
      '(--build-from-source -s --force-bottle)'{--build-from-source,-s}'[compile the specified formula from source even if a bottle is provided]' \
      '(--build-from-source -s)--force-bottle[install from a bottle if it exists for the current version of OS X, even if it would not normally be used for installation]' \
      '--keep-tmp[don''t delete temporary files created during installation]' \
      '--display-times[display installation times at end of run]' \
      '*::formula:__brew_installed_formulae' \
    - interactive-install \
      '--interactive[download and patch formula, then open a shell]' \
      '::formula:__brew_installed_formulae'
}

# brew search, -S:
# brew search [--desc] text|/text/:
# brew search (--cask|--debian|--fedora|--fink|--macports|--opensuse|--ubuntu) text:
_brew_search() {
  _arguments \
    '(--cask --debian --fedora --fink --macports --opensuse --ubuntu)--desc[include description for each package]:text: ' \
    '(--desc --cask --debian --fedora --fink --macports --opensuse --ubuntu)'{--debian,--fedora,--fink,--macports,--opensuse,--ubuntu}'[search for text in given package manager''s list]' \
    '(--desc --cask --debian --fedora --fink --macports --opensuse 
    --ubuntu)--cask[search for text in Casks list]'
}

# brew sh [--env=std]:
# TODO missing argument docs
_brew_sh() {
  _arguments \
    '--env=-:environment:(std)'
}

# brew style [--fix] [--display-cop-names] [formulae|files]:
_brew_style() {
  _arguments \
    '--fix[fix style violations automatically]' \
    '--display-cop-names[include RuboCop name for each violation in output]' \
    '*::formula:__brew_formulae_or_ruby_files'
}

# brew switch name version:
_brew_switch() {
  local -a versions
  if [[ -n ${words[2]} ]]; then
    versions=(${$(brew ls "${words[2]}" --versions)#${words[2]}})
  fi
  _arguments -S \
    '1::formula:__brew_formulae' \
    "2:: :(${versions[*]})" \
    && ret=0
}

# brew tap:
# brew tap [--full] user/repo [URL]:
# brew tap --repair:
# brew tap --list-pinned:
_brew_tap() {
  _arguments \
    - empty-args \
    - repo-args \
      '--full[perform a full clone]' \
      '::url:_urls' \
    - repair-args \
      '--repair' \
    - list-pinned \
      '--list-pinned[list all pinned taps]'
}

# brew tap-info:
# brew tap-info (--installed|taps):
# brew tap-info --json=version (--installed|taps):
_brew_tap_info() {
  _arguments \
    '(--installed *)--installed[display information on all installed taps]' \
    '--json=-[print a JSON representation of taps]:version:(v1)' \
    '(--installed)*:taps:__brew_installed_taps'
}

# brew tap_readme [-v] name:
# TODO missing argument docs (verbose perhaps)
_brew_tap_readme() {
  _arguments \
    '(-v)-v' \
    ':name: '
}

# brew test [--devel|--HEAD] [--debug] [--keep-tmp] formulae:
_brew_test() {
  _arguments \
    '(--devel --HEAD)'{--devel,--HEAD}'[use the development / head version of the formula]' \
    '--debug[launch an interactive debugger if test fails]' \
    '--keep-tmp[don''t delete temporary files]' \
    '*:formula:__brew_formulae_or_ruby_files'
}

# brew test-bot [options]  url|formula:
_brew_test_bot() {
  _arguments \
    '--dry-run' \
    '--local' \
    '--keep-logs' \
    '--cleanup' \
    '--clean-cache' \
    '--skip-setup' \
    '--skip-homebrew' \
    '--junit' \
    '--no-bottle' \
    '--keep-old' \
    '--skip-relocation' \
    '--HEAD' \
    '--tap' \
    '--fail-fast' \
    '--verbose' \
    '--fast' \
    '--keep-tmp' \
    '--no-pull' \
    '--coverage' \
    '--ci-master' \
    '--ci-pr' \
    '--ci-testing' \
    '--ci-upload'
}

# brew tests [-v] [--coverage] [--generic] [--no-compat]
#   [--only=test_script:test_method] [--seed seed] [--trace] [--online]:
_brew_tests() {
  _arguments \
  '-v' \
  '--coverage' \
  '--generic' \
  '--no-compat' \
  '--only=-:test_method: ' \
  '--seed:seed: ' \
  '--trace' \
  '--online'
}

# brew uninstall, rm, remove [--force] formulae:
_brew_uninstall() {
  _arguments \
    '--force[delete all installed versions of formula]' \
    '*:formula:__brew_installed_formulae'
}

# brew unlink [--dry-run] formulae:
_brew_unlink() {
  _arguments \
    '(--dry-run -n)'{--dry-run,-n}'[don''t unlink or delete any files]' \
    '*:formula:__brew_installed_formulae'
}

# brew unpack [--git|--patch] [--destdir=path] formulae:
_brew_unpack() {
  _arguments \
    '(--git --patch)--git[initialize a Git repository in the unpacked source]' \
    '(--git --patch)--patch[apply patches for formula]' \
    '--destdir=-[create subdirectories under path]:path:_directories' \
    '*:formula:__brew_formulae'
}

# brew unpin formulae:
_brew_unpin() {
  _arguments \
    '*:formula:__brew_formulae'
}

# brew update [--merge] [--force]:
_brew_update() {
  _arguments \
    '--merge[use git merge instead of git rebase]' \
    '--force[do a slower full update check]'
}

# brew update_report:
_brew_update_report() {
  return 1
}

# brew update-test [--commit=sha1] [--before=date] [--keep-tmp]:
_brew_update_test() {
  _arguments \
    '(--commit=sha1)--commit=-[use sha1 as the start commit]:sha1: ' \
    '(--before=date)--before=-[use the commit at date as the start commit]:date:_dates' \
    '--keep-tmp[retain the temporary directory]'
}

# brew upgrade [install-options] [--cleanup] [--fetch-HEAD] [formulae]
# install-options is copied from brew install
_brew_upgrade() {
  _arguments \
  '--cask[upgrade installed Casks with newer versions]' \
  '--cleanup[remove previously installed formula version(s)]' \
  '--fetch-HEAD[detect if the HEAD installation of the formula is outdated]' \
  - normal-install \
    '--debug[if brewing fails, open an interactive debugging session]' \
    -'-env=-[use standard or super environment]:environment:(std super)' \
    '--ignore-dependencies[skip installing any dependencies of any kind]' \
    '--only-dependencies[install the dependencies but do not install the specified formula]' \
    '--cc=-[attempt to compile using compiler]:compiler: ' \
    '(--build-from-source -s --force-bottle)'{--build-from-source,-s}'[compile the specified formula from source even if a bottle is provided]' \
    '(--build-from-source -s)--force-bottle[install from a bottle if it exists for the current version of OS X, even if it would not normally be used for installation]' \
    '(--devel --HEAD)'{--devel,--HEAD}'[install the development / HEAD version]' \
    '--keep-tmp[don''t delete temporary files created during installation]' \
    '--display-times[display installation times at end of run]' \
    '*: : __brew_outdated_formulae' \
  - interactive-install \
    '--interactive[download and patch formula, then open a shell]' \
    '--git' \
    ': : __brew_outdated_formulae'

}

# brew uses [--installed] [--recursive] [--include-build] [--include-optional]
#   [--skip-recommended] [--devel|--HEAD] formulae:
_brew_uses() {
  _arguments \
    '--installed[only list installed formulae]' \
    '--recursive[resolve more than one level of dependencies]' \
    '--include-build[include the :build type dependencies]' \
    '--include-optional[include the :optional dependencies]' \
    '--skip-recommended[skip :recommended type dependencies]' \
    '(--devel --HEAD)'{--devel,--HEAD}'[find cases where formula is used by development / HEAD build]' \
    '*:formula:__brew_formulae'
}

# brew vendor-install [target]:
# TODO args missing docs
_brew_vendor_install() {
  _arguments \
    '--target'
}

# the main completion function
_brew() {
  local curcontext="$curcontext" state state_descr line expl
  local tmp ret=1

  _arguments -C : \
    '(-v)-v[verbose]' \
    '1:command:->command' \
    '*::options:->options' && return 0

  case "$state" in
    command)
      # set default cache policy
      zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp ||
         zstyle ":completion:${curcontext%:*}:*" cache-policy __brew_completion_caching_policy
      zstyle -s ":completion:${curcontext%:*}:*" use-cache tmp ||
         zstyle ":completion:${curcontext%:*}:*" use-cache true

      __brew_commands && return 0
      ;;
    options)
      local command_or_alias command
      local -A aliases

      # expand alias e.g. ls -> list
      command_or_alias="${line[1]}"
      aliases=($(__brew_list_aliases))
      command="${aliases[$command_or_alias]:-$command_or_alias}"

      # change context to e.g. brew-list
      curcontext="${curcontext%:*}-${command}:${curcontext##*:}"

      # set default cache policy (we repeat this dance because the context
      # service differs from above)
      zstyle -s ":completion:${curcontext%:*}:*" cache-policy tmp ||
         zstyle ":completion:${curcontext%:*}:*" cache-policy __brew_completion_caching_policy
      zstyle -s ":completion:${curcontext%:*}:*" use-cache tmp ||
         zstyle ":completion:${curcontext%:*}:*" use-cache true

      # call completion for named command e.g. _brew_list
      local completion_func="_brew_${command//-/_}"
      _call_function ret "${completion_func}" && return ret

      _message "a completion function is not defined for command or alias: ${command_or_alias}"
      return 1
    ;;
  esac
}

_brew "$@"
