More efficient multi line scanning
This commit is contained in:
parent
2ddbe2a2bc
commit
a3a89b3e21
@ -3,12 +3,13 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"kitty/tools/utils"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"kitty/tools/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
@ -41,6 +42,51 @@ the specified depth.
|
|||||||
Set the help text to "!" to have an option hidden.
|
Set the help text to "!" to have an option hidden.
|
||||||
*/
|
*/
|
||||||
func OptionFromString(entries ...string) (*Option, error) {
|
func OptionFromString(entries ...string) (*Option, error) {
|
||||||
|
return option_from_string(map[string]string{}, entries...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func OptionsFromStruct(pointer_to_options_struct interface{}) ([]*Option, error) {
|
||||||
|
val := reflect.ValueOf(pointer_to_options_struct).Elem()
|
||||||
|
if val.Kind() != reflect.Struct {
|
||||||
|
return nil, fmt.Errorf("Need a pointer to a struct to set option values on")
|
||||||
|
}
|
||||||
|
ans := make([]*Option, 0, val.NumField())
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
f := val.Field(i)
|
||||||
|
field_name := val.Type().Field(i).Name
|
||||||
|
tag := val.Type().Field(i).Tag
|
||||||
|
if utils.Capitalize(field_name) != field_name || !f.CanSet() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
typ := "str"
|
||||||
|
switch f.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
typ = "list"
|
||||||
|
case reflect.Int:
|
||||||
|
typ = "int"
|
||||||
|
case reflect.Float64:
|
||||||
|
typ = "float"
|
||||||
|
case reflect.Bool:
|
||||||
|
typ = "bool-set"
|
||||||
|
}
|
||||||
|
overrides := map[string]string{"dest": field_name, "type": typ}
|
||||||
|
opt, err := option_from_string(overrides, string(tag))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ans = append(ans, opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type multi_scan struct {
|
||||||
|
entries []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var mpat *regexp.Regexp
|
||||||
|
|
||||||
|
func option_from_string(overrides map[string]string, entries ...string) (*Option, error) {
|
||||||
if mpat == nil {
|
if mpat == nil {
|
||||||
mpat = regexp.MustCompile("^([a-z]+)=(.+)")
|
mpat = regexp.MustCompile("^([a-z]+)=(.+)")
|
||||||
}
|
}
|
||||||
@ -48,7 +94,7 @@ func OptionFromString(entries ...string) (*Option, error) {
|
|||||||
values_from_cmdline: make([]string, 0, 1),
|
values_from_cmdline: make([]string, 0, 1),
|
||||||
parsed_values_from_cmdline: make([]interface{}, 0, 1),
|
parsed_values_from_cmdline: make([]interface{}, 0, 1),
|
||||||
}
|
}
|
||||||
scanner := bufio.NewScanner(strings.NewReader(strings.Join(entries, "\n")))
|
scanner := utils.NewScanLines(entries...)
|
||||||
in_help := false
|
in_help := false
|
||||||
prev_indent := 0
|
prev_indent := 0
|
||||||
help := strings.Builder{}
|
help := strings.Builder{}
|
||||||
@ -66,12 +112,55 @@ func OptionFromString(entries ...string) (*Option, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_type := func(v string) error {
|
||||||
|
switch v {
|
||||||
|
case "choice", "choices":
|
||||||
|
ans.OptionType = StringOption
|
||||||
|
case "int":
|
||||||
|
ans.OptionType = IntegerOption
|
||||||
|
set_default("0")
|
||||||
|
case "float":
|
||||||
|
ans.OptionType = FloatOption
|
||||||
|
set_default("0")
|
||||||
|
case "count":
|
||||||
|
ans.OptionType = CountOption
|
||||||
|
set_default("0")
|
||||||
|
case "bool-set":
|
||||||
|
ans.OptionType = BoolOption
|
||||||
|
set_default("false")
|
||||||
|
case "bool-reset":
|
||||||
|
ans.OptionType = BoolOption
|
||||||
|
set_default("true")
|
||||||
|
for _, a := range ans.Aliases {
|
||||||
|
a.IsUnset = true
|
||||||
|
}
|
||||||
|
case "list":
|
||||||
|
ans.IsList = true
|
||||||
|
fallthrough
|
||||||
|
case "str", "string":
|
||||||
|
ans.OptionType = StringOption
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unknown option type: %s", v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if dq, found := overrides["type"]; found {
|
||||||
|
err := set_type(dq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
if ans.Aliases == nil {
|
if ans.Aliases == nil {
|
||||||
if strings.HasPrefix(line, "--") {
|
if strings.HasPrefix(line, "--") {
|
||||||
parts := strings.Split(line, " ")
|
parts := strings.Split(line, " ")
|
||||||
|
if dq, found := overrides["dest"]; found {
|
||||||
|
ans.Name = camel_case_dest(dq)
|
||||||
|
} else {
|
||||||
ans.Name = camel_case_dest(parts[0])
|
ans.Name = camel_case_dest(parts[0])
|
||||||
|
}
|
||||||
ans.Aliases = make([]Alias, 0, len(parts))
|
ans.Aliases = make([]Alias, 0, len(parts))
|
||||||
for i, x := range parts {
|
for i, x := range parts {
|
||||||
ans.Aliases[i] = Alias{NameWithoutHyphens: strings.TrimLeft(x, "-"), IsShort: !strings.HasPrefix(x, "--")}
|
ans.Aliases[i] = Alias{NameWithoutHyphens: strings.TrimLeft(x, "-"), IsShort: !strings.HasPrefix(x, "--")}
|
||||||
@ -120,7 +209,11 @@ func OptionFromString(entries ...string) (*Option, error) {
|
|||||||
case "default":
|
case "default":
|
||||||
ans.Default = v
|
ans.Default = v
|
||||||
case "dest":
|
case "dest":
|
||||||
|
if dq, found := overrides["dest"]; found {
|
||||||
|
ans.Name = camel_case_dest(dq)
|
||||||
|
} else {
|
||||||
ans.Name = camel_case_dest(v)
|
ans.Name = camel_case_dest(v)
|
||||||
|
}
|
||||||
case "depth":
|
case "depth":
|
||||||
depth, err := strconv.ParseInt(v, 0, 0)
|
depth, err := strconv.ParseInt(v, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -131,34 +224,9 @@ func OptionFromString(entries ...string) (*Option, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unknown option metadata key: %s", k)
|
return nil, fmt.Errorf("Unknown option metadata key: %s", k)
|
||||||
case "type":
|
case "type":
|
||||||
switch v {
|
err := set_type(v)
|
||||||
case "choice", "choices":
|
if err != nil {
|
||||||
ans.OptionType = StringOption
|
return nil, err
|
||||||
case "int":
|
|
||||||
ans.OptionType = IntegerOption
|
|
||||||
set_default("0")
|
|
||||||
case "float":
|
|
||||||
ans.OptionType = FloatOption
|
|
||||||
set_default("0")
|
|
||||||
case "count":
|
|
||||||
ans.OptionType = CountOption
|
|
||||||
set_default("0")
|
|
||||||
case "bool-set":
|
|
||||||
ans.OptionType = BoolOption
|
|
||||||
set_default("false")
|
|
||||||
case "bool-reset":
|
|
||||||
ans.OptionType = BoolOption
|
|
||||||
set_default("true")
|
|
||||||
for _, a := range ans.Aliases {
|
|
||||||
a.IsUnset = true
|
|
||||||
}
|
|
||||||
case "list":
|
|
||||||
ans.IsList = true
|
|
||||||
fallthrough
|
|
||||||
case "str", "string":
|
|
||||||
ans.OptionType = StringOption
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("Unknown option type: %s", v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,5 +241,11 @@ func OptionFromString(entries ...string) (*Option, error) {
|
|||||||
if ans.IsList {
|
if ans.IsList {
|
||||||
ans.parsed_default = []string{}
|
ans.parsed_default = []string{}
|
||||||
}
|
}
|
||||||
|
if ans.Aliases == nil || len(ans.Aliases) == 0 {
|
||||||
|
return nil, fmt.Errorf("No --aliases specified for option")
|
||||||
|
}
|
||||||
|
if ans.Name == "" {
|
||||||
|
return nil, fmt.Errorf("No dest specified for option")
|
||||||
|
}
|
||||||
return &ans, nil
|
return &ans, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,8 +69,6 @@ func (self *Option) HasAlias(name_without_hyphens string, is_short bool) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var mpat *regexp.Regexp
|
|
||||||
|
|
||||||
type ParseError struct {
|
type ParseError struct {
|
||||||
Option *Option
|
Option *Option
|
||||||
Message string
|
Message string
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
@ -18,3 +19,46 @@ func Capitalize(x string) string {
|
|||||||
cr := strings.ToUpper(string(s))
|
cr := strings.ToUpper(string(s))
|
||||||
return cr + x[sz:]
|
return cr + x[sz:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScanLines struct {
|
||||||
|
entries []string
|
||||||
|
|
||||||
|
scanner *bufio.Scanner
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScanLines(entries ...string) *ScanLines {
|
||||||
|
return &ScanLines{entries: entries}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ScanLines) Scan() bool {
|
||||||
|
if self.scanner == nil {
|
||||||
|
if len(self.entries) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
self.scanner = bufio.NewScanner(strings.NewReader(self.entries[0]))
|
||||||
|
self.entries = self.entries[1:]
|
||||||
|
return self.Scan()
|
||||||
|
} else {
|
||||||
|
if self.scanner.Scan() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
self.scanner = nil
|
||||||
|
return self.Scan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ScanLines) Text() string {
|
||||||
|
if self.scanner == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return self.scanner.Text()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Splitlines(x string) []string {
|
||||||
|
ans := make([]string, 0, 8)
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(x))
|
||||||
|
for scanner.Scan() {
|
||||||
|
ans = append(ans, scanner.Text())
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user