Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Commit

Permalink
improve subcommand selection
Browse files Browse the repository at this point in the history
Signed-off-by: Achille Roussel <[email protected]>
  • Loading branch information
achille-roussel committed May 28, 2023
1 parent 2604308 commit 9f26e8d
Showing 1 changed file with 47 additions and 19 deletions.
66 changes: 47 additions & 19 deletions internal/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var resources = [...]resource{
},
{
name: "module",
alt: []string{"mo", "mods", "modules"},
alt: []string{"mo", "mod", "mods", "modules"},
get: getModules,
},
{
Expand Down Expand Up @@ -94,30 +94,27 @@ func get(ctx context.Context, args []string) error {

args = flagSet.Args()
if len(args) == 0 {
return errors.New(`expected exactly one resource name as argument`)
return errors.New(`expected exactly one resource name as argument` + useGet())
}
resourceNamePrefix := args[0]
parseFlags(flagSet, args[1:])

matchingResources := selectMatchingResources(resourceNamePrefix, resources[:])
if len(matchingResources) == 0 {
return fmt.Errorf(`no resources matching '%s'`, resourceNamePrefix)
}
if len(matchingResources) > 1 {
resource, ok := findResource(resourceNamePrefix, resources[:])
if !ok {
matchingResources := findMatchingResources(resourceNamePrefix, resources[:])
if len(matchingResources) == 0 {
return fmt.Errorf(`no resources matching '%s'`+useGet(), resourceNamePrefix)
}
return fmt.Errorf(`no resources matching '%s'
Did you mean?
$ timecraft get %s
`, resourceNamePrefix, matchingResources[0].name)
Did you mean?%s`, resourceNamePrefix, joinResourceNames(matchingResources, "\n "))
}

registry, err := openRegistry(registryPath)
if err != nil {
return err
}

resource := matchingResources[0]
reader := registry.ListResources(ctx, resource.name, timeRange)
defer reader.Close()

Expand Down Expand Up @@ -226,22 +223,53 @@ func newDescTableWriter[T any](w io.Writer, conv func(*format.Descriptor) (T, er
return stream.NewWriteCloser(cw, tw)
}

func selectMatchingResources(name string, options []resource) []resource {
var matches []resource

func findResource(name string, options []resource) (resource, bool) {
for _, option := range options {
if option.name == name {
return []resource{option}
return option, true
}
for _, alt := range option.alt {
if alt == name {
return []resource{option}
return option, true
}
}
if strings.HasPrefix(option.name, name) {
}
return resource{}, false
}

func findMatchingResources(name string, options []resource) (matches []resource) {
for _, option := range options {
if prefixLength(option.name, name) > 1 || prefixLength(name, option.name) > 1 {
matches = append(matches, option)
}
}

return matches
}

func prefixLength(base, prefix string) int {
n := 0
for n < len(base) && n < len(prefix) && base[n] == prefix[n] {
n++
}
return n
}

func joinResourceNames(resources []resource, prefix string) string {
s := new(strings.Builder)
for _, r := range resources {
s.WriteString(prefix)
s.WriteString(r.name)
}
return s.String()
}

func useGet() string {
s := new(strings.Builder)
s.WriteString("\n\n")
s.WriteString(`Use 'timecraft <resource>' where the supported resource names are:`)
for _, r := range resources {
s.WriteString("\n ")
s.WriteString(r.name)
}
return s.String()
}

0 comments on commit 9f26e8d

Please sign in to comment.