#!/usr/bin/env bash

# 用于 soup 命令行工具的补全脚本
# 
# (1)soup 命令补全主入口

# soup 命令调试环境变量
# 如果此环境变量被设置将会打印命令在补全时的调试信息
_soup_debug() {
    # 使用 BASH_COMP_SOUP_DEBUG_FILE 指定的文件进行输出调试信息
    #          v 如果在 bash 命令行中定义了这个环境变量，将传入本函数的所有内容输出(追加)到调试文件
    if [[ -n ${BASH_COMP_SOUP_DEBUG_FILE:-} ]]; then
        echo "$@" >> "${BASH_COMP_SOUP_DEBUG_FILE}"
    fi
}

# soup 命令调试文件清空函数
# 与 _soup_debug 不相同，且用于首次触发执行补全时清空调试文件
_soup_debug_clean() {
    if [[ -n ${BASH_COMP_SOUP_DEBUG_FILE:-} ]]; then
        echo "" > "${BASH_COMP_SOUP_DEBUG_FILE}"
    fi
}

_initialize_global_variable() {
    GLOBAL=
    if [[ "${words[*]}" == *" -g "* ]]; then
        GLOBAL='-g'
    fi
}

_convert_() {
    # 将所有的供选项进行添加 '' 号
    for((i=0; i<${#COMPREPLY[@]}; i++)); do
        COMPREPLY[$i]="'${COMPREPLY[i]}'"
    done
}

_soup_if_global() {
    if [[ "${words[*]}" == *"-g"* ]]; then
        _soup_debug "${words} contains: -g"
        return 0
    fi
    return 1
}


# soup 命令补全入口
_soup() {
    # 调试操作: 清空调试文件内容
    _soup_debug_clean

    # 1. 准备一些基本的信息，这些都是最基本的，也是在补全脚本中仅能获取的有限内容

    # 定义一些函数内变量，由 completion 驱动内置进行初始化内容
        # cur   当前的位置
        # prev  上一个词
        # words 所有词
        # cword 位置引用
    local cur prev words cword
    _init_completion || return

    # 为了更好的进行识别
        # 将第一个词标记为可执行程序名称
        # 将第二个词标记为子命令
    local binary="${words[0]}"
    local command="${words[1]}"

    _soup_debug "========== _soup function env ============"
    _soup_debug "_soup words: " "%${words[*]}%" "-- 所有词"
    _soup_debug "_soup prev:  " "%${prev}%"     "-- 前词"
    _soup_debug "_soup cur:   " "%${cur}%"      "-- 当前词"
    _soup_debug "_soup cword: " "%${cword}%"    "-- 位置引用"
    _soup_debug
    _soup_debug "_soup binary: " "%${binary}%"  "-- 当前程序"
    _soup_debug "_soup command:" "%${command}%" "-- 当前子命令" 
    _soup_debug "========== _soup function env ============"
    _soup_debug ""

# 2. 准备此命令有关的次级信息

    # 子命令集合，如果子命令不在此中，将认为尚未完成子命令的提示，可直接使用此处进行补全
    local soup_help_commands=(
        
    )

    # 子命令完整集合，包含额外的 help 命令
    local soup_commands=(
        # help 
        ${soup_help_commands[*]}
    )

    COMPREPLY=()

    # 冲突选项
    CONFLICT_FLAGS=(
        -i --input
        -r --range
    )
    # 通用选项
    FLAGS=(
        -s --suffix
        -j --json
        -m --select
        -a --attr
        -w --separator
        -v --version
        -l --outline
    )

    if [[ "${cur}" == '-'* ]]; then
        if [[ 
            "${words[*]}" == *" -i "* ||
            "${words[*]}" == *" -r "* ||
            "${words[*]}" == *" --input "* ||
            "${words[*]}" == *" --range "* 
         ]]; then
            COMPREPLY=( $(compgen -W "${FLAGS[*]}" -- ${cur}) )
        else
            COMPREPLY=( $(compgen -W "${CONFLICT_FLAGS[*]} ${FLAGS[*]}" -- ${cur}) )
        fi
    else
        case ${prev} in 
            -i|--input)
                _filedir # 当需要指定文件时直接显示文件列表
                ;;
            *)
                ;;
        esac
    fi 

    _soup_debug "_soup 可用结果: ${COMPREPLY[*]}"
}

# 在 Bash 中，输入 soup 时，补全操作将尝试调用 _soup 函数尝试生成补全内容。
    # _soup 函数将被输入三个参数：
        # 要补全的命令名、当前光标所在的词、当前光标所在的词的前一个词
        # COMP_WORDS
        # COMP_CWORD
        # COMP_LINE
complete -F _soup soup
complete -F _soup soup-cli


# compgen：
# 用法：compgen [-abcdefgjksuv] [-o 选项]  [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [词语]
    # -W wordlist
        # wordlist 被使用 IFS 特殊变量中的字符作为定界符来拆分，每个结果的词被扩展。可能的补全是结果列表 中匹配要补全的词的那一些。

# 在 Bash 中，借助 compgen 强大的可用函数列表、命令、词语列表输出能力，即可生成最终补全内容
    # 例如从一组词语中进行补全匹配，即可得到结果：补全 j 在提供的 词语列表 中可能匹配的补全
        # $ compgen -W "c++ java json rust" -- j
    # 则会输出以下内容
        # java
        # json