Skip to content

Commit 36b0bd8

Browse files
M09Icclaude
authored andcommitted
fix(completion): hide carapace internal command from completions
Carapace injects an internal _carapace command for completion plumbing. In an interactive console that implementation detail should never be offered as a user command: hide it recursively after carapace.Gen has initialized completion state, and filter it out when converting carapace values into readline completions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0199308 commit 36b0bd8

2 files changed

Lines changed: 70 additions & 5 deletions

File tree

completer.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/carapace-sh/carapace/pkg/style"
88
completer "github.com/carapace-sh/carapace/pkg/x"
99
"github.com/reeflective/readline"
10+
"github.com/spf13/cobra"
1011

1112
"github.com/reeflective/console/internal/completion"
1213
"github.com/reeflective/console/internal/line"
@@ -18,6 +19,7 @@ func (c *Console) complete(input []rune, pos int) readline.Completions {
1819
// Ensure the carapace library is called so that the function
1920
// completer.Complete() variable is correctly initialized before use.
2021
carapace.Gen(menu.Command)
22+
hideCarapaceCommands(menu.Command)
2123

2224
// Split the line as shell words, only using
2325
// what the right buffer (up to the cursor)
@@ -32,10 +34,14 @@ func (c *Console) complete(input []rune, pos int) readline.Completions {
3234

3335
// The completions are never nil: fill out our own object
3436
// with everything it contains, regardless of errors.
35-
raw := make([]readline.Completion, len(completions.Values))
37+
raw := make([]readline.Completion, 0, len(completions.Values))
3638

37-
for idx, val := range completions.Values {
38-
raw[idx] = readline.Completion{
39+
for _, val := range completions.Values {
40+
if strings.TrimSpace(val.Value) == "_carapace" {
41+
continue
42+
}
43+
44+
comp := readline.Completion{
3945
Value: line.UnescapeValue(prefixComp, prefixLine, val.Value),
4046
Display: val.Display,
4147
Description: val.Description,
@@ -44,15 +50,17 @@ func (c *Console) complete(input []rune, pos int) readline.Completions {
4450
}
4551

4652
if !completions.Nospace.Matches(val.Value) {
47-
raw[idx].Value = val.Value + " "
53+
comp.Value = val.Value + " "
4854
}
4955

5056
// Remove short/long flags grouping
5157
// join to single tag group for classic zsh side-by-side view
5258
switch val.Tag {
5359
case "shorthand flags", "longhand flags":
54-
raw[idx].Tag = "flags"
60+
comp.Tag = "flags"
5561
}
62+
63+
raw = append(raw, comp)
5664
}
5765

5866
// Assign both completions and command/flags/args usage strings.
@@ -115,6 +123,23 @@ func (c *Console) justifyCommandComps(comps readline.Completions) readline.Compl
115123
return comps
116124
}
117125

126+
// hideCarapaceCommands recursively hides carapace's internal completion command
127+
// so it is never offered as a normal user command in an interactive console.
128+
func hideCarapaceCommands(root *cobra.Command) {
129+
if root == nil {
130+
return
131+
}
132+
133+
for _, cmd := range root.Commands() {
134+
if cmd.Name() == "_carapace" {
135+
cmd.Hidden = true
136+
continue
137+
}
138+
139+
hideCarapaceCommands(cmd)
140+
}
141+
}
142+
118143
// highlightSyntax - Entrypoint to all input syntax highlighting in the Wiregost console.
119144
func (c *Console) highlightSyntax(input []rune) string {
120145
// Serve a memoized result when the input has not changed since the last

completer_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package console
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/reeflective/readline"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
func TestCompleteHidesCarapaceCommand(t *testing.T) {
12+
c := New("test")
13+
root := &cobra.Command{Use: "root"}
14+
internal := &cobra.Command{Use: "_carapace"}
15+
root.AddCommand(internal, &cobra.Command{Use: "visible"})
16+
c.activeMenu().Command = root
17+
18+
comps := c.complete(nil, 0)
19+
20+
if !internal.Hidden {
21+
t.Fatal("_carapace command was not hidden")
22+
}
23+
24+
for _, value := range completionValues(comps) {
25+
if strings.TrimSpace(value) == "_carapace" {
26+
t.Fatalf("completion values include internal command: %v", completionValues(comps))
27+
}
28+
}
29+
}
30+
31+
func completionValues(comps readline.Completions) []string {
32+
var values []string
33+
34+
comps.EachValue(func(comp readline.Completion) readline.Completion {
35+
values = append(values, comp.Value)
36+
return comp
37+
})
38+
39+
return values
40+
}

0 commit comments

Comments
 (0)