help API

help

package

API reference for the help package.

T
type

Translator

Translator is a function that translates a key.

pkg/help/help.go:12-12
type Translator func(string) string
F
function

GenerateHelp

GenerateHelp generates a formatted help string for a command node.

Parameters

Returns

string
pkg/help/help.go:20-107
func GenerateHelp(node *parser.CommandNode, tr Translator) string

{
	var sb strings.Builder

	t := func(s string) string {
		if tr != nil && strings.HasPrefix(s, "pr:") {
			return tr(strings.TrimPrefix(s, "pr:"))
		}
		return s
	}

	fmt.Fprintf(&sb, "Usage: %s [flags]", node.Name)
	if len(node.Children) > 0 {
		fmt.Fprintf(&sb, " [command]")
	}
	if len(node.Args) > 0 {
		for _, arg := range node.Args {
			if arg.IsGreedy {
				fmt.Fprintf(&sb, " [%s...]", t(arg.Description))
			} else {
				fmt.Fprintf(&sb, " [%s]", t(arg.Description))
			}
		}
	}
	fmt.Fprint(&sb, "\n\n")

	if node.Description != "" {
		fmt.Fprintf(&sb, "%s\n\n", t(node.Description))
	}

	if len(node.Children) > 0 {
		fmt.Fprint(&sb, "Commands:\n")
		cmdNames := make([]string, 0, len(node.Children))
		for name := range node.Children {
			if node.Children[name].Name == name {
				cmdNames = append(cmdNames, name)
			}
		}
		sort.Strings(cmdNames)

		for _, name := range cmdNames {
			child := node.Children[name]
			aliases := ""
			if len(child.Aliases) > 0 {
				aliases = fmt.Sprintf(" (aliases: %s)", strings.Join(child.Aliases, ", "))
			}
			fmt.Fprintf(&sb, "  %-15s %s%s\n", name, t(child.Description), aliases)
		}
		fmt.Fprint(&sb, "\n")
	}

	if len(node.Flags) > 0 {
		fmt.Fprint(&sb, "Flags:\n")

		flagNames := make([]string, 0, len(node.Flags))
		for name := range node.Flags {
			flagNames = append(flagNames, name)
		}
		sort.Strings(flagNames)

		for _, name := range flagNames {
			meta := node.Flags[name]
			short := ""
			if meta.Short != "" {
				short = fmt.Sprintf("-%s, ", meta.Short)
			}

			details := []string{}
			if meta.Env != "" {
				details = append(details, fmt.Sprintf("env: %s", meta.Env))
			}
			if meta.Default != "" {
				details = append(details, fmt.Sprintf("default: %s", meta.Default))
			}
			if meta.Required {
				details = append(details, "required")
			}

			detailStr := ""
			if len(details) > 0 {
				detailStr = fmt.Sprintf(" (%s)", strings.Join(details, ", "))
			}

			fmt.Fprintf(&sb, "  %s--%-12s %s%s\n", short, name, t(meta.Description), detailStr)
		}
	}

	return sb.String()
}

Example

helpText := help.GenerateHelp(rootNode, nil)
fmt.Println(helpText)
F
function

newTestNode

Parameters

name
string
desc
string
pkg/help/help_test.go:11-13
func newTestNode(name, desc string) *parser.CommandNode

{
	return parser.NewCommandNode(name, desc, reflect.ValueOf(struct{}{}))
}
F
function

TestGenerateHelp_RootOnly

Parameters

pkg/help/help_test.go:15-21
func TestGenerateHelp_RootOnly(t *testing.T)

{
	node := newTestNode("app", "")
	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "Usage: app [flags]") {
		t.Errorf("expected usage line, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithDescription

Parameters

pkg/help/help_test.go:23-29
func TestGenerateHelp_WithDescription(t *testing.T)

{
	node := newTestNode("app", "My awesome CLI app")
	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "My awesome CLI app") {
		t.Errorf("expected description in help, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithChildren

Parameters

pkg/help/help_test.go:31-46
func TestGenerateHelp_WithChildren(t *testing.T)

{
	node := newTestNode("app", "")
	child := newTestNode("add", "Add a new item")
	node.Children["add"] = child

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "Commands:") {
		t.Errorf("expected Commands section, got: %s", out)
	}
	if !strings.Contains(out, "add") {
		t.Errorf("expected 'add' in help, got: %s", out)
	}
	if !strings.Contains(out, "Add a new item") {
		t.Errorf("expected child description, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithAliases

Parameters

pkg/help/help_test.go:48-60
func TestGenerateHelp_WithAliases(t *testing.T)

{
	node := newTestNode("app", "")
	child := newTestNode("add", "Add")
	child.Aliases = []string{"a", "ad"}
	node.Children["add"] = child
	node.Children["a"] = child
	node.Children["ad"] = child

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "aliases:") {
		t.Errorf("expected aliases in help, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithFlags

Parameters

pkg/help/help_test.go:62-84
func TestGenerateHelp_WithFlags(t *testing.T)

{
	node := newTestNode("app", "")
	node.Flags["verbose"] = &parser.FlagMetadata{
		Name:        "verbose",
		Short:       "v",
		Description: "Enable verbose",
		Field:       reflect.Value{},
	}

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "Flags:") {
		t.Errorf("expected Flags section, got: %s", out)
	}
	if !strings.Contains(out, "--verbose") {
		t.Errorf("expected --verbose, got: %s", out)
	}
	if !strings.Contains(out, "-v") {
		t.Errorf("expected -v shorthand, got: %s", out)
	}
	if !strings.Contains(out, "Enable verbose") {
		t.Errorf("expected flag description, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithFlagEnv

Parameters

pkg/help/help_test.go:86-98
func TestGenerateHelp_WithFlagEnv(t *testing.T)

{
	node := newTestNode("app", "")
	node.Flags["name"] = &parser.FlagMetadata{
		Name:  "name",
		Env:   "NAME_ENV",
		Field: reflect.Value{},
	}

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "env: NAME_ENV") {
		t.Errorf("expected env in details, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithFlagDefault

Parameters

pkg/help/help_test.go:100-112
func TestGenerateHelp_WithFlagDefault(t *testing.T)

{
	node := newTestNode("app", "")
	node.Flags["name"] = &parser.FlagMetadata{
		Name:    "name",
		Default: "world",
		Field:   reflect.Value{},
	}

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "default: world") {
		t.Errorf("expected default in details, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithFlagRequired

Parameters

pkg/help/help_test.go:114-126
func TestGenerateHelp_WithFlagRequired(t *testing.T)

{
	node := newTestNode("app", "")
	node.Flags["count"] = &parser.FlagMetadata{
		Name:     "count",
		Required: true,
		Field:    reflect.Value{},
	}

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "required") {
		t.Errorf("expected required in details, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithArgs

Parameters

pkg/help/help_test.go:128-139
func TestGenerateHelp_WithArgs(t *testing.T)

{
	node := newTestNode("app", "")
	node.Args = append(node.Args, &parser.ArgMetadata{
		Description: "item",
		Required:    true,
	})

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "[item]") {
		t.Errorf("expected [item] in help, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithGreedyArgs

Parameters

pkg/help/help_test.go:141-152
func TestGenerateHelp_WithGreedyArgs(t *testing.T)

{
	node := newTestNode("app", "")
	node.Args = append(node.Args, &parser.ArgMetadata{
		Description: "files",
		IsGreedy:    true,
	})

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "[files...]") {
		t.Errorf("expected [files...] in help, got: %s", out)
	}
}
F
function

TestGenerateHelp_WithTranslator

Parameters

pkg/help/help_test.go:154-174
func TestGenerateHelp_WithTranslator(t *testing.T)

{
	node := newTestNode("app", "pr:app.desc")
	child := newTestNode("add", "pr:add.desc")
	node.Children["add"] = child

	tr := func(s string) string {
		m := map[string]string{
			"app.desc": "My App",
			"add.desc": "Add items",
		}
		return m[s]
	}

	out := GenerateHelp(node, tr)
	if !strings.Contains(out, "My App") {
		t.Errorf("expected translated desc, got: %s", out)
	}
	if !strings.Contains(out, "Add items") {
		t.Errorf("expected translated child desc, got: %s", out)
	}
}
F
function

TestGenerateHelp_MultiFlag

Parameters

pkg/help/help_test.go:176-208
func TestGenerateHelp_MultiFlag(t *testing.T)

{
	node := newTestNode("app", "")
	node.Flags["verbose"] = &parser.FlagMetadata{
		Name:        "verbose",
		Short:       "v",
		Description: "Verbose output",
		Field:       reflect.Value{},
	}
	node.Flags["name"] = &parser.FlagMetadata{
		Name:        "name",
		Short:       "n",
		Description: "Your name",
		Default:     "world",
		Field:       reflect.Value{},
	}
	node.Flags["count"] = &parser.FlagMetadata{
		Name:        "count",
		Description: "Count things",
		Required:    true,
		Field:       reflect.Value{},
	}

	out := GenerateHelp(node, nil)
	if !strings.Contains(out, "--verbose") {
		t.Errorf("expected --verbose, got: %s", out)
	}
	if !strings.Contains(out, "--name") {
		t.Errorf("expected --name, got: %s", out)
	}
	if !strings.Contains(out, "--count") {
		t.Errorf("expected --count, got: %s", out)
	}
}