# bash completion for nim                             -*- shell-script -*-

# (NOTE) The following functions SHOULD be identical to those
# in nim source tree: __is_short_or_long, __ask_for_subcmd_or_subopts,
# __ask_for_subcmd, __ask_for_subcmd_opts

__is_short_or_long()
{
    local actual short long
    actual="$1"
    short="$2"
    long="$3"
    [[ ! -z $short && $actual == $short ]] && return 0
    [[ ! -z $long && $actual == $long ]] && return 0
    return 1
}

__ask_for_subcmd_or_subopts()
{
    local args cmd subcmd words sub_words word_first word_last word_lastlast
    local len ilast ilastlast i ele sub_len n_nopts
    
    args=("$@")
    ask_for_what="${args[0]}"
    cmd="${args[1]}"
    subcmd="${args[2]}"
    ilast="${args[3]}"
    words=("${args[@]:4}")
    len=${#words[@]}
    ilastlast=$((ilast - 1))
    sub_words=("${words[@]:0:ilast}")
    sub_len=${#sub_words[@]}
    word_first=${words[0]}
    word_last=${words[ilast]}
    word_lastlast=${words[ilastlast]}
    n_nopts=0

    # printf "\n[DBUG] word_first:${word_first}|ilast:${ilast}|words(${len}):${words[*]}|sub_words(${sub_len}):${sub_words[*]}\n"

    if [[ $word_first != $cmd ]]
    then
	return 1
    fi

    i=0
    while [[ $i -lt $len ]]
    do
	ele=${words[i]}
	if [[ ! $ele =~ ^- ]]
	then
	    if [[ $ele == $cmd || $ele == $subcmd ]]
	    then
		((n_nopts+=1))
	    elif [[ $i -eq $ilast && $ele =~ ^[a-zA-Z] ]]
	    then
	        ((i=i))
	    elif [[ -z $ele ]]
	    then
	        ((i=i))
	    elif [[ $ele =~ ^: ]]
	    then
		((i+=1))
	    else
		return 1
	    fi
	fi
	((i+=1))
    done

    case $ask_for_what in
	1)
	    if [[ n_nopts -eq 1 ]]
	    then
		if [[ -z $word_last || $word_last =~ ^[a-zA-Z] ]] && [[ $word_lastlast != : ]]
		then
		    return 0
		fi
	    fi
	    ;;
	2)
	    if [[ n_nopts -eq 2 ]]
	    then
		if [[ -z $word_last ]] || [[ $word_last =~ ^[-:] ]]
		then
		    return 0
		fi
	    fi
    esac

    return 1
}

__ask_for_subcmd()
{
    __ask_for_subcmd_or_subopts 1 "$@"
}

__ask_for_subcmd_opts()
{
    __ask_for_subcmd_or_subopts 2 "$@"
}

_nimble()
{
    local i_curr n_words i_prev i_prevprev curr prev prevprev words
    COMPREPLY=()
    i_curr=$COMP_CWORD
    n_words=$((i_curr+1))
    i_prev=$((i_curr-1))
    i_prevprev=$((i_curr-2))
    curr="${COMP_WORDS[i_curr]}"
    prev="${COMP_WORDS[i_prev]}"
    prevprev="${COMP_WORDS[i_prevprev]}"
    words=("${COMP_WORDS[@]:0:n_words}")

    local subcmds opts candids
    # printf "\n[DBUG] i_curr:$i_curr|curr:$curr|prev:$prev|words(${#words[*]}):${words[*]}\n"

    # Asking for a subcommand
    if __ask_for_subcmd nimble nimble $i_curr "${words[@]}"
    then
        subcmds=""
	subcmds="${subcmds} install"
	subcmds="${subcmds} develop"
	subcmds="${subcmds} check"
	subcmds="${subcmds} init"
	subcmds="${subcmds} publish"
	subcmds="${subcmds} publishTags"
	subcmds="${subcmds} uninstall"
	subcmds="${subcmds} build"
	subcmds="${subcmds} clean"
	subcmds="${subcmds} guide"
	subcmds="${subcmds} add"
	subcmds="${subcmds} run"
	subcmds="${subcmds} c cc js"
	subcmds="${subcmds} test"
	subcmds="${subcmds} doc doc2"
	subcmds="${subcmds} refresh"
	subcmds="${subcmds} search"
	subcmds="${subcmds} list"
	subcmds="${subcmds} tasks"
	subcmds="${subcmds} path"
	subcmds="${subcmds} dump"
	subcmds="${subcmds} lock"
	subcmds="${subcmds} search"
	subcmds="${subcmds} upgrade"
	subcmds="${subcmds} deps"
	subcmds="${subcmds} sync"
	subcmds="${subcmds} setup"
	subcmds="${subcmds} shell"
	subcmds="${subcmds} shellenv"
	subcmds="${subcmds} upgrade"
	COMPREPLY=( $( compgen -W "${subcmds}" -- ${curr}) )
	return 0
    fi

    # Priorize subcmd over opt
    if false
    then
	return 124
    elif __ask_for_subcmd_opts nimble install $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-d" "--depsOnly" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-p" "--passNim" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--noRebuild" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble develop $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("" "--withDependencies" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-p" "--patch" "PATH") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-a" "--add" "PATH") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-r" "--removePath" "PATH") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-n" "--removeName" "NAME") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-i" "--include" "FILE") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-e" "--exclude" "FILE") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-g" "--global" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble check $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble publish $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble init $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("" "--git" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--hg" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble publish $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble publishTags $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-l" "--listOnly" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble uninstall $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-i" "--inclDeps" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble build $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble clean $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble guide $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble add $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble run $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble c $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble cc $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble js $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble test $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-c" "--continue" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble doc $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble doc2 $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble refresh $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble search $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("" "--ver" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--version" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble list $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-i" "--installed" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--ver" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--version" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-n" "--nimbinaries" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble tasks $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble path $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble dump $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("" "--ini" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--json" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble lock $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble upgrade $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble deps $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("" "--tree" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--inverted" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--format" "TYPE") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble sync $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()
	opts+=("-l" "--listOnly" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})

    elif  __ask_for_subcmd_opts nimble setup $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble shell $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    elif  __ask_for_subcmd_opts nimble shellenv $i_curr "${words[@]}"
    then
	opts=() \
	    && candids=()

    else
	opts=() \
	    && candids=()
	opts+=("-h" "--help" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-v" "--version" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-y" "--accept" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-n" "--reject" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-l" "--localdeps" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-p" "--package" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("-t" "--tarballs" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--ver" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--nimbleDir" "DIRNAME") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--nim" "PATH") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--silent" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--info" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--verbose" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--debug" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--offline" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--noColor" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--noSslCheck" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--lockFile" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--noLockFile" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--developFile" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--useSystemNim" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--solver" "sat legacy") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--requires" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--disableNimBinaries" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--maximumTaggedVersions" "") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
	opts+=("" "--parser" "declarative nimvm") \
	    && candids+=(${opts[$((${#opts[@]}-3))]} ${opts[$((${#opts[@]}-2))]})
    fi

    local len i idx0 idx1 idx2 c_short c_long c_accvals

    case $curr in
	# Asking for accepted optvalues, e.g., `out:`
	:)
	    len=${#opts[@]}
	    i=0

	    while [[ $i -lt $len ]]
	    do
		idx0=$((i / 3 * 3))
	        idx1=$((idx0 + 1))
		idx2=$((idx1 + 1))
		c_short=${opts[idx0]}
		c_long=${opts[idx1]}
		c_accvals=${opts[idx2]}
		(false \
		     || __is_short_or_long $prev ${c_short} ${c_long} \
		     || false) \
		    && COMPREPLY=( $(compgen -W "${c_accvals}" --) ) \
		    && return 0
		((i+=3))
	    done
	    return 124
	    ;;

	*)
	    # When in a incomplete opt value, e.g., `--check:of`
	    if [[ $prev == : ]]
	    then
		len=${#opts[@]}
		i=0
		while [[ $i -lt $len ]]
		do
		    idx0=$((i / 3 * 3))
		    idx1=$((idx0 + 1))
		    idx2=$((idx1 + 1))
		    c_short=${opts[idx0]}
		    c_long=${opts[idx1]}
		    c_accvals=${opts[idx2]}
		    (false \
			 || __is_short_or_long $prevprev ${c_short} ${c_long} \
			 || false) \
			&& COMPREPLY=( $(compgen -W "${c_accvals}" -- ${curr}) ) \
			&& return 0
		    ((i+=3))
		done
		return 124
	    fi

	    # When in a complete optname, might need optvalue, e.g., `--check`
	    if [[ $curr =~ ^--?[:()a-zA-Z]+$ ]]
	    then
	        len=${#opts[@]}
		i=0
		while [[ $i -lt $len ]]
		do
		    idx0=$(((i / 3 * 3)))
		    idx1=$((idx0 + 1))
		    idx2=$((idx1 + 1))
		    c_short=${opts[idx0]}
		    c_long=${opts[idx1]}
		    c_accvals=${opts[idx2]}

		    if __is_short_or_long $curr ${c_short} ${c_long}
		    then
			if [[ ! -z $c_accvals ]]
			then
			    COMPREPLY=( $(compgen -W "${curr}:" -- ${curr}) ) \
				&& compopt -o nospace \
				&& return 0
			else
			    COMPREPLY=( $(compgen -W "${curr}" -- ${curr}) ) \
				&& return 0
			fi
		    fi

		    ((i+=3))
		done # while

		if true
		then
		    COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
		    compopt -o nospace
		    return 0
		fi

		# When in an incomplete optname, e.g., `--chec`
	    elif [[ $curr =~ ^--?[^:]* ]]
	    then
		if true
		then
		    COMPREPLY=( $(compgen -W "${candids[*]}" -- "$curr") )
		    compopt -o nospace
		    return 0
		fi
	    fi

	    if true
	    then
		compopt -o filenames
		COMPREPLY=( $(compgen -f -- "$curr") )
		compopt -o nospace
		return 0
	    fi

	    ;;
    esac
    return 0

} &&
    complete -F _nimble nimble

# ex: filetype=sh
