Skip to content

Commit 9b8ce43

Browse files
authored
Handle multi line option and argument description in the generated help message (#96)
The help output will resemble: ``` Usage: app [-o] ARG Longer App Desc Arguments: ARG Argument Description Multiple Lines Options: -o, --opt Option does something another line (env $XXX_TEST) (default "default") -f, --force Force does something another line (env $YYY_TEST) ```
1 parent 8742552 commit 9b8ce43

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

cli_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,36 @@ func TestLongHelpMessage(t *testing.T) {
887887
require.Equal(t, expected, []byte(err))
888888
}
889889

890+
func TestMultiLineDescInHelpMessage(t *testing.T) {
891+
var out, err string
892+
defer captureAndRestoreOutput(&out, &err)()
893+
894+
exitCalled := false
895+
defer exitShouldBeCalledWith(t, 0, &exitCalled)()
896+
897+
app := App("app", "App Desc")
898+
app.LongDesc = "Longer App Desc"
899+
app.Spec = "[-o] ARG"
900+
901+
app.String(StringOpt{Name: "o opt", Value: "default", EnvVar: "XXX_TEST", Desc: "Option\ndoes something\n another line"})
902+
app.Bool(BoolOpt{Name: "f force", Value: false, EnvVar: "YYY_TEST", Desc: "Force\ndoes something\n another line"})
903+
app.String(StringArg{Name: "ARG", Value: "", Desc: "Argument\nDescription\nMultiple\nLines"})
904+
905+
app.Action = func() {}
906+
require.NoError(t,
907+
app.Run([]string{"app", "-h"}))
908+
909+
if *genGolden {
910+
require.NoError(t,
911+
ioutil.WriteFile("testdata/multi-line-desc-help-output.txt.golden", []byte(err), 0644))
912+
}
913+
914+
expected, e := ioutil.ReadFile("testdata/multi-line-desc-help-output.txt")
915+
require.NoError(t, e, "Failed to read the expected help output from testdata/long-help-output.txt")
916+
917+
require.Equal(t, expected, []byte(err))
918+
}
919+
890920
func TestVersionShortcut(t *testing.T) {
891921
defer suppressOutput()()
892922
exitCalled := false

commands.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli
33
import (
44
"flag"
55
"fmt"
6+
"io"
67
"strings"
78
"text/tabwriter"
89

@@ -545,7 +546,7 @@ func (c *Cmd) printHelp(longDesc bool) {
545546
env = formatEnvVarsForHelp(arg.EnvVar)
546547
value = formatValueForHelp(arg.HideValue, arg.Value)
547548
)
548-
fmt.Fprintf(w, " %s\t%s\n", arg.Name, joinStrings(arg.Desc, env, value))
549+
printTabbedRow(w, arg.Name, joinStrings(arg.Desc, env, value))
549550
}
550551
}
551552

@@ -558,7 +559,7 @@ func (c *Cmd) printHelp(longDesc bool) {
558559
env = formatEnvVarsForHelp(opt.EnvVar)
559560
value = formatValueForHelp(opt.HideValue, opt.Value)
560561
)
561-
fmt.Fprintf(w, " %s\t%s\n", optNames, joinStrings(opt.Desc, env, value))
562+
printTabbedRow(w, optNames, joinStrings(opt.Desc, env, value))
562563
}
563564
}
564565

@@ -765,3 +766,16 @@ func joinStrings(parts ...string) string {
765766
}
766767
return res
767768
}
769+
770+
func printTabbedRow(w io.Writer, s1 string, s2 string) {
771+
lines := strings.Split(s2, "\n")
772+
fmt.Fprintf(w, " %s\t%s\n", s1, strings.TrimSpace(lines[0]))
773+
774+
if len(lines) == 1 {
775+
return
776+
}
777+
778+
for _, line := range lines[1:] {
779+
fmt.Fprintf(w, " %s\t%s\n", "", strings.TrimSpace(line))
780+
}
781+
}

commands_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,3 +1379,27 @@ func TestJoinStrings(t *testing.T) {
13791379
})
13801380
}
13811381
}
1382+
1383+
func TestPrintTabbedRow(t *testing.T) {
1384+
cases := []struct {
1385+
s1, s2 string
1386+
expected string
1387+
}{
1388+
{"", "", " \t\n"},
1389+
{"a", "", " a\t\n"},
1390+
{"a", "b", " a\tb\n"},
1391+
{"a", " b", " a\tb\n"},
1392+
{"a", "b\n", " a\tb\n \t\n"},
1393+
{"a", "b\nc", " a\tb\n \tc\n"},
1394+
}
1395+
1396+
for _, cas := range cases {
1397+
t.Run(fmt.Sprintf("%q, %q", cas.s1, cas.s2), func(t *testing.T) {
1398+
t.Logf("Testing %q, %q", cas.s1, cas.s2)
1399+
var out strings.Builder
1400+
printTabbedRow(&out, cas.s1, cas.s2)
1401+
1402+
require.Equal(t, cas.expected, out.String())
1403+
})
1404+
}
1405+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
Usage: app [-o] ARG
3+
4+
Longer App Desc
5+
6+
Arguments:
7+
ARG Argument
8+
Description
9+
Multiple
10+
Lines
11+
12+
Options:
13+
-o, --opt Option
14+
does something
15+
another line (env $XXX_TEST) (default "default")
16+
-f, --force Force
17+
does something
18+
another line (env $YYY_TEST)

0 commit comments

Comments
 (0)