return CommandLine.Set(name, value)
}
-// PrintDefaults prints, to standard error unless configured
-// otherwise, the default values of all defined flags in the set.
+// isZeroValue guesses whether the string represents the zero
+// value for a flag. It is not accurate but in practice works OK.
+func isZeroValue(value string) bool {
+ switch value {
+ case "false":
+ return true
+ case "":
+ return true
+ case "0":
+ return true
+ }
+ return false
+}
+
+// UnquoteUsage extracts a back-quoted name from the usage
+// string for a flag and returns it and the un-quoted usage.
+// Given "a `name` to show" it returns ("name", "a name to show").
+// If there are no back quotes, the name is an educated guess of the
+// type of the flag's value, or the empty string if the flag is boolean.
+func UnquoteUsage(flag *Flag) (name string, usage string) {
+ // Look for a back-quoted name, but avoid the strings package.
+ usage = flag.Usage
+ for i := 0; i < len(usage); i++ {
+ if usage[i] == '`' {
+ for j := i + 1; j < len(usage); j++ {
+ if usage[j] == '`' {
+ name = usage[i+1 : j]
+ usage = usage[:i] + name + usage[j+1:]
+ return name, usage
+ }
+ }
+ break // Only one back quote; use type name.
+ }
+ }
+ // No explicit name, so use type if we can find one.
+ name = "value"
+ switch flag.Value.(type) {
+ case boolFlag:
+ name = ""
+ case *durationValue:
+ name = "duration"
+ case *float64Value:
+ name = "float"
+ case *intValue, *int64Value:
+ name = "int"
+ case *stringValue:
+ name = "string"
+ case *uintValue, *uint64Value:
+ name = "uint"
+ }
+ return
+}
+
+// PrintDefaults prints to standard error the default values of all
+// defined command-line flags in the set. See the documentation for
+// the global function PrintDefaults for more information.
func (f *FlagSet) PrintDefaults() {
f.VisitAll(func(flag *Flag) {
- format := " -%s=%s: %s\n"
- if _, ok := flag.Value.(*stringValue); ok {
- // put quotes on the value
- format = " -%s=%q: %s\n"
+ s := fmt.Sprintf(" -%s", flag.Name) // Two spaces before -; see next two comments.
+ name, usage := UnquoteUsage(flag)
+ if len(name) > 0 {
+ s += " " + name
+ }
+ // Boolean flags of one ASCII letter are so common we
+ // treat them specially, putting their usage on the same line.
+ if len(s) <= 4 { // space, space, '-', 'x'.
+ s += "\t"
+ } else {
+ // Three spaces before the tab triggers good alignment
+ // for both 4- and 8-space tab stops.
+ s += "\n \t"
+ }
+ s += usage
+ if !isZeroValue(flag.DefValue) {
+ if _, ok := flag.Value.(*stringValue); ok {
+ // put quotes on the value
+ s += fmt.Sprintf(" (default %q)", flag.DefValue)
+ } else {
+ s += fmt.Sprintf(" (default %v)", flag.DefValue)
+ }
}
- fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
+ fmt.Fprint(f.out(), s, "\n")
})
}
-// PrintDefaults prints to standard error the default values of all defined command-line flags.
+// PrintDefaults prints, to standard error unless configured otherwise,
+// a usage message showing the default settings of all defined
+// command-line flags.
+// For an integer valued flag x, the default output has the form
+// -x int
+// usage-message-for-x (default 7)
+// The usage message will appear on a separate line for anything but
+// a bool flag with a one-byte name. For bool flags, the type is
+// omitted and if the flag name is one byte the usage message appears
+// on the same line. The parenthetical default is omitted if the
+// default is the zero value for the type. The listed type, here int,
+// can be changed by placing a back-quoted name in the flag's usage
+// string; the first such item in the message is taken to be a parameter
+// name to show in the message and the back quotes are stripped from
+// the message when displayed. For instance, given
+// flag.String("I", "", "search `directory` for include files")
+// the output will be
+// -I directory
+// search directory for include files.
func PrintDefaults() {
CommandLine.PrintDefaults()
}
// Usage prints to standard error a usage message documenting all defined command-line flags.
// It is called when an error occurs while parsing flags.
// The function is a variable that may be changed to point to a custom function.
+// By default it prints a simple header and calls PrintDefaults; for details about the
+// format of the output and how to control it, see the documentation for PrintDefaults.
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
PrintDefaults()
t.Fatal("help was called; should not have been for defined help flag")
}
}
+
+const defaultOutput = ` -A for bootstrapping, allow 'any' type
+ -Alongflagname
+ disable bounds checking
+ -C a boolean defaulting to true (default true)
+ -D path
+ set relative path for local imports
+ -F number
+ a non-zero number (default 2.7)
+ -G float
+ a float that defaults to zero
+ -N int
+ a non-zero int (default 27)
+ -Z int
+ an int that defaults to zero
+ -maxT timeout
+ set timeout for dial
+`
+
+func TestPrintDefaults(t *testing.T) {
+ fs := NewFlagSet("print defaults test", ContinueOnError)
+ var buf bytes.Buffer
+ fs.SetOutput(&buf)
+ fs.Bool("A", false, "for bootstrapping, allow 'any' type")
+ fs.Bool("Alongflagname", false, "disable bounds checking")
+ fs.Bool("C", true, "a boolean defaulting to true")
+ fs.String("D", "", "set relative `path` for local imports")
+ fs.Float64("F", 2.7, "a non-zero `number`")
+ fs.Float64("G", 0, "a float that defaults to zero")
+ fs.Int("N", 27, "a non-zero int")
+ fs.Int("Z", 0, "an int that defaults to zero")
+ fs.Duration("maxT", 0, "set `timeout` for dial")
+ fs.PrintDefaults()
+ got := buf.String()
+ if got != defaultOutput {
+ t.Errorf("got %q want %q\n", got, defaultOutput)
+ }
+}