Interpret flags and operands for completion
This commit is contained in:
@@ -8,52 +8,27 @@ import (
|
||||
)
|
||||
|
||||
func interpretFlagTokens(argv []string, flags []commandmeta.Flag, aliases []commandmeta.FlagAlias) ([]string, map[string][]string, []commandmeta.FlagOccurrence, *commandmeta.Failure) {
|
||||
canonical := make(map[string]commandmeta.Flag, len(flags)*2+2)
|
||||
help := commandmeta.HelpFlag()
|
||||
canonical["--help"] = help
|
||||
canonical["-h"] = help
|
||||
for _, flag := range flags {
|
||||
canonical["--"+flag.Name] = flag
|
||||
if flag.Short != "" {
|
||||
canonical["-"+flag.Short] = flag
|
||||
}
|
||||
}
|
||||
|
||||
byAlias := make(map[string]commandmeta.Flag, len(aliases))
|
||||
for _, alias := range aliases {
|
||||
if target, ok := canonical[alias.Target]; ok {
|
||||
byAlias[alias.Source] = target
|
||||
}
|
||||
}
|
||||
lookup := commandmeta.NewFlagLookup(flags, aliases)
|
||||
|
||||
spellings := make(map[string][]string)
|
||||
var occurrences []commandmeta.FlagOccurrence
|
||||
var interpreted []string
|
||||
for index := 0; index < len(argv); {
|
||||
token := argv[index]
|
||||
if token == "--" {
|
||||
kind := commandmeta.ClassifyFlagToken(token)
|
||||
if kind == commandmeta.TerminatorToken {
|
||||
interpreted = append(interpreted, argv[index:]...)
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(token, "--") && len(token) > 2 {
|
||||
body := token[2:]
|
||||
equal := strings.IndexByte(body, '=')
|
||||
inputName := body
|
||||
if equal >= 0 {
|
||||
inputName = body[:equal]
|
||||
}
|
||||
original := "--" + inputName
|
||||
flag, ok := canonical[original]
|
||||
if !ok {
|
||||
flag, ok = byAlias[original]
|
||||
}
|
||||
if kind == commandmeta.LongFlagToken {
|
||||
original, value, attached := commandmeta.SplitLongFlag(token)
|
||||
flag, ok := lookup.Find(original)
|
||||
if !ok {
|
||||
interpreted = append(interpreted, token)
|
||||
return interpreted, spellings, occurrences, nil
|
||||
}
|
||||
spellings[flag.Name] = append(spellings[flag.Name], original)
|
||||
if equal >= 0 {
|
||||
value := body[equal+1:]
|
||||
if attached {
|
||||
interpreted = append(interpreted, "--"+flag.Name+"="+value)
|
||||
occurrences = append(occurrences, commandmeta.FlagOccurrence{Name: flag.Name, Spelling: original, RawValue: value})
|
||||
index++
|
||||
@@ -74,19 +49,11 @@ func interpretFlagTokens(argv []string, flags []commandmeta.Flag, aliases []comm
|
||||
index++
|
||||
continue
|
||||
}
|
||||
if len(token) > 1 && token[0] == '-' {
|
||||
if token == "-" {
|
||||
interpreted = append(interpreted, token)
|
||||
index++
|
||||
continue
|
||||
}
|
||||
if kind == commandmeta.ShortFlagToken {
|
||||
consumedNext := false
|
||||
for offset := 1; offset < len(token); {
|
||||
original := "-" + token[offset:offset+1]
|
||||
flag, ok := canonical[original]
|
||||
if !ok {
|
||||
flag, ok = byAlias[original]
|
||||
}
|
||||
flag, ok := lookup.Find(original)
|
||||
if !ok {
|
||||
interpreted = append(interpreted, "-"+token[offset:])
|
||||
return interpreted, spellings, occurrences, nil
|
||||
|
||||
67
internal/commandmeta/flags.go
Normal file
67
internal/commandmeta/flags.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package commandmeta
|
||||
|
||||
import "strings"
|
||||
|
||||
// FlagTokenKind identifies the portion of the shared option grammar a token uses.
|
||||
type FlagTokenKind uint8
|
||||
|
||||
const (
|
||||
OperandToken FlagTokenKind = iota
|
||||
TerminatorToken
|
||||
LongFlagToken
|
||||
ShortFlagToken
|
||||
)
|
||||
|
||||
// ClassifyFlagToken distinguishes option tokens without consuming their values.
|
||||
func ClassifyFlagToken(token string) FlagTokenKind {
|
||||
if token == "--" {
|
||||
return TerminatorToken
|
||||
}
|
||||
if strings.HasPrefix(token, "--") && len(token) > 2 {
|
||||
return LongFlagToken
|
||||
}
|
||||
if len(token) > 1 && token[0] == '-' {
|
||||
return ShortFlagToken
|
||||
}
|
||||
return OperandToken
|
||||
}
|
||||
|
||||
// SplitLongFlag separates the entered spelling from an optional attached value.
|
||||
func SplitLongFlag(token string) (spelling, value string, attached bool) {
|
||||
return strings.Cut(token, "=")
|
||||
}
|
||||
|
||||
// FlagLookup maps canonical and applicable alias spellings to neutral flags.
|
||||
type FlagLookup struct {
|
||||
canonical map[string]Flag
|
||||
aliases map[string]Flag
|
||||
}
|
||||
|
||||
// NewFlagLookup includes the built-in help flag alongside the supplied flags.
|
||||
func NewFlagLookup(flags []Flag, aliases []FlagAlias) FlagLookup {
|
||||
canonical := make(map[string]Flag, len(flags)*2+2)
|
||||
help := HelpFlag()
|
||||
canonical["--help"], canonical["-h"] = help, help
|
||||
for _, flag := range flags {
|
||||
canonical["--"+flag.Name] = flag
|
||||
if flag.Short != "" {
|
||||
canonical["-"+flag.Short] = flag
|
||||
}
|
||||
}
|
||||
lookup := FlagLookup{canonical: canonical, aliases: make(map[string]Flag, len(aliases))}
|
||||
for _, alias := range aliases {
|
||||
if target, ok := canonical[alias.Target]; ok {
|
||||
lookup.aliases[alias.Source] = target
|
||||
}
|
||||
}
|
||||
return lookup
|
||||
}
|
||||
|
||||
// Find returns the canonical flag for an entered spelling.
|
||||
func (lookup FlagLookup) Find(spelling string) (Flag, bool) {
|
||||
flag, ok := lookup.canonical[spelling]
|
||||
if !ok {
|
||||
flag, ok = lookup.aliases[spelling]
|
||||
}
|
||||
return flag, ok
|
||||
}
|
||||
Reference in New Issue
Block a user