Skip to content

Commit 2a4809f

Browse files
authored
Merge pull request #1506 from dearchap/issue_1505
Fix:(issue_1505) Fix flag alignment in help
2 parents 8f469ab + 86809ce commit 2a4809f

File tree

8 files changed

+222
-107
lines changed

8 files changed

+222
-107
lines changed

app_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func ExampleApp_Run_commandHelp() {
177177
// greet describeit - use it to see a description
178178
//
179179
// USAGE:
180-
// greet describeit [command options] [arguments...]
180+
// greet describeit [arguments...]
181181
//
182182
// DESCRIPTION:
183183
// This is how we describe describeit the function

command.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,17 @@ func (c *Command) startApp(ctx *Context) error {
295295
return app.RunAsSubcommand(ctx)
296296
}
297297

298+
// VisibleCommands returns a slice of the Commands with Hidden=false
299+
func (c *Command) VisibleCommands() []*Command {
300+
var ret []*Command
301+
for _, command := range c.Subcommands {
302+
if !command.Hidden {
303+
ret = append(ret, command)
304+
}
305+
}
306+
return ret
307+
}
308+
298309
// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
299310
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory {
300311
if c.flagCategories == nil {

command_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,30 @@ func TestCommand_CanAddVFlagOnCommands(t *testing.T) {
422422
err := app.Run([]string{"foo", "bar"})
423423
expect(t, err, nil)
424424
}
425+
426+
func TestCommand_VisibleSubcCommands(t *testing.T) {
427+
428+
subc1 := &Command{
429+
Name: "subc1",
430+
Usage: "subc1 command1",
431+
}
432+
subc3 := &Command{
433+
Name: "subc3",
434+
Usage: "subc3 command2",
435+
}
436+
c := &Command{
437+
Name: "bar",
438+
Usage: "this is for testing",
439+
Subcommands: []*Command{
440+
subc1,
441+
{
442+
Name: "subc2",
443+
Usage: "subc2 command2",
444+
Hidden: true,
445+
},
446+
subc3,
447+
},
448+
}
449+
450+
expect(t, c.VisibleCommands(), []*Command{subc1, subc3})
451+
}

godoc-current.txt

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var (
3232
SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate
3333
)
3434
var AppHelpTemplate = `NAME:
35-
{{$v := offset .Name 6}}{{wrap .Name 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}
35+
{{template "helpNameTemplate" .}}
3636

3737
USAGE:
3838
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
@@ -41,52 +41,39 @@ VERSION:
4141
{{.Version}}{{end}}{{end}}{{if .Description}}
4242

4343
DESCRIPTION:
44-
{{wrap .Description 3}}{{end}}{{if len .Authors}}
44+
{{template "descriptionTemplate" .}}{{end}}
45+
{{- if len .Authors}}
4546

46-
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
47-
{{range $index, $author := .Authors}}{{if $index}}
48-
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
47+
AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}}
4948

50-
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
51-
{{.Name}}:{{range .VisibleCommands}}
52-
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
53-
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
49+
COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
5450

55-
GLOBAL OPTIONS:{{range .VisibleFlagCategories}}
56-
{{if .Name}}{{.Name}}
57-
{{end}}{{range .Flags}}{{.}}
58-
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
51+
GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
5952

60-
GLOBAL OPTIONS:
61-
{{range $index, $option := .VisibleFlags}}{{if $index}}
62-
{{end}}{{wrap $option.String 6}}{{end}}{{end}}{{end}}{{if .Copyright}}
53+
GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}
6354

6455
COPYRIGHT:
65-
{{wrap .Copyright 3}}{{end}}
56+
{{template "copyrightTemplate" .}}{{end}}
6657
`
6758
AppHelpTemplate is the text template for the Default help topic. cli.go
6859
uses text/template to render templates. You can render custom help text by
6960
setting this variable.
7061

7162
var CommandHelpTemplate = `NAME:
72-
{{$v := offset .HelpName 6}}{{wrap .HelpName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}
63+
{{template "helpNameTemplate" .}}
7364

7465
USAGE:
75-
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
66+
{{template "usageTemplate" .}}{{if .Category}}
7667

7768
CATEGORY:
7869
{{.Category}}{{end}}{{if .Description}}
7970

8071
DESCRIPTION:
81-
{{wrap .Description 3}}{{end}}{{if .VisibleFlagCategories}}
72+
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
8273

83-
OPTIONS:{{range .VisibleFlagCategories}}
84-
{{if .Name}}{{.Name}}
85-
{{end}}{{range .Flags}}{{.}}{{end}}{{end}}{{else}}{{if .VisibleFlags}}
74+
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
8675

87-
OPTIONS:
88-
{{range .VisibleFlags}}{{.}}{{end}}{{end}}{{end}}
89-
`
76+
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
9077
CommandHelpTemplate is the text template for the command help topic. cli.go
9178
uses text/template to render templates. You can render custom help text by
9279
setting this variable.
@@ -145,22 +132,19 @@ var OsExiter = os.Exit
145132
os.Exit.
146133

147134
var SubcommandHelpTemplate = `NAME:
148-
{{.HelpName}} - {{.Usage}}
135+
{{template "helpNameTemplate" .}}
149136

150137
USAGE:
151138
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
152139

153140
DESCRIPTION:
154-
{{wrap .Description 3}}{{end}}
141+
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
155142

156-
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
157-
{{.Name}}:{{range .VisibleCommands}}
158-
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
159-
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
143+
COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
160144

161-
OPTIONS:
162-
{{range .VisibleFlags}}{{.}}{{end}}{{end}}
163-
`
145+
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
146+
147+
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
164148
SubcommandHelpTemplate is the text template for the subcommand help topic.
165149
cli.go uses text/template to render templates. You can render custom help
166150
text by setting this variable.
@@ -585,6 +569,9 @@ func (c *Command) Run(ctx *Context) (err error)
585569
Run invokes the command given the context, parses ctx.Args() to generate
586570
command-specific flags
587571

572+
func (c *Command) VisibleCommands() []*Command
573+
VisibleCommands returns a slice of the Commands with Hidden=false
574+
588575
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory
589576
VisibleFlagCategories returns a slice containing all the visible flag
590577
categories with the flags they contain

help.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,11 @@ func ShowCommandHelp(ctx *Context, command string) error {
242242
c.Subcommands = append(c.Subcommands, helpCommandDontUse)
243243
}
244244
if !ctx.App.HideHelp && HelpFlag != nil {
245-
c.appendFlag(HelpFlag)
245+
if c.flagCategories == nil {
246+
c.flagCategories = newFlagCategoriesFromFlags([]Flag{HelpFlag})
247+
} else {
248+
c.flagCategories.AddFlag("", HelpFlag)
249+
}
246250
}
247251
templ := c.CustomHelpTemplate
248252
if templ == "" {
@@ -358,6 +362,17 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs
358362

359363
w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
360364
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
365+
t.New("helpNameTemplate").Parse(helpNameTemplate)
366+
t.New("usageTemplate").Parse(usageTemplate)
367+
t.New("descriptionTemplate").Parse(descriptionTemplate)
368+
t.New("visibleCommandTemplate").Parse(visibleCommandTemplate)
369+
t.New("copyrightTemplate").Parse(copyrightTemplate)
370+
t.New("versionTemplate").Parse(versionTemplate)
371+
t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate)
372+
t.New("visibleFlagTemplate").Parse(visibleFlagTemplate)
373+
t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1))
374+
t.New("authorsTemplate").Parse(authorsTemplate)
375+
t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate)
361376

362377
err := t.Execute(w, data)
363378
if err != nil {

help_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,3 +1443,79 @@ OPTIONS:
14431443
output.String(), expected)
14441444
}
14451445
}
1446+
1447+
func TestWrappedHelpSubcommand(t *testing.T) {
1448+
1449+
// Reset HelpPrinter after this test.
1450+
defer func(old helpPrinter) {
1451+
HelpPrinter = old
1452+
}(HelpPrinter)
1453+
1454+
output := new(bytes.Buffer)
1455+
app := &App{
1456+
Name: "cli.test",
1457+
Writer: output,
1458+
Commands: []*Command{
1459+
{
1460+
Name: "bar",
1461+
Aliases: []string{"a"},
1462+
Usage: "add a task to the list",
1463+
UsageText: "this is an even longer way of describing adding a task to the list",
1464+
Description: "and a description long enough to wrap in this test case",
1465+
Action: func(c *Context) error {
1466+
return nil
1467+
},
1468+
Subcommands: []*Command{
1469+
{
1470+
Name: "grok",
1471+
Usage: "remove an existing template",
1472+
UsageText: "longer usage text goes here, la la la, hopefully this is long enough to wrap even more",
1473+
Action: func(c *Context) error {
1474+
return nil
1475+
},
1476+
Flags: []Flag{
1477+
&StringFlag{
1478+
Name: "test-f",
1479+
Usage: "my test usage",
1480+
},
1481+
},
1482+
},
1483+
},
1484+
},
1485+
},
1486+
}
1487+
1488+
HelpPrinter = func(w io.Writer, templ string, data interface{}) {
1489+
funcMap := map[string]interface{}{
1490+
"wrapAt": func() int {
1491+
return 30
1492+
},
1493+
}
1494+
1495+
HelpPrinterCustom(w, templ, data, funcMap)
1496+
}
1497+
1498+
_ = app.Run([]string{"foo", "bar", "help", "grok"})
1499+
1500+
expected := `NAME:
1501+
cli.test bar grok - remove
1502+
an
1503+
existing
1504+
template
1505+
1506+
USAGE:
1507+
longer usage text goes
1508+
here, la la la, hopefully
1509+
this is long enough to wrap
1510+
even more
1511+
1512+
OPTIONS:
1513+
--help, -h show help (default: false)
1514+
--test-f value my test usage
1515+
`
1516+
1517+
if output.String() != expected {
1518+
t.Errorf("Unexpected wrapping, got:\n%s\nexpected: %s",
1519+
output.String(), expected)
1520+
}
1521+
}

0 commit comments

Comments
 (0)