add subcommands to usage string
This commit is contained in:
parent
edd1af4667
commit
15bf383f1d
|
@ -135,3 +135,40 @@ func Example_usageString() {
|
||||||
// optimization level
|
// optimization level
|
||||||
// --help, -h display this help and exit
|
// --help, -h display this help and exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This example shows the usage string generated by go-arg
|
||||||
|
func Example_usageStringWithSubcommand() {
|
||||||
|
// These are the args you would pass in on the command line
|
||||||
|
os.Args = split("./example --help")
|
||||||
|
|
||||||
|
type getCmd struct {
|
||||||
|
Item string `arg:"positional" help:"item to fetch"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type listCmd struct {
|
||||||
|
Format string `help:"output format"`
|
||||||
|
Limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
var args struct {
|
||||||
|
Verbose bool
|
||||||
|
Get *getCmd `arg:"subcommand" help:"fetch an item and print it"`
|
||||||
|
List *listCmd `arg:"subcommand" help:"list available items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only necessary when running inside golang's runnable example harness
|
||||||
|
osExit = func(int) {}
|
||||||
|
|
||||||
|
MustParse(&args)
|
||||||
|
|
||||||
|
// output:
|
||||||
|
// Usage: example [--verbose]
|
||||||
|
//
|
||||||
|
// Options:
|
||||||
|
// --verbose
|
||||||
|
// --help, -h display this help and exit
|
||||||
|
//
|
||||||
|
// Commands:
|
||||||
|
// get fetch an item and print it
|
||||||
|
// list list available items
|
||||||
|
}
|
||||||
|
|
3
parse.go
3
parse.go
|
@ -59,6 +59,7 @@ type spec struct {
|
||||||
// command represents a named subcommand, or the top-level command
|
// command represents a named subcommand, or the top-level command
|
||||||
type command struct {
|
type command struct {
|
||||||
name string
|
name string
|
||||||
|
help string
|
||||||
dest path
|
dest path
|
||||||
specs []*spec
|
specs []*spec
|
||||||
subcommands []*command
|
subcommands []*command
|
||||||
|
@ -296,6 +297,8 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subcmd.help = field.Tag.Get("help")
|
||||||
|
|
||||||
cmd.subcommands = append(cmd.subcommands, subcmd)
|
cmd.subcommands = append(cmd.subcommands, subcmd)
|
||||||
isSubcommand = true
|
isSubcommand = true
|
||||||
default:
|
default:
|
||||||
|
|
63
usage.go
63
usage.go
|
@ -69,6 +69,23 @@ func (p *Parser) WriteUsage(w io.Writer) {
|
||||||
fmt.Fprint(w, "\n")
|
fmt.Fprint(w, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printTwoCols(w io.Writer, left, help string, defaultVal *string) {
|
||||||
|
lhs := " " + left
|
||||||
|
fmt.Fprint(w, lhs)
|
||||||
|
if help != "" {
|
||||||
|
if len(lhs)+2 < colWidth {
|
||||||
|
fmt.Fprint(w, strings.Repeat(" ", colWidth-len(lhs)))
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth))
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, help)
|
||||||
|
}
|
||||||
|
if defaultVal != nil {
|
||||||
|
fmt.Fprintf(w, " [default: %s]", *defaultVal)
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
// WriteHelp writes the usage string followed by the full help string for each option
|
// WriteHelp writes the usage string followed by the full help string for each option
|
||||||
func (p *Parser) WriteHelp(w io.Writer) {
|
func (p *Parser) WriteHelp(w io.Writer) {
|
||||||
var positionals, options []*spec
|
var positionals, options []*spec
|
||||||
|
@ -89,17 +106,7 @@ func (p *Parser) WriteHelp(w io.Writer) {
|
||||||
if len(positionals) > 0 {
|
if len(positionals) > 0 {
|
||||||
fmt.Fprint(w, "\nPositional arguments:\n")
|
fmt.Fprint(w, "\nPositional arguments:\n")
|
||||||
for _, spec := range positionals {
|
for _, spec := range positionals {
|
||||||
left := " " + strings.ToUpper(spec.long)
|
printTwoCols(w, strings.ToUpper(spec.long), spec.help, nil)
|
||||||
fmt.Fprint(w, 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")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,42 +130,44 @@ func (p *Parser) WriteHelp(w io.Writer) {
|
||||||
help: "display version and exit",
|
help: "display version and exit",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write the list of subcommands
|
||||||
|
if len(p.cmd.subcommands) > 0 {
|
||||||
|
fmt.Fprint(w, "\nCommands:\n")
|
||||||
|
for _, subcmd := range p.cmd.subcommands {
|
||||||
|
printTwoCols(w, subcmd.name, subcmd.help, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) printOption(w io.Writer, spec *spec) {
|
func (p *Parser) printOption(w io.Writer, spec *spec) {
|
||||||
left := " " + synopsis(spec, "--"+spec.long)
|
left := synopsis(spec, "--"+spec.long)
|
||||||
if spec.short != "" {
|
if spec.short != "" {
|
||||||
left += ", " + synopsis(spec, "-"+spec.short)
|
left += ", " + synopsis(spec, "-"+spec.short)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, 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)
|
|
||||||
}
|
|
||||||
// If spec.dest is not the zero value then a default value has been added.
|
// If spec.dest is not the zero value then a default value has been added.
|
||||||
var v reflect.Value
|
var v reflect.Value
|
||||||
if len(spec.dest.fields) > 0 {
|
if len(spec.dest.fields) > 0 {
|
||||||
v = p.readable(spec.dest)
|
v = p.readable(spec.dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultVal *string
|
||||||
if v.IsValid() {
|
if v.IsValid() {
|
||||||
z := reflect.Zero(v.Type())
|
z := reflect.Zero(v.Type())
|
||||||
if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
|
if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
|
||||||
if scalar, ok := v.Interface().(encoding.TextMarshaler); ok {
|
if scalar, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||||
if value, err := scalar.MarshalText(); err != nil {
|
if value, err := scalar.MarshalText(); err != nil {
|
||||||
fmt.Fprintf(w, " [default: error: %v]", err)
|
defaultVal = ptrTo(fmt.Sprintf("error: %v", err))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, " [default: %v]", string(value))
|
defaultVal = ptrTo(fmt.Sprintf("%v", string(value)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, " [default: %v]", v)
|
defaultVal = ptrTo(fmt.Sprintf("%v", v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, "\n")
|
printTwoCols(w, left, spec.help, defaultVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func synopsis(spec *spec, form string) string {
|
func synopsis(spec *spec, form string) string {
|
||||||
|
@ -167,3 +176,7 @@ func synopsis(spec *spec, form string) string {
|
||||||
}
|
}
|
||||||
return form + " " + strings.ToUpper(spec.long)
|
return form + " " + strings.ToUpper(spec.long)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ptrTo(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue