github.com/simonferquel/app@v0.6.1-0.20181012141724-68b7cccf26ac/cmd/docker-app/completion.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/docker/cli/cli"
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/spf13/cobra"
    11  )
    12  
    13  func completionCmd(dockerCli command.Cli, rootCmd *cobra.Command) *cobra.Command {
    14  	return &cobra.Command{
    15  		Use:   "completion SHELL",
    16  		Short: "Generates completion scripts for the specified shell (bash or zsh)",
    17  		Long: `# Load the docker-app completion code for bash into the current shell
    18  . <(docker-app completion bash)
    19  # Set the docker-app completion code for bash to autoload on startup in your ~/.bashrc,
    20  # ~/.profile or ~/.bash_profile
    21  . <(docker-app completion bash)
    22  # Note: bash-completion is needed.
    23  
    24  # Load the docker-app completion code for zsh into the current shell
    25  source <(docker-app completion zsh)
    26  # Set the docker-app completion code for zsh to autoload on startup in your ~/.zshrc
    27  source <(docker-app completion zsh)
    28  `,
    29  		Args: cli.RequiresMaxArgs(1),
    30  		RunE: func(cmd *cobra.Command, args []string) error {
    31  			switch {
    32  			case len(args) == 0:
    33  				return rootCmd.GenBashCompletion(dockerCli.Out())
    34  			case args[0] == "bash":
    35  				return rootCmd.GenBashCompletion(dockerCli.Out())
    36  			case args[0] == "zsh":
    37  				return runCompletionZsh(dockerCli.Out(), rootCmd)
    38  			default:
    39  				return fmt.Errorf("%q is not a supported shell", args[0])
    40  			}
    41  		},
    42  	}
    43  }
    44  
    45  const (
    46  	// Largely inspired by https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/completion.go
    47  	zshHead = `#compdef dockerapp
    48  __dockerapp_bash_source() {
    49  	alias shopt=':'
    50  	alias _expand=_bash_expand
    51  	alias _complete=_bash_comp
    52  	emulate -L sh
    53  	setopt kshglob noshglob braceexpand
    54   	source "$@"
    55  }
    56   __dockerapp_type() {
    57  	# -t is not supported by zsh
    58  	if [ "$1" == "-t" ]; then
    59  		shift
    60   		# fake Bash 4 to disable "complete -o nospace". Instead
    61  		# "compopt +-o nospace" is used in the code to toggle trailing
    62  		# spaces. We don't support that, but leave trailing spaces on
    63  		# all the time
    64  		if [ "$1" = "__dockerapp_compopt" ]; then
    65  			echo builtin
    66  			return 0
    67  		fi
    68  	fi
    69  	type "$@"
    70  }
    71   __dockerapp_compgen() {
    72  	local completions w
    73  	completions=( $(compgen "$@") ) || return $?
    74   	# filter by given word as prefix
    75  	while [[ "$1" = -* && "$1" != -- ]]; do
    76  		shift
    77  		shift
    78  	done
    79  	if [[ "$1" == -- ]]; then
    80  		shift
    81  	fi
    82  	for w in "${completions[@]}"; do
    83  		if [[ "${w}" = "$1"* ]]; then
    84  			echo "${w}"
    85  		fi
    86  	done
    87  }
    88   __dockerapp_compopt() {
    89  	true # don't do anything. Not supported by bashcompinit in zsh
    90  }
    91   __dockerapp_ltrim_colon_completions()
    92  {
    93  	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
    94  		# Remove colon-word prefix from COMPREPLY items
    95  		local colon_word=${1%${1##*:}}
    96  		local i=${#COMPREPLY[*]}
    97  		while [[ $((--i)) -ge 0 ]]; do
    98  			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
    99  		done
   100  	fi
   101  }
   102   __dockerapp_get_comp_words_by_ref() {
   103  	cur="${COMP_WORDS[COMP_CWORD]}"
   104  	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
   105  	words=("${COMP_WORDS[@]}")
   106  	cword=("${COMP_CWORD[@]}")
   107  }
   108   __dockerapp_filedir() {
   109  	local RET OLD_IFS w qw
   110   	__debug "_filedir $@ cur=$cur"
   111  	if [[ "$1" = \~* ]]; then
   112  		# somehow does not work. Maybe, zsh does not call this at all
   113  		eval echo "$1"
   114  		return 0
   115  	fi
   116   	OLD_IFS="$IFS"
   117  	IFS=$'\n'
   118  	if [ "$1" = "-d" ]; then
   119  		shift
   120  		RET=( $(compgen -d) )
   121  	else
   122  		RET=( $(compgen -f) )
   123  	fi
   124  	IFS="$OLD_IFS"
   125   	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
   126   	for w in ${RET[@]}; do
   127  		if [[ ! "${w}" = "${cur}"* ]]; then
   128  			continue
   129  		fi
   130  		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
   131  			qw="$(__dockerapp_quote "${w}")"
   132  			if [ -d "${w}" ]; then
   133  				COMPREPLY+=("${qw}/")
   134  			else
   135  				COMPREPLY+=("${qw}")
   136  			fi
   137  		fi
   138  	done
   139  }
   140   __dockerapp_quote() {
   141      if [[ $1 == \'* || $1 == \"* ]]; then
   142          # Leave out first character
   143          printf %q "${1:1}"
   144      else
   145      	printf %q "$1"
   146      fi
   147  }
   148   autoload -U +X bashcompinit && bashcompinit
   149   # use word boundary patterns for BSD or GNU sed
   150  LWORD='[[:<:]]'
   151  RWORD='[[:>:]]'
   152  if sed --help 2>&1 | grep -q GNU; then
   153  	LWORD='\<'
   154  	RWORD='\>'
   155  fi
   156   __dockerapp_convert_bash_to_zsh() {
   157  	sed \
   158  	-e 's/declare -F/whence -w/' \
   159  	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
   160  	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
   161  	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
   162  	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
   163  	-e "s/${LWORD}_filedir${RWORD}/__dockerapp_filedir/g" \
   164  	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__dockerapp_get_comp_words_by_ref/g" \
   165  	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__dockerapp_ltrim_colon_completions/g" \
   166  	-e "s/${LWORD}compgen${RWORD}/__dockerapp_compgen/g" \
   167  	-e "s/${LWORD}compopt${RWORD}/__dockerapp_compopt/g" \
   168  	-e "s/${LWORD}declare${RWORD}/builtin declare/g" \
   169  	-e "s/\\\$(type${RWORD}/\$(__dockerapp_type/g" \
   170  	<<'BASH_COMPLETION_EOF'
   171  `
   172  	zshTail = `
   173  BASH_COMPLETION_EOF
   174  }
   175   __dockerapp_bash_source <(__dockerapp_convert_bash_to_zsh)
   176  _complete dockerapp 2>/dev/null
   177  `
   178  )
   179  
   180  func runCompletionZsh(out io.Writer, rootCmd *cobra.Command) error {
   181  	fmt.Fprint(out, zshHead)
   182  	buf := new(bytes.Buffer)
   183  	rootCmd.GenBashCompletion(buf)
   184  	fmt.Fprint(out, buf.String())
   185  	fmt.Fprint(out, zshTail)
   186  	return nil
   187  }