diff options
author | Jesse Luehrs <doy@tozt.net> | 2021-12-04 19:13:26 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2021-12-04 19:13:26 -0500 |
commit | 7f9c724e1b7afe81e1c07a472db75f7c0592c123 (patch) | |
tree | 7d93259c94f37e69c0dbb3384cfee6255d55f604 | |
parent | f4c1c2b4d5e50b5266a5bffef1e2360e5fcd48cb (diff) | |
download | ttyrec-bin-7f9c724e1b7afe81e1c07a472db75f7c0592c123.tar.gz ttyrec-bin-7f9c724e1b7afe81e1c07a472db75f7c0592c123.zip |
split stuff out into multiple files
-rw-r--r-- | src/bin/ttyplay/display.rs | 21 | ||||
-rw-r--r-- | src/bin/ttyplay/event.rs | 6 | ||||
-rw-r--r-- | src/bin/ttyplay/frames.rs | 75 | ||||
-rw-r--r-- | src/bin/ttyplay/input.rs | 15 | ||||
-rw-r--r-- | src/bin/ttyplay/main.rs | 154 |
5 files changed, 163 insertions, 108 deletions
diff --git a/src/bin/ttyplay/display.rs b/src/bin/ttyplay/display.rs new file mode 100644 index 0000000..4868154 --- /dev/null +++ b/src/bin/ttyplay/display.rs @@ -0,0 +1,21 @@ +use textmode::Textmode as _; + +pub struct Display {} + +impl Display { + pub fn new() -> Self { + Self {} + } + + pub async fn render( + &self, + screen: &vt100::Screen, + output: &mut textmode::Output, + ) -> anyhow::Result<()> { + output.clear(); + output.move_to(0, 0); + output.write(&screen.contents_formatted()); + output.refresh().await?; + Ok(()) + } +} diff --git a/src/bin/ttyplay/event.rs b/src/bin/ttyplay/event.rs new file mode 100644 index 0000000..82a200e --- /dev/null +++ b/src/bin/ttyplay/event.rs @@ -0,0 +1,6 @@ +pub enum Event { + Render(vt100::Screen), + Key(textmode::Key), + Pause, + Quit, +} diff --git a/src/bin/ttyplay/frames.rs b/src/bin/ttyplay/frames.rs new file mode 100644 index 0000000..231f84a --- /dev/null +++ b/src/bin/ttyplay/frames.rs @@ -0,0 +1,75 @@ +#[derive(Debug, Clone)] +pub struct Frame { + screen: vt100::Screen, + delay: std::time::Duration, +} + +impl Frame { + pub fn new(screen: vt100::Screen, delay: std::time::Duration) -> Self { + Self { screen, delay } + } + + pub fn into_screen(self) -> vt100::Screen { + self.screen + } + + pub fn delay(&self) -> std::time::Duration { + self.delay + } +} + +pub struct FrameData { + frames: Vec<Frame>, + done_reading: bool, + new_frame_w: async_std::channel::Sender<Option<usize>>, + new_frame_r: async_std::channel::Receiver<Option<usize>>, +} + +impl FrameData { + pub fn new() -> Self { + let (new_frame_w, new_frame_r) = async_std::channel::unbounded(); + Self { + frames: vec![], + done_reading: false, + new_frame_w, + new_frame_r, + } + } + + pub fn get(&self, i: usize) -> Option<&Frame> { + self.frames.get(i) + } + + pub async fn add_frame(&mut self, frame: Frame) { + self.frames.push(frame); + self.new_frame_w + .send(Some(self.frames.len())) + .await + .unwrap() + } + + pub async fn done_reading(&mut self) { + self.done_reading = true; + self.new_frame_w.send(None).await.unwrap(); + } + + pub fn wait_for_frame( + &self, + i: usize, + ) -> std::pin::Pin< + Box<dyn std::future::Future<Output = bool> + 'static + Send>, + > { + if i < self.frames.len() { + return Box::pin(std::future::ready(true)); + } + let new_frame_r = self.new_frame_r.clone(); + Box::pin(async move { + while let Some(new_len) = new_frame_r.recv().await.unwrap() { + if i < new_len { + return true; + } + } + false + }) + } +} diff --git a/src/bin/ttyplay/input.rs b/src/bin/ttyplay/input.rs new file mode 100644 index 0000000..7221f63 --- /dev/null +++ b/src/bin/ttyplay/input.rs @@ -0,0 +1,15 @@ +pub async fn handle_input( + key: textmode::Key, + event_w: async_std::channel::Sender<crate::event::Event>, +) -> anyhow::Result<()> { + match key { + textmode::Key::Char('q') => { + event_w.send(crate::event::Event::Quit).await? + } + textmode::Key::Char(' ') => { + event_w.send(crate::event::Event::Pause).await?; + } + _ => {} + } + Ok(()) +} diff --git a/src/bin/ttyplay/main.rs b/src/bin/ttyplay/main.rs index 768f1a5..8446bd6 100644 --- a/src/bin/ttyplay/main.rs +++ b/src/bin/ttyplay/main.rs @@ -1,5 +1,9 @@ use async_std::prelude::FutureExt as _; -use textmode::Textmode as _; + +mod display; +mod event; +mod frames; +mod input; #[derive(Debug, structopt::StructOpt)] #[structopt(about = "ttyplay")] @@ -8,85 +12,21 @@ struct Opt { file: std::ffi::OsString, } -#[derive(Debug, Clone)] -struct Frame { - screen: vt100::Screen, - delay: std::time::Duration, -} - -struct FrameData { - frames: Vec<Frame>, - done_reading: bool, - new_frame_w: async_std::channel::Sender<Option<usize>>, - new_frame_r: async_std::channel::Receiver<Option<usize>>, -} - -impl FrameData { - fn new() -> Self { - let (new_frame_w, new_frame_r) = async_std::channel::unbounded(); - Self { - frames: vec![], - done_reading: false, - new_frame_w, - new_frame_r, - } - } - - fn get(&self, i: usize) -> Option<&Frame> { - self.frames.get(i) - } - - async fn add_frame(&mut self, frame: Frame) { - self.frames.push(frame); - self.new_frame_w - .send(Some(self.frames.len())) - .await - .unwrap() - } - - async fn done_reading(&mut self) { - self.done_reading = true; - self.new_frame_w.send(None).await.unwrap(); - } - - fn wait_for_frame( - &self, - i: usize, - ) -> std::pin::Pin< - Box<dyn std::future::Future<Output = bool> + 'static + Send>, - > { - if i < self.frames.len() { - return Box::pin(std::future::ready(true)); - } - let new_frame_r = self.new_frame_r.clone(); - Box::pin(async move { - while let Some(new_len) = new_frame_r.recv().await.unwrap() { - if i < new_len { - return true; - } - } - false - }) - } -} - -enum Event { - Render { screen: vt100::Screen }, - Key(textmode::Key), - Quit, -} - enum TimerAction { Pause, + Quit, } fn spawn_frame_reader_task( - frames: async_std::sync::Arc<async_std::sync::Mutex<FrameData>>, - size: (u16, u16), + frames: async_std::sync::Arc<async_std::sync::Mutex<frames::FrameData>>, fh: async_std::fs::File, ) { async_std::task::spawn(async move { let mut reader = ttyrec::Reader::new(fh); + let size = terminal_size::terminal_size().map_or( + (24, 80), + |(terminal_size::Width(w), terminal_size::Height(h))| (h, w), + ); let mut parser = vt100::Parser::new(size.0, size.1, 0); while let Ok(frame) = reader.read_frame().await { let delay = if let Some(time) = reader.offset() { @@ -98,10 +38,7 @@ fn spawn_frame_reader_task( frames .lock_arc() .await - .add_frame(Frame { - screen: parser.screen().clone(), - delay, - }) + .add_frame(frames::Frame::new(parser.screen().clone(), delay)) .await; } frames.lock_arc().await.done_reading().await; @@ -109,10 +46,10 @@ fn spawn_frame_reader_task( } fn spawn_timer_task( - frames: async_std::sync::Arc<async_std::sync::Mutex<FrameData>>, + event_w: async_std::channel::Sender<event::Event>, + frames: async_std::sync::Arc<async_std::sync::Mutex<frames::FrameData>>, timer_r: async_std::channel::Receiver<TimerAction>, - event_w: async_std::channel::Sender<Event>, -) { +) -> async_std::task::JoinHandle<()> { async_std::task::spawn(async move { let mut idx = 0; let mut start_time = std::time::Instant::now(); @@ -134,13 +71,13 @@ fn spawn_timer_task( let frame = frames.lock_arc().await.get(idx).unwrap().clone(); async_std::task::sleep( - (start_time + frame.delay) + (start_time + frame.delay()) .saturating_duration_since( std::time::Instant::now(), ), ) .await; - Res::Wait(Some(frame.screen)) + Res::Wait(Some(frame.into_screen())) } else { Res::Wait(None) } @@ -149,10 +86,14 @@ fn spawn_timer_task( let action = async { Res::TimerAction(timer_r.recv().await) }; match wait.race(action).await { Res::Wait(Some(screen)) => { - event_w.send(Event::Render { screen }).await.unwrap(); + event_w.send(event::Event::Render(screen)).await.unwrap(); idx += 1; } - Res::Wait(None) => break, + Res::Wait(None) => { + if paused_time.is_none() { + paused_time = Some(std::time::Instant::now()); + } + } Res::TimerAction(Ok(action)) => match action { TimerAction::Pause => { let now = std::time::Instant::now(); @@ -162,21 +103,21 @@ fn spawn_timer_task( paused_time = Some(now); } } + TimerAction::Quit => break, }, - Res::TimerAction(Err(_)) => break, + Res::TimerAction(Err(e)) => panic!("{}", e), } } - event_w.send(Event::Quit).await.unwrap(); - }); + }) } fn spawn_input_task( + event_w: async_std::channel::Sender<event::Event>, mut input: textmode::Input, - event_w: async_std::channel::Sender<Event>, ) { async_std::task::spawn(async move { while let Some(key) = input.read_key().await.unwrap() { - event_w.send(Event::Key(key)).await.unwrap(); + event_w.send(event::Event::Key(key)).await.unwrap(); } }); } @@ -185,10 +126,6 @@ async fn async_main(opt: Opt) -> anyhow::Result<()> { let Opt { file } = opt; let fh = async_std::fs::File::open(file).await?; - let size = terminal_size::terminal_size().map_or( - (24, 80), - |(terminal_size::Width(w), terminal_size::Height(h))| (h, w), - ); let mut input = textmode::Input::new().await?; let mut output = textmode::Output::new().await?; @@ -196,35 +133,36 @@ async fn async_main(opt: Opt) -> anyhow::Result<()> { let _output_guard = output.take_screen_guard(); let frames = async_std::sync::Arc::new(async_std::sync::Mutex::new( - FrameData::new(), + frames::FrameData::new(), )); let (event_w, event_r) = async_std::channel::unbounded(); let (timer_w, timer_r) = async_std::channel::unbounded(); - spawn_frame_reader_task(frames.clone(), size, fh); - spawn_timer_task(frames.clone(), timer_r, event_w.clone()); - spawn_input_task(input, event_w.clone()); + spawn_frame_reader_task(frames.clone(), fh); + spawn_input_task(event_w.clone(), input); + let timer_task = + spawn_timer_task(event_w.clone(), frames.clone(), timer_r); + let display = display::Display::new(); loop { let event = event_r.recv().await?; match event { - Event::Render { screen } => { - output.clear(); - output.move_to(0, 0); - output.write(&screen.contents_formatted()); - output.refresh().await?; + event::Event::Render(screen) => { + display.render(&screen, &mut output).await?; + } + event::Event::Key(key) => { + input::handle_input(key, event_w.clone()).await? + } + event::Event::Pause => timer_w.send(TimerAction::Pause).await?, + event::Event::Quit => { + timer_w.send(TimerAction::Quit).await?; + break; } - Event::Key(key) => match key { - textmode::Key::Char('q') => break, - textmode::Key::Char(' ') => { - timer_w.send(TimerAction::Pause).await.unwrap(); - } - _ => {} - }, - Event::Quit => break, } } + timer_task.await; + Ok(()) } |