summaryrefslogtreecommitdiff
path: root/usage.go
diff options
context:
space:
mode:
authorAlex Flint <[email protected]>2015-10-31 18:32:20 -0700
committerAlex Flint <[email protected]>2015-10-31 18:32:20 -0700
commit76293a5a725eb962839b8c69a2bda1296e1fdbdf (patch)
treee96d1e4f5b9f3261dbd2a6ac9f9e37e09455b629 /usage.go
parentbdbdf034c7dd7402917b12ec3639be16a6fe6bbb (diff)
add usage.go
Diffstat (limited to 'usage.go')
-rw-r--r--usage.go112
1 files changed, 112 insertions, 0 deletions
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")
+ }
+ }
+}