Help Rendering: Dynamic Layouts and Custom Styles
Unlike many CLI frameworks that hardcode text templates or construct static string blocks, clish generates all help displays dynamically at runtime. This ensures that help text remains fully synchronized with the underlying types, validations, and default values.
This page explains how the help engine measures terminal column widths, resolves layout elements, and formats the output with configurable styles.
The Metadata Source
The help engine relies on the static list of ParamEntry structs generated for each command. Every parameter property is parsed at startup:
pub struct ParamEntry {
pub name: &'static str,
pub short: char,
pub help: &'static str,
pub details: &'static str,
pub kind: &'static str,
pub placeholder: &'static str,
...
}
Dynamic Layout & Column Alignment
To prevent jagged text layouts, clish computes column margins dynamically based on the longest parameter description:
flowchart TD
A[Compile Help Elements] --> B[Calculate Label Widths]
B --> C[Positional\ne.g. '<TARGET>']
B --> D[Named Option\ne.g. '-p, --port <P>']
B --> E[Flag\ne.g. '-f, --force']
C --> F[Find Max Label String Length\nmax_width]
D --> F
E --> F
F --> G[Format Table Column]
G --> H["Print: [Label] + [Padding to max_width] + [Help] + [Hints]"]
1. Label Formatting (param_label)
First, the engine translates each parameter's properties into a display label.
* Positional parameters:
* Required: <NAME> (e.g. <TARGET>)
* Optional: [<NAME>] (e.g. [<TARGET>])
* Variadic: <NAME>... (e.g. <TARGET>...)
* Named parameters:
* Without short alias: --port <PORT>
* With short alias: -p, --port <PORT>
* Flag parameters:
* Without short alias: --force
* With short alias: -f, --force
The generic name inside the brackets is determined by the placeholder attribute, falling back to the uppercase parameter name.
2. Alignment Calculation
The engine loops through all parameter display labels to determine the length of the longest string. Let's call this max_width.
When printing, the label column is padded to max_width using spaces, followed by two spaces of buffer, and then the parameter's help description. This creates a clean vertical alignment across all lines:
Options:
-p, --port <PORT> Port number
-f, --force Force deployment
--verbose Print detailed logs
^~~~~~~~~~~~~~~~~^ ^
label (padded) description
3. Compact Usage Collapse
If a command has many named options and flags, the usage line can become
excessively long. The App::compact_usage_limit field controls when the usage
line collapses to [OPTIONS]:
None-- never collapseSome(0)-- always collapseSome(n)-- collapse whennamed + flags > n
The collapse only affects the usage line. The full Arguments and Options sections below it always show every parameter with its metadata.
The default threshold is Some(5), which means commands with 6 or more
options/flags get a compact usage line.
The Styling Engine: farben & anstyle
clish supports a customizable styling system through the AppStyles structure. Each style field (like header or brand) is represented by the AppStyle enum:
pub enum AppStyle {
Markup(&'static str),
Anstyle(anstyle::Style),
}
This hybrid model gives developers the flexibility to choose their styling paradigm:
1. Farben Markup
farben is a text markup library. It uses embedded tags inside strings to define colors:
let my_style: AppStyle = "[bold cyan]".into();
farben translates "[bold cyan]" into standard ANSI escape codes (\x1b[1;36m) and automatically resets the terminal coloring at the end of the text.
2. anstyle Structs
anstyle is a lightweight, zero-dependency styling specification crate. It is the modern standard for writing CLI tool colors in Rust:
use anstyle::{Style, AnsiColor};
let my_style: AppStyle = Style::new()
.fg_color(Some(AnsiColor::Cyan.into()))
.bold()
.into();
Detailed vs. Short Help
clish automatically manages two levels of help display detail:
flowchart LR
S["Short Help\n(-h)"] --> S1[App Name, Version and Description]
S --> S2[Parameter Labels and Short Help]
S --> S3[Omits long details]
D["Detailed Help\n(--help)"] --> D1[Everything in Short Help]
D --> D2[Long App and Command Details]
D --> D3[Parameter-specific Details]
D --> D4["Parameter Fallback Hints\n(Env, Defaults)"]
Short Help (-h)
Triggered by running <command> -h or <app> -h.
* Displays the application name, version, and primary description.
* Lists parameters with their standard display labels and short help summaries.
* Omits the long command details and parameter details to keep output compact.
Detailed Help (--help)
Triggered by running <command> --help or <app> --help.
* Includes everything from the short help.
* Appends the command's long details block below the primary description.
* Appends parameter-specific details below their respective parameter rows.
* Displays argument fallback hints (choices, environment variables, and defaults) inside parentheses:
-p, --port <PORT> Port number (env: PORT, default: 8080)
Next, let's explore App Dispatch to see how clish initializes the program and resolves subcommand routing.