# bash completion support for xkbcli.

# See completion API documentation: https://github.com/scop/bash-completion
# NOTE: The script parses the commands help messages to provide the completions,
#       thus any new subcommand or option will be supported, as long as it has its
#       entry in the help messages. This should result in low maintenancei effort.

___xkbcli_main()
{
    # Initialization: https://github.com/scop/bash-completion/blob/fdf4456186eb4548ef628e65fb1be73d8e4695e9/bash_completion.d/000_bash_completion_compat.bash#L205
    local cur prev words cword cmd
    _init_completion -s || return

    # Find subcommand
    local i=1
    while [[ "$i" -lt "$COMP_CWORD" ]]; do
        local s="${COMP_WORDS[i]}"
        case "$s" in
            -*) ;;
            *)
            cmd="$s"
            break
            ;;
        esac
        (( i++ ))
    done

    # Parse available subcommands
    local line
    local is_command_list=false
    local subcommands=()
    while IFS='' read -r line; do
        # Traverse subcommand list
        if [[ "$is_command_list" == true ]]; then
            # Check for subcommand based on the indentation
            if [[ "$line" =~ ^[[:blank:]]{2}([[:alpha:]]([[:alnum:]]|-)+)$ ]]; then
                subcommands+=("${BASH_REMATCH[1]}")
            # Detect end of subcommand list based on indentation
            elif [[ "$line" =~ ^[[:graph:]] ]]; then
                is_command_list=false
            fi
        # Detect start of subcommand list
        elif [[ "$line" == "Commands:" ]]; then
            is_command_list=true
        fi
    # NOTE: <( COMMAND ) Bash construct is “process substitution”.
    done < <(xkbcli --help)

    # No previous subcommand or incomplete: completion for root xkbcli command
    if [[ "$i" -eq "$COMP_CWORD" ]]; then
        local opts
        # Doc for _parse_help: https://github.com/scop/bash-completion/blob/fdf4456186eb4548ef628e65fb1be73d8e4695e9/bash_completion.d/000_bash_completion_compat.bash#L311
        opts=$(_parse_help xkbcli)
        local cur="${COMP_WORDS[COMP_CWORD]}"
        COMPREPLY=($(compgen -W "${subcommands[*]} $opts" -- "$cur"))
        return
    fi

    # Found a supported subcommand: proceed to completion
    if [[ "${subcommands[*]}" =~ (^| )$cmd( |$) ]]; then
        ___xkbcli_subcommand "$cmd"
    fi
}

___xkbcli_subcommand()
{
    # Some special cases
    case $1 in
        compile-keymap | interactive-evdev)
            case ${COMP_WORDS[COMP_CWORD-1]} in
                --include | --keymap)
                    _filedir
                    return;;
            esac
            ;;
        compile-compose)
            case ${COMP_WORDS[COMP_CWORD-1]} in
                --file)
                    _filedir
                    return;;
            esac
            ;;
        list)
            if [[ ${COMP_WORDS[COMP_CWORD]} != -* ]]; then
                _filedir
                return
            fi
            ;;
    esac

    # Parse help to get command options
    local opts
    # Doc for _parse_usage and _parse_help:
    # • https://github.com/scop/bash-completion/blob/fdf4456186eb4548ef628e65fb1be73d8e4695e9/bash_completion.d/000_bash_completion_compat.bash#L335
    # • https://github.com/scop/bash-completion/blob/fdf4456186eb4548ef628e65fb1be73d8e4695e9/bash_completion.d/000_bash_completion_compat.bash#L311
    # We need both as the current help messages adopt both GNU and BSD styles.
    opts=$(_parse_usage xkbcli "$1 --help")
    opts+="
    "
    opts+=$(_parse_help xkbcli "$1 --help")
    local cur="${COMP_WORDS[COMP_CWORD]}"
    COMPREPLY=($(compgen -W "$opts" -- "$cur"))
}

complete -F ___xkbcli_main xkbcli
