2 releases
Uses new Rust 2024
| 0.1.1 | Mar 4, 2026 |
|---|---|
| 0.1.0 | Mar 4, 2026 |
#243 in Command-line interface
57KB
991 lines
cliclack-yaml
A Rust crate that lets you configure cliclack interactive CLI prompts using YAML files instead of code.
Features
- Define CLI prompts entirely in YAML — no Rust code needed per prompt
- 11 step types:
intro,outro,input,password,confirm,select,multiselect,spinner,print,progress,clearscreen - Variable interpolation with
{variable_name}syntax - Conditional step execution based on previous step results
- Text styling (colors, backgrounds) for intro/outro steps
- Input validation (not-empty, regex, min-length)
Installation
Add to your Cargo.toml:
[dependencies]
cliclack_yaml = "0.1.1"
Quick Start
1. Set up a prompts folder
Create a folder in your project to hold YAML prompt files, for example:
src/
prompts/
auth/
login.yaml
init/
setup.yaml
greeting.yaml
2. Configure cliclack_yaml in main.rs
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Set the application root (typically the current working directory)
cliclack_yaml::set_app_root(env::current_dir()?)?;
// Set the prompt folder relative to app root
cliclack_yaml::set_prompt_folder("src/prompts")?;
// Run a prompt defined in src/prompts/greeting.yaml
let results = cliclack_yaml::render_prompt_interaction("greeting")?;
println!("User said: {:?}", results);
Ok(())
}
3. Write YAML prompt files
Simple greeting (src/prompts/greeting.yaml):
- type: intro
text: " Welcome to My CLI "
style:
color: black
background: cyan
- type: input
prompt: "What is your name?"
output: "name"
- type: outro
text: " Hello, {name}! "
style:
color: black
background: green
Login flow with password (src/prompts/auth/login.yaml):
- type: intro
text: " 🔐 Login "
style:
color: black
background: cyan
- type: input
prompt: "Email address"
output: "email"
- type: password
prompt: "Password"
output: "password"
- type: outro
text: " Authenticating... "
style:
color: black
background: blue
Run nested prompts using the folder path:
let results = cliclack_yaml::render_prompt_interaction("auth/login")?;
let email = results.get("email").unwrap();
Passing Variables
You can pass variables into prompts and reference them with {variable_name}:
let results = cliclack_yaml::render_prompt_interaction_with_vars(
"init/setup",
vec![("config_path", "/home/user/.config/myapp")],
)?;
- type: print
text: "Config will be created at: {config_path}"
YAML Step Reference
clearscreen
Clears the terminal screen.
- type: clearscreen
intro
Displays a styled introduction banner.
- type: intro
text: " My Application "
style:
color: black # black, white, red, green, blue
background: cyan # cyan, green, red, yellow
input
Prompts for text input with optional validation.
- type: input
prompt: "Project name"
placeholder: "my-project"
output: "project_name"
validate:
- type: not-empty
message: "Project name is required"
- type: must-start-with-letter
message: "Must start with a letter"
- type: regex
pattern: "^[a-z][a-z0-9-]*$"
message: "Only lowercase letters, numbers, and hyphens"
password
Prompts for password input with masking.
- type: password
prompt: "Enter password"
output: "password"
mask: '*'
confirm_password: true
confirm_prompt: "Confirm password"
validate:
- type: not-empty
message: "Password is required"
- type: min-length
length: 8
message: "Must be at least 8 characters"
confirm
Prompts for yes/no confirmation. Returns true/false in the output.
- type: confirm
prompt: "Continue?"
output: "confirmed"
default: true
select
Prompts the user to select one option from a list.
- type: select
prompt: "Choose a framework"
output: "framework"
items:
- label: "React"
value: "react"
- label: "Vue"
value: "vue"
hint: "Recommended"
- label: "Angular"
value: "angular"
multiselect
Prompts the user to select multiple options.
- type: multiselect
prompt: "Select features"
output: "features"
required: true
items:
- label: "Authentication"
value: "auth"
- label: "Database"
value: "db"
is_selected: true
- label: "API"
value: "api"
spinner
Displays a spinner while executing a named function.
- type: spinner
start_text: "Installing dependencies..."
stop_text: "Dependencies installed!"
run_fn: "install_deps"
output: "install_result"
Note: The
run_fnvalue must match a function name registered in yourexecute_function_by_namehandler.
Prints a message within the CLI frame. The loglevel field controls the visual style:
loglevel |
Symbol | Description |
|---|---|---|
| (omitted) | │ |
Bar continuation — blends into the frame |
none |
├ |
Remark — connect-left, no marker icon |
info |
● |
Info marker (blue) |
warning/warn |
▲ |
Warning marker (yellow) |
error |
■ |
Error marker (red) |
Plain text (no loglevel) — blends into the frame:
- type: print
text: "This text appears as part of the frame"
With log level marker:
- type: print
loglevel: info
text: "Config path: {config_path}"
input: config_path # optional: variable to read
Remark style (connect-left, no icon):
- type: print
loglevel: none
text: "A remark without a marker icon"
Tip: Use no
loglevelfor content like tables or formatted output that should blend seamlessly into the cliclack frame. Useloglevel: nonewhen you want a visual separator (├) without an icon. Useinfo/warning/errorfor messages that need attention markers.
progress
Displays a progress bar or spinner for long-running tasks.
- type: progress
progress_type: Bar
start_message: "Downloading..."
stop_message: "Download complete!"
items:
- name: "file1.zip"
duration_ms: 2000
- name: "file2.zip"
duration_ms: 1500
multi-progress
Displays multiple progress bars simultaneously.
- type: multi-progress
title: "Installing components"
progress_bars:
- label: "Core"
progress_type: Bar
duration_ms: 3000
- label: "Plugins"
progress_type: Spinner
duration_ms: 2000
outro
Displays a styled closing message.
- type: outro
text: " All done! "
input: result_var # optional: variable to display
style:
color: black
background: green
Conditional Steps
Steps can be conditionally executed based on previous step results:
- type: confirm
prompt: "Enable advanced mode?"
output: "advanced"
step_name: "advanced_check"
- type: input
prompt: "Enter API key"
output: "api_key"
condition:
parent: "advanced_check"
value: true
The input step only runs if the user confirmed "advanced_check".
Advanced: Embedded Prompts with Fallback
For distributing your CLI as a single binary, you can embed YAML files at compile time using include_dir and fall back to them when no external prompt folder is found:
use std::collections::HashMap;
use anyhow::Result;
use include_dir::{include_dir, Dir};
// Embed all YAML files from src/prompts/ into the binary
static EMBEDDED_PROMPTS: Dir = include_dir!("src/prompts");
fn get_embedded_yaml(prompt_name: &str) -> Result<String> {
let file_path = format!("{}.yaml", prompt_name);
EMBEDDED_PROMPTS
.get_file(&file_path)
.and_then(|f| f.contents_utf8())
.map(|s| s.to_string())
.ok_or_else(|| anyhow::anyhow!("Prompt '{}' not found", prompt_name))
}
/// Try external folder first, fall back to embedded prompts
pub fn run_prompt(
prompt_name: &str,
vars: Option<HashMap<String, String>>,
) -> Result<HashMap<String, String>> {
let yaml_str = match cliclack_yaml::get_yaml_content(prompt_name) {
Ok(content) => content,
Err(_) => get_embedded_yaml(prompt_name)?,
};
let steps: Vec<cliclack_yaml::PromptStep> = serde_yml::from_str(&yaml_str)?;
cliclack_yaml::create_prompt_with_vars_custom(steps, vars)
}
This pattern lets users override prompts by placing YAML files in the configured prompt folder, while keeping defaults baked into the binary.
License
MIT
Examples
See the examples/config/ folder for a complete set of white-label YAML configurations covering auth flows, initialization, config management, CRUD operations, installation progress, system checks, and showcases for every feature (conditionals, variables, validation, styling).
For a full working CLI application that integrates cliclack_yaml with clap, see the cliclack-yaml-cli-example repository. It demonstrates embedded prompts, configuration management, and how to structure a white-label CLI project using this crate.
Dependencies
~11–16MB
~348K SLoC