diff --git a/src/cli.rs b/src/cli.rs index 8826a7d..d59ca53 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -36,6 +36,10 @@ pub enum Mode { #[clap(subcommand)] brightness_command: BrightnessCommand, }, + StreamStdin { + #[arg(long, short, default_value_t = false)] + slow: bool + } } #[derive(clap::Parser, std::fmt::Debug)] diff --git a/src/execute.rs b/src/execute.rs index bbad4ed..fa28cdd 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -1,6 +1,7 @@ use crate::cli::{BrightnessCommand, Mode, PixelCommand}; use log::info; use servicepoint::{Brightness, Command, Connection}; +use crate::stream_stdin::stream_stdin; pub fn execute_mode(mode: Mode, connection: Connection) { match mode { @@ -10,6 +11,7 @@ pub fn execute_mode(mode: Mode, connection: Connection) { } Mode::Pixels { pixel_command } => pixels(&connection, pixel_command), Mode::Brightness { brightness_command } => brightness(&connection, brightness_command), + Mode::StreamStdin{slow} => stream_stdin(&connection, slow), } } diff --git a/src/main.rs b/src/main.rs index cb6515a..76db66a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use servicepoint::Connection; mod cli; mod execute; +mod stream_stdin; fn main() { let cli = Cli::parse(); diff --git a/src/stream_stdin.rs b/src/stream_stdin.rs new file mode 100644 index 0000000..5deffb3 --- /dev/null +++ b/src/stream_stdin.rs @@ -0,0 +1,81 @@ +use std::thread::sleep; +use log::warn; +use servicepoint::*; + +pub(crate) fn stream_stdin(connection: &Connection, slow: bool) { + warn!("This mode will break when using multi-byte characters and does not support ANSI escape sequences yet."); + let mut app = App { + connection, + mirror: CharGrid::new(TILE_WIDTH, TILE_HEIGHT), + y: 0, + slow + }; + app.run() +} + +struct App<'t> { + connection: &'t Connection, + mirror: CharGrid, + y: usize, + slow: bool, +} + +impl<'t> App<'t> { + fn run(&mut self) { + self.connection + .send(Command::Clear) + .expect("couldn't clear screen"); + let last_y = self.mirror.height() - 1; + for line in std::io::stdin().lines() { + let line = line.expect("could not read from stdin"); + + if self.y <= last_y { + self.single_line(&line); + self.y += 1; + } else { + self.shift_rows(); + Self::line_onto_grid(&mut self.mirror, last_y, &line); + self.send_mirror() + // we stay on last y + } + + if self.slow { + sleep(FRAME_PACING); + } + } + } + + fn shift_rows(&mut self) { + let data = self.mirror.data_ref_mut(); + data.rotate_left(TILE_WIDTH); + if let Some(row) = data.last_chunk_mut::() { + row.fill(' ') + } + } + + fn line_onto_grid(grid: &mut CharGrid, y: usize, line: &str) { + for (x, char) in line.chars().enumerate() { + if x < grid.width() { + grid.set(x, y, char); + } + } + } + + fn send_mirror(&self) { + self.connection + .send(Command::Cp437Data( + Origin::ZERO, + Cp437Grid::from(&self.mirror), + )) + .expect("couldn't send screen to display"); + } + + fn single_line(&mut self, line: &str) { + let mut line_grid = CharGrid::new(TILE_WIDTH, 1); + Self::line_onto_grid(&mut line_grid, 0, line); + Self::line_onto_grid(&mut self.mirror, self.y, line); + self.connection + .send(Command::Utf8Data(Origin::new(0, self.y), line_grid)) + .expect("couldn't send single line to screen"); + } +}