Skip to main content

sl/
lib.rs

1pub mod terminal;
2pub mod train;
3pub mod smoke;
4pub mod config;
5pub mod render;
6pub mod debug;
7
8use crate::terminal::{Terminal, InputAction};
9use crate::config::Config;
10use crate::render::render_frame;
11use std::thread;
12use std::time::Duration;
13use std::io;
14
15const FRAME_TIME_MS: u64 = 40;
16
17/// Runs the SL animation with the given arguments.
18pub fn run<I, T>(args: I) -> io::Result<()> 
19where
20    I: IntoIterator<Item = T>,
21    T: AsRef<str>,
22{
23    run_with_token(args, None)
24}
25
26/// Runs the SL animation with a cancellation token.
27pub fn run_with_token<I, T>(args: I, cancel_token: Option<wasibox_core::CancellationToken>) -> io::Result<()>
28where
29    I: IntoIterator<Item = T>,
30    T: AsRef<str>,
31{
32    let config = Config::from_args(args);
33    let terminal = Terminal::new()?;
34
35    let width = terminal.width() as i32;
36    let max_length = if config.logo { 40 } else if config.c51 { 95 } else { 83 };
37
38    let mut pattern = 0usize;
39    let mut paused = false;
40
41    for x in (-(max_length + 10)..=(width + 10)).rev() {
42        if let Some(token) = &cancel_token {
43            if token.is_cancelled() {
44                break;
45            }
46        }
47        // Unified input handler
48        match terminal.check_input()? {
49            InputAction::Quit => break,
50            InputAction::Pause => {
51                paused = !paused;
52                if paused {
53                    eprintln!("⏸️  PAUSED - Press Space or P to resume, Ctrl+C to quit");
54                }
55            }
56            InputAction::None => {}
57        }
58
59        // If paused, wait for resume signal without advancing animation
60        while paused {
61            if let Some(token) = &cancel_token {
62                if token.is_cancelled() {
63                    return Ok(());
64                }
65            }
66            thread::sleep(Duration::from_millis(100));
67            match terminal.check_input()? {
68                InputAction::Pause => {
69                    paused = false;
70                    eprintln!("▶️  RESUMED");
71                }
72                InputAction::Quit => return Ok(()),
73                InputAction::None => {}
74            }
75        }
76
77        render_frame(&terminal, x, pattern, &config)?;
78
79        pattern = (pattern + 1) % 6;
80        thread::sleep(Duration::from_millis(FRAME_TIME_MS));
81    }
82
83    Ok(())
84}