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

feat(Command): add status for the helptext #225

Merged
merged 2 commits into from
Mar 18, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 85 additions & 20 deletions cli/helptext.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ const (
)

type helpFields struct {
Indent string
Usage string
Path string
Tagline string
Arguments string
Options string
Synopsis string
Subcommands string
Description string
MoreHelp bool
Indent string
Warning string
Usage string
Path string
Tagline string
Arguments string
Options string
Synopsis string
Subcommands string
ExperimentalSubcommands string
DeprecatedSubcommands string
RemovedSubcommands string
Description string
MoreHelp bool
}

// TrimNewlines removes extra newlines from fields. This makes aligning
Expand All @@ -50,12 +54,16 @@ type helpFields struct {
// `
func (f *helpFields) TrimNewlines() {
f.Path = strings.Trim(f.Path, "\n")
f.Warning = strings.Trim(f.Warning, "\n")
f.Usage = strings.Trim(f.Usage, "\n")
f.Tagline = strings.Trim(f.Tagline, "\n")
f.Arguments = strings.Trim(f.Arguments, "\n")
f.Options = strings.Trim(f.Options, "\n")
f.Synopsis = strings.Trim(f.Synopsis, "\n")
f.Subcommands = strings.Trim(f.Subcommands, "\n")
f.ExperimentalSubcommands = strings.Trim(f.ExperimentalSubcommands, "\n")
f.DeprecatedSubcommands = strings.Trim(f.DeprecatedSubcommands, "\n")
f.RemovedSubcommands = strings.Trim(f.RemovedSubcommands, "\n")
f.Description = strings.Trim(f.Description, "\n")
}

Expand All @@ -68,15 +76,21 @@ func (f *helpFields) IndentAll() {
return indentString(s, indentStr)
}

f.Warning = indent(f.Warning)
f.Usage = indent(f.Usage)
f.Arguments = indent(f.Arguments)
f.Options = indent(f.Options)
f.Synopsis = indent(f.Synopsis)
f.Subcommands = indent(f.Subcommands)
f.DeprecatedSubcommands = indent(f.DeprecatedSubcommands)
f.ExperimentalSubcommands = indent(f.ExperimentalSubcommands)
f.RemovedSubcommands = indent(f.RemovedSubcommands)
f.Description = indent(f.Description)
}

const longHelpFormat = `USAGE
const longHelpFormat = `{{if .Warning}}WARNING: {{.Warning}}

{{end}}USAGE
{{.Usage}}

{{if .Synopsis}}SYNOPSIS
Expand All @@ -99,9 +113,21 @@ const longHelpFormat = `USAGE

{{.Indent}}For more information about each command, use:
{{.Indent}}'{{.Path}} <subcmd> --help'

{{end}}{{if .ExperimentalSubcommands}}EXPERIMENTAL SUBCOMMANDS
{{.ExperimentalSubcommands}}

{{end}}{{if .DeprecatedSubcommands}}DEPRECATED SUBCOMMANDS
{{.DeprecatedSubcommands}}

{{end}}{{if .RemovedSubcommands}}REMOVED SUBCOMMANDS
{{.RemovedSubcommands}}

{{end}}
`
const shortHelpFormat = `USAGE
const shortHelpFormat = `{{if .Warning}}WARNING: {{.Warning}}

{{end}}USAGE
{{.Usage}}
{{if .Synopsis}}
{{.Synopsis}}
Expand All @@ -113,6 +139,16 @@ SUBCOMMANDS
{{end}}{{if .MoreHelp}}
{{.Indent}}For more information about each command, use:
{{.Indent}}'{{.Path}} <subcmd> --help'

{{end}}{{if .ExperimentalSubcommands}}EXPERIMENTAL SUBCOMMANDS
{{.ExperimentalSubcommands}}

{{end}}{{if .DeprecatedSubcommands}}DEPRECATED SUBCOMMANDS
{{.DeprecatedSubcommands}}

{{end}}{{if .RemovedSubcommands}}REMOVED SUBCOMMANDS
{{.RemovedSubcommands}}

{{end}}
`

Expand Down Expand Up @@ -188,6 +224,7 @@ func LongHelp(rootName string, root *cmds.Command, path []string, out io.Writer)
}

// autogen fields that are empty
fields.Warning = generateWarningText(cmd)
if len(cmd.Helptext.Usage) > 0 {
fields.Usage = cmd.Helptext.Usage
} else {
Expand All @@ -200,7 +237,10 @@ func LongHelp(rootName string, root *cmds.Command, path []string, out io.Writer)
fields.Options = strings.Join(optionText(width, cmd), "\n")
}
if len(fields.Subcommands) == 0 {
fields.Subcommands = strings.Join(subcommandText(width, cmd, rootName, path), "\n")
fields.Subcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Active), "\n")
fields.ExperimentalSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Experimental), "\n")
fields.DeprecatedSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Deprecated), "\n")
fields.RemovedSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Removed), "\n")
}
if len(fields.Synopsis) == 0 {
fields.Synopsis = generateSynopsis(width, cmd, pathStr)
Expand Down Expand Up @@ -245,13 +285,17 @@ func ShortHelp(rootName string, root *cmds.Command, path []string, out io.Writer
width := getTerminalWidth(out) - len(indentStr)

// autogen fields that are empty
fields.Warning = generateWarningText(cmd)
if len(cmd.Helptext.Usage) > 0 {
fields.Usage = cmd.Helptext.Usage
} else {
fields.Usage = commandUsageText(width, cmd, rootName, path)
}
if len(fields.Subcommands) == 0 {
fields.Subcommands = strings.Join(subcommandText(width, cmd, rootName, path), "\n")
fields.Subcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Active), "\n")
fields.ExperimentalSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Experimental), "\n")
fields.DeprecatedSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Deprecated), "\n")
fields.RemovedSubcommands = strings.Join(subcommandText(width, cmd, rootName, path, cmds.Removed), "\n")
}
if len(fields.Synopsis) == 0 {
fields.Synopsis = generateSynopsis(width, cmd, pathStr)
Expand Down Expand Up @@ -409,24 +453,28 @@ func optionText(width int, cmd ...*cmds.Command) []string {
return lines
}

func subcommandText(width int, cmd *cmds.Command, rootName string, path []string) []string {
func subcommandText(width int, cmd *cmds.Command, rootName string, path []string, status cmds.Status) []string {
prefix := fmt.Sprintf("%v %v", rootName, strings.Join(path, " "))
if len(path) > 0 {
prefix += " "
}

subCmds := make(map[string]*cmds.Command, len(cmd.Subcommands))
// Sorting fixes changing order bug #2981.
sortedNames := make([]string, 0)
for name := range cmd.Subcommands {
sortedNames = append(sortedNames, name)
for name, c := range cmd.Subcommands {
if c.Status == status {
sortedNames = append(sortedNames, name)
subCmds[name] = c
}
}
sort.Strings(sortedNames)

subcmds := make([]*cmds.Command, len(cmd.Subcommands))
lines := make([]string, len(cmd.Subcommands))
subcmds := make([]*cmds.Command, len(subCmds))
lines := make([]string, len(subCmds))

for i, name := range sortedNames {
sub := cmd.Subcommands[name]
sub := subCmds[name]
usage := usageText(sub)
if len(usage) > 0 {
usage = " " + usage
Expand All @@ -445,6 +493,23 @@ func subcommandText(width int, cmd *cmds.Command, rootName string, path []string
return lines
}

// Text printed at the beginning of --help,
// after 'WARNING: ' tag at the start of the command.
func generateWarningText(cmd *cmds.Command) string {
switch cmd.Status {
case cmds.Active:
return "" // We don't print a warning for a normal active command.
case cmds.Deprecated:
return "DEPRECATED, command will be removed in the future"
case cmds.Experimental:
return "EXPERIMENTAL, command may change in future releases"
case cmds.Removed:
return "REMOVED, command is no longer available"
Comment on lines +502 to +507
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IF this text looks ok, then we can merge and ship this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, looks fair.

default:
panic("unknown command status")
}
}

func commandUsageText(width int, cmd *cmds.Command, rootName string, path []string) string {
text := fmt.Sprintf("%v %v", rootName, strings.Join(path, " "))
argUsage := usageText(cmd)
Expand Down
16 changes: 16 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,26 @@ type Command struct {
// NoLocal denotes that a command cannot be executed in a local environment
NoLocal bool

// Status of the command showed in the help.
Status Status

// Extra contains a set of other command-specific parameters
Extra *Extra
}

// Status indicates whether this command is active/deprecated/experimental/etc
// which is signaled in the help text produced.
type Status int

const (
// Active command, doesn't produce any special indication.
Active Status = iota
// Other commands will be shown their statuses in the help text.
Experimental
Deprecated
Removed
)

// Extra is a set of tag information for a command
type Extra struct {
m map[interface{}]interface{}
Expand Down