github.com/sdbaiguanghe/helm@v2.16.7+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  }