For what it is worth, here is an example of how I currently use Args with the flags package. This is an excerpt from a little weather program I made for myself. I’ve tried several ways to automate customization, and settled on the following after realizing how much code I had to write to traverse nested types, etc. It became more than it was worth. I decided to compromise and do this.
I posted about recommendation to facilitate custom usage functionality here write_usage
package custom_usage_example
import "core:fmt"
import "core:os"
import "core:reflect"
import "core:flags"
import "base:runtime"
import "base:intrinsics"
Args :: struct {
loc: string `args:"name=l,pos=0" usage:"Location: Zip, City, or City-st. If empty, location is based in IP."`,
moon: bool `args:"name=m" usage:"Get moon phase information. Debug not availible."`,
report: bool `args:"name=r" usage:"Verbose 3 day report."`,
sol: bool `args:"name=s" usage:"Get Sun position times."`,
weather: bool `args:"name=w" usage:"Get weather for today and 3 day forecast."`,
debug: bool `args:"name=d" usage:"Print debug information for weather service."`,
}
parse_args :: proc(args: ^$T, usage: proc(typeid)) -> (ok: bool) where intrinsics.type_is_struct(T) {
if len(os.args) <= 1 {
usage(T)
} else {
switch err in flags.parse(args, os.args[1:]) {
case flags.Help_Request: usage(T)
case flags.Validation_Error: fmt.printfln("%v", err.message)
case flags.Parse_Error: fmt.printfln("%v", err.message)
case flags.Open_File_Error: fmt.printfln("%v", err)
case: ok = true
}
}
return
}
usage_tag :: proc(tags: []reflect.Struct_Tag, tag: string) -> (usage: string) {
for t in tags {
args := reflect.struct_tag_lookup(t, "args") or_continue
if name := flags.get_subtag(args, "name") or_continue; name == tag {
usage = reflect.struct_tag_lookup(t, "usage") or_break
return
}
}
return
}
usage :: proc(T: typeid) {
tinfo := runtime.type_info_base(type_info_of(T))
t, ok := tinfo.variant.(runtime.Type_Info_Struct)
tags := ok ? transmute([]reflect.Struct_Tag)t.tags[:t.field_count] : nil
usage := [][]string {
{"Usage:", "mist l [-m] [-r] [-s] [-w] [-d]"},
{"",""},
{"-l:<string>", usage_tag(tags, "l")},
{"-m:<bool>" , usage_tag(tags, "m")},
{"-r:<bool>" , usage_tag(tags, "r")},
{"-s:<bool>" , usage_tag(tags, "s")},
{"-w:<bool>" , usage_tag(tags, "w")},
{"-d:<bool>" , usage_tag(tags, "d")},
}
for u in usage {
fmt.printfln("%-12s%s", u[0], u[1])
}
}
main :: proc() {
if args: Args; parse_args(&args, usage) {
//do stuff
}
}