Skip to content

Commit 98e8f0a

Browse files
authored
Merge pull request #190 from rsteube/bridge-allow-empty
bridge: alle empty arguments
2 parents 5eda4c1 + b20e52a commit 98e8f0a

15 files changed

+514
-544
lines changed

pkg/actions/bridge/argcomplete.go

+59-61
Original file line numberDiff line numberDiff line change
@@ -29,77 +29,75 @@ import (
2929
// )
3030
// }
3131
func ActionArgcomplete(command ...string) carapace.Action {
32-
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
33-
if len(command) == 0 {
34-
return carapace.ActionMessage("missing argument [ActionArgcomplete]")
35-
}
36-
37-
if _, err := exec.LookPath(command[0]); err != nil {
38-
return carapace.ActionMessage(err.Error())
39-
}
32+
return actionCommand(command...)(func(command ...string) carapace.Action {
33+
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
34+
if _, err := exec.LookPath(command[0]); err != nil {
35+
return carapace.ActionMessage(err.Error())
36+
}
4037

41-
args := append(command[1:], c.Args...)
42-
current := c.Value
38+
args := append(command[1:], c.Args...)
39+
current := c.Value
4340

44-
prefix := ""
45-
if strings.HasPrefix(current, "--") {
46-
if strings.Contains(current, "=") { // optarg flag which is handled as normal arg by the completer
47-
splitted := strings.SplitN(current, "=", 2)
48-
prefix = splitted[0] + "="
49-
args = append(args, splitted[0]) // add flag as arg
50-
current = "" // seem partial optarg value isn't completed
41+
prefix := ""
42+
if strings.HasPrefix(current, "--") {
43+
if strings.Contains(current, "=") { // optarg flag which is handled as normal arg by the completer
44+
splitted := strings.SplitN(current, "=", 2)
45+
prefix = splitted[0] + "="
46+
args = append(args, splitted[0]) // add flag as arg
47+
current = "" // seem partial optarg value isn't completed
5148

49+
} else {
50+
current = "--" // seems partial flag names aren't completed so get all
51+
}
5252
} else {
53-
current = "--" // seems partial flag names aren't completed so get all
53+
current = "" // seems partial positional arguments aren't completed as well
5454
}
55-
} else {
56-
current = "" // seems partial positional arguments aren't completed as well
57-
}
5855

59-
compLine := command[0] + " " + strings.Join(append(args, current), " ") // TODO escape/quote special characters
60-
c.Setenv("_ARGCOMPLETE", "1")
61-
c.Setenv("_ARGCOMPLETE_DFS", "\t")
62-
c.Setenv("_ARGCOMPLETE_IFS", "\n")
63-
c.Setenv("_ARGCOMPLETE_SHELL", "fish")
64-
c.Setenv("_ARGCOMPLETE_SUPPRESS_SPACE", "1") // TODO needed? relevant for nospace detection?
65-
// c.Setenv("_ARGCOMPLETE_COMP_WORDBREAKS", " ") // TODO set to space-only for multiparts?
66-
c.Setenv("_ARGCOMPLETE", "1")
67-
c.Setenv("COMP_LINE", compLine)
68-
c.Setenv("COMP_POINT", strconv.Itoa(len(compLine)))
69-
nospace := false
70-
a := carapace.ActionExecCommand("sh", "-c", command[0]+" 8>&1 9>&2 1>/dev/null 2>/dev/null")(func(output []byte) carapace.Action {
71-
lines := strings.Split(string(output), "\n")
72-
vals := make([]string, 0)
73-
isFlag := strings.HasPrefix(c.Value, "-")
74-
for _, line := range lines[:len(lines)-1] {
75-
if !isFlag && strings.HasPrefix(line, "-") {
76-
continue
77-
}
78-
if strings.HasSuffix(line, "=") ||
79-
strings.HasSuffix(line, "/") ||
80-
strings.HasSuffix(line, ",") {
81-
nospace = true
82-
}
83-
if splitted := strings.SplitN(line, "\t", 2); splitted[0] != "" {
84-
vals = append(vals, splitted...)
85-
if len(splitted) < 2 {
86-
vals = append(vals, "")
56+
compLine := command[0] + " " + strings.Join(append(args, current), " ") // TODO escape/quote special characters
57+
c.Setenv("_ARGCOMPLETE", "1")
58+
c.Setenv("_ARGCOMPLETE_DFS", "\t")
59+
c.Setenv("_ARGCOMPLETE_IFS", "\n")
60+
c.Setenv("_ARGCOMPLETE_SHELL", "fish")
61+
c.Setenv("_ARGCOMPLETE_SUPPRESS_SPACE", "1") // TODO needed? relevant for nospace detection?
62+
// c.Setenv("_ARGCOMPLETE_COMP_WORDBREAKS", " ") // TODO set to space-only for multiparts?
63+
c.Setenv("_ARGCOMPLETE", "1")
64+
c.Setenv("COMP_LINE", compLine)
65+
c.Setenv("COMP_POINT", strconv.Itoa(len(compLine)))
66+
nospace := false
67+
a := carapace.ActionExecCommand("sh", "-c", command[0]+" 8>&1 9>&2 1>/dev/null 2>/dev/null")(func(output []byte) carapace.Action {
68+
lines := strings.Split(string(output), "\n")
69+
vals := make([]string, 0)
70+
isFlag := strings.HasPrefix(c.Value, "-")
71+
for _, line := range lines[:len(lines)-1] {
72+
if !isFlag && strings.HasPrefix(line, "-") {
73+
continue
74+
}
75+
if strings.HasSuffix(line, "=") ||
76+
strings.HasSuffix(line, "/") ||
77+
strings.HasSuffix(line, ",") {
78+
nospace = true
79+
}
80+
if splitted := strings.SplitN(line, "\t", 2); splitted[0] != "" {
81+
vals = append(vals, splitted...)
82+
if len(splitted) < 2 {
83+
vals = append(vals, "")
84+
}
8785
}
8886
}
89-
}
9087

91-
if len(vals) == 0 {
92-
// fallback to file completions when no values returned
93-
if index := strings.Index(c.Value, "="); index > -1 {
94-
return carapace.ActionFiles().Invoke(carapace.Context{Value: c.Value[index+1:]}).ToA()
88+
if len(vals) == 0 {
89+
// fallback to file completions when no values returned
90+
if index := strings.Index(c.Value, "="); index > -1 {
91+
return carapace.ActionFiles().Invoke(carapace.Context{Value: c.Value[index+1:]}).ToA()
92+
}
93+
return carapace.ActionFiles()
9594
}
96-
return carapace.ActionFiles()
95+
return carapace.ActionValuesDescribed(vals...)
96+
}).Invoke(c).Prefix(prefix).ToA() // re-add optarg prefix
97+
if nospace {
98+
return a.NoSpace()
9799
}
98-
return carapace.ActionValuesDescribed(vals...)
99-
}).Invoke(c).Prefix(prefix).ToA() // re-add optarg prefix
100-
if nospace {
101-
return a.NoSpace()
102-
}
103-
return a
100+
return a
101+
})
104102
})
105103
}

pkg/actions/bridge/bash.go

+44-46
Original file line numberDiff line numberDiff line change
@@ -18,59 +18,57 @@ var bashSnippet string
1818
// ActionBash bridges completions registered in bash
1919
// (uses custom `.bashrc` in “~/.config/carapace/bridge/bash`)
2020
func ActionBash(command ...string) carapace.Action {
21-
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
22-
if len(command) == 0 {
23-
return carapace.ActionMessage("missing argument [ActionBash]")
24-
}
25-
26-
configDir, err := xdg.UserConfigDir()
27-
if err != nil {
28-
return carapace.ActionMessage(err.Error())
29-
}
21+
return actionCommand(command...)(func(command ...string) carapace.Action {
22+
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
23+
configDir, err := xdg.UserConfigDir()
24+
if err != nil {
25+
return carapace.ActionMessage(err.Error())
26+
}
3027

31-
args := append(command, c.Args...)
32-
args = append(args, c.Value)
28+
args := append(command, c.Args...)
29+
args = append(args, c.Value)
3330

34-
configPath := fmt.Sprintf("%v/carapace/bridge/bash/.bashrc", configDir)
35-
if err := ensureExists(configPath); err != nil {
36-
return carapace.ActionMessage(err.Error())
37-
}
31+
configPath := fmt.Sprintf("%v/carapace/bridge/bash/.bashrc", configDir)
32+
if err := ensureExists(configPath); err != nil {
33+
return carapace.ActionMessage(err.Error())
34+
}
3835

39-
joined := shlex.Join(args)
40-
if c.Value == "" {
41-
joined = strings.TrimSuffix(joined, `""`)
42-
}
43-
c.Setenv("COMP_LINE", joined)
36+
joined := shlex.Join(args)
37+
if c.Value == "" {
38+
joined = strings.TrimSuffix(joined, `""`)
39+
}
40+
c.Setenv("COMP_LINE", joined)
4441

45-
file, err := os.CreateTemp(os.TempDir(), "carapace-bridge_bash_*")
46-
if err != nil {
47-
return carapace.ActionMessage(err.Error())
48-
}
49-
defer os.Remove(file.Name())
42+
file, err := os.CreateTemp(os.TempDir(), "carapace-bridge_bash_*")
43+
if err != nil {
44+
return carapace.ActionMessage(err.Error())
45+
}
46+
defer os.Remove(file.Name())
5047

51-
os.WriteFile(file.Name(), []byte(bashSnippet), os.ModePerm)
48+
os.WriteFile(file.Name(), []byte(bashSnippet), os.ModePerm)
5249

53-
return carapace.ActionExecCommand("bash", "--rcfile", configPath, "-i", file.Name())(func(output []byte) carapace.Action {
54-
lines := strings.Split(string(output), "\n")
50+
return carapace.ActionExecCommand("bash", "--rcfile", configPath, "-i", file.Name())(func(output []byte) carapace.Action {
51+
lines := strings.Split(string(output), "\n")
5552

56-
vals := make([]string, 0)
57-
for _, line := range lines[:len(lines)-1] {
58-
if splitted := strings.SplitN(line, "(", 2); len(splitted) == 2 {
59-
// assume results contain descriptions in the format `value (description)` (spf13/cobra, rsteube/carapace)
60-
vals = append(vals,
61-
strings.TrimSpace(splitted[0]),
62-
strings.TrimSpace(strings.TrimSuffix(splitted[1], ")")),
63-
)
64-
} else {
65-
vals = append(vals, strings.TrimSpace(line), "")
53+
vals := make([]string, 0)
54+
for _, line := range lines[:len(lines)-1] {
55+
if splitted := strings.SplitN(line, "(", 2); len(splitted) == 2 {
56+
// assume results contain descriptions in the format `value (description)` (spf13/cobra, rsteube/carapace)
57+
vals = append(vals,
58+
strings.TrimSpace(splitted[0]),
59+
strings.TrimSpace(strings.TrimSuffix(splitted[1], ")")),
60+
)
61+
} else {
62+
vals = append(vals, strings.TrimSpace(line), "")
63+
}
6664
}
67-
}
68-
switch len(vals) {
69-
case 0:
70-
return carapace.ActionFiles()
71-
default:
72-
return carapace.ActionValuesDescribed(vals...).StyleF(style.ForPath)
73-
}
74-
}).Invoke(c).ToA().NoSpace([]rune("/=@:.,")...) // TODO check compopt for nospace
65+
switch len(vals) {
66+
case 0:
67+
return carapace.ActionFiles()
68+
default:
69+
return carapace.ActionValuesDescribed(vals...).StyleF(style.ForPath)
70+
}
71+
}).Invoke(c).ToA().NoSpace([]rune("/=@:.,")...) // TODO check compopt for nospace
72+
})
7573
})
7674
}

pkg/actions/bridge/bridge.go

+53-55
Original file line numberDiff line numberDiff line change
@@ -10,66 +10,64 @@ import (
1010

1111
// Bridges bridges completions as defined in bridges.yaml and CARAPACE_BRIDGE environment variable
1212
func ActionBridges(command ...string) carapace.Action {
13-
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
14-
if len(command) == 0 {
15-
return carapace.ActionMessage("missing argument [ActionBridges]")
16-
}
17-
18-
if bridge, ok := bridges.Config()[command[0]]; ok {
19-
switch bridge {
20-
case "argcomplete":
21-
return ActionArgcomplete(command...)
22-
case "bash":
23-
return ActionBash(command...)
24-
case "carapace":
25-
return ActionCarapace(command...)
26-
case "clap":
27-
return ActionClap(command...)
28-
case "click":
29-
return ActionClick(command...)
30-
case "cobra":
31-
return ActionCobra(command...)
32-
case "complete":
33-
return ActionComplete(command...)
34-
case "fish":
35-
return ActionFish(command...)
36-
case "inshellisense":
37-
return ActionInshellisense(command...)
38-
case "kingpin":
39-
return ActionKingpin(command...)
40-
case "powershell":
41-
return ActionPowershell(command...)
42-
case "urfavecli":
43-
return ActionUrfavecli(command...)
44-
case "yargs":
45-
return ActionYargs(command...)
46-
case "zsh":
47-
return ActionZsh(command...)
48-
default:
49-
return carapace.ActionMessage("unknown bridge: %v", bridge)
50-
}
51-
}
52-
53-
for _, b := range env.Bridges() {
54-
switch b {
55-
case "bash":
56-
if slices.Contains(bridges.Bash(), command[0]) {
13+
return actionCommand(command...)(func(command ...string) carapace.Action {
14+
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
15+
if bridge, ok := bridges.Config()[command[0]]; ok {
16+
switch bridge {
17+
case "argcomplete":
18+
return ActionArgcomplete(command...)
19+
case "bash":
5720
return ActionBash(command...)
58-
}
59-
case "fish":
60-
if slices.Contains(bridges.Fish(), command[0]) {
21+
case "carapace":
22+
return ActionCarapace(command...)
23+
case "clap":
24+
return ActionClap(command...)
25+
case "click":
26+
return ActionClick(command...)
27+
case "cobra":
28+
return ActionCobra(command...)
29+
case "complete":
30+
return ActionComplete(command...)
31+
case "fish":
6132
return ActionFish(command...)
62-
}
63-
case "inshellisense":
64-
if slices.Contains(bridges.Inshellisense(), command[0]) {
33+
case "inshellisense":
6534
return ActionInshellisense(command...)
66-
}
67-
case "zsh":
68-
if slices.Contains(bridges.Zsh(), command[0]) {
35+
case "kingpin":
36+
return ActionKingpin(command...)
37+
case "powershell":
38+
return ActionPowershell(command...)
39+
case "urfavecli":
40+
return ActionUrfavecli(command...)
41+
case "yargs":
42+
return ActionYargs(command...)
43+
case "zsh":
6944
return ActionZsh(command...)
45+
default:
46+
return carapace.ActionMessage("unknown bridge: %v", bridge)
47+
}
48+
}
49+
50+
for _, b := range env.Bridges() {
51+
switch b {
52+
case "bash":
53+
if slices.Contains(bridges.Bash(), command[0]) {
54+
return ActionBash(command...)
55+
}
56+
case "fish":
57+
if slices.Contains(bridges.Fish(), command[0]) {
58+
return ActionFish(command...)
59+
}
60+
case "inshellisense":
61+
if slices.Contains(bridges.Inshellisense(), command[0]) {
62+
return ActionInshellisense(command...)
63+
}
64+
case "zsh":
65+
if slices.Contains(bridges.Zsh(), command[0]) {
66+
return ActionZsh(command...)
67+
}
7068
}
7169
}
72-
}
73-
return carapace.ActionValues()
70+
return carapace.ActionValues()
71+
})
7472
})
7573
}

pkg/actions/bridge/carapace.go

+12-14
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,18 @@ import (
1111

1212
// ActionCarapace bridges https://github.com/rsteube/carapace
1313
func ActionCarapace(command ...string) carapace.Action {
14-
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
15-
if len(command) == 0 {
16-
return carapace.ActionMessage("missing argument [ActionCarapace]")
17-
}
18-
19-
args := []string{"_carapace", "export", ""}
20-
args = append(args, command[1:]...)
21-
args = append(args, c.Args...)
22-
args = append(args, c.Value)
23-
return carapace.ActionExecCommand(command[0], args...)(func(output []byte) carapace.Action {
24-
if string(output) == "" {
25-
return carapace.ActionValues()
26-
}
27-
return carapace.ActionImport(output)
14+
return actionCommand(command...)(func(command ...string) carapace.Action {
15+
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
16+
args := []string{"_carapace", "export", ""}
17+
args = append(args, command[1:]...)
18+
args = append(args, c.Args...)
19+
args = append(args, c.Value)
20+
return carapace.ActionExecCommand(command[0], args...)(func(output []byte) carapace.Action {
21+
if string(output) == "" {
22+
return carapace.ActionValues()
23+
}
24+
return carapace.ActionImport(output)
25+
})
2826
})
2927
})
3028
}

0 commit comments

Comments
 (0)