Update the autocompletion logic to return `Completion` struct:
type Completion struct {
Value string
Description string
}
This will allow application that uses autocompletion to do what it wants
with the description.
Implements: https://todo.sr.ht/~rjarry/aerc/271
Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
---
Not sure if the function that's passed to the "complete" argument should
return `[]Completion`?
README.md | 4 ++++
complete.go | 29 +++++++++++++++++++----------
opt.go | 2 +-
3 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index e2f5590..e942094 100644
--- a/README.md
+++ b/README.md
@@ -237,6 +237,10 @@ be a method with a pointer receiver to the struct itself, takes a single
`string` argument and may return an `error` to abort parsing. The `action`
method is responsible of updating the struct.
+### `description:"foobaz"`
+
+A description that appears alongside arguments during autocompletion.
+
### `default:"foobaz"`
Default `string` value if not specified by the user. Will be processed by the
diff --git a/complete.go b/complete.go
index f003e88..1178301 100644
--- a/complete.go
+++ b/complete.go
@@ -5,8 +5,13 @@ import (
"strings"
)
-func (c *CmdSpec) unseenFlags(arg string) []string {
- var flags []string
+type Completion struct {
+ Value string
+ Description string
+}
+
+func (c *CmdSpec) unseenFlags(arg string) []Completion {
+ var flags []Completion
for i := 0; i < len(c.opts); i++ {
spec := &c.opts[i]
if !spec.appliesToAlias(c.name) || spec.seen {
@@ -15,10 +20,10 @@ func (c *CmdSpec) unseenFlags(arg string) []string {
switch spec.kind {
case flag, option:
if spec.short != "" && strings.HasPrefix(spec.short, arg) {
- flags = append(flags, spec.short+" ")
+ flags = append(flags, Completion{Value: spec.short + " ", Description: spec.description})
}
if spec.long != "" && strings.HasPrefix(spec.long, arg) {
- flags = append(flags, spec.long+" ")
+ flags = append(flags, Completion{Value: spec.long + " ", Description: spec.description})
}
}
}
@@ -40,25 +45,29 @@ func (c *CmdSpec) nextPositional() *optSpec {
return spec
}
-func (s *optSpec) getCompletions(arg string) []string {
+func (s *optSpec) getCompletions(arg string) []Completion {
if s.complete.IsValid() {
in := []reflect.Value{reflect.ValueOf(arg)}
out := s.complete.Call(in)
if res, ok := out[0].Interface().([]string); ok {
- return res
+ var completions []Completion
+ for _, value := range res {
+ completions = append(completions, Completion{Value: value})
+ }
+ return completions
}
}
return nil
}
-func (c *CmdSpec) GetCompletions(args *Args) ([]string, string) {
+func (c *CmdSpec) GetCompletions(args *Args) ([]Completion, string) {
if args.Count() == 0 || (args.Count() == 1 && args.TrailingSpace() == "") {
return nil, ""
}
- var completions []string
+ var completions []Completion
var prefix string
- var flags []string
+ var flags []Completion
var last *seenArg
var spec *optSpec
@@ -95,7 +104,7 @@ func (c *CmdSpec) GetCompletions(args *Args) ([]string, string) {
case (s.kind == flag || s.kind == option) && (s.short == arg || s.long == arg):
// Current argument is precisely a flag.
spec = nil
- completions = []string{arg + " "}
+ completions = []Completion{{Value: arg + " ", Description: s.description}}
case s.kind == option && f != "=" && strings.HasPrefix(arg, f):
// Current argument is a long flag in the format:
// --flag=value
diff --git a/opt.go b/opt.go
index 610c0ba..3d9cd7e 100644
--- a/opt.go
+++ b/opt.go
@@ -148,7 +148,7 @@ func ArgsToStruct(args *Args, v any) error {
return nil
}
-func GetCompletions(cmdline string, v any) (completions []string, prefix string) {
+func GetCompletions(cmdline string, v any) (completions []Completion, prefix string) {
args := LexArgs(cmdline)
if args.Count() == 0 {
return nil, ""
--
2.45.2
Update test cases to ensure that the expected completions are of type
`Completion`.
Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
---
complete_test.go | 86 +++++++++++++++++++++++++++---------------------
1 file changed, 49 insertions(+), 37 deletions(-)
diff --git a/complete_test.go b/complete_test.go
index a210efc..d2e58f9 100644
--- a/complete_test.go
+++ b/complete_test.go
@@ -47,93 +47,105 @@ func (c *CompleteStruct) CompleteTag(arg string) []string {
func TestComplete(t *testing.T) {
vectors := []struct {
cmdline string
- completions []string
+ completions []opt.Completion
prefix string
}{
{
"foo --delay 33..33.3 -n",
- []string{"-n "},
+ []opt.Completion{{Value: "-n "}},
"foo --delay 33..33.3 ",
},
{
"foo --delay 33..33.3 -n ",
- []string{"leonardo", "michelangelo", "rafaelo", "donatello"},
+ []opt.Completion{
+ {Value: "leonardo"},
+ {Value: "michelangelo"},
+ {Value: "rafaelo"},
+ {Value: "donatello"},
+ },
"foo --delay 33..33.3 -n ",
},
{
"foo --delay 33..33.3 -n don",
- []string{"donatello"},
+ []opt.Completion{{Value: "donatello"}},
"foo --delay 33..33.3 -n ",
},
{
"foo --delay 33..33.3 --name=",
- []string{"leonardo", "michelangelo", "rafaelo", "donatello"},
+ []opt.Completion{
+ {Value: "leonardo"},
+ {Value: "michelangelo"},
+ {Value: "rafaelo"},
+ {Value: "donatello"},
+ },
"foo --delay 33..33.3 --name=",
},
{
"foo --delay 33..33.3 --name=leo",
- []string{"leonardo"},
+ []opt.Completion{{Value: "leonardo"}},
"foo --delay 33..33.3 --name=",
},
{
"foo --nam",
- []string{
- "--name ",
- },
+ []opt.Completion{{Value: "--name "}},
"foo ",
},
{
"foo --delay 33..33.3 --backoff",
- []string{
- "--backoff ",
- },
+ []opt.Completion{{Value: "--backoff "}},
"foo --delay 33..33.3 ",
},
{
"foo --delay 33..33.3 -",
- []string{
- "-unread",
- "-sent",
- "-important",
- "-inbox",
- "-trash",
- "-n ",
- "--name ",
- "-z ",
- "-B ",
- "--backoff ",
+ []opt.Completion{
+ {Value: "-unread"},
+ {Value: "-sent"},
+ {Value: "-important"},
+ {Value: "-inbox"},
+ {Value: "-trash"},
+ {Value: "-n "},
+ {Value: "--name "},
+ {Value: "-z "},
+ {Value: "-B "},
+ {Value: "--backoff "},
},
"foo --delay 33..33.3 ",
},
{
"foo --delay 33..33.3 ",
- []string{
- "unread",
- "sent",
- "important",
- "inbox",
- "trash",
- "-n ",
- "--name ",
- "-z ",
- "-B ",
- "--backoff ",
+ []opt.Completion{
+ {Value: "unread"},
+ {Value: "sent"},
+ {Value: "important"},
+ {Value: "inbox"},
+ {Value: "trash"},
+ {Value: "-n "},
+ {Value: "--name "},
+ {Value: "-z "},
+ {Value: "-B "},
+ {Value: "--backoff "},
},
"foo --delay 33..33.3 ",
},
{
"foo --delay 33..33.3 -n leonardo i",
- []string{"important", "inbox"},
+ []opt.Completion{{Value: "important"}, {Value: "inbox"}},
"foo --delay 33..33.3 -n leonardo ",
},
{
"foo +",
- []string{"+unread", "+sent", "+important", "+inbox", "+trash"},
+ []opt.Completion{
+ {Value: "+unread"},
+ {Value: "+sent"},
+ {Value: "+important"},
+ {Value: "+inbox"},
+ {Value: "+trash"},
+ },
"foo ",
},
{
"foo -i",
- []string{"-important", "-inbox"},
+ []opt.Completion{{Value: "-important"}, {Value: "-inbox"}},
"foo ",
},
}
--
2.45.2
Add test cases to verify that the `description` field is correctly
integrated into the autocompletion output.
Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
---
complete_test.go | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/complete_test.go b/complete_test.go
index d2e58f9..3349e9b 100644
--- a/complete_test.go
+++ b/complete_test.go
@@ -9,11 +9,12 @@ import (
)
type CompleteStruct struct {
- Name string `opt:"-n,--name" required:"true" complete:"CompleteName"`
- Delay float64 `opt:"--delay"`
- Zero bool `opt:"-z"`
- Backoff bool `opt:"-B,--backoff"`
- Tags []string `opt:"..." complete:"CompleteTag"`
+ Name string `opt:"-n,--name" required:"true" complete:"CompleteName"`
+ Delay float64 `opt:"--delay"`
+ Zero bool `opt:"-z"`
+ Backoff bool `opt:"-B,--backoff"`
+ Description string `opt:"-d" description:"Argument description"`
+ Tags []string `opt:"..." complete:"CompleteTag"`
}
func (c *CompleteStruct) CompleteName(arg string) []string {
@@ -108,6 +109,7 @@ func TestComplete(t *testing.T) {
{Value: "-z "},
{Value: "-B "},
{Value: "--backoff "},
+ {Value: "-d ", Description: "Argument description"},
},
"foo --delay 33..33.3 ",
},
@@ -124,6 +126,7 @@ func TestComplete(t *testing.T) {
{Value: "-z "},
{Value: "-B "},
{Value: "--backoff "},
+ {Value: "-d ", Description: "Argument description"},
},
"foo --delay 33..33.3 ",
},
@@ -148,6 +151,11 @@ func TestComplete(t *testing.T) {
[]opt.Completion{{Value: "-important"}, {Value: "-inbox"}},
"foo ",
},
+ {
+ "foo --delay 33..33.3 -d",
+ []opt.Completion{{Value: "-d ", Description: "Argument description"}},
+ "foo --delay 33..33.3 ",
+ },
}
for _, v := range vectors {
--
2.45.2