Something went wrong. Try again.
A Twitter-Bot that is going to increase your followers.
Something went wrong. Try again.
14 kB · 389 lines
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389#!/bin/bash## Bash completion generated for '{{name}}' at {{date}}.## The original template lives here:# https://github.com/trentm/node-dashdash/blob/master/etc/dashdash.bash_completion.in#
## Copyright 2016 Trent Mick# Copyright 2016 Joyent, Inc.### A generic Bash completion driver script.## This is meant to provide a re-usable chunk of Bash to use for# "etc/bash_completion.d/" files for individual tools. Only the "Configuration"# section with tool-specific info need differ. Features:## - support for short and long opts# - support for knowing which options take arguments# - support for subcommands (e.g. 'git log <TAB>' to show just options for the# log subcommand)# - does the right thing with "--" to stop options# - custom optarg and arg types for custom completions# - (TODO) support for shells other than Bash (tcsh, zsh, fish?, etc.)### Examples/design:## 1. Bash "default" completion. By default Bash's 'complete -o default' is# enabled. That means when there are no completions (e.g. if no opts match# the current word), then you'll get Bash's default completion. Most notably# that means you get filename completion. E.g.:# $ tool ./<TAB># $ tool READ<TAB>## 2. all opts and subcmds:# $ tool <TAB># $ tool -v <TAB> # assuming '-v' doesn't take an arg# $ tool -<TAB> # matching opts# $ git lo<TAB> # matching subcmds## Long opt completions are given *without* the '=', i.e. we prefer space# separated because that's easier for good completions.## 3. long opt arg with '='# $ tool --file=<TAB># $ tool --file=./d<TAB># We maintain the "--file=" prefix. Limitation: With the attached prefix# the 'complete -o filenames' doesn't know to do dirname '/' suffixing. Meh.## 4. envvars:# $ tool $<TAB># $ tool $P<TAB># Limitation: Currently only getting exported vars, so we miss "PS1" and# others.## 5. Defer to other completion in a subshell:# $ tool --file $(cat ./<TAB># We get this from 'complete -o default ...'.## 6. Custom completion types from a provided bash function.# $ tool --profile <TAB> # complete available "profiles"### Dev Notes:# - compgen notes, from http://unix.stackexchange.com/questions/151118/understand-compgen-builtin-command# - https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html#
# Debugging this completion:# 1. Uncomment the "_{{name}}_log_file=..." line.# 2. 'tail -f /var/tmp/dashdash-completion.log' in one terminal.# 3. Re-source this bash completion file.#_{{name}}_log=/var/tmp/dashdash-completion.log
function _{{name}}_completer {
# ---- cmd definition
{{spec}}
# ---- locals
declare -a argv
# ---- support functions
function trace { [[ -n "$_{{name}}_log" ]] && echo "$*" >&2 }
function _dashdash_complete { local idx context idx=$1 context=$2
local shortopts longopts optargs subcmds allsubcmds argtypes shortopts="$(eval "echo \${cmd${context}_shortopts}")" longopts="$(eval "echo \${cmd${context}_longopts}")" optargs="$(eval "echo \${cmd${context}_optargs}")" subcmds="$(eval "echo \${cmd${context}_subcmds}")" allsubcmds="$(eval "echo \${cmd${context}_allsubcmds}")" IFS=', ' read -r -a argtypes <<< "$(eval "echo \${cmd${context}_argtypes}")"
trace "" trace "_dashdash_complete(idx=$idx, context=$context)" trace " shortopts: $shortopts" trace " longopts: $longopts" trace " optargs: $optargs" trace " subcmds: $subcmds" trace " allsubcmds: $allsubcmds"
# Get 'state' of option parsing at this COMP_POINT. # Copying "dashdash.js#parse()" behaviour here. local state= local nargs=0 local i=$idx local argtype local optname local prefix local word local dashdashseen= while [[ $i -lt $len && $i -le $COMP_CWORD ]]; do argtype= optname= prefix= word=
arg=${argv[$i]} trace " consider argv[$i]: '$arg'"
if [[ "$arg" == "--" && $i -lt $COMP_CWORD ]]; then trace " dashdash seen" dashdashseen=yes state=arg word=$arg elif [[ -z "$dashdashseen" && "${arg:0:2}" == "--" ]]; then arg=${arg:2} if [[ "$arg" == *"="* ]]; then optname=${arg%%=*} val=${arg##*=} trace " long opt: optname='$optname' val='$val'" state=arg argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) word=$val prefix="--$optname=" else optname=$arg val= trace " long opt: optname='$optname'" state=longopt word=--$optname
if [[ "$optargs" == *"-$optname="* && $i -lt $COMP_CWORD ]]; then i=$(( $i + 1 )) state=arg argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) word=${argv[$i]} trace " takes arg (consume argv[$i], word='$word')" fi fi elif [[ -z "$dashdashseen" && "${arg:0:1}" == "-" ]]; then trace " short opt group" state=shortopt word=$arg
local j=1 while [[ $j -lt ${#arg} ]]; do optname=${arg:$j:1} trace " consider index $j: optname '$optname'"
if [[ "$optargs" == *"-$optname="* ]]; then argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) if [[ $(( $j + 1 )) -lt ${#arg} ]]; then state=arg word=${arg:$(( $j + 1 ))} trace " takes arg (rest of this arg, word='$word', argtype='$argtype')" elif [[ $i -lt $COMP_CWORD ]]; then state=arg i=$(( $i + 1 )) word=${argv[$i]} trace " takes arg (word='$word', argtype='$argtype')" fi break fi
j=$(( $j + 1 )) done elif [[ $i -lt $COMP_CWORD && -n "$arg" ]] && $(echo "$allsubcmds" | grep -w "$arg" >/dev/null); then trace " complete subcmd: recurse _dashdash_complete" _dashdash_complete $(( $i + 1 )) "${context}__${arg/-/_}" return else trace " not an opt or a complete subcmd" state=arg word=$arg nargs=$(( $nargs + 1 )) if [[ ${#argtypes[@]} -gt 0 ]]; then argtype="${argtypes[$(( $nargs - 1 ))]}" if [[ -z "$argtype" ]]; then # If we have more args than argtypes, we use the # last type. argtype="${argtypes[@]: -1:1}" fi fi fi
trace " state=$state prefix='$prefix' word='$word'" i=$(( $i + 1 )) done
trace " parsed: state=$state optname='$optname' argtype='$argtype' prefix='$prefix' word='$word' dashdashseen=$dashdashseen" local compgen_opts= if [[ -n "$prefix" ]]; then compgen_opts="$compgen_opts -P $prefix" fi
case $state in shortopt) compgen $compgen_opts -W "$shortopts $longopts" -- "$word" ;; longopt) compgen $compgen_opts -W "$longopts" -- "$word" ;; arg) # If we don't know what completion to do, then emit nothing. We # expect that we are running with: # complete -o default ... # where "default" means: "Use Readline's default completion if # the compspec generates no matches." This gives us the good filename # completion, completion in subshells/backticks. # # We cannot support an argtype="directory" because # compgen -S '/' -A directory -- "$word" # doesn't give a satisfying result. It doesn't stop at the trailing '/' # so you cannot descend into dirs. if [[ "${word:0:1}" == '$' ]]; then # By default, Bash will complete '$<TAB>' to all envvars. Apparently # 'complete -o default' does *not* give us that. The following # gets *close* to the same completions: '-A export' misses envvars # like "PS1". trace " completing envvars" compgen $compgen_opts -P '$' -A export -- "${word:1}" elif [[ -z "$argtype" ]]; then # Only include opts in completions if $word is not empty. # This is to avoid completing the leading '-', which foils # using 'default' completion. if [[ -n "$dashdashseen" ]]; then trace " completing subcmds, if any (no argtype, dashdash seen)" compgen $compgen_opts -W "$subcmds" -- "$word" elif [[ -z "$word" ]]; then trace " completing subcmds, if any (no argtype, empty word)" compgen $compgen_opts -W "$subcmds" -- "$word" else trace " completing opts & subcmds (no argtype)" compgen $compgen_opts -W "$shortopts $longopts $subcmds" -- "$word" fi elif [[ $argtype == "none" ]]; then # We want *no* completions, i.e. some way to get the active # 'complete -o default' to not do filename completion. trace " completing 'none' (hack to imply no completions)" echo "##-no-completion- -results-##" elif [[ $argtype == "file" ]]; then # 'complete -o default' gives the best filename completion, at least # on Mac. trace " completing 'file' (let 'complete -o default' handle it)" echo "" elif ! type complete_$argtype 2>/dev/null >/dev/null; then trace " completing '$argtype' (fallback to default b/c complete_$argtype is unknown)" echo "" else trace " completing custom '$argtype'" completions=$(complete_$argtype "$word") if [[ -z "$completions" ]]; then trace " no custom '$argtype' completions" # These are in ascii and "dictionary" order so they sort # correctly. echo "##-no-completion- -results-##" else echo $completions fi fi ;; *) trace " unknown state: $state" ;; esac }
trace "" trace "-- $(date)" #trace "\$IFS: '$IFS'" #trace "\$@: '$@'" #trace "COMP_WORDBREAKS: '$COMP_WORDBREAKS'" trace "COMP_CWORD: '$COMP_CWORD'" trace "COMP_LINE: '$COMP_LINE'" trace "COMP_POINT: $COMP_POINT"
# Guard against negative COMP_CWORD. This is a Bash bug at least on # Mac 10.10.4's bash. See # <https://lists.gnu.org/archive/html/bug-bash/2009-07/msg00125.html>. if [[ $COMP_CWORD -lt 0 ]]; then trace "abort on negative COMP_CWORD" exit 1; fi
# I don't know how to do array manip on argv vars, # so copy over to argv array to work on them. shift # the leading '--' i=0 len=$# while [[ $# -gt 0 ]]; do argv[$i]=$1 shift; i=$(( $i + 1 )) done trace "argv: '${argv[@]}'" trace "argv[COMP_CWORD-1]: '${argv[$(( $COMP_CWORD - 1 ))]}'" trace "argv[COMP_CWORD]: '${argv[$COMP_CWORD]}'" trace "argv len: '$len'"
_dashdash_complete 1 ""}
# ---- mainline
# Note: This if-block to help work with 'compdef' and 'compctl' is# adapted from 'npm completion'.if type complete &>/dev/null; then function _{{name}}_completion { local _log_file=/dev/null [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \ COMP_LINE="$COMP_LINE" \ COMP_POINT="$COMP_POINT" \ _{{name}}_completer -- "${COMP_WORDS[@]}" \ 2>$_log_file)) || return $? } complete -o default -F _{{name}}_completion {{name}}elif type compdef &>/dev/null; then function _{{name}}_completion { local _log_file=/dev/null [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" compadd -- $(COMP_CWORD=$((CURRENT-1)) \ COMP_LINE=$BUFFER \ COMP_POINT=0 \ _{{name}}_completer -- "${words[@]}" \ 2>$_log_file) } compdef _{{name}}_completion {{name}}elif type compctl &>/dev/null; then function _{{name}}_completion { local cword line point words si read -Ac words read -cn cword let cword-=1 read -l line read -ln point local _log_file=/dev/null [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" reply=($(COMP_CWORD="$cword" \ COMP_LINE="$line" \ COMP_POINT="$point" \ _{{name}}_completer -- "${words[@]}" \ 2>$_log_file)) || return $? } compctl -K _{{name}}_completion {{name}}fi
#### This is a Bash completion file for the '{{name}}' command. You can install## with either:#### cp FILE /usr/local/etc/bash_completion.d/{{name}} # Mac## cp FILE /etc/bash_completion.d/{{name}} # Linux#### or:#### cp FILE > ~/.{{name}}.completion## echo "source ~/.{{name}}.completion" >> ~/.bashrc##