github.com/latiif/helm@v2.15.0+incompatible/cmd/helm/completion.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package main 17 18 import ( 19 "bytes" 20 "fmt" 21 "io" 22 23 "github.com/spf13/cobra" 24 ) 25 26 const completionDesc = ` 27 Generate autocompletions script for Helm for the specified shell (bash or zsh). 28 29 This command can generate shell autocompletions. e.g. 30 31 $ helm completion bash 32 33 Can be sourced as such 34 35 $ source <(helm completion bash) 36 ` 37 38 var ( 39 completionShells = map[string]func(out io.Writer, cmd *cobra.Command) error{ 40 "bash": runCompletionBash, 41 "zsh": runCompletionZsh, 42 } 43 ) 44 45 func newCompletionCmd(out io.Writer) *cobra.Command { 46 shells := []string{} 47 for s := range completionShells { 48 shells = append(shells, s) 49 } 50 51 cmd := &cobra.Command{ 52 Use: "completion SHELL", 53 Short: "Generate autocompletions script for the specified shell (bash or zsh)", 54 Long: completionDesc, 55 RunE: func(cmd *cobra.Command, args []string) error { 56 return runCompletion(out, cmd, args) 57 }, 58 ValidArgs: shells, 59 } 60 61 return cmd 62 } 63 64 func runCompletion(out io.Writer, cmd *cobra.Command, args []string) error { 65 if len(args) == 0 { 66 return fmt.Errorf("shell not specified") 67 } 68 if len(args) > 1 { 69 return fmt.Errorf("too many arguments, expected only the shell type") 70 } 71 run, found := completionShells[args[0]] 72 if !found { 73 return fmt.Errorf("unsupported shell type %q", args[0]) 74 } 75 76 return run(out, cmd) 77 } 78 79 func runCompletionBash(out io.Writer, cmd *cobra.Command) error { 80 return cmd.Root().GenBashCompletion(out) 81 } 82 83 func runCompletionZsh(out io.Writer, cmd *cobra.Command) error { 84 zshInitialization := `#compdef helm 85 86 __helm_bash_source() { 87 alias shopt=':' 88 alias _expand=_bash_expand 89 alias _complete=_bash_comp 90 emulate -L sh 91 setopt kshglob noshglob braceexpand 92 source "$@" 93 } 94 __helm_type() { 95 # -t is not supported by zsh 96 if [ "$1" == "-t" ]; then 97 shift 98 # fake Bash 4 to disable "complete -o nospace". Instead 99 # "compopt +-o nospace" is used in the code to toggle trailing 100 # spaces. We don't support that, but leave trailing spaces on 101 # all the time 102 if [ "$1" = "__helm_compopt" ]; then 103 echo builtin 104 return 0 105 fi 106 fi 107 type "$@" 108 } 109 __helm_compgen() { 110 local completions w 111 completions=( $(compgen "$@") ) || return $? 112 # filter by given word as prefix 113 while [[ "$1" = -* && "$1" != -- ]]; do 114 shift 115 shift 116 done 117 if [[ "$1" == -- ]]; then 118 shift 119 fi 120 for w in "${completions[@]}"; do 121 if [[ "${w}" = "$1"* ]]; then 122 echo "${w}" 123 fi 124 done 125 } 126 __helm_compopt() { 127 true # don't do anything. Not supported by bashcompinit in zsh 128 } 129 __helm_ltrim_colon_completions() 130 { 131 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then 132 # Remove colon-word prefix from COMPREPLY items 133 local colon_word=${1%${1##*:}} 134 local i=${#COMPREPLY[*]} 135 while [[ $((--i)) -ge 0 ]]; do 136 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} 137 done 138 fi 139 } 140 __helm_get_comp_words_by_ref() { 141 cur="${COMP_WORDS[COMP_CWORD]}" 142 prev="${COMP_WORDS[${COMP_CWORD}-1]}" 143 words=("${COMP_WORDS[@]}") 144 cword=("${COMP_CWORD[@]}") 145 } 146 __helm_filedir() { 147 local RET OLD_IFS w qw 148 __debug "_filedir $@ cur=$cur" 149 if [[ "$1" = \~* ]]; then 150 # somehow does not work. Maybe, zsh does not call this at all 151 eval echo "$1" 152 return 0 153 fi 154 OLD_IFS="$IFS" 155 IFS=$'\n' 156 if [ "$1" = "-d" ]; then 157 shift 158 RET=( $(compgen -d) ) 159 else 160 RET=( $(compgen -f) ) 161 fi 162 IFS="$OLD_IFS" 163 IFS="," __debug "RET=${RET[@]} len=${#RET[@]}" 164 for w in ${RET[@]}; do 165 if [[ ! "${w}" = "${cur}"* ]]; then 166 continue 167 fi 168 if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then 169 qw="$(__helm_quote "${w}")" 170 if [ -d "${w}" ]; then 171 COMPREPLY+=("${qw}/") 172 else 173 COMPREPLY+=("${qw}") 174 fi 175 fi 176 done 177 } 178 __helm_quote() { 179 if [[ $1 == \'* || $1 == \"* ]]; then 180 # Leave out first character 181 printf %q "${1:1}" 182 else 183 printf %q "$1" 184 fi 185 } 186 autoload -U +X bashcompinit && bashcompinit 187 # use word boundary patterns for BSD or GNU sed 188 LWORD='[[:<:]]' 189 RWORD='[[:>:]]' 190 if sed --help 2>&1 | grep -q 'GNU\|BusyBox'; then 191 LWORD='\<' 192 RWORD='\>' 193 fi 194 __helm_convert_bash_to_zsh() { 195 sed \ 196 -e 's/declare -F/whence -w/' \ 197 -e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ 198 -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ 199 -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ 200 -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ 201 -e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \ 202 -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \ 203 -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \ 204 -e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \ 205 -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ 206 -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ 207 -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ 208 -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ 209 -e 's/FUNCNAME/funcstack/g' \ 210 <<'BASH_COMPLETION_EOF' 211 ` 212 out.Write([]byte(zshInitialization)) 213 214 buf := new(bytes.Buffer) 215 cmd.Root().GenBashCompletion(buf) 216 out.Write(buf.Bytes()) 217 218 zshTail := ` 219 BASH_COMPLETION_EOF 220 } 221 __helm_bash_source <(__helm_convert_bash_to_zsh) 222 ` 223 out.Write([]byte(zshTail)) 224 return nil 225 }