Skip to main content

demo/
demo.rs

1use std::env;
2use std::io::{self, Write};
3use std::str::FromStr;
4use std::thread;
5use std::time::Duration;
6
7use aisling::{Effect, EffectConfig, EffectKind};
8
9fn main() {
10    let args = Args::parse();
11    let kind = EffectKind::from_str(&args.effect).unwrap_or(EffectKind::Wipe);
12    let mut config = EffectConfig::default()
13        .with_duration(args.duration)
14        .with_seed(args.seed);
15
16    if let (Some(width), Some(height)) = (args.width, args.height) {
17        config = config.with_canvas_size(width.max(1), height.max(1));
18    }
19
20    let effect = Effect::with_config(kind, args.text, config);
21
22    let mut stdout = io::stdout();
23    for frame in effect.iter() {
24        write!(stdout, "\x1b[2J\x1b[H{}", frame.to_ansi_string()).unwrap();
25        stdout.flush().unwrap();
26        thread::sleep(Duration::from_millis((1000 / args.fps.max(1)) as u64));
27    }
28    writeln!(stdout).unwrap();
29}
30
31struct Args {
32    effect: String,
33    text: String,
34    width: Option<usize>,
35    height: Option<usize>,
36    fps: u64,
37    duration: usize,
38    seed: u64,
39}
40
41impl Args {
42    fn parse() -> Self {
43        let mut width = None;
44        let mut height = None;
45        let mut fps = 24u64;
46        let mut duration = None;
47        let mut seconds = None;
48        let mut seed = 7u64;
49        let mut text = None;
50        let mut positional: Vec<String> = Vec::new();
51
52        let mut args = env::args().skip(1).peekable();
53        while let Some(arg) = args.next() {
54            match arg.as_str() {
55                "--width" => {
56                    width = args.next().and_then(|value| value.parse::<usize>().ok());
57                }
58                "--height" => {
59                    height = args.next().and_then(|value| value.parse::<usize>().ok());
60                }
61                "--fps" => {
62                    fps = args
63                        .next()
64                        .and_then(|value| value.parse::<u64>().ok())
65                        .unwrap_or(fps);
66                }
67                "--duration" => {
68                    duration = args
69                        .next()
70                        .and_then(|value| value.parse::<usize>().ok())
71                        .map(|value| value.max(1));
72                }
73                "--seconds" => {
74                    seconds = args
75                        .next()
76                        .and_then(|value| value.parse::<u64>().ok())
77                        .map(|value| value.max(1));
78                }
79                "--seed" => {
80                    seed = args
81                        .next()
82                        .and_then(|value| value.parse::<u64>().ok())
83                        .unwrap_or(seed);
84                }
85                "--text" => {
86                    text = args.next();
87                }
88                "-h" | "--help" | "help" => {
89                    usage();
90                    std::process::exit(0);
91                }
92                _ if !arg.starts_with('-') => {
93                    positional.push(arg);
94                }
95                _ => {
96                    eprintln!("Ignoring unknown argument: {arg}");
97                }
98            }
99        }
100
101        let effect = positional
102            .first()
103            .cloned()
104            .unwrap_or_else(|| "wipe".to_string());
105        let text = text
106            .or_else(|| positional.get(1).cloned())
107            .unwrap_or_else(|| "Aisling".to_string());
108        let duration = duration
109            .or_else(|| seconds.map(|value| (value as usize).saturating_mul(fps as usize)))
110            .unwrap_or(90);
111
112        Self {
113            effect,
114            text,
115            width,
116            height,
117            fps,
118            duration,
119            seed,
120        }
121    }
122}
123
124fn usage() {
125    println!("Usage:");
126    println!("  cargo run --example demo [effect] [text]");
127    println!("  cargo run --example demo -- [effect] [text] --width <cols> --height <rows> --fps <n> --duration <frames>");
128    println!("  cargo run --example demo -- [effect] --text <text> --seconds <seconds> --fps <n>");
129    println!();
130    println!("Examples:");
131    println!("  cargo run --example demo -- wipe \"Aisling\"");
132    println!("  cargo run --example demo -- matrix \"Hello\" --width 120 --height 30 --fps 24");
133}