diff --git a/build.go b/build.go index e607617..666025b 100644 --- a/build.go +++ b/build.go @@ -6,6 +6,8 @@ import ( "strings" ) +var helpProviderType = reflect.TypeOf((*HelpProvider)(nil)).Elem() + func build(k *Kong, ast interface{}) (app *Application, err error) { defer catch(&err) v := reflect.ValueOf(ast) @@ -107,6 +109,10 @@ func buildChild(k *Kong, node *Node, typ NodeType, v reflect.Value, ft reflect.S child.Help = tag.Help child.Hidden = tag.Hidden + if fv.Type().Implements(helpProviderType) { + child.Detail = fv.Interface().(HelpProvider).Help() + } + // A branching argument. This is a bit hairy, as we let buildNode() do the parsing, then check that // a positional argument is provided to the child, and move it to the branching argument field. if tag.Arg { diff --git a/help.go b/help.go index 4d27b50..abee58d 100644 --- a/help.go +++ b/help.go @@ -25,6 +25,12 @@ type HelpOptions struct { Compact bool } +// HelpProvider can be implemented by commands/args to provide detailed help. +type HelpProvider interface { + // This string is formatted by go/doc and thus has the same formatting rules. + Help() string +} + // HelpPrinter is used to print context-sensitive help. type HelpPrinter func(options HelpOptions, ctx *Context) error @@ -77,6 +83,10 @@ func printNodeDetail(w *helpWriter, node *Node) { if w.Summary { return } + if node.Detail != "" { + w.Print("") + w.Wrap(node.Detail) + } if len(node.Positional) > 0 { w.Print("") w.Print("Arguments:") diff --git a/help_test.go b/help_test.go index 8b5bca9..54caae9 100644 --- a/help_test.go +++ b/help_test.go @@ -9,6 +9,16 @@ import ( "github.com/alecthomas/kong" ) +// nolint: govet +type threeArg struct { + RequiredThree bool `required` + Three string `arg` +} + +func (threeArg) Help() string { + return `Detailed help provided through the HelpProvider interface.` +} + func TestHelp(t *testing.T) { // nolint: govet var cli struct { @@ -26,10 +36,7 @@ func TestHelp(t *testing.T) { Flag string `help:"Nested flag under two."` RequiredTwo bool `required` - Three struct { - RequiredThree bool `required` - Three string `arg` - } `arg help:"Sub-sub-arg."` + Three threeArg `arg help:"Sub-sub-arg."` Four struct { } `cmd help:"Sub-sub-command."` @@ -95,6 +102,8 @@ Run "test-app --help" for more information on a command. Sub-sub-arg. +Detailed help provided through the HelpProvider interface. + Flags: --help Show context-sensitive help. --string=STRING A string flag. diff --git a/model.go b/model.go index 38f1d0d..df009ac 100644 --- a/model.go +++ b/model.go @@ -35,7 +35,8 @@ type Node struct { Type NodeType Parent *Node Name string - Help string + Help string // Short help displayed in summaries. + Detail string // Detailed help displayed when describing command/arg alone. Hidden bool Flags []*Flag Positional []*Positional