Glob as variant of Arg Flag type : accepts multiple files, as shell-expanded. use in um sort and um cat
NOTE: um sort expects .md files, while um cat expects .um : .um filelists are concatted together, while .md lists are just lists
This commit is contained in:
parent
65ed68460f
commit
5aac37f8a8
5 changed files with 74 additions and 22 deletions
|
|
@ -31,6 +31,11 @@ type Arg struct {
|
|||
Help string
|
||||
}
|
||||
|
||||
type Glob struct {
|
||||
Val []string
|
||||
Help string
|
||||
}
|
||||
|
||||
type String struct {
|
||||
Long string
|
||||
Short string
|
||||
|
|
@ -69,6 +74,33 @@ func (f *Arg) MaybeIncrement(i int) int {
|
|||
return i
|
||||
}
|
||||
|
||||
func (f *Glob) Set(arg string) {
|
||||
f.Val = append(f.Val, arg)
|
||||
}
|
||||
|
||||
func (f *Glob) Valid(args []string, i int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *Glob) Match(arg string, i, j int) bool {
|
||||
// NOTE: this is the key difference from Arg: by not requiring that the arg and flag positions
|
||||
// match, a shell-expanded glob of files of any length will populate the value.
|
||||
return i >= j && !hasDashPrefix(arg)
|
||||
}
|
||||
|
||||
func (f *Glob) IsSet() bool {
|
||||
return f.Val != nil && len(f.Val) != 0
|
||||
}
|
||||
|
||||
func (f *Glob) IsHelp() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Glob) MaybeIncrement(i int) int {
|
||||
// NOTE: because this is only needed where a flag --prefix exists:
|
||||
return i
|
||||
}
|
||||
|
||||
func (f *String) Set(arg string) {
|
||||
f.Val = arg
|
||||
}
|
||||
|
|
@ -145,16 +177,16 @@ func expandOpts(opts any) ([]Flag, error) {
|
|||
for j := 0; j < v.NumField(); j++ {
|
||||
field := v.Field(j)
|
||||
if field.Kind() != reflect.Struct {
|
||||
return nil, ParseError{fmt.Sprintf("field must be a struct: %#v", field.Kind())}
|
||||
return nil, ParseError{fmt.Sprintf("field must be a struct: %v", field.Kind())}
|
||||
}
|
||||
if !field.CanAddr() {
|
||||
return nil, ParseError{fmt.Sprintf("field must be addressable type: %#v", field.Type())}
|
||||
return nil, ParseError{fmt.Sprintf("field must be addressable type: %v", field.Type())}
|
||||
}
|
||||
// NOTE: Addr() gets the underlying address:
|
||||
if f, ok := field.Addr().Interface().(Flag); ok {
|
||||
flags = append(flags, f)
|
||||
} else {
|
||||
return nil, ParseError{fmt.Sprintf("field must be a []Flag interface: %#v", field.Type())}
|
||||
return nil, ParseError{fmt.Sprintf("field must be a []Flag interface: %v", field.Type())}
|
||||
}
|
||||
}
|
||||
return flags, nil
|
||||
|
|
|
|||
|
|
@ -61,9 +61,12 @@ func (h HelpError) Help(opts any) error {
|
|||
tField := t.Field(i)
|
||||
vField := v.Field(i)
|
||||
switch vField.Interface().(type) {
|
||||
case Arg:
|
||||
case Arg, Glob:
|
||||
positional += fmt.Sprintf(" [%s]", strings.ToLower(tField.Name))
|
||||
fmt.Fprintf(w, "[%v]\tstring\t%v\n", strings.ToLower(tField.Name), vField.FieldByName("Help"))
|
||||
fmt.Fprintf(w, "[%v]\t%v\t%v\n",
|
||||
strings.ToLower(tField.Name),
|
||||
vField.FieldByName("Val").Type(),
|
||||
vField.FieldByName("Help"))
|
||||
case String, Bool:
|
||||
if tField.Name != "Help" {
|
||||
positional += fmt.Sprintf(" [%s]", vField.FieldByName("Long"))
|
||||
|
|
@ -75,7 +78,7 @@ func (h HelpError) Help(opts any) error {
|
|||
vField.FieldByName("Help"),
|
||||
)
|
||||
default:
|
||||
return ParseError{fmt.Sprintf("needs a []Flag interface: %#v", vField.Type())}
|
||||
return ParseError{fmt.Sprintf("Help did not recognize the Flag: %v", vField.Type())}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue