use clap::{Parser, Subcommand};
use glyphs::Color;
use lacquer::Border;
use chant::{choose, confirm, filter, input, spin, style_text};
use scoria::SpinnerStyle;
use std::time::Duration;
#[derive(Parser)]
#[command(name = "rune")]
#[command(about = "Shell glamour - beautiful prompts and output 🪄")]
#[command(version)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Input {
#[arg(short, long, default_value = "Enter value")]
prompt: String,
#[arg(long)]
placeholder: Option<String>,
#[arg(short, long)]
default: Option<String>,
#[arg(long)]
password: bool,
#[arg(long)]
header: Option<String>,
},
Confirm {
prompt: String,
#[arg(long)]
default: Option<bool>,
},
Choose {
options: Vec<String>,
#[arg(long)]
header: Option<String>,
#[arg(short, long)]
limit: Option<usize>,
},
Filter {
options: Vec<String>,
#[arg(long)]
header: Option<String>,
#[arg(short, long, default_value = "10")]
limit: usize,
},
Spin {
title: String,
#[arg(short, long, default_value = "3")]
duration: u64,
#[arg(short, long, default_value = "dots")]
style: String,
},
Style {
text: String,
#[arg(long)]
foreground: Option<String>,
#[arg(long)]
background: Option<String>,
#[arg(long)]
bold: bool,
#[arg(long)]
italic: bool,
#[arg(long)]
underline: bool,
#[arg(long)]
border: Option<String>,
#[arg(long)]
padding: Option<String>,
#[arg(short, long)]
width: Option<u16>,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Input {
prompt,
placeholder,
default,
password,
header,
} => {
let mut cmd = input(&prompt);
if let Some(p) = placeholder {
cmd = cmd.placeholder(p);
}
if let Some(d) = default {
cmd = cmd.default(d);
}
if password {
cmd = cmd.password();
}
if let Some(h) = header {
cmd = cmd.header(h);
}
let result = cmd.run();
println!("{}", result);
}
Commands::Confirm { prompt, default } => {
let mut cmd = confirm(&prompt);
if let Some(d) = default {
cmd = cmd.default(d);
}
let result = cmd.run();
std::process::exit(if result { 0 } else { 1 });
}
Commands::Choose {
options,
header,
limit,
} => {
let mut cmd = choose(&options);
if let Some(h) = header {
cmd = cmd.header(h);
}
if let Some(l) = limit {
cmd = cmd.limit(l);
}
if let Some(result) = cmd.run() {
println!("{}", result);
}
}
Commands::Filter {
options,
header,
limit,
} => {
let mut cmd = filter(&options);
if let Some(h) = header {
cmd = cmd.header(h);
}
cmd = cmd.limit(limit);
if let Some(result) = cmd.run() {
println!("{}", result);
}
}
Commands::Spin {
title,
duration,
style,
} => {
let spinner_style = match style.to_lowercase().as_str() {
"line" => SpinnerStyle::Line,
"dots" => SpinnerStyle::Dots,
"arrow" => SpinnerStyle::Arrow,
"circle" => SpinnerStyle::Circle,
"moon" => SpinnerStyle::Moon,
"fire" => SpinnerStyle::Fire,
_ => SpinnerStyle::Dots,
};
spin(&title).style(spinner_style).run(|| {
std::thread::sleep(Duration::from_secs(duration));
});
}
Commands::Style {
text,
foreground,
background,
bold,
italic,
underline,
border,
padding,
width,
} => {
let mut cmd = style_text(&text);
if let Some(fg) = foreground {
cmd = cmd.foreground(Color::from_hex(&fg));
}
if let Some(bg) = background {
cmd = cmd.background(Color::from_hex(&bg));
}
if bold {
cmd = cmd.bold();
}
if italic {
cmd = cmd.italic();
}
if underline {
cmd = cmd.underline();
}
if let Some(b) = border {
let border_style = match b.to_lowercase().as_str() {
"rounded" => Border::Rounded,
"double" => Border::Double,
"thick" => Border::Thick,
"normal" => Border::Normal,
"ascii" => Border::Ascii,
_ => Border::Rounded,
};
cmd = cmd.border(border_style);
}
if let Some(p) = padding {
let parts: Vec<u16> = p.split(',').filter_map(|s| s.trim().parse().ok()).collect();
if parts.len() == 2 {
cmd = cmd.padding(parts[0], parts[1]);
} else if parts.len() == 1 {
cmd = cmd.padding(parts[0], parts[0]);
}
}
if let Some(w) = width {
cmd = cmd.width(w);
}
cmd.print();
}
}
}