spf13 / cobra

A Commander for modern Go CLI interactions
https://cobra.dev
Apache License 2.0
38.09k stars 2.85k forks source link

Shell completions with whitespace seem to work differently on bash vs. other supported shells #1740

Open kangasta opened 2 years ago

kangasta commented 2 years ago

Other shell completions escape whitespace in completions, but bash completions seems to add completions with whitespace as multiple suggestions or multiple arguments depending on bash version. I would expect also bash completions to escape whitespace in completions from ValidArgsFunction.

bash v3:

$ ./sh-completion-demo whitespace [TAB][TAB]
no-whitespace    with whitespace
$ ./sh-completion-demo whitespace w[TAB]
$ ./sh-completion-demo whitespace with whitespace

bash v4 & v5

$ ./sh-completion-demo whitespace [TAB][TAB]
no-whitespace  whitespace     with 

fish:

> ./sh-completion-demo whitespace [TAB]
no-whitespace  with whitespace
> ./sh-completion-demo whitespace w[TAB]
> ./sh-completion-demo whitespace with\ whitespace

zsh:

% ./sh-completion-demo whitespace [TAB]
no-whitespace    with whitespace
% ./sh-completion-demo whitespace w[TAB]
% ./sh-completion-demo whitespace with\ whitespace

powershell

> .\sh-completion-demo.exe whitespace [TAB]
> .\sh-completion-demo.exe whitespace with` whitespace

Minimal code to reproduce above usage with github.com/spf13/cobra v1.5.0 (Gist):

package main

import (
    "fmt"
    "os"

    "github.com/spf13/cobra"
)

var RootCmd = &cobra.Command{
    Use:  "sh-completion-demo",
    Long: "Demo shell completion with whitespace",
}

var WhitespaceCmd = &cobra.Command{
    Use:   "whitespace",
    Short: "Noun with completion that includes whitespace",
    RunE: func(cmd *cobra.Command, args []string) error {
        if args[0] != "with whitespace" && args[0] != "no-whitespace" {
            return fmt.Errorf(`argument must be "with whitespace" or "no-whitespace"`)
        }
        return nil
    },
    SilenceUsage: true,
    ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
        return []string{"with whitespace", "no-whitespace"}, cobra.ShellCompDirectiveNoFileComp
    },
}

func init() {
    RootCmd.AddCommand(WhitespaceCmd)
}

func main() {
    if err := RootCmd.Execute(); err != nil {
        os.Exit(1)
    }
}
marckhouzam commented 2 years ago

@scop, you may have some expertise on this. Do you have special handling if a completion has a space in it for bash?

scop commented 2 years ago

Hi @kangasta ;)

It's annoyingly difficult in bash.

A cheap generic way is to fake the completions to be filenames. That does take care of the escaping, but it's obviously semantically incorrect for completions that really aren't filenames. And it may have side effects.

Another one is to run the strings through printf %q ... here and there in the completion code. Some related discussion e.g. at https://stackoverflow.com/questions/26509260/bash-tab-completion-with-spaces

Anyway I believe neither of these options is currently available for cobra users. I'll have a quick peek at PR #1743.

github-actions[bot] commented 2 years ago

The Cobra project currently lacks enough contributors to adequately respond to all issues. This bot triages issues and PRs according to the following rules:

kangasta commented 2 years ago

Rebased related PR and added comment there as well: #1743

github-actions[bot] commented 1 year ago

The Cobra project currently lacks enough contributors to adequately respond to all issues. This bot triages issues and PRs according to the following rules:

kangasta commented 1 year ago

Adding a comment to keep this from being closed.

JeffFaer commented 8 months ago

I ran across this the other day. This isn't just limited to whitespace, but all characters that need escaping in bash. My completions were using >, which is kinda unfortunate because cobra started redirecting output to random places during completion