Documentation
¶
Overview ¶
Package clifford is a CLI argument parsing library for Go that uses reflection and struct tags to define command-line interfaces declaratively.
It supports positional arguments, short and long flags, required arguments, and automatic generation of help and version output.
The library is designed to be easy to use and integrate into Go CLI tools, providing a clean API for defining and parsing command-line parameters.
Example (Defaults) ¶
Example_defaults demonstrates default values are applied when flags are omitted.
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
os.Args = []string{"app"}
target := struct {
clifford.Clifford `name:"app" desc:"App showing defaults"`
Port struct {
Value int `default:"8080"`
clifford.Clifford `long:"port" desc:"Port to run the server on"`
}
}{}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
fmt.Println("Port:", target.Port.Value)
}
Output: Port: 8080
Example (Disable_shorthand) ¶
package main
import (
"fmt"
"github.com/chriso345/clifford"
)
func main() {
// Demonstrate disabling -h/-v short forms on the top-level command
target := struct {
clifford.Clifford `name:"no-shorts" version:"0.1.0" help_short:"false" version_short:"false"`
clifford.Help
clifford.Version
}{}
if _, err := clifford.BuildHelp(&target, false); err != nil {
panic(err)
}
fmt.Println("version")
}
Output: version
Example (Error_types) ¶
Example_error_types demonstrates checking for specific error kinds with errors.Is and accessing details with errors.As.
package main
import (
"fmt"
"os"
stderrors "errors"
"github.com/chriso345/clifford"
"github.com/chriso345/clifford/errors"
)
func main() {
os.Args = []string{"app"}
target := struct {
clifford.Clifford `name:"app"`
File struct {
Value string
clifford.Required `required:"true"`
}
}{}
err := clifford.Parse(&target)
if err == nil {
fmt.Println("no error")
return
}
if stderrors.Is(err, errors.ErrMissingArg) {
fmt.Println("missing argument detected")
}
var ma errors.MissingArgError
if stderrors.As(err, &ma) {
fmt.Println("missing field:", ma.Field)
}
}
Output: missing field: File
Example (Flag) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
target := struct {
clifford.Clifford `name:"sampleapp"`
Flag struct {
Value bool
clifford.Clifford `short:"f" long:"flag" desc:"A sample boolean flag"`
}
}{}
// Simulate command line arguments
os.Args = []string{"sampleapp", "-f"}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
fmt.Println("Flag value:", target.Flag.Value)
}
Output: Flag value: true
Example (Help_as_subcommand) ¶
Example_help_as_subcommand demonstrates generating help for a subcommand while keeping parent name in usage.
package main
import (
"fmt"
"regexp"
"github.com/chriso345/clifford"
)
func stripANSI(input string) string {
re := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
return re.ReplaceAllString(input, "")
}
func main() {
parent := struct {
clifford.Clifford `name:"app" desc:"Parent app"`
clifford.Help
Serve struct {
clifford.Subcommand `name:"serve" desc:"Start server"`
Port struct {
Value int
clifford.Clifford `long:"port" desc:"Port number"`
}
}
}{}
sub := parent.Serve
help, err := clifford.BuildHelpWithParent(&parent, "serve", &sub, false)
if err != nil {
panic(err)
}
fmt.Println(stripANSI(help))
}
Output: Usage: app serve [OPTIONS] Options: --port [PORT] Port number
Example (Help_output) ¶
Example_help_output demonstrates building help for a parent with multiple subcommands.
package main
import (
"fmt"
"regexp"
"github.com/chriso345/clifford"
)
func main() {
// Parent help shows subcommands and their descriptions
target := struct {
clifford.Clifford `name:"app" desc:"App for help output"`
clifford.Help
Serve struct {
clifford.Subcommand `name:"serve" desc:"Start the server"`
}
Status struct {
clifford.Subcommand `name:"status" desc:"Show server status"`
}
}{}
help, err := clifford.BuildHelp(&target, false)
if err != nil {
panic(err)
}
fmt.Println(stripANSI(help))
}
func stripANSI(input string) string {
re := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
return re.ReplaceAllString(input, "")
}
Example (Inline) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
cli := struct {
clifford.Clifford `name:"myapp"`
Value string `long:"value" desc:"A simple value flag"`
Color string `short:"c" long:"color" desc:"Color option"`
}{}
// Simulate command line arguments
os.Args = []string{"myapp", "--value", "42", "-c", "red"}
err := clifford.Parse(&cli)
if err != nil {
panic(err)
}
fmt.Println("Value:", cli.Value)
fmt.Println("Color:", cli.Color)
}
Output: Value: 42 Color: red
Example (List_subcommands) ¶
package main
import (
"fmt"
"github.com/chriso345/clifford"
)
func main() {
// Build help that lists multiple subcommands and print a marker line for the example.
target := struct {
clifford.Clifford `name:"app" desc:"Application with multiple subcommands"`
clifford.Help
Serve struct {
clifford.Subcommand `name:"serve" desc:"Start the server"`
}
Status struct {
clifford.Subcommand `name:"status" desc:"Show server status"`
}
}{}
if _, err := clifford.BuildHelp(&target, false); err != nil {
panic(err)
}
fmt.Println("Subcommands:")
}
Output: Subcommands:
Example (Nested_subcommands) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
// Demonstrate nested subcommands: app remote add --name foo
os.Args = []string{"app", "remote", "add", "--name", "origin"}
target := struct {
clifford.Clifford `name:"app"`
clifford.Help
Remote struct {
clifford.Subcommand `name:"remote" desc:"Remote operations"`
Add struct {
clifford.Subcommand `name:"add" desc:"Add a remote"`
Name struct {
Value string
clifford.Clifford `long:"name" desc:"Name of the remote"`
}
}
}
}{}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
fmt.Println("Remote add name:", target.Remote.Add.Name.Value)
}
Output: Remote add name: origin
Example (Readme) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
// Simulate command line arguments
os.Args = []string{"mytool", "--name", "Alice", "-a", "30"}
target := struct {
clifford.Clifford `name:"mytool"` // Set the name of the CLI tool
clifford.Version `version:"1.2.3"` // Enable automatic version flag
clifford.Help // Enable automatic help flags
Name struct {
Value string
clifford.Clifford `short:"n" long:"name" desc:"User name"`
}
Age struct {
Value string
clifford.ShortTag // auto generates -a
clifford.LongTag // auto generates --age
clifford.Desc `desc:"Age of the user"`
}
}{}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
fmt.Printf("Name: %s\n", target.Name.Value)
fmt.Printf("Age: %s\n", target.Age.Value)
}
Output: Name: Alice Age: 30
Example (Simple_cli) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
// Simulate command line arguments
os.Args = []string{"example_cli", "bob"}
target := struct {
clifford.Clifford `name:"example_cli"` // This is the name of the cli command
clifford.Version `version:"1.0.0"`
clifford.Help
Name struct {
Value string
}
}{}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
if target.Name.Value != "" {
fmt.Println("Hello, " + target.Name.Value + "!")
} else {
fmt.Println("Hello, World!")
}
}
Output: Hello, bob!
Example (Subcommand) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
// Demonstrate a single-level subcommand parse
os.Args = []string{"app", "serve", "--port", "8080"}
target := struct {
clifford.Clifford `name:"app"`
clifford.Help
Serve struct {
clifford.Subcommand `name:"serve" desc:"Start the server"`
Port struct {
Value int
clifford.Clifford `long:"port" desc:"Port to run the server on"`
}
}
Status struct {
clifford.Subcommand `name:"status" desc:"Show server status"`
}
}{}
err := clifford.Parse(&target)
if err != nil {
panic(err)
}
fmt.Println("Serve port:", target.Serve.Port.Value)
}
Output: Serve port: 8080
Example (Subcommands_inline) ¶
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
args := struct {
clifford.Clifford `name:"tool"`
clifford.Help
Mode struct {
clifford.Subcommand `short:"m" long:"mode" desc:"Mode to run in"`
MaxItems int `short:"n" long:"max-items" desc:"Max items to show"`
LogLevel string `long:"log-level" desc:"Set log level"`
}
Other struct {
Value string
clifford.Clifford `long:"other" desc:"Other mode"`
}
}{}
// Simulate command line arguments
os.Args = []string{"tool", "mode", "--max-items", "20", "--log-level", "debug"}
err := clifford.Parse(&args)
if err != nil {
panic(err)
}
if args.Mode.Subcommand {
fmt.Println("Mode: mode")
}
fmt.Println("MaxItems:", args.Mode.MaxItems)
fmt.Println("LogLevel:", args.Mode.LogLevel)
fmt.Println("Other:", args.Other.Value)
}
Output: Mode: mode MaxItems: 20 LogLevel: debug Other:
Example (Unknown_subcommand) ¶
Example_unknown_subcommand shows the parser returning a helpful suggestion for mistyped subcommands.
package main
import (
"fmt"
"os"
"github.com/chriso345/clifford"
)
func main() {
os.Args = []string{"app", "srve"}
target := struct {
clifford.Clifford `name:"app"`
clifford.Help
Serve struct {
clifford.Subcommand `name:"serve" desc:"Start server"`
}
}{}
err := clifford.Parse(&target)
if err != nil {
fmt.Println(err.Error())
}
}
Output: unknown subcommand: srve (did you mean "serve"?)
Index ¶
Examples ¶
- Package (Defaults)
- Package (Disable_shorthand)
- Package (Error_types)
- Package (Flag)
- Package (Help_as_subcommand)
- Package (Help_output)
- Package (Inline)
- Package (List_subcommands)
- Package (Nested_subcommands)
- Package (Readme)
- Package (Simple_cli)
- Package (Subcommand)
- Package (Subcommands_inline)
- Package (Unknown_subcommand)
Constants ¶
This section is empty.
Variables ¶
var BuildHelp = display.BuildHelp
BuildHelp generates and returns a formatted help message for a CLI tool defined by the given struct pointer. BuildHelp also takes in a boolean `long` parameter that, if set to true, will print a more detailed help message with the long_about description
The `target` must be a pointer to a struct that embeds a `Clifford` field with a `name` tag. This tag specifies the CLI tool's name and is displayed in the usage header.
The function inspects the struct to determine CLI arguments and options, including those marked as required. It outputs a help string that includes:
- The usage line with the command name and expected arguments
- A section for required arguments (based on `Required` tags)
- A section for optional flags (based on `short` or `long` tags)
If no `name` tag is found on any embedded `Clifford` field, the function returns an error.
Example:
target := struct {
clifford.Clifford `name:"mytool"`
Filename struct {
Value string
clifford.Required
clifford.Desc `desc:"Input file path"`
}
Verbose struct {
Value bool
clifford.Clifford `short:"v" long:"verbose" desc:"Enable verbose output"`
}
}{}
helpText, err := clifford.BuildHelp(&target, false)
if err != nil {
log.Fatal(err)
}
fmt.Println(helpText)
var BuildVersion = display.BuildVersion
BuildVersion returns a formatted version string for the CLI tool defined by the provided struct pointer.
The `target` must be a pointer to a struct that embeds a `Clifford` field with a `version` tag. This tag specifies the version number of the CLI tool. If no version tag is found, the function returns an error.
This function is automatically invoked by `Parse` if the CLI arguments include `--version`.
Example:
target := struct {
clifford.Clifford `name:"mytool" version:"1.2.3"`
}{}
version, err := clifford.BuildVersion(&target)
if err != nil {
log.Fatal(err)
}
fmt.Println(version) // Output: mytool v1.2.3
var Parse = core.Parse
Parse parses command-line arguments into the provided target struct.
The target must be a pointer to a struct where each field represents either a CLI argument or a group of options. Each sub-struct should contain a `Value` field to hold the parsed value, and may be annotated using `clifford` tags or helper types like `ShortTag`, `LongTag`, `Required`, and `Desc`.
If the first argument passed to the CLI is `-h` or `--help`, Parse will automatically call BuildHelp and exit the program.
Usage:
target := struct {
clifford.Clifford `name:"mytool"`
Name struct {
Value string
clifford.Clifford `short:"n" long:"name" desc:"User name"`
}
Age struct {
Value string
clifford.ShortTag // Auto-generates: -a
clifford.LongTag // Auto-generates: --age
clifford.Desc `desc:"Age of the user"`
}
}{}
err := clifford.Parse(&target)
if err != nil {
log.Fatal(err)
}
Functions ¶
func BuildHelpWithParent ¶
BuildHelpWithParent exposes the subcommand-aware help builder for callers/tests.
func ModuleVersion ¶
func ModuleVersion() string
ModuleVersion returns the version of the clifford module, if available.
Types ¶
type Clifford ¶
Clifford is the primary metadata marker for CLI definitions.
It can be embedded in the root struct to define metadata for the CLI tool itself, such as its name, version, or other global settings via struct tags.
It can also be embedded into sub-structs to provide additional annotations such as `short`, `long`, `desc`, and `required`, either directly or via helper types.
Usage:
Root-level CLI tool definition:
cli := struct {
Clifford `name:"mytool" version:"1.0.0"`
...
}{}
Sub-struct flag definition using Clifford for metadata:
cli := struct {
Clifford `name:"mytool"`
Name struct {
Value string
Clifford `short:"n" long:"name" desc:"User name"`
}
}{}
type Desc ¶
Desc is a helper type that allows you to annotate a CLI option or argument with a description.
This description will be included in the generated help output.
Usage:
cli := struct {
Name struct {
Value string
Desc `desc:"Name of the user"`
}
}{}
type Help ¶
Help is a marker type that enables the automatic `--help` and `-h` flag handling.
When embedded in the root struct, this allows the user to request usage help. If `-h` or `--help` is passed as the first CLI argument, Clifford will invoke BuildHelp automatically and exit gracefully.
Usage:
cli := struct {
Clifford `name:"mytool"`
Help
...
}{}
type LongTag ¶
LongTag is a helper type used to automatically generate a long flag (e.g. `--name`) for a CLI option based on the parent struct field name.
Usage:
cli := struct {
Name struct {
Value string
LongTag // Will auto-generate: --name
}
}{}
type Required ¶
Required is a marker type that indicates the associated argument or flag is required.
If a required argument or flag is not provided in the CLI input, the parser will return an error.
Usage:
cli := struct {
File struct {
Value string
Required // Must be supplied on the command line
}
}{}
type ShortTag ¶
ShortTag is a helper type used to automatically generate a short flag (e.g. `-n`) for a CLI option based on the parent struct field name.
You can embed it in a sub-struct to indicate that a short flag should be derived from the first letter of the field name, unless explicitly overridden.
Usage:
cli := struct {
Name struct {
Value string
ShortTag // Will auto-generate: -n
}
}{}
type Subcommand ¶
type Subcommand = core.Subcommand
Subcommand is a helper exported from core to mark fields as subcommands. Usage:
cli := struct {
CommandA struct {
Value string
Subcommand // Marks this field as a subcommand
}
}{}
type Version ¶
Version is a marker type that indicates the CLI tool supports a `--version` flag.
When included in the root struct, `Version` enables version display logic. If the `version` struct tag is set, Clifford will use it directly. If left empty, Clifford may attempt to auto-detect or fallback to a default (implementation dependent).
Usage:
// Automatic detection or programmatic assignment
cli := struct {
Clifford `name:"mytool"`
Version
}{}
// Static version string via struct tag
cli := struct {
Clifford `name:"mytool"`
Version `version:"1.0.0"`
}{}
Directories
¶
| Path | Synopsis |
|---|---|
|
Package core contains the core logic for parsing command-line arguments into user-defined structs using reflection.
|
Package core contains the core logic for parsing command-line arguments into user-defined structs using reflection. |
|
Package display provides utilities for generating user-facing CLI output, including help messages, version strings, and ANSI formatting.
|
Package display provides utilities for generating user-facing CLI output, including help messages, version strings, and ANSI formatting. |
|
Package errors defines error types and utilities related to CLI parsing and validation within the clifford library.
|
Package errors defines error types and utilities related to CLI parsing and validation within the clifford library. |
|
internal
|
|
|
common
Package common provides internal utility functions and helpers used across the clifford library.
|
Package common provides internal utility functions and helpers used across the clifford library. |