outstanding-clap

Crates.iooutstanding-clap
lib.rsoutstanding-clap
version1.0.0
created_at2026-01-04 23:30:51.526406+00
updated_at2026-01-14 01:37:39.696543+00
descriptionClap integration for Outstanding template engine - topics and styled help
homepage
repositoryhttps://github.com/arthur-debert/outstanding-rs
max_upload_size
id2022764
size342,619
Arthur Debert (arthur-debert)

documentation

README

outstanding-clap

Batteries-included integration of outstanding with clap. This crate provides styled CLI output with minimal setup.

Installation

[dependencies]
outstanding-clap = "0.12"
clap = "4"
serde = { version = "1", features = ["derive"] }

Quick Start

Simplest Usage

use clap::Command;
use outstanding_clap::Outstanding;

let matches = Outstanding::run(Command::new("my-app"));

Your CLI now has styled help and an --output flag.

With Command Handlers

use clap::Command;
use outstanding_clap::{Outstanding, CommandResult};
use serde::Serialize;

#[derive(Serialize)]
struct ListOutput {
    items: Vec<String>,
}

fn main() {
    let cmd = Command::new("my-app")
        .subcommand(Command::new("list").about("List all items"));

    Outstanding::builder()
        .command("list", |_matches, _ctx| {
            CommandResult::Ok(ListOutput {
                items: vec!["apple".into(), "banana".into()],
            })
        }, "{% for item in items %}- {{ item }}\n{% endfor %}")
        .run_and_print(cmd, std::env::args());
}

Now your CLI supports:

my-app list              # Rendered template output
my-app list --output=json # JSON output

With Embedded Styles

Use YAML stylesheets with the macros feature:

[dependencies]
outstanding-clap = { version = "0.12", features = ["macros"] }

Create a stylesheet in styles/default.yaml:

item:
  fg: cyan
header:
  fg: white
  bold: true

Then use it:

use clap::Command;
use outstanding_clap::{Outstanding, CommandResult, embed_styles};
use serde::Serialize;

#[derive(Serialize)]
struct ListOutput { items: Vec<String> }

fn main() {
    let cmd = Command::new("my-app")
        .subcommand(Command::new("list"));

    Outstanding::builder()
        .styles(embed_styles!("styles"))
        .default_theme("default")
        .command("list", |_m, _ctx| {
            CommandResult::Ok(ListOutput {
                items: vec!["apple".into(), "banana".into()],
            })
        }, "{% for item in items %}- {{ item | style(\"item\") }}\n{% endfor %}")
        .run_and_print(cmd, std::env::args());
}

With Help Topics

Add extended documentation from markdown or text files:

Outstanding::builder()
    .topics_dir("docs/topics")
    .run(cmd);

Users access via:

my-app help topics           # List all topics
my-app help getting-started  # View specific topic

Output Modes

Users control output format via --output:

my-app list                  # Rendered template (default)
my-app list --output=json    # JSON serialization
my-app list --output=yaml    # YAML serialization
my-app list --output=text    # Plain text (no ANSI codes)

Command Handlers

Register handlers that return serializable data:

.command("list", |matches, ctx| {
    // matches: &ArgMatches - parsed arguments
    // ctx: &CommandContext - command path, output mode, etc.

    let items = fetch_items();
    CommandResult::Ok(ListOutput { items })
}, "{% for item in items %}{{ item }}\n{% endfor %}")

CommandResult Variants

Variant Description
Ok(data) Success with serializable data
Err(error) Error to display
Silent No output
Archive(bytes, filename) Binary file output

Hooks

Run custom code before/after command execution:

use outstanding_clap::Hooks;

Outstanding::builder()
    .command("export", handler, template)
    .hooks("export", Hooks::new()
        .pre_dispatch(|_m, ctx| {
            println!("Running: {:?}", ctx.command_path);
            Ok(())
        })
        .post_output(|_m, _ctx, output| {
            // Transform output, copy to clipboard, etc.
            Ok(output)
        }))
    .run_and_print(cmd, args);

Embed Macros

The embed_styles! macro embeds stylesheets at compile time with debug hot-reload:

  • At compile time: Walk directory and embed all .yaml/.yml files
  • In debug mode: If source directory exists, read from disk (hot-reload)
  • In release mode: Use embedded content (zero file I/O)
// Embeds all .yaml, .yml files from styles/
.styles(embed_styles!("styles"))
.default_theme("default")  // Use styles/default.yaml

Documentation

License

MIT

Commit count: 233

cargo fmt