diff --git a/README.md b/README.md
index a96c059..315c7a7 100644
--- a/README.md
+++ b/README.md
@@ -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,
-
-
## 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.
### `Bind(...)` - bind values for callback hooks and Run() methods
diff --git a/help.go b/help.go
index 8bb67cd..4814b1c 100644
--- a/help.go
+++ b/help.go
@@ -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)})
}
}
}
diff --git a/help_test.go b/help_test.go
index fbe4a47..3f6f368 100644
--- a/help_test.go
+++ b/help_test.go
@@ -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.")
+}
diff --git a/interpolate.go b/interpolate.go
index bbfff54..9de1ff7 100644
--- a/interpolate.go
+++ b/interpolate.go
@@ -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 := ""
diff --git a/kong.go b/kong.go
index 5296ef2..882e4ad 100644
--- a/kong.go
+++ b/kong.go
@@ -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)
}
diff --git a/kong_test.go b/kong_test.go
index 087252a..b55093a 100644
--- a/kong_test.go
+++ b/kong_test.go
@@ -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"`
diff --git a/options.go b/options.go
index aec7164..1bf5219 100644
--- a/options.go
+++ b/options.go
@@ -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 {