Merge pull request #357 from kevin-cantwell/parse-usage-placeholders
Parses usage placeholders via back quotes. Resolves #333
This commit is contained in:
commit
7528b17cc6
21
README.md
21
README.md
@ -195,6 +195,27 @@ app.Action = func(c *cli.Context) {
|
|||||||
|
|
||||||
See full list of flags at http://godoc.org/github.com/codegangsta/cli
|
See full list of flags at http://godoc.org/github.com/codegangsta/cli
|
||||||
|
|
||||||
|
#### Placeholder Values
|
||||||
|
|
||||||
|
Sometimes it's useful to specify a flag's value within the usage string itself. Such placeholders are
|
||||||
|
indicated with back quotes.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
```go
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "config, c",
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--config FILE, -c FILE Load configuration from FILE
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that only the first placeholder is used. Subsequent back-quoted words will be left as-is.
|
||||||
|
|
||||||
#### Alternate Names
|
#### Alternate Names
|
||||||
|
|
||||||
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
|
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
|
||||||
|
52
flag.go
52
flag.go
@ -74,7 +74,8 @@ type GenericFlag struct {
|
|||||||
// help text to the user (uses the String() method of the generic flag to show
|
// help text to the user (uses the String() method of the generic flag to show
|
||||||
// the value)
|
// the value)
|
||||||
func (f GenericFlag) String() string {
|
func (f GenericFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name, placeholder), f.FormatValueHelp(), usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f GenericFlag) FormatValueHelp() string {
|
func (f GenericFlag) FormatValueHelp() string {
|
||||||
@ -143,7 +144,8 @@ type StringSliceFlag struct {
|
|||||||
func (f StringSliceFlag) String() string {
|
func (f StringSliceFlag) String() string {
|
||||||
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||||
pref := prefixFor(firstName)
|
pref := prefixFor(firstName)
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name, placeholder), pref+firstName+" option "+pref+firstName+" option", usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -212,7 +214,8 @@ type IntSliceFlag struct {
|
|||||||
func (f IntSliceFlag) String() string {
|
func (f IntSliceFlag) String() string {
|
||||||
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||||
pref := prefixFor(firstName)
|
pref := prefixFor(firstName)
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name, placeholder), pref+firstName+" option "+pref+firstName+" option", usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -257,7 +260,8 @@ type BoolFlag struct {
|
|||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
func (f BoolFlag) String() string {
|
func (f BoolFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name, placeholder), usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -300,7 +304,8 @@ type BoolTFlag struct {
|
|||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
func (f BoolTFlag) String() string {
|
func (f BoolTFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name, placeholder), usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -343,7 +348,8 @@ type StringFlag struct {
|
|||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f StringFlag) String() string {
|
func (f StringFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name), f.FormatValueHelp(), f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s %v\t%v", prefixedNames(f.Name, placeholder), f.FormatValueHelp(), usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f StringFlag) FormatValueHelp() string {
|
func (f StringFlag) FormatValueHelp() string {
|
||||||
@ -391,7 +397,8 @@ type IntFlag struct {
|
|||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f IntFlag) String() string {
|
func (f IntFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name, placeholder), f.Value, usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -434,7 +441,8 @@ type DurationFlag struct {
|
|||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
func (f DurationFlag) String() string {
|
func (f DurationFlag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name, placeholder), f.Value, usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -477,7 +485,8 @@ type Float64Flag struct {
|
|||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f Float64Flag) String() string {
|
func (f Float64Flag) String() string {
|
||||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
placeholder, usage := unquoteUsage(f.Usage)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name, placeholder), f.Value, usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
@ -517,16 +526,37 @@ func prefixFor(name string) (prefix string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func prefixedNames(fullName string) (prefixed string) {
|
// Returns the placeholder, if any, and the unquoted usage string.
|
||||||
|
func unquoteUsage(usage string) (string, string) {
|
||||||
|
for i := 0; i < len(usage); i++ {
|
||||||
|
if usage[i] == '`' {
|
||||||
|
for j := i + 1; j < len(usage); j++ {
|
||||||
|
if usage[j] == '`' {
|
||||||
|
name := usage[i+1 : j]
|
||||||
|
usage = usage[:i] + name + usage[j+1:]
|
||||||
|
return name, usage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", usage
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixedNames(fullName, placeholder string) string {
|
||||||
|
var prefixed string
|
||||||
parts := strings.Split(fullName, ",")
|
parts := strings.Split(fullName, ",")
|
||||||
for i, name := range parts {
|
for i, name := range parts {
|
||||||
name = strings.Trim(name, " ")
|
name = strings.Trim(name, " ")
|
||||||
prefixed += prefixFor(name) + name
|
prefixed += prefixFor(name) + name
|
||||||
|
if placeholder != "" {
|
||||||
|
prefixed += " " + placeholder
|
||||||
|
}
|
||||||
if i < len(parts)-1 {
|
if i < len(parts)-1 {
|
||||||
prefixed += ", "
|
prefixed += ", "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return prefixed
|
||||||
}
|
}
|
||||||
|
|
||||||
func withEnvHint(envVar, str string) string {
|
func withEnvHint(envVar, str string) string {
|
||||||
|
28
flag_test.go
28
flag_test.go
@ -4,9 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var boolFlagTests = []struct {
|
var boolFlagTests = []struct {
|
||||||
@ -31,19 +31,21 @@ func TestBoolFlagHelpOutput(t *testing.T) {
|
|||||||
|
|
||||||
var stringFlagTests = []struct {
|
var stringFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
|
usage string
|
||||||
value string
|
value string
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{"help", "", "--help \t"},
|
{"help", "", "", "--help \t"},
|
||||||
{"h", "", "-h \t"},
|
{"h", "", "", "-h \t"},
|
||||||
{"h", "", "-h \t"},
|
{"h", "", "", "-h \t"},
|
||||||
{"test", "Something", "--test \"Something\"\t"},
|
{"test", "", "Something", "--test \"Something\"\t"},
|
||||||
|
{"config,c", "Load configuration from `FILE`", "", "--config FILE, -c FILE \tLoad configuration from FILE"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringFlagHelpOutput(t *testing.T) {
|
func TestStringFlagHelpOutput(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range stringFlagTests {
|
for _, test := range stringFlagTests {
|
||||||
flag := StringFlag{Name: test.name, Value: test.value}
|
flag := StringFlag{Name: test.name, Usage: test.usage, Value: test.value}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -64,7 +66,7 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_FOO%]"
|
expectedSuffix = " [%APP_FOO%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%s does not end with" + expectedSuffix, output)
|
t.Errorf("%s does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +122,7 @@ func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_QWWX%]"
|
expectedSuffix = " [%APP_QWWX%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%q does not end with" + expectedSuffix, output)
|
t.Errorf("%q does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +159,7 @@ func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_BAR%]"
|
expectedSuffix = " [%APP_BAR%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%s does not end with" + expectedSuffix, output)
|
t.Errorf("%s does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +196,7 @@ func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_BAR%]"
|
expectedSuffix = " [%APP_BAR%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%s does not end with" + expectedSuffix, output)
|
t.Errorf("%s does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +240,7 @@ func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_SMURF%]"
|
expectedSuffix = " [%APP_SMURF%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%q does not end with" + expectedSuffix, output)
|
t.Errorf("%q does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +277,7 @@ func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_BAZ%]"
|
expectedSuffix = " [%APP_BAZ%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%s does not end with" + expectedSuffix, output)
|
t.Errorf("%s does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,7 +315,7 @@ func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
expectedSuffix = " [%APP_ZAP%]"
|
expectedSuffix = " [%APP_ZAP%]"
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(output, expectedSuffix) {
|
if !strings.HasSuffix(output, expectedSuffix) {
|
||||||
t.Errorf("%s does not end with" + expectedSuffix, output)
|
t.Errorf("%s does not end with"+expectedSuffix, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user