feat: add a command tree help view (#32)

Add a command tree help view.

Following up #29 and #30, I noticed that the default help looks quite duplicative since only the help text of the last command in chain is viewed. I needed an option to also show the help text of the command nodes in an appropriate way.  This is what I came up with.
This commit is contained in:
Matthias Fax
2019-01-21 14:14:26 +01:00
committed by Alec Thomas
parent fcf5f9bc1a
commit 2a90ca2ad3
2 changed files with 176 additions and 10 deletions
+81 -10
View File
@@ -37,6 +37,14 @@ type HelpOptions struct {
// Write help in a more compact, but still fully-specified, form.
Compact bool
// Tree writes command chains in a tree structure instead of listing them separately.
Tree bool
// Indenter modulates the given prefix for the next layer in the tree view.
// The following exported templates can be used: kong.SpaceIndenter, kong.LineIndenter, kong.TreeIndenter
// The kong.SpaceIndenter will be used by default.
Indenter HelpIndenter
}
// HelpProvider can be implemented by commands/args to provide detailed help.
@@ -45,6 +53,9 @@ type HelpProvider interface {
Help() string
}
// HelpIndenter is used to indent new layers in the help tree.
type HelpIndenter func(prefix string) string
// HelpPrinter is used to print context-sensitive help.
type HelpPrinter func(options HelpOptions, ctx *Context) error
@@ -115,19 +126,32 @@ func printNodeDetail(w *helpWriter, node *Node, hide bool) {
cmds := node.Leaves(hide)
if len(cmds) > 0 {
w.Print("")
w.Print("Commands:")
iw := w.Indent()
if w.Compact {
rows := [][2]string{}
for _, cmd := range cmds {
rows = append(rows, [2]string{cmd.Path(), cmd.Help})
if w.Tree {
w.Print("Command Tree:")
iw := w.Indent()
var rows [][2]string
for i, cmd := range node.Children {
rows = append(rows, w.commandTree(cmd, "")...)
if i != len(node.Children)-1 {
rows = append(rows, [2]string{"", ""})
}
}
writeTwoColumns(iw, defaultColumnPadding, rows)
} else {
for i, cmd := range cmds {
printCommandSummary(iw, cmd)
if i != len(cmds)-1 {
iw.Print("")
w.Print("Commands:")
iw := w.Indent()
if w.Compact {
rows := [][2]string{}
for _, cmd := range cmds {
rows = append(rows, [2]string{cmd.Path(), cmd.Help})
}
writeTwoColumns(iw, defaultColumnPadding, rows)
} else {
for i, cmd := range cmds {
printCommandSummary(iw, cmd)
if i != len(cmds)-1 {
iw.Print("")
}
}
}
}
@@ -276,3 +300,50 @@ func formatFlag(haveShort bool, flag *Flag) string {
}
return flagString
}
// commandTree creates a tree with the given node name as root and its children's arguments and sub commands as leaves.
func (w *HelpOptions) commandTree(node *Node, prefix string) (rows [][2]string) {
var nodeName string
switch node.Type {
default:
nodeName += prefix + node.Name
case ArgumentNode:
nodeName += prefix + "<" + node.Name + ">"
}
rows = append(rows, [2]string{nodeName, node.Help})
if w.Indenter == nil {
prefix = SpaceIndenter(prefix)
} else {
prefix = w.Indenter(prefix)
}
for _, arg := range node.Positional {
rows = append(rows, [2]string{prefix + arg.Summary(), arg.Help})
}
for _, subCmd := range node.Children {
rows = append(rows, w.commandTree(subCmd, prefix)...)
}
return
}
// SpaceIndenter adds a space indent to the given prefix.
func SpaceIndenter(prefix string) string {
return prefix + strings.Repeat(" ", defaultIndent)
}
// SpaceIndenter adds line points to every new indent.
func LineIndenter(prefix string) string {
if prefix == "" {
return "- "
} else {
return strings.Repeat(" ", defaultIndent) + prefix
}
}
// TreeIndenter adds line points to every new indent and vertical lines to every layer.
func TreeIndenter(prefix string) string {
if prefix == "" {
return "|- "
} else {
return "|" + strings.Repeat(" ", defaultIndent) + prefix
}
}