Parses usage placeholders via back quotes. Resolves #333

This commit is contained in:
Kevin Cantwell 2016-04-21 23:02:06 -04:00
parent 71f57d300d
commit 13b7eedc13
2 changed files with 56 additions and 24 deletions

52
flag.go
View File

@ -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 {

View File

@ -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)
} }
} }
} }