Cli.bash_engine: def of cli@0.2.0.0 Import: import cli@0.2.0.0/cli.bend as Cli Lines 6603-6711 of cli@0.2.0.0/cli.bend: https://jend.leeeet.dev/read.txt?path=cli@0.2.0.0/cli.bend&start_line=6603&end_line=6711 import Base # The rest of every bash script, for function prefix id and the quoted # command name: the parser of COMP_WORDS, then the binding. def bash_engine(+id: String, name: String) -> List<&2, String>: [ "", "# Offers each value of kind that starts with $1, written after $2 and cut to", "# the part readline completes: the text after the last \"=\" or \":\". Readline", "# quotes files and directories; words are quoted here.", String.concat([id, "_offer() {"]), " local word full i", " case $kind in", " f) compopt -o filenames; mapfile -t values < <(compgen -f -- \"$1\") ;;", " d) compopt -o filenames; mapfile -t values < <(compgen -d -- \"$1\") ;;", " w)", " for ((i = 0; i < ${#values[@]}; i++)); do", " printf -v 'values[i]' %q \"${values[i]}\"", " done ;;", " *) return ;;", " esac", " for word in \"${values[@]}\"; do", " full=$2$word", " [[ $word == \"$1\"* ]] && COMPREPLY+=(\"${full:${#2}+${#1}-${#tail}}\")", " done", "}", "", String.concat([id, "() {"]), " local -a words=() opts=() subs=() dests=() values=()", " local cur tail word line gap path= want= kind opt many rest i j n=0 end=0 help=0", " COMPREPLY=()", " # Rejoin the \"=\" and \":\" that bash splits words at. COMP_LINE has no blank", " # at such a split, so a \"=\" typed as its own word stays one.", " line=${COMP_LINE#*\"${COMP_WORDS[0]}\"}", " for ((i = 1; i <= COMP_CWORD; i++)); do", " word=${COMP_WORDS[i]}", " tail=${COMP_WORDS[i-1]}", " gap=${line%%[![:blank:]]*}", " line=${line:${#gap}+${#word}}", " if ((i > 1)) && [[ -z $gap ]] &&", " [[ -n $word && -z ${word//[=:]} || -n $tail && -z ${tail//[=:]} ]]; then", " words[${#words[@]}-1]+=$word", " else", " words+=(\"$word\")", " fi", " done", " tail=${COMP_WORDS[COMP_CWORD]}", " [[ -z ${tail//[=:]} ]] && tail=", " cur=${words[${#words[@]}-1]}", " unset 'words[${#words[@]}-1]'", String.concat([" ", id, "_scope"]), " for word in \"${words[@]}\"; do", " if [[ -n $want ]]; then", " want=", " elif ((!end)) && [[ $word == -- ]]; then", " end=1", " elif ((!end)) && [[ $word == --* ]]; then", String.concat([" ", id, "_arg \"${word%%=*}\""]), " [[ -n $kind && $opt == 0 && $word != *=* ]] && want=$word", " elif ((!end)) && [[ $word == -?* ]]; then", " for ((j = 1; j < ${#word}; j++)); do", String.concat([" ", id, "_arg \"-${word:j:1}\""]), " [[ -n $kind ]] || continue", " ((j + 1 == ${#word})) && want=-${word:j:1}", " break", " done", " elif ((${#subs[@]})); then", " ((end)) && return", " if [[ $word == help ]] && ((!help)); then", " help=1", " continue", " fi", " for ((j = 0; j < ${#subs[@]}; j++)); do", " [[ $word == \"${subs[j]}\" ]] && break", " done", " ((j < ${#subs[@]})) || return", " path=${dests[j]}", String.concat([" ", id, "_scope"]), " else", " # n counts the slots filled. The variadic slot stays open, but a rest()", " # value takes every later word, so nothing more completes.", " n=$((n + 1))", " if ((n == many && rest)); then", " end=1", " elif ((n == many)); then", " n=$((n - 1))", " fi", " fi", " done", " if [[ -n $want ]]; then", String.concat([" ", id, "_arg \"$want\""]), String.concat([" ", id, "_offer \"$cur\" ''"]), " elif ((!end)) && [[ $cur == --*=* ]]; then", String.concat([" ", id, "_arg \"${cur%%=*}\""]), String.concat([" ", id, "_offer \"${cur#*=}\" \"${cur%%=*}=\""]), " elif ((!end)) && [[ $cur == -* ]]; then", " values=(\"${opts[@]}\") kind=w", " ((help)) && values=('-h' '--help')", String.concat([" ", id, "_offer \"$cur\" ''"]), " elif ((!end && ${#subs[@]})); then", " values=(\"${subs[@]}\") kind=w", " ((help)) || values+=('help')", String.concat([" ", id, "_offer \"$cur\" ''"]), " elif ((!help)); then", String.concat([" ", id, "_arg $((n + 1))"]), String.concat([" ", id, "_offer \"$cur\" ''"]), " fi", "}", "", String.concat(["complete -F ", id, " ", name]), ] Uses (3): https://jend.leeeet.dev/definition.txt?path=Base/base.bend&name=List https://jend.leeeet.dev/definition.txt?path=Base/base.bend&name=String https://jend.leeeet.dev/definition.txt?path=Base/base.bend&name=String.concat