Unbreak README.

This commit is contained in:
Alec Thomas
2020-10-21 19:38:05 +11:00
parent 38db823367
commit 74d8f6d21b
+138 -164
View File
@@ -2,7 +2,6 @@
<p align="center"><img width="90%" src="kong.png" /></p> <p align="center"><img width="90%" src="kong.png" /></p>
# Kong is a command-line parser for Go # Kong is a command-line parser for Go
[![](https://godoc.org/github.com/alecthomas/kong?status.svg)](http://godoc.org/github.com/alecthomas/kong) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/kong.svg)](https://circleci.com/gh/alecthomas/kong) [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/kong)](https://goreportcard.com/report/github.com/alecthomas/kong) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://gophers.slack.com/messages/CN9DS8YF3) [![](https://godoc.org/github.com/alecthomas/kong?status.svg)](http://godoc.org/github.com/alecthomas/kong) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/kong.svg)](https://circleci.com/gh/alecthomas/kong) [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/kong)](https://goreportcard.com/report/github.com/alecthomas/kong) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://gophers.slack.com/messages/CN9DS8YF3)
<!-- TOC depthFrom:2 updateOnSave:true withLinks:true --> <!-- TOC depthFrom:2 updateOnSave:true withLinks:true -->
@@ -26,14 +25,6 @@
- [Plugins](#plugins) - [Plugins](#plugins)
- [Variable interpolation](#variable-interpolation) - [Variable interpolation](#variable-interpolation)
- [Validation](#validation) - [Validation](#validation)
- [Modifying Kong's behaviour](#modifying-kongs-behaviour)
- [`Name(help)` and `Description(help)` - set the application name description](#namehelp-and-descriptionhelp---set-the-application-name-description)
- [`Configuration(loader, paths...)` - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
- [`Resolver(...)` - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
- [`*Mapper(...)` - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
- [`ConfigureHelp(HelpOptions)` and `Help(HelpFunc)` - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
- [`Bind(...)` - bind values for callback hooks and Run() methods](#bind---bind-values-for-callback-hooks-and-run-methods)
- [Other options](#other-options)
<!-- /TOC --> <!-- /TOC -->
@@ -41,8 +32,7 @@
Kong aims to support arbitrarily complex command-line structures with as little developer effort as possible. Kong aims to support arbitrarily complex command-line structures with as little developer effort as possible.
To achieve that, command-lines are expressed as Go types, with the structure and tags directing how the command line is To achieve that, command-lines are expressed as Go types, with the structure and tags directing how the command line is mapped onto the struct.
mapped onto the struct.
For example, the following command-line: For example, the following command-line:
@@ -57,33 +47,32 @@ package main
import "github.com/alecthomas/kong" import "github.com/alecthomas/kong"
var CLI struct { var CLI struct {
Rm struct { Rm struct {
Force bool `help:"Force removal."` Force bool `help:"Force removal."`
Recursive bool `help:"Recursively remove files."` Recursive bool `help:"Recursively remove files."`
Paths []string `arg name:"path" help:"Paths to remove." type:"path"` Paths []string `arg name:"path" help:"Paths to remove." type:"path"`
} `cmd help:"Remove files."` } `cmd help:"Remove files."`
Ls struct { Ls struct {
Paths []string `arg optional name:"path" help:"Paths to list." type:"path"` Paths []string `arg optional name:"path" help:"Paths to list." type:"path"`
} `cmd help:"List paths."` } `cmd help:"List paths."`
} }
func main() { func main() {
ctx := kong.Parse(&CLI) ctx := kong.Parse(&CLI)
switch ctx.Command() { switch ctx.Command() {
case "rm <path>": case "rm <path>":
case "ls": case "ls":
default: default:
panic(ctx.Command()) panic(ctx.Command())
} }
} }
``` ```
## Help ## Help
Help is automatically generated. With no other arguments provided, help will display a full summary of all available Help is automatically generated. With no other arguments provided, help will display a full summary of all available commands.
commands.
eg. eg.
@@ -121,8 +110,9 @@ eg.
-f, --force Force removal. -f, --force Force removal.
-r, --recursive Recursively remove files. -r, --recursive Recursively remove files.
For flags with associated environment variables, the variable `${env}` can be interpolated into the help string. In the For flags with associated environment variables, the variable `${env}` can be
absence of this variable in the help, interpolated into the help string. In the absence of this variable in the help,
## Command handling ## Command handling
@@ -130,9 +120,7 @@ There are two ways to handle commands in Kong.
### Switch on the command string ### Switch on the command string
When you call `kong.Parse()` it will return a unique string representation of the command. Each command branch in the When you call `kong.Parse()` it will return a unique string representation of the command. Each command branch in the hierarchy will be a bare word and each branching argument or required positional argument will be the name surrounded by angle brackets. Here's an example:
hierarchy will be a bare word and each branching argument or required positional argument will be the name surrounded by
angle brackets. Here's an example:
There's an example of this pattern [here](https://github.com/alecthomas/kong/blob/master/_examples/shell/main.go). There's an example of this pattern [here](https://github.com/alecthomas/kong/blob/master/_examples/shell/main.go).
@@ -144,31 +132,30 @@ package main
import "github.com/alecthomas/kong" import "github.com/alecthomas/kong"
var CLI struct { var CLI struct {
Rm struct { Rm struct {
Force bool `help:"Force removal."` Force bool `help:"Force removal."`
Recursive bool `help:"Recursively remove files."` Recursive bool `help:"Recursively remove files."`
Paths []string `arg name:"path" help:"Paths to remove." type:"path"` Paths []string `arg name:"path" help:"Paths to remove." type:"path"`
} `cmd help:"Remove files."` } `cmd help:"Remove files."`
Ls struct { Ls struct {
Paths []string `arg optional name:"path" help:"Paths to list." type:"path"` Paths []string `arg optional name:"path" help:"Paths to list." type:"path"`
} `cmd help:"List paths."` } `cmd help:"List paths."`
} }
func main() { func main() {
ctx := kong.Parse(&CLI) ctx := kong.Parse(&CLI)
switch ctx.Command() { switch ctx.Command() {
case "rm <path>": case "rm <path>":
case "ls": case "ls":
default: default:
panic(ctx.Command()) panic(ctx.Command())
} }
} }
``` ```
This has the advantage that it is convenient, but the downside that if you modify your CLI structure, the strings may This has the advantage that it is convenient, but the downside that if you modify your CLI structure, the strings may change. This can be fragile.
change. This can be fragile.
### Attach a `Run(...) error` method to each command ### Attach a `Run(...) error` method to each command
@@ -179,71 +166,69 @@ A more robust approach is to break each command out into their own structs:
3. Call `kong.Kong.Parse()` to obtain a `kong.Context`. 3. Call `kong.Kong.Parse()` to obtain a `kong.Context`.
4. Call `kong.Context.Run(bindings...)` to call the selected parsed command. 4. Call `kong.Context.Run(bindings...)` to call the selected parsed command.
Once a command node is selected by Kong it will search from that node back to the root. Each encountered command node Once a command node is selected by Kong it will search from that node back to the root. Each
with a `Run(...) error` will be called in reverse order. This allows sub-trees to be re-used fairly conveniently. encountered command node with a `Run(...) error` will be called in reverse order. This allows
sub-trees to be re-used fairly conveniently.
In addition to values bound with the `kong.Bind(...)` option, any values passed through to `kong.Context.Run(...)` are In addition to values bound with the `kong.Bind(...)` option, any values
also bindable to the target's passed through to `kong.Context.Run(...)` are also bindable to the target's
`Run()` arguments. `Run()` arguments.
Finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`. Finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`.
There's a full example emulating part of the Docker There's a full example emulating part of the Docker CLI [here](https://github.com/alecthomas/kong/tree/master/_examples/docker).
CLI [here](https://github.com/alecthomas/kong/tree/master/_examples/docker).
eg. eg.
```go ```go
type Context struct { type Context struct {
Debug bool Debug bool
} }
type RmCmd struct { type RmCmd struct {
Force bool `help:"Force removal."` Force bool `help:"Force removal."`
Recursive bool `help:"Recursively remove files."` Recursive bool `help:"Recursively remove files."`
Paths []string `arg name:"path" help:"Paths to remove." type:"path"` Paths []string `arg name:"path" help:"Paths to remove." type:"path"`
} }
func (r *RmCmd) Run(ctx *Context) error { func (r *RmCmd) Run(ctx *Context) error {
fmt.Println("rm", r.Paths) fmt.Println("rm", r.Paths)
return nil return nil
} }
type LsCmd struct { type LsCmd struct {
Paths []string `arg optional name:"path" help:"Paths to list." type:"path"` Paths []string `arg optional name:"path" help:"Paths to list." type:"path"`
} }
func (l *LsCmd) Run(ctx *Context) error { func (l *LsCmd) Run(ctx *Context) error {
fmt.Println("ls", l.Paths) fmt.Println("ls", l.Paths)
return nil return nil
} }
var cli struct { var cli struct {
Debug bool `help:"Enable debug mode."` Debug bool `help:"Enable debug mode."`
Rm RmCmd `cmd help:"Remove files."` Rm RmCmd `cmd help:"Remove files."`
Ls LsCmd `cmd help:"List paths."` Ls LsCmd `cmd help:"List paths."`
} }
func main() { func main() {
ctx := kong.Parse(&cli) ctx := kong.Parse(&cli)
// Call the Run() method of the selected parsed command. // Call the Run() method of the selected parsed command.
err := ctx.Run(&Context{Debug: cli.Debug}) err := ctx.Run(&Context{Debug: cli.Debug})
ctx.FatalIfErrorf(err) ctx.FatalIfErrorf(err)
} }
``` ```
## Hooks: BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option ## Hooks: BeforeResolve(), BeforeApply(), AfterApply() and the Bind() option
If a node in the grammar has a `BeforeResolve(...)`, `BeforeApply(...) error` and/or `AfterApply(...) error` method, If a node in the grammar has a `BeforeResolve(...)`, `BeforeApply(...) error` and/or `AfterApply(...) error` method, those methods will be called before validation/assignment and after validation/assignment, respectively.
those methods will be called before validation/assignment and after validation/assignment, respectively.
The `--help` flag is implemented with a `BeforeApply` hook. The `--help` flag is implemented with a `BeforeApply` hook.
Arguments to hooks are provided via the `Run(...)` method or `Bind(...)` option. `*Kong`, `*Context` and `*Path` are Arguments to hooks are provided via the `Run(...)` method or `Bind(...)` option. `*Kong`, `*Context` and `*Path` are also bound and finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`.
also bound and finally, hooks can also contribute bindings via `kong.Context.Bind()` and `kong.Context.BindTo()`.
eg. eg.
@@ -252,34 +237,33 @@ eg.
type debugFlag bool type debugFlag bool
func (d debugFlag) BeforeApply(logger *log.Logger) error { func (d debugFlag) BeforeApply(logger *log.Logger) error {
logger.SetOutput(os.Stdout) logger.SetOutput(os.Stdout)
return nil return nil
} }
var cli struct { var cli struct {
Debug debugFlag `help:"Enable debug logging."` Debug debugFlag `help:"Enable debug logging."`
} }
func main() { func main() {
// Debug logger going to discard. // Debug logger going to discard.
logger := log.New(ioutil.Discard, "", log.LstdFlags) logger := log.New(ioutil.Discard, "", log.LstdFlags)
ctx := kong.Parse(&cli, kong.Bind(logger)) ctx := kong.Parse(&cli, kong.Bind(logger))
// ... // ...
} }
``` ```
## Flags ## Flags
Any [mapped](#mapper---customising-how-the-command-line-is-mapped-to-go-values) field in the command structure *not* Any [mapped](#mapper---customising-how-the-command-line-is-mapped-to-go-values) field in the command structure *not* tagged with `cmd` or `arg` will be a flag. Flags are optional by default.
tagged with `cmd` or `arg` will be a flag. Flags are optional by default.
eg. The command-line `app [--flag="foo"]` can be represented by the following. eg. The command-line `app [--flag="foo"]` can be represented by the following.
```go ```go
type CLI struct { type CLI struct {
Flag string Flag string
} }
``` ```
@@ -291,12 +275,12 @@ eg. The following struct represents the CLI structure `command [--flag="str"] su
```go ```go
type CLI struct { type CLI struct {
Command struct { Command struct {
Flag string Flag string
SubCommand struct { SubCommand struct {
} `cmd` } `cmd`
} `cmd` } `cmd`
} }
``` ```
@@ -306,9 +290,7 @@ If a sub-command is tagged with `default:"1"` it will be selected if there are n
In addition to sub-commands, structs can also be configured as branching positional arguments. In addition to sub-commands, structs can also be configured as branching positional arguments.
This is achieved by tagging an [unmapped](#mapper---customising-how-the-command-line-is-mapped-to-go-values) nested This is achieved by tagging an [unmapped](#mapper---customising-how-the-command-line-is-mapped-to-go-values) nested struct field with `arg`, then including a positional argument field inside that struct _with the same name_. For example, the following command structure:
struct field with `arg`, then including a positional argument field inside that struct _with the same name_. For
example, the following command structure:
app rename <name> to <name> app rename <name> to <name>
@@ -316,16 +298,16 @@ Can be represented with the following:
```go ```go
var CLI struct { var CLI struct {
Rename struct { Rename struct {
Name struct { Name struct {
Name string `arg` // <-- NOTE: identical name to enclosing struct field. Name string `arg` // <-- NOTE: identical name to enclosing struct field.
To struct { To struct {
Name struct { Name struct {
Name string `arg` Name string `arg`
} `arg` } `arg`
} `cmd` } `cmd`
} `arg` } `arg`
} `cmd` } `cmd`
} }
``` ```
@@ -333,16 +315,13 @@ This looks a little verbose in this contrived example, but typically this will n
## Terminating positional arguments ## Terminating positional arguments
If a [mapped type](#mapper---customising-how-the-command-line-is-mapped-to-go-values) is tagged with `arg` it will be If a [mapped type](#mapper---customising-how-the-command-line-is-mapped-to-go-values) is tagged with `arg` it will be treated as the final positional values to be parsed on the command line.
treated as the final positional values to be parsed on the command line.
If a positional argument is a slice, all remaining arguments will be appended to that slice. If a positional argument is a slice, all remaining arguments will be appended to that slice.
## Slices ## Slices
Slice values are treated specially. First the input is split on the `sep:"<rune>"` tag (defaults to `,`), then each Slice values are treated specially. First the input is split on the `sep:"<rune>"` tag (defaults to `,`), then each element is parsed by the slice element type and appended to the slice. If the same value is encountered multiple times, elements continue to be appended.
element is parsed by the slice element type and appended to the slice. If the same value is encountered multiple times,
elements continue to be appended.
To represent the following command-line: To represent the following command-line:
@@ -352,16 +331,15 @@ You would use the following:
```go ```go
var CLI struct { var CLI struct {
Ls struct { Ls struct {
Files []string `arg type:"existingfile"` Files []string `arg type:"existingfile"`
} `cmd` } `cmd`
} }
``` ```
## Maps ## Maps
Maps are similar to slices except that only one key/value pair can be assigned per value, and the `sep` tag denotes the Maps are similar to slices except that only one key/value pair can be assigned per value, and the `sep` tag denotes the assignment character and defaults to `=`.
assignment character and defaults to `=`.
To represent the following command-line: To represent the following command-line:
@@ -371,21 +349,21 @@ You would use the following:
```go ```go
var CLI struct { var CLI struct {
Config struct { Config struct {
Set struct { Set struct {
Config map[string]float64 `arg type:"file:"` Config map[string]float64 `arg type:"file:"`
} `cmd` } `cmd`
} `cmd` } `cmd`
} }
``` ```
For flags, multiple key+value pairs should be separated by `mapsep:"rune"` tag (defaults to `;`) For flags, multiple key+value pairs should be separated by `mapsep:"rune"` tag (defaults to `;`) eg. `--set="key1=value1;key2=value2"`.
eg. `--set="key1=value1;key2=value2"`.
## Custom named decoders ## Custom named decoders
Kong includes a number of builtin custom type mappers. These can be used by specifying the tag `type:"<type>"`. They are Kong includes a number of builtin custom type mappers. These can be used by
registered with the option function `NamedMapper(name, mapper)`. specifying the tag `type:"<type>"`. They are registered with the option
function `NamedMapper(name, mapper)`.
| Name | Description | Name | Description
|-------------------|--------------------------------------------------- |-------------------|---------------------------------------------------
@@ -394,16 +372,19 @@ registered with the option function `NamedMapper(name, mapper)`.
| `existingdir` | An existing directory. ~ expansion is applied. | `existingdir` | An existing directory. ~ expansion is applied.
| `counter` | Increment a numeric field. Useful for `-vvv`. Can accept `-s`, `--long` or `--long=N`. | `counter` | Increment a numeric field. Useful for `-vvv`. Can accept `-s`, `--long` or `--long=N`.
Slices and maps treat type tags specially. For slices, the `type:""` tag specifies the element type. For maps, the tag
has the format Slices and maps treat type tags specially. For slices, the `type:""` tag
specifies the element type. For maps, the tag has the format
`tag:"[<key>]:[<value>]"` where either may be omitted. `tag:"[<key>]:[<value>]"` where either may be omitted.
## Supported field types ## Supported field types
## Custom decoders (mappers) ## Custom decoders (mappers)
Any field implementing `encoding.TextUnmarshaler` or `json.Unmarshaler` will use those interfaces for decoding values.
Kong also includes builtin support for many common Go types: Any field implementing `encoding.TextUnmarshaler` or `json.Unmarshaler` will use those interfaces
for decoding values. Kong also includes builtin support for many common Go types:
| Type | Description | Type | Description
|---------------------|-------------------------------------------- |---------------------|--------------------------------------------
@@ -453,19 +434,18 @@ Tag | Description
## Plugins ## Plugins
Kong CLI's can be extended by embedding the `kong.Plugin` type and populating it with pointers to Kong annotated Kong CLI's can be extended by embedding the `kong.Plugin` type and populating it with pointers to Kong annotated structs. For example:
structs. For example:
```go ```go
var pluginOne struct { var pluginOne struct {
PluginOneFlag string PluginOneFlag string
} }
var pluginTwo struct { var pluginTwo struct {
PluginTwoFlag string PluginTwoFlag string
} }
var cli struct { var cli struct {
BaseFlag string BaseFlag string
kong.Plugins kong.Plugins
} }
cli.Plugins = kong.Plugins{&pluginOne, &pluginTwo} cli.Plugins = kong.Plugins{&pluginOne, &pluginTwo}
``` ```
@@ -474,20 +454,23 @@ Additionally if an interface type is embedded, it can also be populated with a K
## Variable interpolation ## Variable interpolation
Kong supports limited variable interpolation into help strings, enum lists and default values. Kong supports limited variable interpolation into help strings, enum lists and
default values.
Variables are in the form: Variables are in the form:
${<name>} ${<name>}
${<name>=<default>} ${<name>=<default>}
Variables are set with the `Vars{"key": "value", ...}` option. Undefined variable references in the grammar without a Variables are set with the `Vars{"key": "value", ...}` option. Undefined
default will result in an error at construction time. variable references in the grammar without a default will result in an error at
construction time.
Variables can also be set via the `set:"K=V"` tag. In this case, those variables will be available for that node and all Variables can also be set via the `set:"K=V"` tag. In this case, those variables will be available for that
children. This is useful for composition by allowing the same struct to be reused. node and all children. This is useful for composition by allowing the same struct to be reused.
When interpolating into flag or argument help strings, some extra variables are defined from the value itself: When interpolating into flag or argument help strings, some extra variables
are defined from the value itself:
${default} ${default}
${enum} ${enum}
@@ -496,17 +479,16 @@ eg.
```go ```go
type cli struct { type cli struct {
Config string `type:"path" default:"${config_file}"` Config string `type:"path" default:"${config_file}"`
} }
func main() { func main() {
kong.Parse(&cli, kong.Parse(&cli,
kong.Vars{ kong.Vars{
"config_file": "~/.app.conf", "config_file": "~/.app.conf",
}) })
} }
``` ```
## Validation ## Validation
Kong does validation on the structure of a command-line, but also supports Kong does validation on the structure of a command-line, but also supports
@@ -516,11 +498,11 @@ interface:
```go ```go
type Validatable interface { type Validatable interface {
Validate() error Validate() error
} }
``` ```
If one of these nodes is in the active command-line it will be called during +If one of these nodes is in the active command-line it will be called during
normal validation. +normal validation.
## Modifying Kong's behaviour ## Modifying Kong's behaviour
@@ -538,8 +520,7 @@ As with all help in Kong, text will be wrapped to the terminal.
### `Configuration(loader, paths...)` - load defaults from configuration files ### `Configuration(loader, paths...)` - load defaults from configuration files
This option provides Kong with support for loading defaults from a set of configuration files. Each file is opened, if This option provides Kong with support for loading defaults from a set of configuration files. Each file is opened, if possible, and the loader called to create a resolver for that file.
possible, and the loader called to create a resolver for that file.
eg. eg.
@@ -547,14 +528,11 @@ eg.
kong.Parse(&cli, kong.Configuration(kong.JSON, "/etc/myapp.json", "~/.myapp.json")) kong.Parse(&cli, kong.Configuration(kong.JSON, "/etc/myapp.json", "~/.myapp.json"))
``` ```
[See the tests](https://github.com/alecthomas/kong/blob/master/resolver_test.go#L103) for an example of how the JSON [See the tests](https://github.com/alecthomas/kong/blob/master/resolver_test.go#L103) for an example of how the JSON file is structured.
file is structured.
### `Resolver(...)` - support for default values from external sources ### `Resolver(...)` - support for default values from external sources
Resolvers are Kong's extension point for providing default values from external sources. As an example, support for Resolvers are Kong's extension point for providing default values from external sources. As an example, support for environment variables via the `env` tag is provided by a resolver. There's also a builtin resolver for JSON configuration files.
environment variables via the `env` tag is provided by a resolver. There's also a builtin resolver for JSON
configuration files.
Example resolvers can be found in [resolver.go](https://github.com/alecthomas/kong/blob/master/resolver.go). Example resolvers can be found in [resolver.go](https://github.com/alecthomas/kong/blob/master/resolver.go).
@@ -573,8 +551,7 @@ type Mapper interface {
} }
``` ```
All builtin Go types (as well as a bunch of useful stdlib types like `time.Time`) have mappers registered by default. All builtin Go types (as well as a bunch of useful stdlib types like `time.Time`) have mappers registered by default. Mappers for custom types can be added using `kong.??Mapper(...)` options. Mappers are applied to fields in four ways:
Mappers for custom types can be added using `kong.??Mapper(...)` options. Mappers are applied to fields in four ways:
1. `NamedMapper(string, Mapper)` and using the tag key `type:"<name>"`. 1. `NamedMapper(string, Mapper)` and using the tag key `type:"<name>"`.
2. `KindMapper(reflect.Kind, Mapper)`. 2. `KindMapper(reflect.Kind, Mapper)`.
@@ -585,12 +562,9 @@ Mappers for custom types can be added using `kong.??Mapper(...)` options. Mapper
The default help output is usually sufficient, but if not there are two solutions. The default help output is usually sufficient, but if not there are two solutions.
1. Use `ConfigureHelp(HelpOptions)` to configure how help is formatted ( 1. Use `ConfigureHelp(HelpOptions)` to configure how help is formatted (see [HelpOptions](https://godoc.org/github.com/alecthomas/kong#HelpOptions) for details).
see [HelpOptions](https://godoc.org/github.com/alecthomas/kong#HelpOptions) for details). 2. Custom help can be wired into Kong via the `Help(HelpFunc)` option. The `HelpFunc` is passed a `Context`, which contains the parsed context for the current command-line. See the implementation of `PrintHelp` for an example.
2. Custom help can be wired into Kong via the `Help(HelpFunc)` option. The `HelpFunc` is passed a `Context`, which 3. Use `HelpFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and arguments.
contains the parsed context for the current command-line. See the implementation of `PrintHelp` for an example.
3. Use `HelpFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and
arguments.
### `Bind(...)` - bind values for callback hooks and Run() methods ### `Bind(...)` - bind values for callback hooks and Run() methods