github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/data/completion/bash/etelpmoc.sh (about) 1 # shellcheck shell=bash 2 # 3 # Copyright (C) 2017 Canonical Ltd 4 # 5 # This program is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License version 3 as 7 # published by the Free Software Foundation. 8 # 9 # This program is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 # etelpmoc is the reverse of complete: it de-serialises the tab completion 18 # request into the appropriate environment variables expected by the tab 19 # completion tools, performs whatever action is wanted, and serialises the 20 # result. It accomplishes this by having functions override the builtin 21 # completion commands. 22 # 23 # this always runs "inside", in the same environment you get when doing "snap 24 # run --shell", and snap-exec is the one setting the first argument to the 25 # completion script set in the snap. The rest of the arguments come through 26 # from snap-run --command=complete <snap> <args...> 27 28 _die() { 29 echo "$*" >&2 30 exit 1 31 } 32 33 if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then 34 _die "ERROR: this is meant to be run, not sourced." 35 fi 36 37 if [[ "${#@}" -lt 8 ]]; then 38 _die "USAGE: $0 <script> <COMP_TYPE> <COMP_KEY> <COMP_POINT> <COMP_CWORD> <COMP_WORDBREAKS> <COMP_LINE> cmd [args...]" 39 fi 40 41 # De-serialize the command line arguments and populate tab completion environment 42 _compscript="$1" 43 shift 44 COMP_TYPE="$1" 45 shift 46 COMP_KEY="$1" 47 shift 48 COMP_POINT="$1" 49 shift 50 COMP_CWORD="$1" 51 shift 52 COMP_WORDBREAKS="$1" 53 shift 54 # duplication, but whitespace is eaten and that throws off COMP_POINT 55 COMP_LINE="$1" 56 shift 57 # rest of the args is the command itself 58 COMP_WORDS=("$@") 59 60 COMPREPLY=() 61 62 if [[ ! "$_compscript" ]]; then 63 _die "ERROR: completion script filename can't be empty" 64 fi 65 if [[ ! -f "$_compscript" ]]; then 66 _die "ERROR: completion script does not exist" 67 fi 68 69 # Source the bash-completion library functions and common completion setup 70 # shellcheck disable=SC1091 71 . /usr/share/bash-completion/bash_completion 72 # Now source the snap's 'completer' script itself 73 # shellcheck disable=SC1090 74 . "$_compscript" 75 76 # _compopts is an associative array, which keys are options. The options are 77 # described in bash(1)'s description of the -o option to the "complete" 78 # builtin, and they affect how the completion options are presented to the user 79 # (e.g. adding a slash for directories, whether to add a space after the 80 # completion, etc). These need setting in the user's environment so need 81 # serializing separately from the completions themselves. 82 declare -A _compopts 83 84 # wrap compgen, setting _compopts for any options given. 85 # (as these options need handling separately from the completions) 86 compgen() { 87 local opt 88 89 while getopts :o: opt; do 90 case "$opt" in 91 o) 92 _compopts["$OPTARG"]=1 93 ;; 94 *) 95 # Do nothing, explicitly. This silences shellcheck's detector 96 # of unhandled command line options. 97 ;; 98 esac 99 done 100 builtin compgen "$@" 101 } 102 103 # compopt replaces the original compopt with one that just sets/unsets entries 104 # in _compopts 105 compopt() { 106 local i 107 108 for ((i=0; i<$#; i++)); do 109 # in bash, ${!x} does variable indirection. Thus if x=1, ${!x} becomes $1. 110 case "${!i}" in 111 -o) 112 ((i++)) 113 _compopts[${!i}]=1 114 ;; 115 +o) 116 ((i++)) 117 unset _compopts[${!i}] 118 ;; 119 esac 120 done 121 } 122 123 _compfunc="_minimal" 124 _compact="" 125 # this is a lot more complicated than it should be, but it's how you 126 # get the result of 'complete -p "$1"' into an array, splitting it as 127 # the shell would. 128 readarray -t _comp < <(xargs -n1 < <(complete -p "$1") ) 129 # _comp is now an array of the appropriate 'complete' invocation, word-split as 130 # the shell would, so we can now inspect it with getopts to determine the 131 # appropriate completion action. 132 # Unfortunately shellcheck doesn't know about readarray: 133 # shellcheck disable=SC2154 134 if [[ "${_comp[*]}" ]]; then 135 while getopts :abcdefgjksuvA:C:W:o:F: opt "${_comp[@]:1}"; do 136 case "$opt" in 137 a) 138 _compact="alias" 139 ;; 140 b) 141 _compact="builtin" 142 ;; 143 c) 144 _compact="command" 145 ;; 146 d) 147 _compact="directory" 148 ;; 149 e) 150 _compact="export" 151 ;; 152 f) 153 _compact="file" 154 ;; 155 g) 156 _compact="group" 157 ;; 158 j) 159 _compact="job" 160 ;; 161 k) 162 _compact="keyword" 163 ;; 164 s) 165 _compact="service" 166 ;; 167 u) 168 _compact="user" 169 ;; 170 v) 171 _compact="variable" 172 ;; 173 A) 174 _compact="$OPTARG" 175 ;; 176 o) 177 _compopts["$OPTARG"]=1 178 ;; 179 C|F) 180 _compfunc="$OPTARG" 181 ;; 182 W) 183 readarray -t COMPREPLY < <( builtin compgen -W "$OPTARG" -- "${COMP_WORDS[COMP_CWORD]}" ) 184 _compfunc="" 185 ;; 186 *) 187 # P, G, S, and X are not supported yet 188 _die "ERROR: unknown option -$OPTARG" 189 ;; 190 esac 191 done 192 fi 193 194 _bounce="" 195 case "$_compact" in 196 # these are for completing things that'll be interpreted by the 197 # "outside" bash, so send them back to be completed there. 198 "alias"|"export"|"job"|"variable") 199 _bounce="$_compact" 200 ;; 201 esac 202 203 if [ ! "$_bounce" ]; then 204 if [ "$_compact" ]; then 205 readarray -t COMPREPLY < <( builtin compgen -A "$_compact" -- "${COMP_WORDS[COMP_CWORD]}" ) 206 elif [ "$_compfunc" ]; then 207 # execute completion function (or the command if -C) 208 209 # from https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html: 210 # When the function or command is invoked, the first argument ($1) is 211 # the name of the command whose arguments are being completed, the 212 # second argument ($2) is the word being completed, and the third 213 # argument ($3) is the word preceding the word being completed on the 214 # current command line. 215 # that's "$1" "${COMP_WORDS[COMP_CWORD]}" and "${COMP_WORDS[COMP_CWORD-1]}" 216 # (probably) 217 $_compfunc "$1" "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD-1]}" 218 fi 219 fi 220 221 # print completions to stdout 222 echo "${!_compopts[@]}" 223 echo "$_bounce" 224 echo "" 225 printf "%s\\n" "${COMPREPLY[@]}"