summaryrefslogtreecommitdiff
path: root/src/buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.rs')
-rw-r--r--src/buffer.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/buffer.rs b/src/buffer.rs
new file mode 100644
index 0000000..fa0feaa
--- /dev/null
+++ b/src/buffer.rs
@@ -0,0 +1,92 @@
+use std::io::Write;
+
+use crossterm::{
+ cursor::{Hide, MoveTo, Show},
+ event::{self, Event},
+ execute,
+ style::{ContentStyle, PrintStyledContent, StyledContent},
+ terminal::{
+ BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate, EnterAlternateScreen,
+ LeaveAlternateScreen, WindowSize, disable_raw_mode, enable_raw_mode, window_size,
+ },
+};
+
+#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
+pub struct Cell {
+ pub character: char,
+ pub style: ContentStyle,
+ pub x: u16,
+ pub y: u16,
+ pub z: u8,
+}
+
+#[derive(Debug)]
+pub struct Buffer<'a, W: Write> {
+ stdout: &'a mut W,
+ pub cells: Vec<Cell>,
+ pub window_size: WindowSize,
+}
+
+impl<'a, W: Write> Buffer<'a, W> {
+ pub fn new(stdout: &'a mut W) -> std::io::Result<Self> {
+ Ok(Self {
+ stdout,
+ cells: Vec::new(),
+ window_size: window_size()?,
+ })
+ }
+
+ fn initialize(writer: &mut impl Write) -> std::io::Result<()> {
+ enable_raw_mode()?;
+ execute!(writer, Hide, EnterAlternateScreen)?;
+ Ok(())
+ }
+
+ fn render(&mut self) -> std::io::Result<()> {
+ self.cells.sort_unstable_by_key(|cell| cell.z);
+ execute!(self.stdout, BeginSynchronizedUpdate, Clear(ClearType::All))?;
+ for cell in &self.cells {
+ execute!(
+ self.stdout,
+ MoveTo(cell.x, cell.y),
+ PrintStyledContent(StyledContent::new(cell.style, cell.character))
+ )?;
+ }
+ execute!(self.stdout, EndSynchronizedUpdate)?;
+ Ok(())
+ }
+
+ pub fn finish(&mut self) -> std::io::Result<()> {
+ execute!(self.stdout, Show, LeaveAlternateScreen)?;
+ disable_raw_mode()?;
+ Ok(())
+ }
+
+ pub fn render_loop(
+ &mut self,
+ mut event_handler: impl FnMut(&mut Self, Event),
+ mut update: impl FnMut(&mut Self),
+ ) -> std::io::Result<()> {
+ Self::initialize(self.stdout)?;
+ let (sender, receiver) = std::sync::mpsc::channel();
+ std::thread::scope(|scope| -> std::io::Result<()> {
+ scope.spawn(|| {
+ loop {
+ let Ok(event) = event::read() else {
+ continue;
+ };
+ let _ = sender.send(event);
+ }
+ });
+ loop {
+ while let Ok(event) = receiver.try_recv() {
+ event_handler(self, event);
+ }
+ update(self);
+ self.render()?;
+ }
+ })?;
+ self.finish()?;
+ Ok(())
+ }
+}