diff --git a/completer.go b/completer.go index c60604d..08b3254 100644 --- a/completer.go +++ b/completer.go @@ -7,6 +7,7 @@ import ( "github.com/carapace-sh/carapace/pkg/style" completer "github.com/carapace-sh/carapace/pkg/x" "github.com/reeflective/readline" + "github.com/spf13/cobra" "github.com/reeflective/console/internal/completion" "github.com/reeflective/console/internal/line" @@ -18,6 +19,7 @@ func (c *Console) complete(input []rune, pos int) readline.Completions { // Ensure the carapace library is called so that the function // completer.Complete() variable is correctly initialized before use. carapace.Gen(menu.Command) + hideCarapaceCommands(menu.Command) // Split the line as shell words, only using // what the right buffer (up to the cursor) @@ -32,10 +34,14 @@ func (c *Console) complete(input []rune, pos int) readline.Completions { // The completions are never nil: fill out our own object // with everything it contains, regardless of errors. - raw := make([]readline.Completion, len(completions.Values)) + raw := make([]readline.Completion, 0, len(completions.Values)) - for idx, val := range completions.Values { - raw[idx] = readline.Completion{ + for _, val := range completions.Values { + if strings.TrimSpace(val.Value) == "_carapace" { + continue + } + + comp := readline.Completion{ Value: line.UnescapeValue(prefixComp, prefixLine, val.Value), Display: val.Display, Description: val.Description, @@ -44,15 +50,17 @@ func (c *Console) complete(input []rune, pos int) readline.Completions { } if !completions.Nospace.Matches(val.Value) { - raw[idx].Value = val.Value + " " + comp.Value = val.Value + " " } // Remove short/long flags grouping // join to single tag group for classic zsh side-by-side view switch val.Tag { case "shorthand flags", "longhand flags": - raw[idx].Tag = "flags" + comp.Tag = "flags" } + + raw = append(raw, comp) } // Assign both completions and command/flags/args usage strings. @@ -131,6 +139,22 @@ func (c *Console) highlightSyntax(input []rune) string { return highlighted } +// hideCarapaceCommands recursively hides carapace's internal completion command. +func hideCarapaceCommands(root *cobra.Command) { + if root == nil { + return + } + + for _, cmd := range root.Commands() { + if cmd.Name() == "_carapace" { + cmd.Hidden = true + continue + } + + hideCarapaceCommands(cmd) + } +} + func (c *Console) computeHighlight(input []rune) string { // Split the line as shellwords args, unprocessed, err := line.Split(string(input), true) diff --git a/completer_test.go b/completer_test.go new file mode 100644 index 0000000..fdfa3d3 --- /dev/null +++ b/completer_test.go @@ -0,0 +1,40 @@ +package console + +import ( + "strings" + "testing" + + "github.com/reeflective/readline" + "github.com/spf13/cobra" +) + +func TestCompleteHidesCarapaceCommand(t *testing.T) { + c := New("test") + root := &cobra.Command{Use: "root"} + internal := &cobra.Command{Use: "_carapace"} + root.AddCommand(internal, &cobra.Command{Use: "visible"}) + c.activeMenu().Command = root + + comps := c.complete(nil, 0) + + if !internal.Hidden { + t.Fatal("_carapace command was not hidden") + } + + for _, value := range completionValues(comps) { + if strings.TrimSpace(value) == "_carapace" { + t.Fatalf("completion values include internal command: %v", completionValues(comps)) + } + } +} + +func completionValues(comps readline.Completions) []string { + var values []string + + comps.EachValue(func(comp readline.Completion) readline.Completion { + values = append(values, comp.Value) + return comp + }) + + return values +}