clish 0.1.0-beta.2

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

# clish

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

A Rust CLI framework that derives command-line interfaces from annotated function signatures.

```rust
#[command]
fn install(package: Pos<String>, version: Named<Option<String>>, force: bool) { ... }
```

</div>

> [!WARNING]
> clish is in beta. The API is not yet stable.
> ```toml
> [dependencies]
> clish = "0.1.0-beta.2"
> ```
> ```sh
> cargo add clish
> ```

---

## How it works

The `#[command]` attribute macro transforms a Rust function into a registered CLI command. Each function parameter type determines the corresponding argument's parsing strategy. The `app!()` macro collects all registered commands, reads `CARGO_PKG_*` environment variables from the Cargo.toml at compile time, and dispatches invocation at runtime.

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

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

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

```sh
myapp deploy production --env prod --force
```

> [!IMPORTANT]
> Importing `clish::*` directly exposes internal framework types. Use `clish::prelude::*` instead for correct name resolution.

---

## Argument types

The parameter type determines how clish parses the corresponding command-line token.

|         Type        |         Behavior        |             Example             |
|---------------------|-------------------------|---------------------------------|
| `Pos<T>`            | Required positional     | `myapp cmd foo`                 |
| `Pos<Option<T>>`    | Optional positional     | `myapp cmd` or `myapp cmd foo`  |
| `Pos<Vec<T>>`       | Variadic positional     | `myapp cmd a b c`               |
| `Named<T>`          | Required `--name val`   | `myapp cmd --env prod`          |
| `Named<Option<T>>`  | Optional `--name val`   |                                 |
| `Named<Vec<T>>`     | Repeatable `--name val` | `myapp cmd --tag a --tag b`     |
| `bool`              | Flag presence           | `myapp cmd --force`             |

Any type `T` that implements `FromStr` is accepted: `String`, `i64`, `u32`, `f64`, and others. A parse failure at runtime produces a styled error message indicating the expected type:

```
error: invalid value for <port>: expected u16
```

The types `Option<Vec<T>>` and `Option<bool>` produce a compile-time error: `Vec<T>` is already zero-or-more (making the outer `Option` redundant), and `bool` is parsed as a flag that is either present or absent.

---

## Command metadata

The `#[command]` attribute accepts metadata keys at the top level:

|         Key         |   Type  | Description |
|---------------------|---------|-------------|
| `help`              | string  | Short description displayed in listing and command help |
| `details`           | string  | Long description displayed only in `--help` output |
| `name`              | string  | Override the CLI command name (defaults to the function name) |
| `aliases`           | array   | Alternative names that resolve to this command |
| `hidden`            | bool    | Omit from app-level help listing; command remains invocable |
| `deprecated`        | bool    | Emit a deprecation warning on invocation |
| `deprecation_note`  | string  | Supplementary message appended to the deprecation warning |

```rust
#[command(
    help = "Deploy the application",
    details = "Runs pre-flight checks, builds the release artifact, then pushes it.",
    aliases = ["ship", "release"],
    deprecated = true,
    deprecation_note = "use 'ship' instead",
)]
fn deploy(...) { ... }
```

Deprecated commands render with the `deprecated` style (dim by default) in the command listing and emit a warning when invoked. Aliased commands are invocable by any of their registered aliases.

---

## Parameter metadata

Individual parameters are configured via `param(ident, key = value, ...)` blocks inside the `#[command]` attribute. The `parameter` keyword is also accepted as a synonym.

### Display

|       Key       |   Type  | Description |
|-----------------|---------|-------------|
| `help`          | string  | Short description shown in argument listings |
| `details`       | string  | Long description shown only in `--help` output |
| `name`          | string  | Override the CLI flag name (for example, `name = "dry-run"` changes `--dry_run` to `--dry-run`) |
| `short`         | char    | Single-character alias (`short = 'd'` registers `-d` alongside the long form) |
| `placeholder`   | string  | Custom help token (`placeholder = "HOST"` renders `<HOST>` instead of the default) |
| `hide`          | bool    | Omit this parameter from all help listings |

### Value resolution

|     Key     |   Type  | Description |
|-------------|---------|-------------|
| `env`       | string  | Environment variable consulted when the argument is not provided on the command line |
| `default`   | string  | Default value used when neither the CLI argument nor the environment variable is present |

Resolution order: CLI argument > `$ENV_VAR` > `default` > error (if the parameter is required).

```rust
#[command(
    param(host, help = "Target host", short = 't', placeholder = "HOST", env = "DEPLOY_HOST"),
    param(port, help = "Port number", short = 'p', default = "8080"),
)]
fn deploy(host: Pos<String>, port: Named<Option<u16>>) { ... }
```

### Validation

|         Key         |   Type  | Description |
|---------------------|---------|-------------|
| `choices`           | array   | Set of permitted string values (`choices = ["debug", "info"]`) |
| `conflicts_with`    | array   | Names of parameters that cannot appear alongside this one (`conflicts_with = ["quiet"]`) |
| `requires`          | array   | Names of parameters that must also be present (`requires = ["output"]`) |

```rust
#[command(
    param(level, short = 'l', choices = ["debug", "info", "error"]),
    param(verbose, short = 'v', conflicts_with = ["quiet"]),
    param(quiet, short = 'q'),
)]
fn log(level: Named<String>, verbose: bool, quiet: bool) { ... }
```

### Completion

|       Key       |   Type  | Description |
|-----------------|---------|-------------|
| `value_hint`    | string  | Hint for shell completion engines (reserved for future use) |

Shell completion generation is not yet implemented.

---

## Help text

Help output is generated automatically from all registered metadata. Two forms are available:

- `myapp -h` (short): displays name, version, one-line description, and the command listing.
- `myapp --help` (long): additionally shows the `details` field when set on the application.
- `myapp <command> --help` (per-command): shows usage, arguments, options, and any param-level metadata.

```
myapp deploy --help
myapp --help deploy
```

Example output:

```
myapp deploy
Deploy the application

Usage: myapp deploy <HOST> [--port <PORT>] [-l <LEVEL>] [-v]

Arguments:
  <HOST>   Target host  [env: DEPLOY_HOST]

Options:
  -p, --port <PORT>   Port number  [default: 8080]
  -l, --level <LEVEL>  Log level  [choices: debug, info, error]
  -v, --verbose        Verbose output
  -q, --quiet          Suppress output
```

---

## App metadata

The `app!()` macro reads `CARGO_PKG_NAME`, `CARGO_PKG_VERSION`, and `CARGO_PKG_DESCRIPTION` from the crate's `Cargo.toml` at compile time. Each value is overridable via builder methods:

```rust
app!()
    .name("myapp")
    .version("1.2.0")
    .description("Does things.")
    .run();
```

---

## Styling

Help text styling is controlled by the `HelpStyles` struct. Each field accepts either a `farben` markup string or an `anstyle::Style` value. Unspecified fields fall back to defaults via `..Default::default()`.

```rust
use clish::prelude::*;
use clish::help::{HelpStyles, HelpStyle};

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

For projects already using `anstyle`:

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

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

### Available fields

|        Field        |      Default       | Context affected |
|---------------------|--------------------|------------------|
| `header`            | `[bold underline]` | Section headings ("Commands:", "Arguments:", "Options:") |
| `command`           | `[bold]`           | Command and parameter names in listings |
| `dim`               | `[dim]`            | Ancillary information (defaults, env vars, choices) |
| `deprecated`        | `[dim]`            | Deprecated command names in listings and deprecation banners |
| `warning`           | `[yellow]`         | Error label prefix |
| `error_label`       | `[bold red]`       | Error label line |
| `error_kind`        | `[red]`            | Error kind identifier ("unknown argument", "missing value") |
| `error_token`       | `[yellow]`         | Flagged tokens in error messages |
| `error_hint`        | `[cyan]`           | Hints and suggestions in error output |

---

## Crate structure

|     Crate     | Purpose |
|---------------|---------|
| `clish`       | Public API crate; the only direct dependency needed |
| `clish-core`  | Runtime types and logic: `App`, `CommandEntry`, argument parsing, help rendering |
| `clish-macros`| Proc-macro crate: `#[command]` attribute macro |

The `clish-core` and `clish-macros` crates are re-exported through `clish` and should not be depended on directly.

---

## Status

Beta. The API is not yet stable.

- [x] Positional arguments
- [x] Named arguments
- [x] Boolean flags
- [x] Optional arguments
- [x] Typed arguments via `FromStr`
- [x] Short flag/option aliases (`-v`, `-o`)
- [x] Environment variable fallback (`env`)
- [x] Default values (`default`)
- [x] Enum-like value constraints (`choices`)
- [x] Mutual exclusion / prerequisites (`conflicts_with`, `requires`)
- [x] Command aliases
- [x] Hidden commands / deprecated commands
- [x] Custom help placeholders
- [x] Hide individual params from help
- [x] Auto-generated help
- [x] `farben` + `anstyle` styling
- [x] Variadic `Vec<T>` in macro
- [ ] Subcommand groups
- [ ] Shell completions

---

## License

Licensed under either of

 * Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
 * MIT license ([LICENSE-MIT]LICENSE-MIT or <http://opensource.org/licenses/MIT>)

at your option.

Cheers, RazkarStudio.

Copyright © 2026 RazkarStudio. All rights reserved.