Skip to content

Commit

Permalink
Merge pull request #928 from rsteube/expose-actioncommands
Browse files Browse the repository at this point in the history
expose ActionCommands
  • Loading branch information
rsteube authored Oct 3, 2023
2 parents f492eb0 + fa284a2 commit 5101680
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 25 deletions.
34 changes: 34 additions & 0 deletions defaultActions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/rsteube/carapace/internal/common"
"github.com/rsteube/carapace/internal/config"
"github.com/rsteube/carapace/internal/env"
"github.com/rsteube/carapace/internal/export"
"github.com/rsteube/carapace/internal/man"
"github.com/rsteube/carapace/pkg/match"
Expand Down Expand Up @@ -480,3 +481,36 @@ func ActionPositional(cmd *cobra.Command) Action {
return a.Invoke(c).ToA()
})
}

// ActionCommands completes (sub)commands of given command.
// `Context.Args` is used to traverse the command tree further down. Use `Action.Shift` to avoid this.
//
// carapace.Gen(helpCmd).PositionalAnyCompletion(
// carapace.ActionCommands(rootCmd),
// )
func ActionCommands(cmd *cobra.Command) Action {
return ActionCallback(func(c Context) Action {
if len(c.Args) > 0 {
for _, subCommand := range cmd.Commands() {
for _, name := range append(subCommand.Aliases, subCommand.Name()) {
if name == c.Args[0] { // cmd.Find is too lenient
return ActionCommands(subCommand).Shift(1)
}
}
}
return ActionMessage("unknown subcommand %#v for %#v", c.Args[0], cmd.Name())
}

batch := Batch()
for _, subcommand := range cmd.Commands() {
if (!subcommand.Hidden || env.Hidden()) && subcommand.Deprecated == "" {
group := common.Group{Cmd: subcommand}
batch = append(batch, ActionStyledValuesDescribed(subcommand.Name(), subcommand.Short, group.Style()).Tag(group.Tag()))
for _, alias := range subcommand.Aliases {
batch = append(batch, ActionStyledValuesDescribed(alias, subcommand.Short, group.Style()).Tag(group.Tag()))
}
}
}
return batch.ToA()
})
}
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
- [ToMultiPartsA](./carapace/invokedAction/toMultiPartsA.md)
- [DefaultActions](./carapace/defaultActions.md)
- [ActionCallback](./carapace/defaultActions/actionCallback.md)
- [ActionCommands](./carapace/defaultActions/actionCommands.md)
- [ActionDirectories](./carapace/defaultActions/actionDirectories.md)
- [ActionExecCommand](./carapace/defaultActions/actionExecCommand.md)
- [ActionExecCommandE](./carapace/defaultActions/actionExecCommandE.md)
Expand Down
92 changes: 92 additions & 0 deletions docs/src/carapace/defaultActions/actionCommands.cast

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions docs/src/carapace/defaultActions/actionCommands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ActionCommands

[`ActionCommands`] completes (sub)commands of given command.

> `Context.Args` is used to traverse the command tree further down.
> Use [Shift](../action/shift.md) to avoid this.

```go
carapace.Gen(helpCmd).PositionalAnyCompletion(
carapace.ActionCommands(cmd),
)
```

![](./actionCommands.cast)

[`ActionCommands`]:https://pkg.go.dev/github.com/rsteube/carapace#ActionCommands
2 changes: 2 additions & 0 deletions example/cmd/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func init() {
rootCmd.AddCommand(actionCmd)

actionCmd.Flags().String("callback", "", "ActionCallback()")
actionCmd.Flags().String("commands", "", "ActionCommands()")
actionCmd.Flags().String("directories", "", "ActionDirectories()")
actionCmd.Flags().String("execcommand", "", "ActionExecCommand()")
actionCmd.Flags().String("execcommandE", "", "ActionExecCommand()")
Expand Down Expand Up @@ -48,6 +49,7 @@ func init() {
}
return carapace.ActionMessage("values flag is not set")
}),
"commands": carapace.ActionCommands(rootCmd).Split(),
"directories": carapace.ActionDirectories(),
"execcommand": carapace.ActionExecCommand("git", "remote")(func(output []byte) carapace.Action {
lines := strings.Split(string(output), "\n")
Expand Down
38 changes: 38 additions & 0 deletions example/cmd/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,44 @@ func TestAction(t *testing.T) {
Expect(carapace.ActionMessage("values flag is not set").
Usage("ActionCallback()"))

s.Run("action", "--commands", "s").
Expect(carapace.ActionValuesDescribed(
"special", "",
"subcommand", "subcommand example",
).Suffix(" ").
NoSpace().
Tag("other commands").
Usage("ActionCommands()"))

s.Run("action", "--commands", "subcommand ").
Expect(carapace.Batch(
carapace.ActionValuesDescribed(
"a1", "subcommand with alias",
"a2", "subcommand with alias",
"alias", "subcommand with alias",
).Tag("other commands"),
carapace.ActionValuesDescribed(
"group", "subcommand with group",
).Style(style.Blue).Tag("group commands"),
).ToA().
Prefix("subcommand ").
Suffix(" ").
NoSpace().
Usage("ActionCommands()"))

s.Run("action", "--commands", "subcommand unknown ").
Expect(carapace.ActionMessage(`unknown subcommand "unknown" for "subcommand"`).NoSpace().
Usage("ActionCommands()"))

s.Run("action", "--commands", "subcommand hidden ").
Expect(carapace.ActionValuesDescribed(
"visible", "visible subcommand of a hidden command",
).Prefix("subcommand hidden ").
Suffix(" ").
NoSpace().
Tag("commands").
Usage("ActionCommands()"))

s.Run("action", "--values", "first", "--callback", "").
Expect(carapace.ActionMessage("values flag is set to: 'first'").
Usage("ActionCallback()"))
Expand Down
1 change: 1 addition & 0 deletions example/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func TestRoot(t *testing.T) {
"interspersed", "interspersed example",
"multiparts", "multiparts example",
"special", "",
"subcommand", "subcommand example",
).Tag("other commands"),
).ToA())

Expand Down
22 changes: 22 additions & 0 deletions example/cmd/subcommand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var subcommandCmd = &cobra.Command{
Use: "subcommand",
Short: "subcommand example",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(subcommandCmd).Standalone()

subcommandCmd.AddGroup(
&cobra.Group{ID: "group", Title: ""},
)

rootCmd.AddCommand(subcommandCmd)
}
19 changes: 19 additions & 0 deletions example/cmd/subcommand_alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var subcommand_aliasCmd = &cobra.Command{
Use: "alias",
Short: "subcommand with alias",
Aliases: []string{"a1", "a2"},
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(subcommand_aliasCmd).Standalone()

subcommandCmd.AddCommand(subcommand_aliasCmd)
}
19 changes: 19 additions & 0 deletions example/cmd/subcommand_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var subcommand_groupCmd = &cobra.Command{
Use: "group",
Short: "subcommand with group",
GroupID: "group",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(subcommand_groupCmd).Standalone()

subcommandCmd.AddCommand(subcommand_groupCmd)
}
19 changes: 19 additions & 0 deletions example/cmd/subcommand_hidden.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var subcommand_hiddenCmd = &cobra.Command{
Use: "hidden",
Short: "hidden subcommand",
Hidden: true,
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(subcommand_hiddenCmd).Standalone()

subcommandCmd.AddCommand(subcommand_hiddenCmd)
}
18 changes: 18 additions & 0 deletions example/cmd/subcommand_hidden_visible.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cmd

import (
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

var subcommand_hidden_visibleCmd = &cobra.Command{
Use: "visible",
Short: "visible subcommand of a hidden command",
Run: func(cmd *cobra.Command, args []string) {},
}

func init() {
carapace.Gen(subcommand_hidden_visibleCmd).Standalone()

subcommand_hiddenCmd.AddCommand(subcommand_hidden_visibleCmd)
}
25 changes: 1 addition & 24 deletions internalActions.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"path/filepath"
"strings"

"github.com/rsteube/carapace/internal/common"
"github.com/rsteube/carapace/internal/env"
"github.com/rsteube/carapace/internal/pflagfork"
"github.com/rsteube/carapace/pkg/style"
Expand Down Expand Up @@ -133,22 +132,6 @@ func actionFlags(cmd *cobra.Command) Action {
}).Tag("flags")
}

func actionSubcommands(cmd *cobra.Command) Action {
return ActionCallback(func(c Context) Action {
batch := Batch()
for _, subcommand := range cmd.Commands() {
if (!subcommand.Hidden || env.Hidden()) && subcommand.Deprecated == "" {
group := common.Group{Cmd: subcommand}
batch = append(batch, ActionStyledValuesDescribed(subcommand.Name(), subcommand.Short, group.Style()).Tag(group.Tag()))
for _, alias := range subcommand.Aliases {
batch = append(batch, ActionStyledValuesDescribed(alias, subcommand.Short, group.Style()).Tag(group.Tag()))
}
}
}
return batch.ToA()
})
}

func initHelpCompletion(cmd *cobra.Command) {
helpCmd, _, err := cmd.Find([]string{"help"})
if err != nil {
Expand All @@ -162,12 +145,6 @@ func initHelpCompletion(cmd *cobra.Command) {
}

Gen(helpCmd).PositionalAnyCompletion(
ActionCallback(func(c Context) Action {
lastCmd, _, err := cmd.Find(c.Args)
if err != nil {
return ActionMessage(err.Error())
}
return actionSubcommands(lastCmd)
}),
ActionCommands(cmd),
)
}
2 changes: 1 addition & 1 deletion traverse.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ loop:
LOG.Printf("completing positionals and subcommands for arg %#v\n", context.Value)
batch := Batch(storage.getPositional(cmd, len(context.Args)))
if cmd.HasAvailableSubCommands() && len(context.Args) == 0 {
batch = append(batch, actionSubcommands(cmd))
batch = append(batch, ActionCommands(cmd))
}
return batch.ToA(), context
}
Expand Down

0 comments on commit 5101680

Please sign in to comment.