github.com/pensu/helm@v2.6.1+incompatible/cmd/helm/completion.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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 := `
    85  __helm_bash_source() {
    86  	alias shopt=':'
    87  	alias _expand=_bash_expand
    88  	alias _complete=_bash_comp
    89  	emulate -L sh
    90  	setopt kshglob noshglob braceexpand
    91  	source "$@"
    92  }
    93  __helm_type() {
    94  	# -t is not supported by zsh
    95  	if [ "$1" == "-t" ]; then
    96  		shift
    97  		# fake Bash 4 to disable "complete -o nospace". Instead
    98  		# "compopt +-o nospace" is used in the code to toggle trailing
    99  		# spaces. We don't support that, but leave trailing spaces on
   100  		# all the time
   101  		if [ "$1" = "__helm_compopt" ]; then
   102  			echo builtin
   103  			return 0
   104  		fi
   105  	fi
   106  	type "$@"
   107  }
   108  __helm_compgen() {
   109  	local completions w
   110  	completions=( $(compgen "$@") ) || return $?
   111  	# filter by given word as prefix
   112  	while [[ "$1" = -* && "$1" != -- ]]; do
   113  		shift
   114  		shift
   115  	done
   116  	if [[ "$1" == -- ]]; then
   117  		shift
   118  	fi
   119  	for w in "${completions[@]}"; do
   120  		if [[ "${w}" = "$1"* ]]; then
   121  			echo "${w}"
   122  		fi
   123  	done
   124  }
   125  __helm_compopt() {
   126  	true # don't do anything. Not supported by bashcompinit in zsh
   127  }
   128  __helm_declare() {
   129  	if [ "$1" == "-F" ]; then
   130  		whence -w "$@"
   131  	else
   132  		builtin declare "$@"
   133  	fi
   134  }
   135  __helm_ltrim_colon_completions()
   136  {
   137  	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
   138  		# Remove colon-word prefix from COMPREPLY items
   139  		local colon_word=${1%${1##*:}}
   140  		local i=${#COMPREPLY[*]}
   141  		while [[ $((--i)) -ge 0 ]]; do
   142  			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
   143  		done
   144  	fi
   145  }
   146  __helm_get_comp_words_by_ref() {
   147  	cur="${COMP_WORDS[COMP_CWORD]}"
   148  	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
   149  	words=("${COMP_WORDS[@]}")
   150  	cword=("${COMP_CWORD[@]}")
   151  }
   152  __helm_filedir() {
   153  	local RET OLD_IFS w qw
   154  	__debug "_filedir $@ cur=$cur"
   155  	if [[ "$1" = \~* ]]; then
   156  		# somehow does not work. Maybe, zsh does not call this at all
   157  		eval echo "$1"
   158  		return 0
   159  	fi
   160  	OLD_IFS="$IFS"
   161  	IFS=$'\n'
   162  	if [ "$1" = "-d" ]; then
   163  		shift
   164  		RET=( $(compgen -d) )
   165  	else
   166  		RET=( $(compgen -f) )
   167  	fi
   168  	IFS="$OLD_IFS"
   169  	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
   170  	for w in ${RET[@]}; do
   171  		if [[ ! "${w}" = "${cur}"* ]]; then
   172  			continue
   173  		fi
   174  		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
   175  			qw="$(__helm_quote "${w}")"
   176  			if [ -d "${w}" ]; then
   177  				COMPREPLY+=("${qw}/")
   178  			else
   179  				COMPREPLY+=("${qw}")
   180  			fi
   181  		fi
   182  	done
   183  }
   184  __helm_quote() {
   185  	if [[ $1 == \'* || $1 == \"* ]]; then
   186  		# Leave out first character
   187  		printf %q "${1:1}"
   188  	else
   189  		printf %q "$1"
   190  	fi
   191  }
   192  autoload -U +X bashcompinit && bashcompinit
   193  # use word boundary patterns for BSD or GNU sed
   194  LWORD='[[:<:]]'
   195  RWORD='[[:>:]]'
   196  if sed --help 2>&1 | grep -q GNU; then
   197  	LWORD='\<'
   198  	RWORD='\>'
   199  fi
   200  __helm_convert_bash_to_zsh() {
   201  	sed \
   202  	-e 's/declare -F/whence -w/' \
   203  	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
   204  	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
   205  	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
   206  	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
   207  	-e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \
   208  	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \
   209  	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \
   210  	-e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \
   211  	-e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \
   212  	-e "s/${LWORD}declare${RWORD}/__helm_declare/g" \
   213  	-e "s/\\\$(type${RWORD}/\$(__helm_type/g" \
   214  	<<'BASH_COMPLETION_EOF'
   215  `
   216  	out.Write([]byte(zshInitialization))
   217  
   218  	buf := new(bytes.Buffer)
   219  	cmd.Root().GenBashCompletion(buf)
   220  	out.Write(buf.Bytes())
   221  
   222  	zshTail := `
   223  BASH_COMPLETION_EOF
   224  }
   225  __helm_bash_source <(__helm_convert_bash_to_zsh)
   226  `
   227  	out.Write([]byte(zshTail))
   228  	return nil
   229  }