<%
# To make changes to the completions:
#
# - For changes to a command under `COMMANDS` or `DEVELOPER COMMANDS` sections):
#   - Find the source file in `Library/Homebrew/[dev-]cmd/<command>.{rb,sh}`.
#   - For `.rb` files, edit the `cmd_args` block. For subcommand metadata,
#     edit `Library/Homebrew/<command>/subcommand.rb` and
#     `Library/Homebrew/<command>/subcommand/*.rb` if they exist.
#   - For `.sh` files, edit the top comment, being sure to use the line prefix
#     `#:` for the comments to be recognized as documentation. If in doubt,
#     compare with already documented commands.
# - For other changes: Edit this file.
#
# When done, regenerate the completions by running `brew generate-man-completions`.
%>
#compdef brew
#autoload

# Brew ZSH completion function
# This file is automatically generated by running `brew generate-man-completions`.
# See Library/Homebrew/completions/zsh.erb for editing instructions.

# 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=(
    <%= aliases.join("\n    ") + "\n" %>
  )
  echo "${aliases}"
}

__brew_user_aliases() {
  local aliases_dir="${HOME}/.config/brew-aliases"
  local pattern="alias: brew ([^[:space:]]+)"
  local file line alias_name
  local -a aliases

  [[ ! -d ${aliases_dir} ]] && aliases_dir="${HOME}/.brew-aliases"
  [[ ! -d ${aliases_dir} ]] && return

  for file in "${aliases_dir}"/*(N); do
    [[ ! -f ${file} || ${file} == *~ ]] && continue
    alias_name="${file:t}"
    {
      read -r line
      if read -r line && [[ ${line} =~ ${pattern} ]]; then
        alias_name="${match[1]}"
      fi
    } < "${file}"
    aliases+=("${alias_name}")
  done
  (( ${#aliases} )) && _describe -t user-aliases 'user aliases' aliases
}

__brew_formulae_or_ruby_files() {
  _alternative '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=( $(brew --repository)/Library/Taps/*/*/.git/index(om[1]N) )
  [[ -z $tmp || $tmp -nt $1 ]]
}

__brew_formulae() {
  [[ -prefix '-' ]] && return 0

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

__brew_installed_formulae() {
  [[ -prefix '-' ]] && return 0

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

__brew_outdated_formulae() {
  [[ -prefix '-' ]] && return 0

  local -a formulae
  formulae=($(HOMEBREW_NO_AUTO_UPDATE=1 brew outdated --formula))
  _describe -t formulae 'outdated formulae' formulae
}

__brew_casks() {
  [[ -prefix '-' ]] && return 0

  local -a list
  local expl
  local comp_cachename=brew_casks

  if ! _retrieve_cache $comp_cachename; then
    list=( $(HOMEBREW_COMPLETION=1 brew casks) )
    _store_cache $comp_cachename list
  fi

  _wanted list expl 'all casks' compadd -a list
}

__brew_installed_casks() {
  [[ -prefix '-' ]] && return 0

  local -a list
  local expl
  list=( $(brew list --cask 2>/dev/null) )
  _wanted list expl 'installed casks' compadd -a list
}

__brew_outdated_casks() {
  [[ -prefix '-' ]] && return 0

  local -a casks
  casks=($(HOMEBREW_NO_AUTO_UPDATE=1 brew outdated --cask 2>/dev/null))
  _describe -t casks 'outdated casks' casks
}

__brew_installed_taps() {
  [[ -prefix '-' ]] && return 0

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

__brew_any_tap() {
  [[ -prefix '-' ]] && return 0

  _alternative \
    'installed-taps:installed taps:__brew_installed_taps'
}

__brew_internal_commands() {
  local -a commands
  commands=(
    <%= builtin_command_descriptions.join("\n    ") + "\n" %>
  )
  if [[ -n ${HOMEBREW_DEVELOPER:-} ]]; then
    commands+=(
      <%= maintainer_descriptions.join("\n      ") + "\n" %>
    )
  fi
  _describe -t internal-commands 'internal commands' commands
}

__brew_external_commands() {
  local -a list
  local comp_cachename=brew_all_commands
  if ! _retrieve_cache $comp_cachename; then
    local cache_dir=$(brew --cache)
    [[ -f $cache_dir/external_commands_list.txt ]] &&
      list=( $(<$cache_dir/external_commands_list.txt) )
    _store_cache $comp_cachename list
  fi
  _describe -t all-commands 'all commands' list
}

__brew_commands() {
  _alternative \
    'internal-commands:command:__brew_internal_commands' \
    'external-commands:command:__brew_external_commands' \
    'user-aliases:alias:__brew_user_aliases'
}

__brew_diagnostic_checks() {
  local -a diagnostic_checks
  diagnostic_checks=($(brew doctor --list-checks))
  _describe -t diagnostic-checks 'diagnostic checks' diagnostic_checks
}

__brew_services() {
  [[ -prefix '-' ]] && return 0

  local -a services
  services=($(command find "$(brew --cellar)" -mindepth 3 -maxdepth 3 -name '*.service' \
    | awk -F'homebrew.|.service' '{print $3}' \
    | sort -d))
  _describe -t services 'services' services
}

<%= completion_functions.join("\n") %>

# 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 "$@"
