Enum value descriptions with core:flags

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
	}
}