diff --git a/Cargo.toml b/Cargo.toml index 6410b29..a53b798 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arkham" -version = "0.1.0" +version = "0.3.0" edition = "2021" [[example]] @@ -37,6 +37,6 @@ path = "examples/paragraph.rs" [dependencies] anyhow = "1.0.71" -crossterm = "0.26.1" +crossterm = "0.27" ctrlc = "3.3.1" textwrap = "0.16.0" diff --git a/src/app.rs b/src/app.rs index 98a394c..f279266 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,12 @@ -use std::{any::Any, cell::RefCell, io::Write, marker::PhantomData, rc::Rc}; +use std::{ + any::Any, + cell::RefCell, + io::Write, + marker::PhantomData, + rc::Rc, + sync::mpsc::{channel, Receiver, Sender}, + time::Duration, +}; use crossterm::{ cursor, @@ -14,6 +22,17 @@ use crate::{ use super::input::Keyboard; +/// A renderer that can signal a render needs to take place. +pub struct Renderer { + tx: Sender<()>, +} + +impl Renderer { + pub fn render(&self) { + let _ = self.tx.send(()); + } +} + /// The app is the core container for the application logic, resources, /// state, and run loop. pub struct App @@ -23,6 +42,8 @@ where { container: Rc>, main_view: View, + render_signal: Receiver<()>, + render_tx: Sender<()>, root: F, args: PhantomData, } @@ -39,14 +60,25 @@ where let container = Rc::new(RefCell::new(Container::default())); let size = terminal::size().unwrap(); let main_view = View::new(size); + let (render_tx, render_signal) = channel(); App { container, root, main_view, + render_tx, + render_signal, args: PhantomData, } } + /// Returns a renderer that can signal the application to rerender. This + /// renderer can be cloned and passed between threads. + pub fn get_renderer(&self) -> Renderer { + Renderer { + tx: self.render_tx.clone(), + } + } + /// Insert a resource which can be injected into component functions. /// /// This resource can only be accessed immutably by reference. @@ -146,24 +178,29 @@ where .unwrap() .reset(); - if let Ok(event) = crossterm::event::read() { - match event { - Event::FocusGained => todo!(), - Event::FocusLost => todo!(), - Event::Key(key_event) if key_event.code == KeyCode::Char('q') => { - break; + if crossterm::event::poll(Duration::from_millis(100)).unwrap_or(false) { + if let Ok(event) = crossterm::event::read() { + match event { + Event::FocusGained => self.render()?, + Event::FocusLost => {} + Event::Key(key_event) if key_event.code == KeyCode::Char('q') => { + break; + } + Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { + let container = self.container.borrow(); + let kb = container.get::>().unwrap(); + kb.set_key(key_event.code); + } + Event::Mouse(_) => todo!(), + Event::Paste(_) => todo!(), + Event::Resize(_, _) => self.render()?, + _ => {} } - Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { - let container = self.container.borrow(); - let kb = container.get::>().unwrap(); - kb.set_key(key_event.code); - } - Event::Mouse(_) => todo!(), - Event::Paste(_) => todo!(), - Event::Resize(_, _) => todo!(), - _ => {} } } + if self.render_signal.try_recv().is_ok() { + self.render()?; + } } self.teardown(); diff --git a/src/components/paragraph.rs b/src/components/paragraph.rs index 1ad76da..b93abd0 100644 --- a/src/components/paragraph.rs +++ b/src/components/paragraph.rs @@ -1,9 +1,7 @@ -use std::ops::Deref; - -use crossterm::style::Color; - use crate::prelude::{Callable, ToRuneExt}; - +use crossterm::style::Color; +use std::ops::Deref; +#[allow(dead_code)] #[derive(Debug)] pub struct Paragraph { content: String, @@ -29,7 +27,7 @@ impl Callable<()> for Paragraph { let lines = textwrap::wrap(&self.content, view.width()); let mut stack = view.vertical_stack(view.size()); for line in lines.iter() { - let l = line.deref().to_runes(); + let _ = line.deref().to_runes(); stack.insert(line); } diff --git a/src/lib.rs b/src/lib.rs index 64efa49..0b4e175 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ mod view; pub mod prelude { pub use super::{ - app::{App, Terminal}, + app::{App, Renderer, Terminal}, container::{Callable, FromContainer, Res, State}, context::ViewContext, geometry::{Pos, Rect, Size}, diff --git a/src/plugins/keybind.rs b/src/plugins/keybind.rs index 8f0016b..182f9ec 100644 --- a/src/plugins/keybind.rs +++ b/src/plugins/keybind.rs @@ -1 +1,2 @@ +#[allow(dead_code)] pub struct KeybindPlugin; diff --git a/src/symbols.rs b/src/symbols.rs index 68fe138..b356868 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -#[cfg(any(not(windows), all(windows)))] mod universal { pub const TICK: char = '✔'; pub const CROSS: char = '✖'; @@ -61,11 +60,9 @@ mod universal { pub const SEVEN_EIGHTHS: char = '⅞'; } -#[cfg(any(not(windows), all(windows)))] pub use universal::*; -#[cfg(all(windows))] -mod win { +pub mod win { pub const TICK: char = '√'; pub const CROSS: char = '×'; pub const STAR: char = '*'; @@ -89,6 +86,3 @@ mod win { pub const QUESTION_MARK_PREFIX: char = '?'; pub const ONE_HALF: char = ' '; } - -#[cfg(all(windows))] -pub use win::*;