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