Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix:(issue_1505) Fix flag alignment in help #1506

Merged
merged 9 commits into from Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion app_test.go
Expand Up @@ -177,7 +177,7 @@ func ExampleApp_Run_commandHelp() {
// greet describeit - use it to see a description
//
// USAGE:
// greet describeit [command options] [arguments...]
// greet describeit [arguments...]
//
// DESCRIPTION:
// This is how we describe describeit the function
Expand Down
11 changes: 11 additions & 0 deletions command.go
Expand Up @@ -295,6 +295,17 @@ func (c *Command) startApp(ctx *Context) error {
return app.RunAsSubcommand(ctx)
}

// VisibleCommands returns a slice of the Commands with Hidden=false
func (c *Command) VisibleCommands() []*Command {
var ret []*Command
for _, command := range c.Subcommands {
if !command.Hidden {
ret = append(ret, command)
}
}
return ret
}

// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory {
if c.flagCategories == nil {
Expand Down
27 changes: 27 additions & 0 deletions command_test.go
Expand Up @@ -422,3 +422,30 @@ func TestCommand_CanAddVFlagOnCommands(t *testing.T) {
err := app.Run([]string{"foo", "bar"})
expect(t, err, nil)
}

func TestCommand_VisibleSubcCommands(t *testing.T) {

subc1 := &Command{
Name: "subc1",
Usage: "subc1 command1",
}
subc3 := &Command{
Name: "subc3",
Usage: "subc3 command2",
}
c := &Command{
Name: "bar",
Usage: "this is for testing",
Subcommands: []*Command{
subc1,
{
Name: "subc2",
Usage: "subc2 command2",
Hidden: true,
},
subc3,
},
}

expect(t, c.VisibleCommands(), []*Command{subc1, subc3})
}
57 changes: 22 additions & 35 deletions godoc-current.txt
Expand Up @@ -32,7 +32,7 @@ var (
SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate
)
var AppHelpTemplate = `NAME:
{{$v := offset .Name 6}}{{wrap .Name 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}
{{template "helpNameTemplate" .}}

USAGE:
{{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}}
Expand All @@ -41,52 +41,39 @@ VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}

DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if len .Authors}}
{{template "descriptionTemplate" .}}{{end}}
{{- if len .Authors}}

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

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

GLOBAL OPTIONS:{{range .VisibleFlagCategories}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}

GLOBAL OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{wrap $option.String 6}}{{end}}{{end}}{{end}}{{if .Copyright}}
GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}

COPYRIGHT:
{{wrap .Copyright 3}}{{end}}
{{template "copyrightTemplate" .}}{{end}}
`
AppHelpTemplate is the text template for the Default help topic. cli.go
uses text/template to render templates. You can render custom help text by
setting this variable.

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

USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
{{template "usageTemplate" .}}{{if .Category}}

CATEGORY:
{{.Category}}{{end}}{{if .Description}}

DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if .VisibleFlagCategories}}
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}}

OPTIONS:{{range .VisibleFlagCategories}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}{{end}}{{end}}{{else}}{{if .VisibleFlags}}
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}

OPTIONS:
{{range .VisibleFlags}}{{.}}{{end}}{{end}}{{end}}
`
OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
CommandHelpTemplate is the text template for the command help topic. cli.go
uses text/template to render templates. You can render custom help text by
setting this variable.
Expand Down Expand Up @@ -145,22 +132,19 @@ var OsExiter = os.Exit
os.Exit.

var SubcommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}}
{{template "helpNameTemplate" .}}

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

DESCRIPTION:
{{wrap .Description 3}}{{end}}
{{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}

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

OPTIONS:
{{range .VisibleFlags}}{{.}}{{end}}{{end}}
`
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}

OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
SubcommandHelpTemplate is the text template for the subcommand help topic.
cli.go uses text/template to render templates. You can render custom help
text by setting this variable.
Expand Down Expand Up @@ -585,6 +569,9 @@ func (c *Command) Run(ctx *Context) (err error)
Run invokes the command given the context, parses ctx.Args() to generate
command-specific flags

func (c *Command) VisibleCommands() []*Command
VisibleCommands returns a slice of the Commands with Hidden=false

func (c *Command) VisibleFlagCategories() []VisibleFlagCategory
VisibleFlagCategories returns a slice containing all the visible flag
categories with the flags they contain
Expand Down
17 changes: 16 additions & 1 deletion help.go
Expand Up @@ -242,7 +242,11 @@ func ShowCommandHelp(ctx *Context, command string) error {
c.Subcommands = append(c.Subcommands, helpCommandDontUse)
}
if !ctx.App.HideHelp && HelpFlag != nil {
c.appendFlag(HelpFlag)
if c.flagCategories == nil {
c.flagCategories = newFlagCategoriesFromFlags([]Flag{HelpFlag})
} else {
c.flagCategories.AddFlag("", HelpFlag)
}
}
templ := c.CustomHelpTemplate
if templ == "" {
Expand Down Expand Up @@ -358,6 +362,17 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs

w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
t.New("helpNameTemplate").Parse(helpNameTemplate)
t.New("usageTemplate").Parse(usageTemplate)
t.New("descriptionTemplate").Parse(descriptionTemplate)
t.New("visibleCommandTemplate").Parse(visibleCommandTemplate)
t.New("copyrightTemplate").Parse(copyrightTemplate)
t.New("versionTemplate").Parse(versionTemplate)
t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate)
t.New("visibleFlagTemplate").Parse(visibleFlagTemplate)
t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1))
t.New("authorsTemplate").Parse(authorsTemplate)
t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate)

err := t.Execute(w, data)
if err != nil {
Expand Down
76 changes: 76 additions & 0 deletions help_test.go
Expand Up @@ -1443,3 +1443,79 @@ OPTIONS:
output.String(), expected)
}
}

func TestWrappedHelpSubcommand(t *testing.T) {

// Reset HelpPrinter after this test.
defer func(old helpPrinter) {
HelpPrinter = old
}(HelpPrinter)

output := new(bytes.Buffer)
app := &App{
Name: "cli.test",
Writer: output,
Commands: []*Command{
{
Name: "bar",
Aliases: []string{"a"},
Usage: "add a task to the list",
UsageText: "this is an even longer way of describing adding a task to the list",
Description: "and a description long enough to wrap in this test case",
Action: func(c *Context) error {
return nil
},
Subcommands: []*Command{
{
Name: "grok",
Usage: "remove an existing template",
UsageText: "longer usage text goes here, la la la, hopefully this is long enough to wrap even more",
Action: func(c *Context) error {
return nil
},
Flags: []Flag{
&StringFlag{
Name: "test-f",
Usage: "my test usage",
},
},
},
},
},
},
}

HelpPrinter = func(w io.Writer, templ string, data interface{}) {
funcMap := map[string]interface{}{
"wrapAt": func() int {
return 30
},
}

HelpPrinterCustom(w, templ, data, funcMap)
}

_ = app.Run([]string{"foo", "bar", "help", "grok"})

expected := `NAME:
cli.test bar grok - remove
an
existing
template

USAGE:
longer usage text goes
here, la la la, hopefully
this is long enough to wrap
even more

OPTIONS:
--help, -h show help (default: false)
--test-f value my test usage
`

if output.String() != expected {
t.Errorf("Unexpected wrapping, got:\n%s\nexpected: %s",
output.String(), expected)
}
}