@@ -27,7 +27,7 @@
|
||||
2. [`Configuration(loader, paths...)` - load defaults from configuration files](#configurationloader-paths---load-defaults-from-configuration-files)
|
||||
3. [`Resolver(...)` - support for default values from external sources](#resolver---support-for-default-values-from-external-sources)
|
||||
4. [`*Mapper(...)` - customising how the command-line is mapped to Go values](#mapper---customising-how-the-command-line-is-mapped-to-go-values)
|
||||
5. [`ConfigureHelp(HelpOptions)` and `Help(HelpFunc)` - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
|
||||
5. [`ConfigureHelp(HelpOptions)`, `Help(HelpFunc)` and `HelpFormatter(HelpValueFormatter)` - customising help](#configurehelphelpoptions-and-helphelpfunc---customising-help)
|
||||
6. [`Bind(...)` - bind values for callback hooks and Run() methods](#bind---bind-values-for-callback-hooks-and-run-methods)
|
||||
7. [Other options](#other-options)
|
||||
|
||||
@@ -117,10 +117,6 @@ eg.
|
||||
-f, --force Force removal.
|
||||
-r, --recursive Recursively remove files.
|
||||
|
||||
For flags with associated environment variables, the variable `${env}` can be
|
||||
interpolated into the help string. In the absence of this variable in the help,
|
||||
|
||||
|
||||
<a id="markdown-command-handling" name="command-handling"></a>
|
||||
## Command handling
|
||||
|
||||
@@ -463,7 +459,6 @@ are defined from the value itself:
|
||||
|
||||
${default}
|
||||
${enum}
|
||||
${env}
|
||||
|
||||
eg.
|
||||
|
||||
@@ -546,6 +541,7 @@ The default help output is usually sufficient, but if not there are two solution
|
||||
|
||||
1. Use `ConfigureHelp(HelpOptions)` to configure how help is formatted (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.
|
||||
3. Use `HelpFormatter(HelpValueFormatter)` if you want to just customize the help text that is accompanied by flags and arguments.
|
||||
|
||||
<a id="markdown-bind---bind-values-for-callback-hooks-and-run-methods" name="bind---bind-values-for-callback-hooks-and-run-methods"></a>
|
||||
### `Bind(...)` - bind values for callback hooks and Run() methods
|
||||
|
||||
@@ -65,6 +65,25 @@ type HelpIndenter func(prefix string) string
|
||||
// HelpPrinter is used to print context-sensitive help.
|
||||
type HelpPrinter func(options HelpOptions, ctx *Context) error
|
||||
|
||||
// HelpValueFormatter is used to format the help text of flags and positional arguments.
|
||||
type HelpValueFormatter func(value *Value) string
|
||||
|
||||
// DefaultHelpValueFormatter is the default HelpValueFormatter.
|
||||
func DefaultHelpValueFormatter(value *Value) string {
|
||||
if value.Tag.Env == "" {
|
||||
return value.Help
|
||||
}
|
||||
suffix := "($" + value.Tag.Env + ")"
|
||||
switch {
|
||||
case strings.HasSuffix(value.Help, "."):
|
||||
return value.Help[:len(value.Help)-1] + " " + suffix + "."
|
||||
case value.Help == "":
|
||||
return suffix
|
||||
default:
|
||||
return value.Help + " " + suffix
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultHelpPrinter is the default HelpPrinter.
|
||||
func DefaultHelpPrinter(options HelpOptions, ctx *Context) error {
|
||||
if ctx.Empty() {
|
||||
@@ -214,19 +233,21 @@ func printCommandSummary(w *helpWriter, cmd *Command) {
|
||||
}
|
||||
|
||||
type helpWriter struct {
|
||||
indent string
|
||||
width int
|
||||
lines *[]string
|
||||
indent string
|
||||
width int
|
||||
lines *[]string
|
||||
helpFormatter HelpValueFormatter
|
||||
HelpOptions
|
||||
}
|
||||
|
||||
func newHelpWriter(ctx *Context, options HelpOptions) *helpWriter {
|
||||
lines := []string{}
|
||||
w := &helpWriter{
|
||||
indent: "",
|
||||
width: guessWidth(ctx.Stdout),
|
||||
lines: &lines,
|
||||
HelpOptions: options,
|
||||
indent: "",
|
||||
width: guessWidth(ctx.Stdout),
|
||||
lines: &lines,
|
||||
helpFormatter: ctx.Kong.helpFormatter,
|
||||
HelpOptions: options,
|
||||
}
|
||||
return w
|
||||
}
|
||||
@@ -240,7 +261,7 @@ func (h *helpWriter) Print(text string) {
|
||||
}
|
||||
|
||||
func (h *helpWriter) Indent() *helpWriter {
|
||||
return &helpWriter{indent: h.indent + " ", lines: h.lines, width: h.width - 2, HelpOptions: h.HelpOptions}
|
||||
return &helpWriter{indent: h.indent + " ", lines: h.lines, width: h.width - 2, HelpOptions: h.HelpOptions, helpFormatter: h.helpFormatter}
|
||||
}
|
||||
|
||||
func (h *helpWriter) String() string {
|
||||
@@ -268,7 +289,7 @@ func (h *helpWriter) Wrap(text string) {
|
||||
func writePositionals(w *helpWriter, args []*Positional) {
|
||||
rows := [][2]string{}
|
||||
for _, arg := range args {
|
||||
rows = append(rows, [2]string{arg.Summary(), arg.Help})
|
||||
rows = append(rows, [2]string{arg.Summary(), w.helpFormatter(arg)})
|
||||
}
|
||||
writeTwoColumns(w, rows)
|
||||
}
|
||||
@@ -290,7 +311,7 @@ func writeFlags(w *helpWriter, groups [][]*Flag) {
|
||||
}
|
||||
for _, flag := range group {
|
||||
if !flag.Hidden {
|
||||
rows = append(rows, [2]string{formatFlag(haveShort, flag), flag.Help})
|
||||
rows = append(rows, [2]string{formatFlag(haveShort, flag), w.helpFormatter(flag.Value)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package kong_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -219,3 +220,31 @@ Commands:
|
||||
require.Equal(t, expected, w.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestEnvarAutoHelp(t *testing.T) {
|
||||
var cli struct {
|
||||
Flag string `env:"FLAG" help:"A flag."`
|
||||
}
|
||||
w := &strings.Builder{}
|
||||
p := mustNew(t, &cli, kong.Writers(w, w), kong.Exit(func(int) {}))
|
||||
_, err := p.Parse([]string{"--help"})
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, w.String(), "A flag ($FLAG).")
|
||||
}
|
||||
|
||||
func TestCustomHelpFormatter(t *testing.T) {
|
||||
var cli struct {
|
||||
Flag string `env:"FLAG" help:"A flag."`
|
||||
}
|
||||
w := &strings.Builder{}
|
||||
p := mustNew(t, &cli,
|
||||
kong.Writers(w, w),
|
||||
kong.Exit(func(int) {}),
|
||||
kong.HelpFormatter(func(value *kong.Value) string {
|
||||
return value.Help
|
||||
}),
|
||||
)
|
||||
_, err := p.Parse([]string{"--help"})
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, w.String(), "A flag.")
|
||||
}
|
||||
|
||||
@@ -7,17 +7,6 @@ import (
|
||||
|
||||
var interpolationRegex = regexp.MustCompile(`((?:\${([[:alpha:]_][[:word:]]*))(?:=([^}]+))?})|(\$)|([^$]+)`)
|
||||
|
||||
// Returns true if the variable "v" is interpolated in "s".
|
||||
func interpolationHasVar(s string, v string) bool {
|
||||
matches := interpolationRegex.FindAllStringSubmatch(s, -1)
|
||||
for _, match := range matches {
|
||||
if name := match[2]; name == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Interpolate variables from vars into s for substrings in the form ${var} or ${var=default}.
|
||||
func interpolate(s string, vars map[string]string) (string, error) {
|
||||
out := ""
|
||||
|
||||
@@ -50,6 +50,7 @@ type Kong struct {
|
||||
noDefaultHelp bool
|
||||
usageOnError bool
|
||||
help HelpPrinter
|
||||
helpFormatter HelpValueFormatter
|
||||
helpOptions HelpOptions
|
||||
helpFlag *Flag
|
||||
vars Vars
|
||||
@@ -63,12 +64,13 @@ type Kong struct {
|
||||
// See the README (https://github.com/alecthomas/kong) for usage instructions.
|
||||
func New(grammar interface{}, options ...Option) (*Kong, error) {
|
||||
k := &Kong{
|
||||
Exit: os.Exit,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
registry: NewRegistry().RegisterDefaults(),
|
||||
vars: Vars{},
|
||||
bindings: bindings{},
|
||||
Exit: os.Exit,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
registry: NewRegistry().RegisterDefaults(),
|
||||
vars: Vars{},
|
||||
bindings: bindings{},
|
||||
helpFormatter: DefaultHelpValueFormatter,
|
||||
}
|
||||
|
||||
options = append(options, Bind(k))
|
||||
@@ -153,22 +155,6 @@ func (k *Kong) interpolateValue(value *Value, vars Vars) (err error) {
|
||||
"default": value.Default,
|
||||
"enum": value.Enum,
|
||||
})
|
||||
if value.Tag.Env != "" {
|
||||
vars["env"] = value.Tag.Env
|
||||
if !interpolationHasVar(value.Help, "env") {
|
||||
suffix := "($" + value.Tag.Env + ")"
|
||||
switch {
|
||||
case strings.HasSuffix(value.Help, "."):
|
||||
value.Help = value.Help[:len(value.Help)-1] + " " + suffix + "."
|
||||
|
||||
case value.Help == "":
|
||||
value.Help += suffix
|
||||
|
||||
default:
|
||||
value.Help += " " + suffix
|
||||
}
|
||||
}
|
||||
}
|
||||
if value.Help, err = interpolate(value.Help, vars); err != nil {
|
||||
return fmt.Errorf("help for %s: %s", value.Summary(), err)
|
||||
}
|
||||
|
||||
@@ -750,17 +750,6 @@ func TestEnvarEnumValidated(t *testing.T) {
|
||||
require.EqualError(t, err, "--flag must be one of \"valid\" but got \"invalid\"")
|
||||
}
|
||||
|
||||
func TestEnvarAutoHelp(t *testing.T) {
|
||||
var cli struct {
|
||||
Flag string `env:"FLAG" help:"A flag."`
|
||||
}
|
||||
w := &strings.Builder{}
|
||||
p := mustNew(t, &cli, kong.Writers(w, w), kong.Exit(func(int) {}))
|
||||
_, err := p.Parse([]string{"--help"})
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, w.String(), "A flag ($FLAG).")
|
||||
}
|
||||
|
||||
func TestXor(t *testing.T) {
|
||||
var cli struct {
|
||||
Hello bool `xor:"another"`
|
||||
|
||||
@@ -158,6 +158,14 @@ func Help(help HelpPrinter) Option {
|
||||
})
|
||||
}
|
||||
|
||||
// HelpFormatter configures how the help text is formatted.
|
||||
func HelpFormatter(helpFormatter HelpValueFormatter) Option {
|
||||
return OptionFunc(func(k *Kong) error {
|
||||
k.helpFormatter = helpFormatter
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// ConfigureHelp sets the HelpOptions to use for printing help.
|
||||
func ConfigureHelp(options HelpOptions) Option {
|
||||
return OptionFunc(func(k *Kong) error {
|
||||
|
||||
Reference in New Issue
Block a user