Skip to content

gechr/clib

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

123 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

clib

A reusable Go library that plugs into existing CLI frameworks to add helpers, shell completions, and more polished help output.

Packages

Package Description
cli/cobra Cobra framework adapters
cli/kong Kong framework adapters
cli/urfave urfave/cli framework adapters
complete Shell completion generation (bash, zsh, fish, pwsh, elvish, nu)
help Structured help rendering with themed output
theme Configurable theme (via lipgloss)

Installation

go get github.com/gechr/clib

Usage

Theme

Use the built-in light/dark pair, or build an explicit pair for your terminal backgrounds:

// Auto-detect the terminal background and select from clib's defaults.
th := theme.Auto()

// Or require an explicit light/dark pair.
themes := theme.MustPair(
    theme.Light().With(
        theme.WithRed(lipgloss.NewStyle().Foreground(lipgloss.Color("#a11d33"))),
        theme.WithEntityColors([]color.Color{lipgloss.Color("#5d4037"), lipgloss.Color("#00695c")}),
    ),
    theme.Dark().With(
        theme.WithRed(lipgloss.NewStyle().Foreground(lipgloss.Color("9"))),
        theme.WithEntityColors([]color.Color{lipgloss.Color("208"), lipgloss.Color("51")}),
    ),
)
th = themes.Auto()

To let users pick themes via the environment, build the pair from <PREFIX>_THEME_LIGHT and <PREFIX>_THEME_DARK (both required):

// Reads CLIB_THEME_LIGHT and CLIB_THEME_DARK (override the prefix with SetEnvPrefix).
themes, err := theme.PairFromEnv()
if err != nil {
    return err
}
th := themes.Auto()

Setting the single <PREFIX>_THEME (e.g. CLIB_THEME=dracula) forces that theme regardless of the terminal background, taking precedence over the light/dark pair. Any Auto() call honors it, including the default theme.Auto() and help.NewRenderer(nil). An unknown name is ignored and detection proceeds as normal.

Help Rendering

Build structured help output. Content blocks implement the help.Content interface: FlagGroup, Args, Usage, Text, Examples, CommandGroup, and nested *Section.

hr := help.NewRenderer(th)

sections := []help.Section{
    {Title: "Flags", Content: []help.Content{
        help.FlagGroup{
            {Short: "q", Long: "query", Placeholder: "text", Desc: "Filter results by query"},
            {
                Short:        "f",
                Long:         "format",
                Placeholder:  "format",
                Desc:         "Output format",
                Enum:         []string{"table", "json", "yaml"},
                EnumDefault:  "table",
            },
        },
    }},
    {Title: "Examples", Content: []help.Content{
        help.Examples{
            {Comment: "List items in JSON format", Command: "catalog list --format json"},
        },
    }},
}

if err := hr.Render(os.Stdout, sections); err != nil {
    return err
}

Flag fields use bare names - the renderer adds dashes (-/--) and angle brackets (</>) automatically. Sections can be nested by including a *help.Section as content.

Framework Adapters

Each adapter provides the same core capabilities for its framework: Extend (or struct tags for Kong), FlagMeta, Sections/HelpFunc, NewCompletion, and CSVFlag.

Annotate your CLI struct with Kong-style tags and a clib:"..." tag for clib-specific metadata (grouping, descriptions, completions, placeholders):

type CLI struct {
    clib.CompletionFlags

    Query  string        `name:"query"  short:"q" help:"Filter results by query" clib:"group='Filters',terse='Query',complete='predictor=query',order=keep"`
    Fields clib.CSVFlag  `name:"fields" help:"Fields to show"                    clib:"complete='predictor=field,comma'"`
    Format string        `name:"format" short:"f" help:"Output format" default:"table" enum:"table,json,yaml"`
}

flags := clib.Reflect(&CLI{})
gen := complete.NewGenerator("catalog").FromFlags(flags)
gen.Install("fish", false)

Integrate with Kong's help system using HelpPrinter or HelpPrinterFunc:

r := help.NewRenderer(th)
k := konglib.Must(&cli,
  konglib.Help(clib.HelpPrinterFunc(r, clib.NodeSectionsFunc())),
)

Use Extend to attach clib metadata to pflag flags:

f := root.Flags()
f.StringP("query", "q", "", "Filter results by query")
f.StringP("format", "f", "table", "Output format")
cobraFields := &cobracli.CSVFlag{}
f.Var(cobraFields, "fields", "Fields to show")

cobracli.Extend(f.Lookup("query"), cobracli.FlagExtra{
  Group: "Filters", Placeholder: "text", Complete: "predictor=query", Order: complete.OrderKeep,
})
cobracli.Extend(f.Lookup("format"), cobracli.FlagExtra{
  Group: "Output", Placeholder: "format", Enum: []string{"table", "json", "yaml"}, EnumDefault: "table",
})
cobracli.Extend(f.Lookup("fields"), cobracli.FlagExtra{
  Complete: "predictor=field,comma",
})

// Auto-grouped help using extras.
root.SetHelpFunc(cobracli.HelpFunc(r, cobracli.Sections))

// Completion flags (hidden).
comp := cobracli.NewCompletion(root)
gen := complete.NewGenerator("catalog").FromFlags(cobracli.FlagMeta(root))
handled, err := comp.Handle(gen, nil)

Use Extend to attach clib metadata to urfave/cli flags:

queryFlag := &clilib.StringFlag{Name: "query", Aliases: []string{"q"}, Usage: "Filter results by query"}
formatFlag := &clilib.StringFlag{Name: "format", Aliases: []string{"f"}, Usage: "Output format", Value: "table"}
fieldsFlag := &clilib.GenericFlag{Name: "fields", Usage: "Fields to show", Value: &cliurfave.CSVFlag{}}

cliurfave.Extend(queryFlag, cliurfave.FlagExtra{
  Group: "Filters", Placeholder: "text", Complete: "predictor=query", Order: complete.OrderKeep,
})
cliurfave.Extend(formatFlag, cliurfave.FlagExtra{
  Group: "Output", Placeholder: "format", Enum: []string{"table", "json", "yaml"}, EnumDefault: "table",
})
cliurfave.Extend(fieldsFlag, cliurfave.FlagExtra{
  Complete: "predictor=field,comma",
})

// Custom help using clib themed renderer.
clilib.HelpPrinter = cliurfave.HelpPrinter(r, cliurfave.Sections)

// Completion flags (hidden).
comp := cliurfave.NewCompletion(root)
gen := complete.NewGenerator("catalog").FromFlags(cliurfave.FlagMeta(cmd))
handled, err := comp.Handle(gen, nil)

Completions

The complete package generates shell completion scripts from flag metadata. The complete tag (Kong) or FlagExtra.Complete field (Cobra/urfave) controls completion behavior:

  • predictor=<name> - dynamic completion via <app> --@complete=<name>
  • comma - comma-separated multi-value mode
  • values=<space-separated> - static completion values

The terse key provides a very short description for completions (falls back to help). Use order=keep (Kong) or Order: complete.OrderKeep (Cobra/urfave) to preserve fish completion order for a flag by emitting complete -k. Use order=shell or Order: complete.OrderShell to force the shell's normal ordering for a flag. Use complete.WithOrder(complete.OrderKeep) to make keep-order the generator default.

Flags hidden from --help are omitted from completions by default. Use complete-hidden (Kong) or FlagExtra.CompleteHidden (Cobra/urfave) to still offer a specific hidden flag as a completion, or complete.WithIncludeHidden() to offer every hidden flag across the command tree.

Enum Formatting

// Styled enum with shortcut letters: [text, json, yaml]
th.FmtEnum([]theme.EnumValue{
  {Name: "text", Bold: "t"},
  {Name: "json", Bold: "j"},
  {Name: "yaml", Bold: "y"},
})

// With default annotation: [text, json, yaml] (default: text)
th.FmtEnumDefault("text", []theme.EnumValue{
  {Name: "text", Bold: "t"},
  {Name: "json", Bold: "j"},
  {Name: "yaml", Bold: "y"},
})

// Dim default/note annotations for flag descriptions.
th.DimDefault("30")    // (default: 30)
th.DimNote("required") // (required)

Markdown Rendering

Render short markdown strings for inline display with themed code spans:

th.RenderMarkdown("Use `--verbose` for debug output")

Shell Detection

shell := shell.Detect() // COMPLETE_SHELL env -> parent process -> SHELL env

Examples

Working examples for each framework adapter are in the examples/ directory:

About

πŸ“š Rich shell completions, styled help and utilities for Go command-line tools

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Contributors