diff --git a/CHANGELOG.md b/CHANGELOG.md index 003b0d5f..29956dd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Added support for all shell completions provided by `cobra`. + +### Changed +- Remove custom bash completion logic and replace it with `completion` command provided by `cobra`. ## [1.5.0] - 2022-07-05 ### Added diff --git a/internal/commands/all/all.go b/internal/commands/all/all.go index 27f02ba3..ce95c579 100644 --- a/internal/commands/all/all.go +++ b/internal/commands/all/all.go @@ -121,15 +121,6 @@ func BuildCommands(rootCmd *cobra.Command, conf *config.Config) { commands.BuildCommand(loadbalancer.ShowCommand(), loadbalancerCommand.Cobra(), conf) // Misc - commands.BuildCommand( - &root.CompletionCommand{ - BaseCommand: commands.New( - "completion", - "Generates shell completion", - "upctl completion bash", - ), - }, rootCmd, conf, - ) commands.BuildCommand( &root.VersionCommand{ BaseCommand: commands.New( diff --git a/internal/commands/bash_completion.go b/internal/commands/bash_completion.go deleted file mode 100644 index 604e7244..00000000 --- a/internal/commands/bash_completion.go +++ /dev/null @@ -1,79 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -// Override Cobra's custom completion function -// This fixes quoting of items with spaces -// TODO: get fixes submitted upstream, otherwise sooner or later something will break if we upgrade cobra -const goCustomCompletion = `__%[1]s_handle_go_custom_completion() -{ - __%[1]s_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}" - - local out requestComp lastParam lastChar comp directive args - - # Prepare the command to request completions for the program. - # Calling ${words[0]} instead of directly %[1]s allows to handle aliases - args=("${words[@]:1}") - requestComp="${words[0]} __completeNoDesc ${args[@]:0:$((${#args[@]}-1))} $'$cur'" - - lastParam=${words[$((${#words[@]}-1))]} - lastChar=${lastParam:$((${#lastParam}-1)):1} - __%[1]s_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}" - - if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then - # If the last parameter is complete (there is a space following it) - # We add an extra empty parameter so we can indicate this to the go method. - __%[1]s_debug "${FUNCNAME[0]}: Adding extra empty parameter" - requestComp="${requestComp} \"\"" - fi - - __%[1]s_debug "${FUNCNAME[0]}: calling ${requestComp}" - # Use eval to handle any environment variables and such - out=$(eval "${requestComp}" 2>/dev/null) - - # Extract the directive integer at the very end of the output following a colon (:) - directive=${out##*:} - # Remove the directive - out=${out%%:*} - if [ "${directive}" = "${out}" ]; then - # There is not directive specified - directive=0 - fi - __%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" - __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" - - if [ $((directive & %[3]d)) -ne 0 ]; then - # Error code. No completion. - __%[1]s_debug "${FUNCNAME[0]}: received error from custom completion go code" - return - else - if [ $((directive & %[4]d)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then - __%[1]s_debug "${FUNCNAME[0]}: activating no space" - compopt -o nospace - fi - fi - if [ $((directive & %[5]d)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then - __%[1]s_debug "${FUNCNAME[0]}: activating no file completion" - compopt +o default - fi - fi - - local IFS=$'\n' - COMPREPLY=($out) - fi -}` - -// CustomBashCompletionFunc returns a bash completion function used by cobras bash completion generator -func CustomBashCompletionFunc(name string) string { - return fmt.Sprintf(goCustomCompletion, name, - cobra.ShellCompNoDescRequestCmd, - cobra.ShellCompDirectiveError, - cobra.ShellCompDirectiveNoSpace, - cobra.ShellCompDirectiveNoFileComp) -} diff --git a/internal/commands/root/completion.go b/internal/commands/root/completion.go deleted file mode 100644 index 27f8dceb..00000000 --- a/internal/commands/root/completion.go +++ /dev/null @@ -1,31 +0,0 @@ -package root - -import ( - "bytes" - "fmt" - - "github.com/UpCloudLtd/upcloud-cli/internal/commands" - "github.com/UpCloudLtd/upcloud-cli/internal/output" - "github.com/UpCloudLtd/upcloud-cli/internal/resolver" -) - -// CompletionCommand creates shell completion scripts -type CompletionCommand struct { - *commands.BaseCommand - resolver.CompletionResolver -} - -// ExecuteSingleArgument implements commands.SingleArgumentCommand -func (s *CompletionCommand) ExecuteSingleArgument(_ commands.Executor, arg string) (output.Output, error) { - if arg == "bash" { - completion := new(bytes.Buffer) - err := s.Cobra().Root().GenBashCompletion(completion) - - return output.Raw(completion.Bytes()), err - } - - return nil, fmt.Errorf("completion for %s is not supported", arg) -} - -// DoesNotUseServices implements commands.OfflineCommand as this command does not use services -func (s *CompletionCommand) DoesNotUseServices() {} diff --git a/internal/completion/helpers.go b/internal/completion/helpers.go index 5ac40f75..805c7c35 100644 --- a/internal/completion/helpers.go +++ b/internal/completion/helpers.go @@ -1,7 +1,6 @@ package completion import ( - "fmt" "strings" ) @@ -9,22 +8,12 @@ import ( func MatchStringPrefix(vals []string, key string, caseSensitive bool) []string { var r []string key = strings.Trim(key, "'\"") - for _, v := range vals { if (caseSensitive && strings.HasPrefix(v, key)) || (!caseSensitive && strings.HasPrefix(strings.ToLower(v), strings.ToLower(key))) || key == "" { - r = append(r, Escape(v)) + r = append(r, v) } } return r } - -// Escape escapes a string according to completion rules (?) -// in effect, this means that the string will be quoted with double quotes if it contains a space or parentheses. -func Escape(s string) string { - if strings.ContainsAny(s, ` ()`) { - return fmt.Sprintf(`"%s"`, s) - } - return s -} diff --git a/internal/completion/helpers_test.go b/internal/completion/helpers_test.go index 5e0f2f1d..32934175 100644 --- a/internal/completion/helpers_test.go +++ b/internal/completion/helpers_test.go @@ -73,11 +73,11 @@ func TestMatchStringPrefix(t *testing.T) { expected: []string{"aba", "aBa", "Aba"}, }, { - name: "escaped output", + name: "output with special characters", vals: []string{"a a ", "a(0)", "aab", "a;