clihelp

package module
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 20 Imported by: 0

README

clihelp

Go Reference Go Report Card llms.txt

clihelp is a Go library for parsing command-line arguments and generating clean, detailed usage and help messages. Similar in functionality to Cobra, it was written by an AI agent as a reusable tool to be used across other projects.

It provides clean, structured usage messages with support for ANSI colors and clickable OSC 8 hyperlinks in supported terminals, alongside pflag-backed flag parsing, hierarchical subcommand routing, argument validation, lifecycle hooks, and automatic GitHub Markdown documentation generation.


Features

  • Declarative CLI Definition — Define applications, subcommands, persistent options, and flags in clean struct definitions.
  • Pflag-Backed Option Parsing — Robust flag parsing supporting aliases, boolean toggle pairs (--[no-]flag), typed values, and custom value parsers.
  • Execution Lifecycle Hooks — Coordinated BeforeRun, PreRun, Run, PostRun, and AfterRun lifecycle execution with context propagation.
  • Positional Argument Validation — Built-in validators (ExactArgs, RangeArgs, MinimumNArgs, NoArgs) executed after flag extraction.
  • Fuzzy Typo Suggestions — Levenshtein-distance suggestions for mistyped commands (e.g. Did you mean "build"?).
  • Prefix Command Matching — Enable abbreviated commands (e.g. podctl b instead of podctl build).
  • Shell Autocompletion & Auto-Installation — Built-in __complete protocol with generators for Bash, Zsh, and Fish, zero-boilerplate CompletionCommand(), and one-command user XDG self-installation (InstallCompletion).
  • Rich Terminal Styling — Theme-driven ANSI colors, auto-detected terminal width with 70-column fallback, and ANSI-aware word wrapping.
  • Inline Markdown & OSC 8 Hyperlinks — Rich text formatting in descriptions: bold, italic, code, strikethrough, and clickable terminal hyperlinks.
  • Markdown Documentation Generator — Automatically generates navigable, GitHub-friendly Markdown doc trees with SHA-256 change-detection caching.
  • Global Flag De-Cluttering & Topic Routing — Categorize global options by group (Option.Group and clihelp.Group), suppress noisy global flags in subcommands (App.OmitGlobalFlagsInCommands), and route dedicated help topics (help flags, help man, help tree, help topics).
  • Comprehensive Paged Manual (help man) — Built-in help man renders an exhaustive Unix man page with all commands, subcommands, arguments, flags, and notes paged through $PAGER.
  • Automatic Paging — When enabled, help output is automatically paged through $PAGER when it exceeds terminal height.
  • Command Tree View — Render the full command hierarchy as a tree with box-drawing characters (help tree).
  • AI & LLM-Optimized — Token-efficient single-file llms.txt specification and declarative syntax eliminating common LLM hallucinations.

Installation

Requires Go 1.26+:

go get github.com/sarielhp/clihelp

Minimal Example

Here is a truly compact, self-contained example demonstrating how clihelp handles required flags and interactive prompts out-of-the-box:

package main

import (
	"fmt"
	"os"

	"github.com/sarielhp/clihelp"
)

func main() {
	var name string

	app := &clihelp.App{
		Name:        "greet",
		Description: "A minimal greeting utility",
		Commands: []clihelp.Command{
			{
				Name:        "hello",
				Description: "Say hello to a user",
				Options: []clihelp.Option{
					clihelp.Required(clihelp.String(&name, "-n, --name VAL", "", "Target name")),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Fprintf(ctx.Stdout, "Hello, %s!\n", name)
					return nil
				},
			},
		},
		InteractiveFallback: true, // Auto-prompts for --name if missing in a TTY
	}

	_ = app.Execute(os.Args[1:])
}

Quick Start

For a larger, more realistic application featuring validation constraints and multi-command routing:

package main

import (
	"fmt"
	"os"

	"github.com/sarielhp/clihelp"
)

func main() {
	var verbose bool
	var config string
	var output string
	var bitrate int
	var normalize bool

	app := &clihelp.App{
		Name:                      "podctl",
		Description:               "Podcast distribution & audio processing tool",
		Version:                   "1.0.0",
		Pager:                     true,
		OmitGlobalFlagsInCommands: true,
		PersistentOptions: []clihelp.Option{
			clihelp.Group("Output & Logging", clihelp.Bool(&verbose, "-v, --verbose", false, "Enable verbose logging")),
			clihelp.Group("Configuration", clihelp.String(&config, "-c, --config PATH", "~/.config/podctl.yaml", "Configuration file path")),
		},
		Commands: []clihelp.Command{
			{
				Name:        "build",
				Description: "Compile & package audio episodes",
				UsageLine:   "podctl build [options] <source-file>",
				Args:        clihelp.ExactArgs(1),
				Options: []clihelp.Option{
					clihelp.String(&output, "-o, --output PATH", "", "Write output to PATH"),
					clihelp.Int(&bitrate, "-b, --bitrate KBPS", 192, "Target audio bitrate in kbps"),
					clihelp.BoolToggle(&normalize, "--[no-]normalize", true, "Apply LUFS loudness normalization"),
				},
				Examples: []clihelp.Example{
					{Line: "podctl build episode01.wav"},
					{Line: "podctl build -o ep01.mp3 --bitrate 320 --no-normalize ep01.wav"},
				},
				Run: func(ctx *clihelp.Context) error {
					source := ctx.Args[0]
					fmt.Fprintf(ctx.Stdout, "Building %s -> %s (bitrate: %d kbps, normalize: %v, verbose: %v, config: %s)\n",
						source, output, bitrate, normalize, verbose, config)
					return nil
				},
			},
		},
	}

	// Execute parses os.Args[1:], routes commands, runs hooks, and handles errors
	if err := app.Execute(os.Args[1:]); err != nil {
		clihelp.PrintError(err)
		os.Exit(1)
	}
}

Options Validation & Interactive Fallback

clihelp provides native, declarative options validation and interactive fallback hooks:

  • Required Options: Wrap any option constructor in clihelp.Required() to enforce that it must be supplied. It will render with a (required) label in the help screen.
  • Interactive Fallback: Setting App.InteractiveFallback = true tells clihelp that if a required flag is missing in a TTY environment, it should prompt the user interactively (e.g. text input or numbered list prompts) instead of failing.
  • Command Constructor Tip: When a user is prompted interactively, clihelp prints an educational command constructor suggestion on completion to teach them the equivalent non-interactive invocation: 💡 Tip: Next time, you can run this directly with: greet hello --name Alice
  • Option Validators: Add declarative relation constraints to Command.OptionsValidator to check combinations of flags:
    OptionsValidator: clihelp.ValidateOptions(
        clihelp.MutuallyExclusive("--json", "--yaml"),
        clihelp.RequiredTogether("--cert", "--key"),
        clihelp.RequiredWith("--upload", "--bucket"),
    )
    
  • Static Sanity Auditing: Run clihelp.Audit(app) inside a unit test to statically verify command consistency in CI/CD:
    func TestAppSanity(t *testing.T) {
        if err := clihelp.Audit(app); err != nil {
            t.Fatalf("CLI design audit failed: %v", err)
        }
    }
    

[!TIP] Recommended: Running the audit helper as a standard Go unit test makes it easy to avoid introducing missing descriptions, duplicate shorthand flags, subcommand name collisions, or confusing path permutations (like job run vs run job) as your CLI expands.


Documentation & Topic Guides

Detailed technical guides and reference documentation are available in the docs/ directory:

Guide Description
🔄 Execution Lifecycle & Routing Execution pipeline, lifecycle hooks (BeforeRun, PreRun, Run, etc.), abort semantics, clihelp.Context, nested subcommands, typo suggestions, and argument validation.
🏷️ Flags & Options Reference Flag spec syntax, constructor reference table (String, Int, BoolToggle, Enum, etc.), aliases, custom binders, and help collision safety.
💻 Shell Autocompletion & Installation Setting up Bash, Zsh, and Fish completion, mounting CompletionCommand(), automatic XDG self-installation (InstallCompletion), dynamic callbacks, and live testing.
📄 Markdown Doc Generation Generating navigable GitHub Markdown docs with RenderMarkdown and SHA-256 change-detection caching.
🍳 Recipes & Patterns Practical patterns for signal cancellation (ExecuteContext), unit testing commands, dynamic completion callbacks, command tree view (RenderTree), custom themes (Theme), and prefix abbreviations (AbbrevCommands).
🤖 AI Coding Agent Guidelines Best practices and prompt rules for LLM coding agents and pair programmers building CLIs with clihelp.
🧠 AI Context Specification (llms.txt) Compact single-file specification formatted for direct ingestion by LLMs and AI developer tools.
⚖️ Comparison with Cobra In-depth comparison with spf13/cobra, architectural differences, code patterns, and tradeoffs.

Terminal Formatting & Styling

Descriptions and notes support markdown-like inline formatting:

Syntax Terminal Output
`code` Green highlighted text
**bold** Bold text
*italic* Italic text
~~strikethrough~~ Strikethrough text
[Label](https://example.com) Clickable OSC 8 terminal hyperlink
\X Escapes special character X
Width & wrapping
  • Terminal width is auto-detected with a 70-column fallback for non-TTY output.
  • Content wraps at indent + MaxContentWidth columns (default MaxContentWidth is 80), so indented lists gain extra horizontal room without exceeding the terminal width. Set Options.MaxContentWidth to change the content cap.
  • Command lists can be grouped with Command.Group; a group heading is rendered when the group value changes.

Migrating from v0.1.x

In v0.2.0+, clihelp transitioned from a standalone help formatter to a full execution framework:

Before (v0.1.x) After (v0.2.x)
app.PrintGlobalUsage() app.RenderGlobal(clihelp.Options{})
app.PrintCommandUsage("config", "set") app.RenderCommand(clihelp.Options{}, "config", "set")
app.PrintUsage(args...) app.Render(clihelp.Options{}, args...)
Manual flag parsing via flag app.Execute(os.Args[1:]) with declarative clihelp.Option

API Reference

Comprehensive Go package API documentation is available on pkg.go.dev.


License

MIT License. See LICENSE for details.

Documentation

Overview

Package clihelp provides a declarative, lightweight CLI application framework and width-aware, colorized help text formatter for Go applications.

Package clihelp provides a declarative, lightweight CLI application framework and width-aware, colorized help text formatter for Go applications.

Core Concepts

clihelp combines declarative command and flag definitions with robust execution lifecycles, pflag-backed option parsing, positional argument validation, shell completion, and GitHub-friendly Markdown generation.

An application is defined using App, which contains a hierarchy of Command nodes, persistent/local Option flags, and lifecycle hooks.

Quick Start

A minimal CLI application:

package main

import (
	"fmt"
	"os"

	"github.com/sarielhp/clihelp"
)

func main() {
	var verbose bool
	var output string

	app := &clihelp.App{
		Name:        "demo",
		Description: "Demonstration command-line tool",
		Version:     "1.0.0",
		Pager:       true,
		Commands: []clihelp.Command{
			{
				Name:        "build",
				Description: "Compile the target package",
				UsageLine:   "demo build [options] <target>",
				Args:        clihelp.ExactArgs(1),
				Options: []clihelp.Option{
					clihelp.String(&output, "-o, --output PATH", "dist", "Output directory"),
					clihelp.Bool(&verbose, "-v, --verbose", false, "Enable verbose logging"),
				},
				Run: func(ctx *clihelp.Context) error {
					target := ctx.Args[0]
					fmt.Fprintf(ctx.Stdout, "Building %s to %s (verbose=%v)\n", target, output, verbose)
					return nil
				},
			},
		},
	}

	if err := app.Execute(os.Args[1:]); err != nil {
		clihelp.PrintError(err)
		os.Exit(1)
	}
}

Execution Lifecycle

When App.Execute or App.ExecuteContext is called, the execution follows a deterministic multi-stage pipeline:

  1. Completion Check: If the first argument is "__complete", shell completion runs.
  2. Version Check: If "--version", "-v", or "version" is passed without a custom version command, the version string is printed to stdout.
  3. Command Resolution: Subcommands and aliases are resolved hierarchically. Unknown command tokens trigger typo suggestions via Levenshtein distance. Built-in "help <subcommand>" is automatically routed.
  4. Flag Binding & Parsing: App.PersistentOptions, ancestor persistent options, and target command options are bound to a pflag.FlagSet and parsed against remaining arguments. Help flags (-h, --help) are automatically registered.
  5. Argument Validation: The command's ArgsValidator validates remaining positional arguments.
  6. Lifecycle Hooks: App.BeforeRun -> Command.PreRun -> Command.Run (or App.Run) -> Command.PostRun -> App.AfterRun

If any hook or validator returns a non-nil error, execution halts immediately and the error is returned.

Flag Specifications

Options are configured using typed helper constructors such as String, Int, Bool, BoolToggle, Duration, StringSlice, Enum, and Var.

Flag specification strings support rich syntax:

  • Short and long flags: "-o, --output PATH"
  • Multiple aliases: "-p, -P, --port, --listen-port <port>"
  • Boolean toggle pairs: "--[no-]cache" (registers both --cache and --no-cache)
  • Value hints / placeholders: "<file>", "PATH", "[value]"

Caution: Do not manually register "-h" or "--help" flags in your Options slices. App.Execute automatically manages help flag registration and help rendering.

Positional Argument Validators

Positional arguments are validated after flag parsing. Built-in validators include:

  • NoArgs: rejects any positional arguments
  • ExactArgs(n): requires exactly n positional arguments
  • MinimumNArgs(n): requires at least n positional arguments
  • MaximumNArgs(n): requires at most n positional arguments
  • RangeArgs(min, max): requires between min and max positional arguments

Validated arguments are available via Context.Args.

Shell Autocompletion

clihelp includes generators for Bash, Zsh, and Fish autocompletion:

Dynamic completion is supported by setting the Option.Complete callback.

Help Topics & Paged Manual

In addition to subcommand help (<command> -h), clihelp automatically routes specialized help topics:

Set App.OmitGlobalFlagsInCommands to true to omit verbose global flag tables from individual subcommand screens.

Subpackages

Additional developer tooling is provided via modular subpackages:

  • github.com/sarielhp/clihelp/doc: Static GitHub-friendly Markdown documentation site generator.
  • github.com/sarielhp/clihelp/tree: Command hierarchy tree visualization with box-drawing characters.

AI & LLM Context

A token-optimized specification file (llms.txt) is provided at the repository root for AI coding agents and LLMs to ingest complete API signatures, lifecycle rules, and canonical examples in a single context window.

Index

Examples

Constants

View Source
const DefaultMaxColIndent = 24

DefaultMaxColIndent defines the standard column threshold for description text alignment in two-column command and option listings (GNU standard: 24).

Variables

View Source
var SupportedShells = []string{"bash", "zsh", "fish"}

SupportedShells lists available shell autocompletion formats.

Functions

func Audit added in v0.3.0

func Audit(app *App) error

Audit traverses the app's command tree to statically verify documentation and consistency.

func AuditWithOptions added in v0.3.0

func AuditWithOptions(app *App, opts AuditOptions) error

AuditWithOptions traverses the app's command tree using customized options.

func ColorizeExampleLine added in v0.3.2

func ColorizeExampleLine(line string, th Theme) string

ColorizeExampleLine applies ANSI syntax colors to a command-line example string. It recognizes comments, shell prompts, subcommands, flags, values, and operators.

func ColorizeExampleLineWithApp added in v0.3.3

func ColorizeExampleLineWithApp(app *App, cmd *Command, line string, th Theme) string

ColorizeExampleLineWithApp applies ANSI syntax colors to an example string using the application command tree to accurately identify subcommands, flags, and arguments.

func CompletionPath added in v0.3.2

func CompletionPath(app *App, shell string) (string, error)

CompletionPath returns the target installation path for the completion script.

func DisplayName

func DisplayName(c Command) string

DisplayName renders a command name followed by its aliases in parentheses.

func DisplayNameWithArgs

func DisplayNameWithArgs(c Command) string

DisplayNameWithArgs renders a command name with aliases and positional argument signature.

func FirstSentence

func FirstSentence(s string) string

FirstSentence returns the first sentence of s, or the first line/paragraph if shorter.

func GenBashCompletion

func GenBashCompletion(app *App, w io.Writer) error

GenBashCompletion writes a Bash tab-completion script to w.

func GenFishCompletion added in v0.3.1

func GenFishCompletion(app *App, w io.Writer) error

GenFishCompletion writes a Fish tab-completion script to w.

func GenZshCompletion

func GenZshCompletion(app *App, w io.Writer) error

GenZshCompletion writes a Zsh tab-completion script to w.

func Inline

func Inline(s string) string

Inline renders inline markdown in s to a string with ANSI/OSC8 sequences. It is the exported form of the internal inline helper used by the renderer.

func InstallCompletion added in v0.3.1

func InstallCompletion(app *App, shell string) (string, error)

InstallCompletion installs the shell completion script for the given app and shell. If shell is empty, it detects the active shell via the SHELL environment variable. Returns the absolute file path where the completion script was written.

func IsCompletionInstalled added in v0.3.2

func IsCompletionInstalled(app *App, shell string) bool

IsCompletionInstalled checks if the shell completion script is already installed in the user's standard XDG directory for the given shell (or detected active shell).

func NoArgs

func NoArgs(args []string) error

NoArgs returns an error if any positional arguments are provided.

func SplitExampleCommandLine added in v0.3.2

func SplitExampleCommandLine(line string) ([]string, error)

SplitExampleCommandLine parses a shell command string into separate argument tokens, properly handling single quotes, double quotes, escape characters, prompt prefixes, and inline comments. If the command contains pipes or operators, the primary command segment before the pipe is tokenized for CLI validation.

func ValidateExample added in v0.3.2

func ValidateExample(app *App, ex Example, cmd *Command) error

ValidateExample statically validates that an Example can be parsed and accepted by the application. It verifies that commands exist, flags are recognized with valid syntax/values, mutually exclusive rules pass, and positional arguments satisfy constraints.

Types

type App

type App struct {
	Name              string
	Description       string
	Version           string
	GlobalNote        string
	UsageLine         string
	PersistentOptions []Option
	Commands          []Command
	Examples          []Example
	BeforeRun         func(ctx *Context) error
	AfterRun          func(ctx *Context) error
	Run               func(ctx *Context) error

	// AbbrevCommands enables prefix-based command matching. When true, a unique
	// prefix of a command name (or alias) is accepted as a match. When the prefix
	// is ambiguous, an error listing the candidates is returned.
	AbbrevCommands bool
	// Pager enables automatic paging through $PAGER when output exceeds
	// the terminal height. When true, help output is buffered and piped through
	// the pager only when it doesn't fit on one screen.
	Pager bool
	// OmitGlobalFlagsInCommands when true replaces the full list of persistent/global
	// flags in subcommand help with a one-line reference pointing to 'help flags'.
	OmitGlobalFlagsInCommands bool
	// InteractiveFallback enables prompting for missing inputs/flags interactively.
	InteractiveFallback bool
	// AutoInstallCompletion when true silently ensures that the shell completion script
	// is installed into the user's standard XDG directory on execution.
	AutoInstallCompletion bool

	// Presentation overrides
	Theme       *Theme
	GlobalFlags []Option
	Shortcuts   []Command
	ConfigPath  string

	// I/O overrides for testing and custom redirection
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

App represents the root CLI application.

func (*App) CheckExample added in v0.3.2

func (a *App) CheckExample(ex Example, cmd *Command) error

CheckExample validates a single Example against a specific command context.

func (*App) CollectOptions added in v0.3.3

func (a *App) CollectOptions(path []string, cmd *Command) []Option

CollectOptions returns the ordered option set for a command path: app PersistentOptions and GlobalFlags, each ancestor's PersistentOptions, then the target's PersistentOptions and Options. Hidden options are skipped.

func (*App) Execute

func (a *App) Execute(args []string) error

Execute runs the application using os.Args[1:] and context.Background().

Example
package main

import (
	"fmt"
	"os"

	"github.com/sarielhp/clihelp"
)

func main() {
	var verbose bool
	var output string

	app := &clihelp.App{
		Name:        "demo",
		Description: "Demonstration CLI tool",
		Version:     "1.0.0",
		Pager:       true,
		Commands: []clihelp.Command{
			{
				Name:        "build",
				Description: "Compile the binary target",
				UsageLine:   "demo build [options] <target>",
				Args:        clihelp.ExactArgs(1),
				Options: []clihelp.Option{
					clihelp.String(&output, "-o, --output PATH", "dist/app", "Output binary path"),
					clihelp.Bool(&verbose, "-v, --verbose", false, "Enable verbose logging"),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("building %s -> %s (verbose: %v)\n", ctx.Args[0], output, verbose)
					return nil
				},
			},
		},
	}

	// Run with build command arguments
	if err := app.Execute([]string{"build", "-o", "bin/demo", "-v", "main.go"}); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}

}
Output:
building main.go -> bin/demo (verbose: true)

func (*App) ExecuteContext

func (a *App) ExecuteContext(ctx context.Context, args []string) error

ExecuteContext runs the application using the given context and argument slice.

Example
package main

import (
	"context"
	"fmt"

	"github.com/sarielhp/clihelp"
)

func main() {
	app := &clihelp.App{
		Name:  "runner",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "run",
				Run: func(ctx *clihelp.Context) error {
					select {
					case <-ctx.Context.Done():
						return ctx.Context.Err()
					default:
						fmt.Println("job completed successfully")
						return nil
					}
				},
			},
		},
	}

	ctx := context.Background()
	_ = app.ExecuteContext(ctx, []string{"run"})

}
Output:
job completed successfully

func (*App) LookupCommand

func (a *App) LookupCommand(path ...string) *Command

LookupCommand traverses the command hierarchy and returns the matching Command pointer, or nil if not found. Matches both Name and Aliases.

func (*App) PrintError

func (a *App) PrintError(err error)

PrintError prints a formatted error message to the App's stderr with colored prefix.

func (*App) Render

func (a *App) Render(o Options, path ...string) bool

Render writes global help when path is empty, or command help for a path.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/sarielhp/clihelp"
)

func main() {
	var buf strings.Builder

	app := &clihelp.App{
		Name:        "webcli",
		Description: "[webcli](https://example.com) — Modern web utility tool with `fast` execution.",
		Pager:       true,
		Commands: []clihelp.Command{
			{
				Name:        "ping",
				Description: "Ping remote server",
			},
		},
	}

	// Render global help to buffer
	app.RenderGlobal(clihelp.Options{Writer: &buf, Width: 80})

	// Output is formatted with colors and OSC 8 hyperlinks in supported terminals
	fmt.Println(strings.Contains(buf.String(), "webcli"))

}
Output:
true

func (*App) RenderCommand

func (a *App) RenderCommand(o Options, path ...string) bool

RenderCommand writes help for the command at path (e.g. "config" "set"), rendering any of these present sections in order: Usage, Description, Subcommands, Parameters, Flags, Examples, Notes. Returns true if the path exists.

func (*App) RenderFlags added in v0.3.2

func (a *App) RenderFlags(o Options)

RenderFlags writes the dedicated global flags overview: usage template, grouped persistent flags, standard help flags, and guidance.

func (*App) RenderGlobal

func (a *App) RenderGlobal(o Options)

RenderGlobal writes the top-level application overview: a command-line usage template, description, command list with aliases, shortcut commands, global flags, and help footer.

func (*App) RenderGlobalFlags added in v0.3.2

func (a *App) RenderGlobalFlags(o Options)

RenderGlobalFlags is an alias for RenderFlags.

func (*App) RenderHelpTopics added in v0.3.2

func (a *App) RenderHelpTopics(o Options)

RenderHelpTopics writes the index of available help topics.

func (*App) RenderMan added in v0.3.2

func (a *App) RenderMan(o Options)

RenderMan writes an exhaustive, Unix manual-style reference containing the full application overview, grouped global options, all command hierarchies, parameters, local flags, examples, notes, and help topics.

func (*App) ValidateAllExamples added in v0.3.2

func (a *App) ValidateAllExamples() error

ValidateAllExamples validates all examples and returns a single combined error if any fail.

func (*App) ValidateExamples added in v0.3.2

func (a *App) ValidateExamples() []error

ValidateExamples validates all examples defined on the application and all its commands. Returns a slice of all validation errors encountered.

type ArgsValidator

type ArgsValidator func(args []string) error

ArgsValidator validates positional arguments after flag parsing.

func ExactArgs

func ExactArgs(n int) ArgsValidator

ExactArgs returns an ArgsValidator that ensures exactly n arguments are provided.

Example
package main

import (
	"fmt"

	"github.com/sarielhp/clihelp"
)

func main() {
	app := &clihelp.App{
		Name:  "tagger",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "tag",
				Args: clihelp.ExactArgs(2),
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("tagging %s with %s\n", ctx.Args[0], ctx.Args[1])
					return nil
				},
			},
		},
	}

	_ = app.Execute([]string{"tag", "file.txt", "v1.0"})

}
Output:
tagging file.txt with v1.0

func MaximumNArgs

func MaximumNArgs(n int) ArgsValidator

MaximumNArgs returns an ArgsValidator that ensures at most n arguments are provided.

func MinimumNArgs

func MinimumNArgs(n int) ArgsValidator

MinimumNArgs returns an ArgsValidator that ensures at least n arguments are provided.

func RangeArgs

func RangeArgs(min, max int) ArgsValidator

RangeArgs returns an ArgsValidator that ensures between min and max arguments are provided.

type AuditOptions added in v0.3.0

type AuditOptions struct {
	AllowPathPermutations [][]string
	SkipExampleValidation bool
}

AuditOptions configures the static analysis audit helper.

type Command

type Command struct {
	Name              string
	Aliases           []string
	Description       string
	UsageLine         string
	Group             string
	Hidden            bool
	PersistentOptions []Option
	Options           []Option
	Subcommands       []Command
	Examples          []Example
	Args              ArgsValidator
	OptionsValidator  OptionsValidator
	PreRun            func(ctx *Context) error
	Run               func(ctx *Context) error
	PostRun           func(ctx *Context) error

	// Presentation / legacy fields
	Title             string
	Parameters        []Param
	SubcommandEntries []Param
	Notes             []Note
}

Command represents an executable command or category node.

func CompletionCommand added in v0.3.1

func CompletionCommand() Command

CompletionCommand returns a standard clihelp.Command providing 'bash', 'zsh', 'fish', and 'install' subcommands.

type Context

type Context struct {
	Context context.Context
	App     *App
	Command *Command
	Args    []string
	RawArgs []string
	Stdout  io.Writer
	Stderr  io.Writer
}

Context encapsulates execution state passed to command handlers and lifecycle hooks.

type Example

type Example struct {
	Line        string
	Description string
}

Example represents a usage line demonstration in command help text.

type Note

type Note struct {
	Heading string
	Text    string
}

Note carries an optional heading (rendered as a section label) and a body of prose that is reflowed to the available width.

type Option

type Option struct {
	Flags       string                           // e.g. "-p, --podcast <name>"
	Description string                           // e.g. "Podcast title, index, or ID"
	Group       string                           // Category heading (e.g. "Authentication", "Logging")
	DefaultText string                           // Custom display override for default value
	Hidden      bool                             // Hidden from help and completion output
	Deprecated  string                           // Deprecation notice
	Required    bool                             // Required flag constraint
	Complete    func(toComplete string) []string // Dynamic shell tab-completion callback
	Binder      func(fs *pflag.FlagSet) error    // Registers the flag on fs; returns an error on duplicate/help-flag conflicts
}

Option represents a command-line flag or option definition.

func Bool

func Bool(target *bool, flags string, defaultVal bool, usage string) Option

Bool binds a boolean flag to target.

func BoolToggle

func BoolToggle(target *bool, flags string, defaultVal bool, usage string) Option

BoolToggle binds a boolean toggle pair (e.g. --[no-]check-new).

Example
package main

import (
	"fmt"

	"github.com/sarielhp/clihelp"
)

func main() {
	var normalize bool

	app := &clihelp.App{
		Name:  "soundctl",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "process",
				Options: []clihelp.Option{
					clihelp.BoolToggle(&normalize, "--[no-]normalize", true, "Apply audio normalization"),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("normalize: %v\n", normalize)
					return nil
				},
			},
		},
	}

	_ = app.Execute([]string{"process", "--no-normalize"})

}
Output:
normalize: false

func Duration

func Duration(target *time.Duration, flags string, defaultVal time.Duration, usage string) Option

Duration binds a time.Duration flag to target.

Example
package main

import (
	"fmt"
	"time"

	"github.com/sarielhp/clihelp"
)

func main() {
	var timeout time.Duration

	app := &clihelp.App{
		Name:  "fetcher",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "fetch",
				Options: []clihelp.Option{
					clihelp.Duration(&timeout, "-t, --timeout DURATION", 10*time.Second, "Request timeout"),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("timeout: %v\n", timeout)
					return nil
				},
			},
		},
	}

	_ = app.Execute([]string{"fetch", "--timeout", "45s"})

}
Output:
timeout: 45s

func Enum

func Enum(target *string, flags string, allowed []string, defaultVal string, usage string) Option

Enum restricts input to an enumerated list of valid strings.

Example
package main

import (
	"fmt"

	"github.com/sarielhp/clihelp"
)

func main() {
	var env string

	app := &clihelp.App{
		Name:  "deployer",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "deploy",
				Options: []clihelp.Option{
					clihelp.Enum(&env, "-e, --env ENV", []string{"dev", "staging", "prod"}, "dev", "Target deployment environment"),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("deploying to: %s\n", env)
					return nil
				},
			},
		},
	}

	_ = app.Execute([]string{"deploy", "--env", "staging"})

}
Output:
deploying to: staging

func Group added in v0.3.2

func Group(group string, opt Option) Option

Group assigns a category heading to an Option.

func Int

func Int(target *int, flags string, defaultVal int, usage string) Option

Int binds an integer flag to target.

func Required added in v0.3.0

func Required(opt Option) Option

Required marks an Option as required.

func String

func String(target *string, flags string, defaultVal string, usage string) Option

String binds a string flag to target.

func StringSlice

func StringSlice(target *[]string, flags string, defaultVal []string, usage string) Option

StringSlice binds a repeatable or comma-separated string slice flag to target.

Example
package main

import (
	"fmt"

	"github.com/sarielhp/clihelp"
)

func main() {
	var tags []string

	app := &clihelp.App{
		Name:  "builder",
		Pager: true,
		Commands: []clihelp.Command{
			{
				Name: "build",
				Options: []clihelp.Option{
					clihelp.StringSlice(&tags, "-t, --tag TAG", []string{"latest"}, "Image tag (repeatable)"),
				},
				Run: func(ctx *clihelp.Context) error {
					fmt.Printf("tags: %v\n", tags)
					return nil
				},
			},
		},
	}

	_ = app.Execute([]string{"build", "-t", "v1.0", "-t", "release"})

}
Output:
tags: [v1.0 release]

func Var

func Var(target pflag.Value, flags string, usage string) Option

Var binds a custom user-defined pflag.Value interface.

type Options

type Options struct {
	// Writer is the output destination. When nil, os.Stdout is used.
	Writer io.Writer
	// Width is the target terminal width in columns. When zero it is
	// auto-detected with a 70-column fallback for non-terminal output.
	Width int
	// MaxContentWidth caps the wrap width to indent+MaxContentWidth columns.
	// When zero it defaults to 80. Set to a larger value to allow content to
	// use more horizontal space than the default 80-column body.
	MaxContentWidth int
	// Theme overrides the App.Theme and the package default. When nil the
	// App's theme (or the default) applies.
	Theme *Theme
	// Pager enables automatic paging through $PAGER when output exceeds
	// the terminal height. When true, output is buffered and piped through
	// the pager only when it doesn't fit on one screen.
	Pager bool
}

Options controls a single render operation.

type OptionsValidator added in v0.3.0

type OptionsValidator func(fs *pflag.FlagSet) error

OptionsValidator validates command-line flags after parsing.

func MutuallyExclusive added in v0.3.0

func MutuallyExclusive(flags ...string) OptionsValidator

MutuallyExclusive ensures at most one of the specified flags is set.

func RequiredIf added in v0.3.0

func RequiredIf(flag string, condition string) OptionsValidator

RequiredIf ensures flag is required if condition is met. The condition can be a bare flag name (meaning the condition flag is set), or key=value format (meaning the condition flag is set to value).

func RequiredTogether added in v0.3.0

func RequiredTogether(flags ...string) OptionsValidator

RequiredTogether ensures if any of the flags are set, all of them must be set.

func RequiredWith added in v0.3.0

func RequiredWith(target string, required ...string) OptionsValidator

RequiredWith ensures if target is set, all required flags must be set.

func ValidateOptions added in v0.3.0

func ValidateOptions(validators ...OptionsValidator) OptionsValidator

ValidateOptions chains multiple OptionsValidators into a single validator.

type Param

type Param struct {
	Name        string
	Description string
}

Param describes a positional argument (or a listable subcommand/flag) with a display name and a free-form description.

type TestResult added in v0.3.0

type TestResult struct {
	Stdout string
	Stderr string
	Error  error
}

TestResult holds the outcome of a TestExecute execution.

func TestExecute added in v0.3.0

func TestExecute(app *App, args []string) *TestResult

TestExecute runs the app with mock buffers and redirected stdout/stderr.

func TestExecuteWithStdin added in v0.3.0

func TestExecuteWithStdin(app *App, args []string, stdin io.Reader) *TestResult

TestExecuteWithStdin runs the app redirecting stdout, stderr, and stdin.

func (*TestResult) AssertErrorContains added in v0.3.0

func (tr *TestResult) AssertErrorContains(t *testing.T, substring string)

AssertErrorContains asserts that an error occurred and contains the substring.

func (*TestResult) AssertNoError added in v0.3.0

func (tr *TestResult) AssertNoError(t *testing.T)

AssertNoError asserts that the command executed successfully without error.

func (*TestResult) AssertStderrContains added in v0.3.0

func (tr *TestResult) AssertStderrContains(t *testing.T, substring string)

AssertStderrContains asserts that stderr contains the substring.

func (*TestResult) AssertStdoutContains added in v0.3.0

func (tr *TestResult) AssertStdoutContains(t *testing.T, substring string)

AssertStdoutContains asserts that stdout contains the substring.

type Theme

type Theme struct {
	// Hdr colors section labels (e.g. "Description:", "Usage:").
	Hdr *color.Color
	// Body colors description/usage prose.
	Body *color.Color
	// Accent colors the help header line, separators, and global command groups.
	Accent *color.Color
	// Subcommand colors subcommand names.
	Subcommand *color.Color
	// Flag colors flag/option names (e.g. "--verbose, -v").
	Flag *color.Color
	// Separator toggles the horizontal rule drawn around the header block.
	Separator bool
	// TitlePrefix is prepended to the command help header line
	// (e.g. "Detailed Usage: ").
	TitlePrefix string

	// ExampleCmd colors command and subcommand names in examples.
	ExampleCmd *color.Color
	// ExampleFlag colors flags and options in examples.
	ExampleFlag *color.Color
	// ExampleArg colors arguments, positional values, and paths in examples.
	ExampleArg *color.Color
	// ExampleComment colors shell comments (# ...) in examples.
	ExampleComment *color.Color
	// ExampleDesc colors example descriptions beneath the command line.
	ExampleDesc *color.Color
}

Theme controls the colors, separators, and header wording used by the renderer. A Theme's zero value is safe: any nil color field falls back to the default mail_cli palette when applied via App.Theme or Options.Theme.

Directories

Path Synopsis
Package main demonstrates how to integrate the 'clihelp' package into a production Go command-line application with declarative routing and flag parsing.
Package main demonstrates how to integrate the 'clihelp' package into a production Go command-line application with declarative routing and flag parsing.
mail_cli_fake command
Command mail_cli_fake regenerates the complete mail_cli usage/help interface using clihelp's data model and unified renderer.
Command mail_cli_fake regenerates the complete mail_cli usage/help interface using clihelp's data model and unified renderer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL