package cmd import ( "io" "text/template" "go.fifitido.net/cmd/opt" ) func WriteBashCompletions(out io.Writer, rootCmd *Command) error { return bashTpl.Execute(out, map[string]any{ "RootCmd": rootCmd, "GlobalOpts": opt.Globals(), }) } // TODO: Add --option|--other-option...) to return nothing for options that require a value // TODO: Add descriptions to completions using https://stackoverflow.com/a/10130007 var bashTpl = template.Must(template.New("bash").Funcs(tplFuncs).Parse(` {{- $rootCmd := .RootCmd -}} {{- $progName := $rootCmd.Name -}} {{- $varName := under $rootCmd.Name -}} {{- define "cmd" }} {{ $currIdx := .Index -}} {{- $nextIdx := inc .Index -}} {{- $indentSize := mult $currIdx 2 -}} {{ indent $indentSize }}"{{ .Cmd.Name }}") {{ indent $indentSize }} case ${COMP_WORDS[{{ $currIdx }}]} in {{ indent $indentSize }} {{ range .Cmd.Subcommands -}} {{ indent $indentSize }} {{ template "cmd" (map "Cmd" . "Index" $nextIdx) -}} {{ indent $indentSize }} {{ end }} {{ indent $indentSize }} *) {{ indent $indentSize }} COMPREPLY=($(compgen -W "{{ join .Cmd.Subcommands.Names " " }} {{ join .Cmd.Opts.Names " " }}" -- $curr)) {{ indent $indentSize }} ;; {{ indent $indentSize }} esac {{ indent $indentSize }};; # {{ .Cmd.Name }} {{- end -}} _{{$varName}}_completions() { COMPREPLY=() case ${COMP_WORDS[1]} in {{- range .RootCmd.Subcommands -}} {{ template "cmd" (map "Cmd" . "Index" 2) -}} {{ end }} *) COMPREPLY=($(compgen -W "{{ join .RootCmd.Subcommands.Names " " }} {{ join .RootCmd.Opts.Names " " }}" -- $curr)) ;; esac # Global Options COMPREPLY+=($(compgen -W "{{ join .GlobalOpts.Names " " }}" -- $curr)) } complete -F _{{$varName}}_completions {{$progName}} `))