From 76293a5a725eb962839b8c69a2bda1296e1fdbdf Mon Sep 17 00:00:00 2001 From: Alex Flint Date: Sat, 31 Oct 2015 18:32:20 -0700 Subject: [PATCH] add usage.go --- usage.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 usage.go diff --git a/usage.go b/usage.go new file mode 100644 index 0000000..06a3ebd --- /dev/null +++ b/usage.go @@ -0,0 +1,112 @@ +package arg + +import ( + "fmt" + "io" + "os" + "reflect" + "strings" +) + +// Usage prints usage information to stdout information and exits with status zero +func Usage(dest ...interface{}) { + if err := WriteUsage(os.Stdout, dest...); err != nil { + fmt.Println(err) + } + os.Exit(0) +} + +// Fail prints usage information to stdout and exits with non-zero status +func Fail(msg string, dest ...interface{}) { + fmt.Println(msg) + if err := WriteUsage(os.Stdout, dest...); err != nil { + fmt.Println(err) + } + os.Exit(1) +} + +// WriteUsage writes usage information to the given writer +func WriteUsage(w io.Writer, dest ...interface{}) error { + spec, err := extractSpec(dest...) + if err != nil { + return err + } + writeUsage(w, spec) + return nil +} + +func synopsis(spec *spec, form string) string { + if spec.dest.Kind() == reflect.Bool { + return form + } else { + return form + " " + strings.ToUpper(spec.long) + } +} + +// writeUsage writes usage information to the given writer +func writeUsage(w io.Writer, specs []*spec) { + var positionals, options []*spec + for _, spec := range specs { + if spec.positional { + positionals = append(positionals, spec) + } else { + options = append(options, spec) + } + } + + fmt.Fprint(w, "usage: ") + + // write the option component of the one-line usage message + for _, spec := range options { + if !spec.required { + fmt.Fprint(w, "[") + } + fmt.Fprint(w, synopsis(spec, "--"+spec.long)) + if !spec.required { + fmt.Fprint(w, "]") + } + fmt.Fprint(w, " ") + } + + // write the positional component of the one-line usage message + for _, spec := range positionals { + up := strings.ToUpper(spec.long) + if spec.multiple { + fmt.Fprintf(w, "[%s [%s ...]]", up) + } else { + fmt.Fprint(w, up) + } + fmt.Fprint(w, " ") + } + fmt.Fprint(w, "\n") + + // write the list of positionals + if len(positionals) > 0 { + fmt.Fprint(w, "\npositional arguments:\n") + for _, spec := range positionals { + fmt.Fprintf(w, " %s\n", spec.long) + } + } + + // write the list of options + if len(options) > 0 { + fmt.Fprint(w, "\noptions:\n") + const colWidth = 25 + for _, spec := range options { + left := fmt.Sprint(synopsis(spec, "--"+spec.long)) + if spec.short != "" { + left += ", " + fmt.Sprint(synopsis(spec, "-"+spec.short)) + } + fmt.Print(left) + if spec.help != "" { + if len(left)+2 < colWidth { + fmt.Fprint(w, strings.Repeat(" ", colWidth-len(left))) + } else { + fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth)) + } + fmt.Fprint(w, spec.help) + } + fmt.Fprint(w, "\n") + } + } +}