# Bash completion for "crystal" command.
# Written by Sergey Potapov <blake131313@gmail.com>.

# Return list of options, that match $pattern
_crystal_compgen_options() {
  local options=$1
  local pattern=$2

  while IFS=$' \n' read -r line; do
    COMPREPLY+=("$line")
  done < <(compgen -W "${options}" -- "${pattern}")
}

# Return list of crystal sources or directories, that match $pattern
_crystal_compgen_sources() {
  local pattern=$1

  type compopt &>/dev/null && compopt -o filenames
  while IFS=$'\n' read -r line; do
    COMPREPLY+=("$line")
  done < <(compgen -f -o plusdirs -X '!*.cr' -- "${pattern}")
}

# Return list of files or directories, that match $pattern (the default action)
_crystal_compgen_files() {
  local pattern=$1

  type compopt &>/dev/null && compopt -o filenames
  while IFS=$'\n' read -r line; do
    COMPREPLY+=("$line")
  done < <(compgen -o default -- "${pattern}")
}

_crystal() {
  local IFS=$' \n'
  local program=${COMP_WORDS[0]}
  local cmd=${COMP_WORDS[1]}
  local cur="${COMP_WORDS[COMP_CWORD]}"
  local prev="${COMP_WORDS[COMP_CWORD - 1]}"
  COMPREPLY=()

  commands="init build clear_cache docs eval play run spec tool help version --help --version"

  case "${cmd}" in
    init)
      if [[ ${prev} == "init" ]]; then
        local opts="app lib"
        _crystal_compgen_options "${opts}" "${cur}"
      else
        _crystal_compgen_files "${cur}"
      fi
      ;;
    build)
      if [[ ${cur} == -* ]]; then
        local opts="--cross-compile --debug --emit --error-on-warnings --exclude-warnings --ll --link-flags --mcpu --no-color --no-codegen --output --prelude --release --single-module --threads --target --verbose --warnings --x86-asm-syntax --help"
        _crystal_compgen_options "${opts}" "${cur}"
      else
        _crystal_compgen_sources "${cur}"
      fi
      ;;
    run)
      if [[ ${cur} == -* ]]; then
        local opts="--debug --define --emit --error-on-warnings --exclude-warnings --format --help --ll --link-flags --mcpu --no-color --no-codegen --output --prelude --release --stats --single-module --threads --verbose --warnings --x86-asm-syntax"
        _crystal_compgen_options "${opts}" "${cur}"
      else
        _crystal_compgen_sources "${cur}"
      fi
      ;;
    tool)
      if [[ ${cur} == -* ]]; then
        local opts="--no-color --prelude --define --format --cursor"
        _crystal_compgen_options "${opts}" "${cur}"
      else
        if [[ ${prev} == "tool" ]]; then
          local subcommands="context dependencies expand flags format hierarchy implementations macro_code_coverage types unreachable"
          _crystal_compgen_options "${subcommands}" "${cur}"
        else
          _crystal_compgen_sources "${cur}"
        fi
      fi
      ;;
    play)
      if [[ ${cur} == -* ]]; then
        local opts="--port --binding --verbose --help"
        _crystal_compgen_options "${opts}" "${cur}"
      else
        _crystal_compgen_sources "${cur}"
      fi
      ;;
    clear_cache | docs | eval | spec | version | help)
      # These commands do not accept any options nor subcommands
      _crystal_compgen_files "${cur}"
      ;;
    *)
      # When any of subcommands matches directly
      if [[ ${prev} == "${program}" && $(compgen -W "${commands}" -- "${cur}") ]]; then
        _crystal_compgen_options "${commands}" "${cur}"
      else
        _crystal_compgen_sources "${cur}"
      fi
      ;;
  esac
  return 0
}

complete -F _crystal crystal
