From 788c166025870bc4653adb5986d03f99c1d14af2 Mon Sep 17 00:00:00 2001 From: Alex Flint Date: Sun, 31 Jan 2021 19:15:49 -0800 Subject: [PATCH] test that short-only options are printed first in the help message --- usage.go | 34 +++++++++++++++++++--------------- usage_test.go | 21 ++++++++++++++++++++- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/usage.go b/usage.go index 4704183..f3f9fe6 100644 --- a/usage.go +++ b/usage.go @@ -117,9 +117,6 @@ func (p *Parser) writeUsageForCommand(w io.Writer, cmd *command) { } func printTwoCols(w io.Writer, left, help string, defaultVal string, envVal string) { - if left == "" { - return - } lhs := " " + left fmt.Fprint(w, lhs) if help != "" { @@ -162,12 +159,15 @@ func (p *Parser) WriteHelp(w io.Writer) { // writeHelp writes the usage string for the given subcommand func (p *Parser) writeHelpForCommand(w io.Writer, cmd *command) { - var positionals, options []*spec + var positionals, longOptions, shortOptions []*spec for _, spec := range cmd.specs { - if spec.positional { + switch { + case spec.positional: positionals = append(positionals, spec) - } else { - options = append(options, spec) + case spec.long != "": + longOptions = append(longOptions, spec) + case spec.short != "": + shortOptions = append(shortOptions, spec) } } @@ -184,10 +184,13 @@ func (p *Parser) writeHelpForCommand(w io.Writer, cmd *command) { } } - // write the list of options - if len(options) > 0 || cmd.parent == nil { + // write the list of options with the short-only ones first to match the usage string + if len(shortOptions)+len(longOptions) > 0 || cmd.parent == nil { fmt.Fprint(w, "\nOptions:\n") - for _, spec := range options { + for _, spec := range shortOptions { + p.printOption(w, spec) + } + for _, spec := range longOptions { p.printOption(w, spec) } } @@ -233,15 +236,16 @@ func (p *Parser) writeHelpForCommand(w io.Writer, cmd *command) { } func (p *Parser) printOption(w io.Writer, spec *spec) { - text := make([]string, 0, 2) + ways := make([]string, 0, 2) if spec.long != "" { - text = append(text, synopsis(spec, "--"+spec.long)) + ways = append(ways, synopsis(spec, "--"+spec.long)) } if spec.short != "" { - text = append(text, synopsis(spec, "-"+spec.short)) + ways = append(ways, synopsis(spec, "-"+spec.short)) + } + if len(ways) > 0 { + printTwoCols(w, strings.Join(ways, ", "), spec.help, spec.defaultVal, spec.env) } - left := strings.Join(text, ", ") - printTwoCols(w, left, spec.help, spec.defaultVal, spec.env) } func synopsis(spec *spec, form string) string { diff --git a/usage_test.go b/usage_test.go index 8e28dc5..6dee402 100644 --- a/usage_test.go +++ b/usage_test.go @@ -310,7 +310,7 @@ Global options: assert.Equal(t, expectedHelp, help.String()) } -func TestUsageWithOptionalLongNames(t *testing.T) { +func TestUsageWithoutLongNames(t *testing.T) { expectedHelp := `Usage: example [-a PLACEHOLDER] -b SHORTONLY2 Options: @@ -329,6 +329,25 @@ Options: assert.Equal(t, expectedHelp, help.String()) } +func TestUsageWithShortFirst(t *testing.T) { + expectedHelp := `Usage: example [-c CAT] [--dog DOG] + +Options: + -c CAT + --dog DOG + --help, -h display this help and exit +` + var args struct { + Dog string + Cat string `arg:"-c,--"` + } + p, err := NewParser(Config{Program: "example"}, &args) + assert.NoError(t, err) + var help bytes.Buffer + p.WriteHelp(&help) + assert.Equal(t, expectedHelp, help.String()) +} + func TestUsageWithEnvOptions(t *testing.T) { expectedHelp := `Usage: example [-s SHORT]