From 823aa80750856a5d070e9686c4e5764728a3a325 Mon Sep 17 00:00:00 2001 From: rsteube Date: Tue, 26 Sep 2023 21:18:03 +0200 Subject: [PATCH] tmp --- compat.go | 13 +++++++------ compat_test.go | 4 ++-- context.go | 2 ++ example/cmd/compat.go | 9 +++++++++ example/cmd/compat_sub.go | 19 +++++++++++++++++++ example/cmd/compat_sub_test.go | 30 ++++++++++++++++++++++++++++++ storage.go | 6 +++--- traverse.go | 1 + 8 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 example/cmd/compat_sub.go create mode 100644 example/cmd/compat_sub_test.go diff --git a/compat.go b/compat.go index 2035fefe2..b61769658 100644 --- a/compat.go +++ b/compat.go @@ -32,7 +32,7 @@ func registerFlagCompletion(cmd *cobra.Command) { err := cmd.RegisterFlagCompletionFunc(f.Name, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { a := storage.getFlag(cmd, f.Name) - action := a.Invoke(Context{Args: args, Value: toComplete}) + action := a.Invoke(Context{Args: args, Value: toComplete}) // TODO cmd might differ for persistentflags and either way args or cmd will be wrong return cobraValuesFor(action), cobraDirectiveFor(action) }) if err != nil { @@ -64,14 +64,15 @@ func cobraDirectiveFor(action InvokedAction) cobra.ShellCompDirective { return directive } -func actionCobra(cmd *cobra.Command, f func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)) Action { +func ActionCobra(f func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)) Action { return ActionCallback(func(c Context) Action { - if f == nil { + switch { + case f == nil: return ActionValues() + case c.cmd == nil: + return ActionMessage("TODO: cmd is nil [ActionCobra]") // TODO test } - - c.Args = cmd.Flags().Args() // TODO verify - ensure it contains all args, this might not be correct at all times (e.g. changed Context.Args) - values, directive := f(cmd, c.Args, c.Value) + values, directive := f(c.cmd, c.cmd.Flags().Args(), c.Value) return compDirective(directive).ToA(values...) }) } diff --git a/compat_test.go b/compat_test.go index fa5590101..0e92024f0 100644 --- a/compat_test.go +++ b/compat_test.go @@ -1,7 +1,7 @@ package carapace import ( - "io/ioutil" + "io" "os" "strings" "testing" @@ -54,7 +54,7 @@ func TestRegisterFlagCompletion(t *testing.T) { _ = cmd.Execute() w.Close() - out, _ := ioutil.ReadAll(r) + out, _ := io.ReadAll(r) os.Stdout = rescueStdout if lines := strings.Split(string(out), "\n"); lines[0] != "1\tone" { diff --git a/context.go b/context.go index bdf02b4fa..984ea8d18 100644 --- a/context.go +++ b/context.go @@ -12,6 +12,7 @@ import ( "github.com/rsteube/carapace/pkg/util" "github.com/rsteube/carapace/third_party/github.com/drone/envsubst" "github.com/rsteube/carapace/third_party/golang.org/x/sys/execabs" + "github.com/spf13/cobra" ) // Context provides information during completion. @@ -28,6 +29,7 @@ type Context struct { Dir string mockedReplies map[string]string + cmd *cobra.Command } // NewContext creates a new context for given arguments. diff --git a/example/cmd/compat.go b/example/cmd/compat.go index 7005331e9..704f3a2a3 100644 --- a/example/cmd/compat.go +++ b/example/cmd/compat.go @@ -28,6 +28,7 @@ func init() { compatCmd.Flags().String("default", "", "ShellCompDirectiveDefault") compatCmd.Flags().String("unset", "", "no completions defined") + compatCmd.PersistentFlags().String("persistent-compat", "", "persistent flag defined with cobra") rootCmd.AddCommand(compatCmd) @@ -61,7 +62,15 @@ func init() { return nil, cobra.ShellCompDirectiveDefault }) + _ = compatCmd.RegisterFlagCompletionFunc("persistent-compat", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{ + fmt.Sprintf("args: %#v toComplete: %#v", args, toComplete), + "alternative", + }, cobra.ShellCompDirectiveNoFileComp + }) + compatCmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + args = cmd.Flags().Args() switch len(args) { case 0: return []string{"p1", "positional1"}, cobra.ShellCompDirectiveDefault diff --git a/example/cmd/compat_sub.go b/example/cmd/compat_sub.go new file mode 100644 index 000000000..e332a56e2 --- /dev/null +++ b/example/cmd/compat_sub.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/rsteube/carapace" + "github.com/spf13/cobra" +) + +var compat_subCmd = &cobra.Command{ + Use: "sub", + Short: "", + Run: func(cmd *cobra.Command, args []string) {}, +} + +func init() { + carapace.Gen(compat_subCmd).Standalone() + + + compatCmd.AddCommand(compat_subCmd) +} diff --git a/example/cmd/compat_sub_test.go b/example/cmd/compat_sub_test.go new file mode 100644 index 000000000..9fa70c27e --- /dev/null +++ b/example/cmd/compat_sub_test.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "testing" + + "github.com/rsteube/carapace" + "github.com/rsteube/carapace/pkg/sandbox" +) + +func TestCompatPersistent(t *testing.T) { + sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) { + s.Run("compat", "sub", "--persistent-compat", ""). + Expect(carapace.ActionValues( + `args: []string(nil) toComplete: ""`, + "alternative", + ).Usage("persistent flag defined with cobra")) + + s.Run("compat", "sub", "one", "--persistent-compat", ""). + Expect(carapace.ActionValues( + `args: []string{"one"} toComplete: ""`, + "alternative", + ).Usage("persistent flag defined with cobra")) + + s.Run("compat", "sub", "one", "two", "--persistent-compat", "a"). + Expect(carapace.ActionValues( + `args: []string{"one", "two"} toComplete: "a"`, + "alternative", + ).Usage("persistent flag defined with cobra")) + }) +} diff --git a/storage.go b/storage.go index ace2cd9b8..ede4fef50 100644 --- a/storage.go +++ b/storage.go @@ -95,7 +95,7 @@ func (s _storage) getFlag(cmd *cobra.Command, name string) Action { flagAction, ok := entry.flag[name] if !ok { if f, ok := cmd.GetFlagCompletionByName(name); ok { - flagAction = actionCobra(cmd, f) + flagAction = ActionCobra(f) } } @@ -162,7 +162,7 @@ func (s _storage) getPositional(cmd *cobra.Command, index int) Action { if entry.positionalAny != nil { a = *entry.positionalAny } else { - a = actionCobra(cmd, cmd.ValidArgsFunction) + a = ActionCobra(cmd.ValidArgsFunction) } case len(entry.dash) > index: a = entry.dash[index] @@ -170,7 +170,7 @@ func (s _storage) getPositional(cmd *cobra.Command, index int) Action { if entry.dashAny != nil { a = *entry.dashAny } else { - a = actionCobra(cmd, cmd.ValidArgsFunction) + a = ActionCobra(cmd.ValidArgsFunction) } } a = s.preinvoke(cmd, nil, a) diff --git a/traverse.go b/traverse.go index 900b63844..c4e2a3ced 100644 --- a/traverse.go +++ b/traverse.go @@ -26,6 +26,7 @@ func traverse(c *cobra.Command, args []string) (Action, Context) { fs := pflagfork.FlagSet{FlagSet: c.Flags()} context := NewContext(args...) + context.cmd = c loop: for i, arg := range context.Args { switch {