~rjarry/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
5 2

[PATCH go-opt 0/3] Add description support to autocompletion

Details
Message ID
<20240904071854.49406-1-bojan@bojangabric.com>
DKIM signature
pass
Download raw message
This is a series of patches that introduce a new field `description`
that appear alongside arguments during autocompletion.

I’m not particularly experienced with Go, but I built this to help me
use `aerc` more effectively.

I’m sharing it in case it’s a useful approach for adding autocompletion
with descriptions. If anyone has suggestions or can point me in the
right direction, I'd appreciate the guidance.

Bojan Gabric (3):
  spec: add description field to arguments
  complete: include `description` in autocompletion output
  complete_test: add tests for `description` field in autocompletion

 README.md        |  4 ++++
 complete.go      | 14 +++++++++++---
 complete_test.go | 18 +++++++++++++-----
 spec.go          |  4 ++++
 4 files changed, 32 insertions(+), 8 deletions(-)

-- 
2.45.2

[PATCH go-opt 1/3] spec: add description field to arguments

Details
Message ID
<20240904071854.49406-2-bojan@bojangabric.com>
In-Reply-To
<20240904071854.49406-1-bojan@bojangabric.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +4 -0
This field will be used to store descriptions that will be displayed
during the autocompletion process.

Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
---
 spec.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/spec.go b/spec.go
index d4960d1..1e07042 100644
--- a/spec.go
+++ b/spec.go
@@ -56,6 +56,8 @@ type optSpec struct {
	kind optKind
	// argument is required
	required bool
	// option/argument description
	description string
	// argument was seen on the command line
	seen bool
	// argument value was seen on the command line (only applies to options)
@@ -218,6 +220,8 @@ func (spec *optSpec) parseField(struc reflect.Value, t reflect.StructField) {
		spec.metavar = metavar
	}

	spec.description = t.Tag.Get("description")

	spec.defval = t.Tag.Get("default")

	switch t.Tag.Get("required") {
-- 
2.45.2

[PATCH go-opt 2/3] complete: include `description` in autocompletion output

Details
Message ID
<20240904071854.49406-3-bojan@bojangabric.com>
In-Reply-To
<20240904071854.49406-1-bojan@bojangabric.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +15 -3
Update the autocompletion logic to append descriptions to the
autocompleted arguments when available.

Implements: https://todo.sr.ht/~rjarry/aerc/271
Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
---
 README.md   |  4 ++++
 complete.go | 14 +++++++++++---
 2 files changed, 15 insertions(+), 3 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..c34a163 100644
--- a/complete.go
+++ b/complete.go
@@ -14,11 +14,15 @@ func (c *CmdSpec) unseenFlags(arg string) []string {
		}
		switch spec.kind {
		case flag, option:
			description := " "
			if spec.description != "" {
				description += spec.description + " "
			}
			if spec.short != "" && strings.HasPrefix(spec.short, arg) {
				flags = append(flags, spec.short+" ")
				flags = append(flags, spec.short+description)
			}
			if spec.long != "" && strings.HasPrefix(spec.long, arg) {
				flags = append(flags, spec.long+" ")
				flags = append(flags, spec.long+description)
			}
		}
	}
@@ -95,7 +99,11 @@ 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 + " "}
				description := " "
				if s.description != "" {
					description += s.description + " "
				}
				completions = []string{arg + description}
			case s.kind == option && f != "=" && strings.HasPrefix(arg, f):
				// Current argument is a long flag in the format:
				//       --flag=value
-- 
2.45.2

[PATCH go-opt 3/3] complete_test: add tests for `description` field in autocompletion

Details
Message ID
<20240904071854.49406-4-bojan@bojangabric.com>
In-Reply-To
<20240904071854.49406-1-bojan@bojangabric.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +13 -5
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 a210efc..b0764de 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 {
@@ -102,6 +103,7 @@ func TestComplete(t *testing.T) {
				"-z ",
				"-B ",
				"--backoff ",
				"-d Argument description ",
			},
			"foo --delay 33..33.3 ",
		},
@@ -118,6 +120,7 @@ func TestComplete(t *testing.T) {
				"-z ",
				"-B ",
				"--backoff ",
				"-d Argument description ",
			},
			"foo --delay 33..33.3 ",
		},
@@ -136,6 +139,11 @@ func TestComplete(t *testing.T) {
			[]string{"-important", "-inbox"},
			"foo ",
		},
		{
			"foo --delay 33..33.3 -d",
			[]string{"-d Argument description "},
			"foo --delay 33..33.3 ",
		},
	}

	for _, v := range vectors {
-- 
2.45.2

Re: [PATCH go-opt 2/3] complete: include `description` in autocompletion output

Details
Message ID
<D3XEEJ3P72S8.NU8RTVV44547@ringo>
In-Reply-To
<20240904071854.49406-3-bojan@bojangabric.com> (view parent)
DKIM signature
pass
Download raw message
Bojan Gabric, Sep 04, 2024 at 09:19:
> Update the autocompletion logic to append descriptions to the
> autocompleted arguments when available.
>
> Implements: https://todo.sr.ht/~rjarry/aerc/271
> Signed-off-by: Bojan Gabric <bojan@bojangabric.com>
> ---

Hi Bojan,

thanks for the patch! I think this requires an API change. The returned 
completion would need to be small structs instead of plain strings.

What do you think of the following suggestion:

type Completion struct {
    value string
    description string
}

func (c *CmdSpec) GetCompletions(args *Args) ([]Completion, string) {
    ....
}

This way, it is up to the application to do what it wants with the 
description as it is not mixed with the completion value.

>  README.md   |  4 ++++
>  complete.go | 14 +++++++++++---
>  2 files changed, 15 insertions(+), 3 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..c34a163 100644
> --- a/complete.go
> +++ b/complete.go
> @@ -14,11 +14,15 @@ func (c *CmdSpec) unseenFlags(arg string) []string {
>  		}
>  		switch spec.kind {
>  		case flag, option:
> +			description := " "
> +			if spec.description != "" {
> +				description += spec.description + " "
> +			}
>  			if spec.short != "" && strings.HasPrefix(spec.short, arg) {
> -				flags = append(flags, spec.short+" ")
> +				flags = append(flags, spec.short+description)
>  			}
>  			if spec.long != "" && strings.HasPrefix(spec.long, arg) {
> -				flags = append(flags, spec.long+" ")
> +				flags = append(flags, spec.long+description)
>  			}
>  		}
>  	}
> @@ -95,7 +99,11 @@ 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 + " "}
> +				description := " "
> +				if s.description != "" {
> +					description += s.description + " "
> +				}
> +				completions = []string{arg + description}
>  			case s.kind == option && f != "=" && strings.HasPrefix(arg, f):
>  				// Current argument is a long flag in the format:
>  				//       --flag=value
> -- 
> 2.45.2

Re: [PATCH go-opt 2/3] complete: include `description` in autocompletion output

Details
Message ID
<D3XIY86W82MG.34827FT0O1J5L@bojangabric.com>
In-Reply-To
<D3XEEJ3P72S8.NU8RTVV44547@ringo> (view parent)
DKIM signature
pass
Download raw message
On Wed Sep 4, 2024 at 11:38 AM CEST, Robin Jarry wrote:
> thanks for the patch! I think this requires an API change. The returned 
> completion would need to be small structs instead of plain strings.
>
> What do you think of the following suggestion:
>
> type Completion struct {
>     value string
>     description string
> }
>
> func (c *CmdSpec) GetCompletions(args *Args) ([]Completion, string) {
>     ....
> }
>
> This way, it is up to the application to do what it wants with the 
> description as it is not mixed with the completion value.

Great idea! I'll update the code and send a new patch.
Reply to thread Export thread (mbox)