github.com/nickgerace/rancher-helm@v3.0.0-beta.3+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  	"io"
    21  
    22  	"github.com/pkg/errors"
    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 errors.New("shell not specified")
    67  	}
    68  	if len(args) > 1 {
    69  		return errors.New("too many arguments, expected only the shell type")
    70  	}
    71  	run, found := completionShells[args[0]]
    72  	if !found {
    73  		return errors.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_declare() {
   130  	if [ "$1" == "-F" ]; then
   131  		whence -w "$@"
   132  	else
   133  		builtin declare "$@"
   134  	fi
   135  }
   136  __helm_ltrim_colon_completions()
   137  {
   138  	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
   139  		# Remove colon-word prefix from COMPREPLY items
   140  		local colon_word=${1%${1##*:}}
   141  		local i=${#COMPREPLY[*]}
   142  		while [[ $((--i)) -ge 0 ]]; do
   143  			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
   144  		done
   145  	fi
   146  }
   147  __helm_get_comp_words_by_ref() {
   148  	cur="${COMP_WORDS[COMP_CWORD]}"
   149  	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
   150  	words=("${COMP_WORDS[@]}")
   151  	cword=("${COMP_CWORD[@]}")
   152  }
   153  __helm_filedir() {
   154  	local RET OLD_IFS w qw
   155  	__debug "_filedir $@ cur=$cur"
   156  	if [[ "$1" = \~* ]]; then
   157  		# somehow does not work. Maybe, zsh does not call this at all
   158  		eval echo "$1"
   159  		return 0
   160  	fi
   161  	OLD_IFS="$IFS"
   162  	IFS=$'\n'
   163  	if [ "$1" = "-d" ]; then
   164  		shift
   165  		RET=( $(compgen -d) )
   166  	else
   167  		RET=( $(compgen -f) )
   168  	fi
   169  	IFS="$OLD_IFS"
   170  	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
   171  	for w in ${RET[@]}; do
   172  		if [[ ! "${w}" = "${cur}"* ]]; then
   173  			continue
   174  		fi
   175  		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
   176  			qw="$(__helm_quote "${w}")"
   177  			if [ -d "${w}" ]; then
   178  				COMPREPLY+=("${qw}/")
   179  			else
   180  				COMPREPLY+=("${qw}")
   181  			fi
   182  		fi
   183  	done
   184  }
   185  __helm_quote() {
   186  	if [[ $1 == \'* || $1 == \"* ]]; then
   187  		# Leave out first character
   188  		printf %q "${1:1}"
   189  	else
   190  		printf %q "$1"
   191  	fi
   192  }
   193  autoload -U +X bashcompinit && bashcompinit
   194  # use word boundary patterns for BSD or GNU sed
   195  LWORD='[[:<:]]'
   196  RWORD='[[:>:]]'
   197  if sed --help 2>&1 | grep -q 'GNU\|BusyBox'; then
   198  	LWORD='\<'
   199  	RWORD='\>'
   200  fi
   201  __helm_convert_bash_to_zsh() {
   202  	sed \
   203  	-e 's/declare -F/whence -w/' \
   204  	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
   205  	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
   206  	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
   207  	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
   208  	-e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \
   209  	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \
   210  	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \
   211  	-e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \
   212  	-e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \
   213  	-e "s/${LWORD}declare${RWORD}/__helm_declare/g" \
   214  	-e "s/\\\$(type${RWORD}/\$(__helm_type/g" \
   215  	-e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \
   216  	<<'BASH_COMPLETION_EOF'
   217  `
   218  	out.Write([]byte(zshInitialization))
   219  
   220  	buf := new(bytes.Buffer)
   221  	cmd.Root().GenBashCompletion(buf)
   222  	out.Write(buf.Bytes())
   223  
   224  	zshTail := `
   225  BASH_COMPLETION_EOF
   226  }
   227  __helm_bash_source <(__helm_convert_bash_to_zsh)
   228  `
   229  	out.Write([]byte(zshTail))
   230  	return nil
   231  }