clish 0.1.0-beta.3

Elegant CLI framework for Rust.
Documentation
<div align="center">

# clish

**The most elegant CLI framework for Rust.**

> clish (/klɪʃ/ "KEL-ish")

[![Crates.io](https://img.shields.io/crates/v/clish?style=for-the-badge)](https://crates.io/crates/clish)
[![Docs.rs](https://img.shields.io/docsrs/clish?style=for-the-badge)](https://docs.rs/clish)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=for-the-badge)](LICENSE-MIT)
[![Docs](https://img.shields.io/badge/docs-codeberg%20pages-7c4dff?style=for-the-badge)](https://razkar.codeberg.page/clish)
[![Rust edition](https://img.shields.io/badge/Rust-2024-edition?style=for-the-badge&logo=rust)](https://rust-lang.org)
[![Repository](https://img.shields.io/badge/repo-on%20codeberg-2185D0?style=for-the-badge&logo=codeberg)](https://codeberg.org/razkar/clish)

```rust
use clish::prelude::*;

#[command]
fn deploy(target: Pos<String>, env: Named<String>, force: bool) {
    println!("Deploying {target} to {env} (force={force})");
}

fn main() {
    app!().run();
}
```

_Inspired by Typer_

</div>

## Quick Start

```toml
[dependencies]
clish = "0.1.0-beta.3"
```

```rust
use clish::prelude::*;

#[command]
fn hello(name: Named<Option<String>>) {
    println!("Hello, {}!", name.unwrap_or("world"));
}

fn main() {
    app!().run();
}
```

```sh
cargo run -- hello --name Alice
# Hello, Alice!
```

## Usage

```sh
app -h                      # Short help
app --help                  # Long help (includes details)
app --version               # Show version
app --verbose --version     # Version + platform info
app <cmd> --help            # Per-command help
app <cmd> --help            # Also works: app --help <cmd>
app <cmd> -- arg1 --arg2    # -- separator: everything after is positional
```

## Argument Types

| Type | CLI Form |
|------|----------|
| `Pos<T>` | `<arg>` required positional |
| `Pos<Option<T>>` | `[arg]` optional positional |
| `Pos<Vec<T>>` | `<arg>...` variadic (zero or more) |
| `Named<T>` | `--name <val>` required option |
| `Named<Option<T>>` | `[--name <val>]` optional option |
| `Named<Vec<T>>` | `--name <val> --name <val>` repeatable |
| `bool` | `--flag` presence flag |

Named options support `--name=value`, `--name value`, `-n value`, and `-nvalue` forms.
Flags support bundling: `-abc` is equivalent to `-a -b -c`.

## Command Options

```rust
#[command(
    help = "Deploy the app",
    details = "Long description shown on --help.",
    aliases = ["ship", "push"],
    hidden = false,
    deprecated = true,
    deprecation_note = "use 'ship' instead",
    param(host, short = 'h', help = "Target host", env = "HOST"),
    param(port, short = 'p', default = "8080"),
    param(level, choices = ["debug", "info"]),
    param(verbose, conflicts_with = ["quiet"]),
    param(output, requires = ["format"]),
)]
fn deploy(host: Pos<String>, port: Named<u16>, level: Named<String>, verbose: bool, quiet: bool, output: Named<Option<String>>, format: Named<Option<String>>) { ... }
```

## Parameter Options

| Key | Type | Description |
|-----|------|-------------|
| `help` | string | Short description |
| `details` | string | Long description (shown only in `--help`) |
| `name` | string | Override the CLI flag name |
| `short` | char | Single-character alias (`-d`) |
| `placeholder` | string | Custom help token |
| `hide` | bool | Omit from help listings |
| `default` | string | Default value |
| `env` | string | Environment variable fallback |
| `choices` | array | Allowed values |
| `conflicts_with` | array | Mutual exclusion |
| `requires` | array | Prerequisites |
| `value_hint` | string | Shell completion hint (reserved) |

Resolution order: CLI argument > `$ENV_VAR` > `default` > error.

## Oneshot Mode

Pass a command function to `app!()` for single-command CLIs without subcommand dispatch:

```rust
use clish::prelude::*;

#[command]
fn greet(name: Pos<String>) {
    println!("Hello, {name}!");
}

fn main() {
    app!(greet).run();
}
```

Oneshot mode enforces that the command has no custom `name`, `aliases`, `hidden`, or `deprecated` attributes, and that no other commands are registered.

## Styling

```rust
use clish::prelude::*;
use clish::help::{AppStyles, AppStyle};

app!()
    .styles(AppStyles {
        header: AppStyle::Markup("[bold cyan underline]"),
        command: AppStyle::Markup("[bold cyan]"),
        ..Default::default()
    })
    .run();
```

Or use `anstyle::Style` values directly:

```rust
use anstyle::{Style, AnsiColor};

app!()
    .styles(AppStyles {
        header: AppStyle::Anstyle(Style::new().fg_color(Some(AnsiColor::Cyan.into()))),
        ..Default::default()
    })
    .run();
```

## Error Handling

Errors are printed to stderr with structured formatting:

```
error: unknown command 'deplyo'
  |
1 | myapp deplyo
  |        ^^^^^^
  |
  = hint: run 'myapp --help' for available commands
```

Command functions can return `Result<(), String>` for custom error handling.

## Documentation

Full docs: <https://razkar.codeberg.page/clish>
API documentation: <https://docs.rs/clish>

## License

MIT or Apache-2.0

Cheers, RazkarStudio.

Copyright (c) 2026 RazkarStudio. All rights reserved.