#!/bin/env bash

##################################################

# « home-manager » command-line completion
#
# © 2019 "Sam Boosalis" <samboosalis@gmail.com>
#
# MIT License
#

##################################################
# Contributing:

# Compatibility — Bash 3.
#
# OSX won't update Bash 3 (last updated circa 2009) to Bash 4,
# and we'd like this completion script to work on both Linux and Mac.
#
# For example, OSX Yosemite (released circa 2014) ships with Bash 3:
#
#  $ echo $BASH_VERSION
#  3.2
#
# While Ubuntu LTS 14.04 (a.k.a. Trusty, also released circa 2016)
# ships with the latest version, Bash 4 (updated circa 2016):
#
#  $ echo $BASH_VERSION
#  4.3
#

# Testing
#
# (1) Invoke « shellcheck »
#
#     * source: « https://github.com/koalaman/shellcheck »
#     * run:    « shellcheck ./share/bash-completion/completions/home-manager »
#
# (2) Interpret via Bash 3
#
#     * run:    « bash --noprofile --norc ./share/bash-completion/completions/home-manager »
#

##################################################
# Examples:

# $ home-manager <TAB>
#
# -A
# -I
# -f
# --file
# -h
# --help
# -n
# --dry-run
# -v
# --verbose
# build
# edit
# expire-generations
# generations
# help
# news
# option
# packages
# remove-generations
# switch
# uninstall

# $ home-manager e<TAB>
#
# edit
# expire-generations

# $ home-manager remove-generations 20<TAB>
#
# 200
# 201
# 202
# 203

##################################################
# Notes:

# « home-manager » Subcommands:
#
#   help
#   edit
#   option
#   build
#   switch
#   generations
#   remove-generations
#   expire-generations
#   packages
#   news
#   uninstall

# « home-manager » Options:
#
#   -b EXT
#   -f FILE
#   --file FILE
#   -A ATTRIBUTE
#   -I PATH
#   -v
#   --verbose
#   -n
#   --dry-run
#   -h
#   --help

# $ home-manager
#
# Usage: /home/sboo/.nix-profile/bin/home-manager [OPTION] COMMAND
#
# Options
#
#   -f FILE      The home configuration file.
#                Default is '~/.config/nixpkgs/home.nix'.
#   -A ATTRIBUTE Optional attribute that selects a configuration
#                expression in the configuration file.
#   -I PATH      Add a path to the Nix expression search path.
#   -b EXT       Move existing files to new path rather than fail.
#   -v           Verbose output
#   -n           Do a dry run, only prints what actions would be taken
#   -h           Print this help
#
# Commands
#
#   help         Print this help
#
#   edit         Open the home configuration in $EDITOR
#
#   option OPTION.NAME
#                Inspect configuration option named OPTION.NAME.
#
#   build        Build configuration into result directory
#
#   switch       Build and activate configuration
#
#   generations  List all home environment generations
#
#   remove-generations ID...
#       Remove indicated generations. Use 'generations' command to
#       find suitable generation numbers.
#
#   expire-generations TIMESTAMP
#       Remove generations older than TIMESTAMP where TIMESTAMP is
#       interpreted as in the -d argument of the date tool. For
#       example "-30 days" or "2018-01-01".
#
#   packages     List all packages installed in home-manager-path
#
#   news         Show news entries in a pager
#
#   uninstall    Remove Home Manager
#
##################################################
# Dependencies:

command -v home-manager >/dev/null
command -v grep         >/dev/null
command -v sed          >/dev/null

##################################################
# Code:

_home-manager_list-generation-identifiers ()

{

    home-manager generations  |  sed -n -e 's/^................ : id \([[:alnum:]]\+\) -> .*/\1/p'

}

# NOTES
#
# (1) the « sed -n -e 's/.../.../p' » invocation:
#
#    * the « -e '...' » option takes a Sed Script.
#    * the « -n » option only prints when « .../p » would print.
#    * the « s/xxx/yyy/ » Sed Script substitutes « yyy » whenever « xxx » is matched.
#
# (2) the « '^................ : id \([[:alnum:]]\+\) -> .*' » regular expression:
#
#    * matches « 199 », for example, in the line « 2019-03-13 15:26 : id 199 -> /nix/store/mv619y9pzgsx3kndq0q7fjfvbqqdy5k8-home-manager-generation »
#
#

#------------------------------------------------#

# shellcheck disable=SC2120
_home-manager_list-nix-attributes ()

{
    local HomeFile
    local HomeAttrsString
    # local HomeAttrsArray
    # local HomeAttr

    if   [ -z "$1" ]
    then
        HomeFile=$(readlink -f "$(_home-manager_get-default-home-file)")
    else
        HomeFile="$1"
    fi

    HomeAttrsString=$(nix-instantiate --eval -E "let home = import ${HomeFile}; in (builtins.trace (builtins.toString (builtins.attrNames home)) null)" |& grep '^trace: ')
    HomeAttrsString="${HomeAttrsString#trace: }"

    echo "${HomeAttrsString}"

    # IFS=" " read -ar HomeAttrsArray <<< "${HomeAttrsString}"
    #
    # local HomeAttr
    # for HomeAttr in "${HomeAttrsArray[@]}"
    # do
    #     echo "${HomeAttr}"
    # done

}

# e.g.:
#
#   $ nix-instantiate --eval -E 'let home = import /home/sboo/configuration/configs/nixpkgs/home-attrs.nix; in (builtins.trace (builtins.toString (builtins.attrNames home)) null)' 1>/dev/null
#   trace: darwin linux
#
#   $ _home-manager_list-nix-attributes
#   linux darwin
#

#------------------------------------------------#

_home-manager_get-default-home-file ()

{
    local HomeFileDefault

    HomeFileDefault="$(_home-manager_xdg-get-config-home)/nixpkgs/home.nix"

    echo "${HomeFileDefault}"
}

# e.g.:
#
#   $ _home-manager_get-default-home-file
#   ~/.config/nixpkgs/home.nix
#

##################################################
# XDG-BaseDirs:

_home-manager_xdg-get-config-home () {

    echo "${XDG_CONFIG_HOME:-$HOME/.config}"

}

#------------------------------------------------#

_home-manager_xdg-get-data-home () {

    echo "${XDG_DATA_HOME:-$HOME/.local/share}"

}


#------------------------------------------------#
_home-manager_xdg-get-cache-home () {

    echo "${XDG_CACHE_HOME:-$HOME/.cache}"

}

##################################################

_hm_subcommands=( "help" "edit" "option" "build" "init" "instantiate" "switch" "generations" "remove-generations" "expire-generations" "packages" "news" "uninstall" )
declare -ra _hm_subcommands

# Finds the active sub-command, if any.
_home-manager_subcommand() {
    local subcommand='' i=
    for ((i = 1; i < ${#COMP_WORDS[@]}; i++)); do
        local word="${COMP_WORDS[i]}"
        if [[ " ${_hm_subcommands[*]} " == *" ${word} "* ]]; then
            subcommand="$word"
            break
        fi
    done

    echo "$subcommand"
}

# shellcheck disable=SC2207
_home-manager_completions ()
{
    local Options
    Options=( "-f" "--file" "-b" "-A" "-I" "-h" "--help" "-n" "--dry-run" "-v" \
              "--verbose" "--cores" "--debug" "--impure" "--keep-failed" \
              "--keep-going" "-j" "--max-jobs" "--no-substitute" "--no-out-link" \
              "-L" "--print-build-logs" "--log-format" \
              "--show-trace" "--flake" "--substitute" "--builders" "--version" \
              "--update-input" "--override-input" "--experimental-features" \
              "--extra-experimental-features" "--refresh")

    # ^ « home-manager »'s options.

    #--------------------------#

    local CurrentWord
    CurrentWord="${COMP_WORDS[$COMP_CWORD]}"

    # ^ the word currently being completed

    local PreviousWord
    if [ "$COMP_CWORD" -ge 1 ]
    then
        PreviousWord="${COMP_WORDS[COMP_CWORD-1]}"
    else
        PreviousWord=""
    fi

    # ^ the word to the left of the current word.
    #
    #   e.g. in « home-manager -v -f ./<TAB> »:
    #
    #       PreviousWord="-f"
    #       CurrentWord="./"

    local CurrentCommand
    CurrentCommand="$(_home-manager_subcommand)"

    #--------------------------#

    COMPREPLY=()

    case "$CurrentCommand" in
        "init")

            COMPREPLY+=( $( compgen -W "--switch" -- "$CurrentWord" ) )
            COMPREPLY+=( $( compgen -A directory -- "$CurrentWord") )
            ;;

        "remove-generations")

            COMPREPLY+=( $( compgen -W "$(_home-manager_list-generation-identifiers)" -- "$CurrentWord" ) )
            ;;

        *)
            case "$PreviousWord" in

                "-f"|"--file")

                    COMPREPLY+=( $( compgen -A file -- "$CurrentWord") )
                    ;;

                "-I")

                    COMPREPLY+=( $( compgen -A directory -- "$CurrentWord") )
                    ;;

                "-A")

                    # shellcheck disable=SC2119
                    COMPREPLY+=( $( compgen -W "$(_home-manager_list-nix-attributes)" -- "$CurrentWord") )
                    ;;
                *)

                    if [[ ! $CurrentCommand ]]; then
                        COMPREPLY+=( $( compgen -W "${_hm_subcommands[*]}" -- "$CurrentWord" ) )
                    fi
                    COMPREPLY+=( $( compgen -W "${Options[*]}" -- "$CurrentWord" ) )
                    ;;

            esac
            ;;
    esac

    #--------------------------#
}

##################################################

complete -F _home-manager_completions -o default home-manager

#complete -W "help edit option build switch generations remove-generations expire-generations packages news" home-manager
