committed by
Alec Thomas
parent
184735e689
commit
3eb5e285ed
@@ -0,0 +1,136 @@
|
||||
package kong
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
Cmd bool
|
||||
Arg bool
|
||||
Required bool
|
||||
Optional bool
|
||||
Help string
|
||||
Type string
|
||||
Default string
|
||||
Format string
|
||||
Placeholder string
|
||||
Env string
|
||||
Short rune
|
||||
}
|
||||
|
||||
func parseCSV(s string) ([]string, error) {
|
||||
num := 0
|
||||
parts := []string{}
|
||||
current := []rune{}
|
||||
|
||||
add := func() {
|
||||
parts = append(parts, string(current))
|
||||
current = []rune{}
|
||||
num++
|
||||
}
|
||||
|
||||
quotes := false
|
||||
|
||||
runes := []rune(s)
|
||||
for idx := 0; idx < len(runes); idx++ {
|
||||
r := runes[idx]
|
||||
next := rune(0)
|
||||
eof := false
|
||||
if idx < len(runes)-1 {
|
||||
next = runes[idx+1]
|
||||
} else {
|
||||
eof = true
|
||||
}
|
||||
if !quotes && r == ',' {
|
||||
add()
|
||||
continue
|
||||
}
|
||||
if r == '\\' {
|
||||
if next == '\'' {
|
||||
idx++
|
||||
r = '\''
|
||||
}
|
||||
} else if r == '\'' {
|
||||
if quotes {
|
||||
quotes = false
|
||||
if next == ',' || eof {
|
||||
continue
|
||||
}
|
||||
return parts, fmt.Errorf("%v has an unexpected char at pos %v", s, idx)
|
||||
} else {
|
||||
quotes = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
current = append(current, r)
|
||||
}
|
||||
if quotes {
|
||||
return parts, fmt.Errorf("%v is not quoted properly", s)
|
||||
}
|
||||
|
||||
add()
|
||||
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
func parseTag(fv reflect.Value, s string) (*Tag, error) {
|
||||
t := &Tag{}
|
||||
if s == "" {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
parts, err := parseCSV(s)
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
|
||||
for _, part := range parts {
|
||||
is := func(m string) bool { return part == m }
|
||||
value := func(m string) (string, bool) {
|
||||
split := strings.SplitN(part, "=", 2)
|
||||
if split[0] != m {
|
||||
return "", false
|
||||
}
|
||||
if len(split) == 1 {
|
||||
return "", true
|
||||
}
|
||||
return split[1], true
|
||||
}
|
||||
|
||||
if is("cmd") {
|
||||
t.Cmd = true
|
||||
} else if is("arg") {
|
||||
t.Arg = true
|
||||
} else if is("required") {
|
||||
t.Required = true
|
||||
} else if is("optional") {
|
||||
t.Optional = true
|
||||
} else if v, ok := value("default"); ok {
|
||||
t.Default = v
|
||||
} else if v, ok := value("help"); ok {
|
||||
t.Help = v
|
||||
} else if v, ok := value("type"); ok {
|
||||
t.Type = v
|
||||
} else if v, ok := value("placeholder"); ok {
|
||||
t.Placeholder = v
|
||||
} else if v, ok := value("env"); ok {
|
||||
t.Env = v
|
||||
} else if v, ok := value("rune"); ok {
|
||||
t.Short, _ = utf8.DecodeRuneInString(v)
|
||||
if t.Short == utf8.RuneError {
|
||||
t.Short = 0
|
||||
}
|
||||
} else {
|
||||
return t, fmt.Errorf("%v is an unknown kong key", part)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Placeholder == "" {
|
||||
t.Placeholder = strings.ToUpper(dashedString(fv.Type().Name()))
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
Reference in New Issue
Block a user