From cc2f102141b75d4c5e93b39a3a1b3de2736c01fc Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 21 May 2022 21:07:24 +0200 Subject: [PATCH] Position cursor via buffer --- examples/hello_world.rs | 1 + src/buffer.rs | 39 +++++++++++++++++++++++++++++++-------- src/terminal.rs | 20 +++++++++++++++++++- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 0b4d6ca..44c10fa 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -24,6 +24,7 @@ fn main() -> io::Result<()> { "Press any key to exit", ContentStyle::default().on_dark_blue(), ); + b.set_cursor(Some(Pos::new(16, 0))); // Show the buffer's contents on screen term.present()?; diff --git a/src/buffer.rs b/src/buffer.rs index 256e3ab..c666cda 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -51,6 +51,7 @@ impl Cell { pub struct Buffer { size: Size, data: Vec, + cursor: Option, } impl Buffer { @@ -59,6 +60,7 @@ impl Buffer { Self { size: Size::ZERO, data: vec![], + cursor: None, } } @@ -77,19 +79,32 @@ impl Buffer { self.size } + /// Resize the buffer and reset its contents. + /// + /// The buffer's contents are reset even if the buffer is already the + /// correct size. pub fn resize(&mut self, size: Size) { - let width: usize = size.width.into(); - let height: usize = size.height.into(); - let len = width * height; + if size == self.size() { + self.data.fill_with(Cell::empty); + self.cursor = None; + } else { + let width: usize = size.width.into(); + let height: usize = size.height.into(); + let len = width * height; - self.size = size; - self.data.clear(); - self.data.resize_with(len, Cell::empty); + self.size = size; + self.data.clear(); + self.data.resize_with(len, Cell::empty); + self.cursor = None; + } } - /// Reset all cells of the buffer to be empty and have no styling. + /// Reset the contents of the buffer. + /// + /// `buf.reset()` is equivalent to `buf.resize(buf.size())`. pub fn reset(&mut self) { - self.resize(self.size); + self.data.fill_with(Cell::empty); + self.cursor = None; } pub fn write(&mut self, mut pos: Pos, content: &str, style: ContentStyle) { @@ -118,6 +133,14 @@ impl Buffer { } } + pub fn cursor(&self) -> Option { + self.cursor + } + + pub fn set_cursor(&mut self, pos: Option) { + self.cursor = pos; + } + pub fn cells(&self) -> Cells<'_> { Cells { buffer: self, diff --git a/src/terminal.rs b/src/terminal.rs index 482644b..7653855 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,7 +1,7 @@ use std::io::Write; use std::{io, mem}; -use crossterm::cursor::MoveTo; +use crossterm::cursor::{Hide, MoveTo, Show}; use crossterm::style::{PrintStyledContent, StyledContent}; use crossterm::terminal::{Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen}; use crossterm::{ExecutableCommand, QueueableCommand}; @@ -65,9 +65,11 @@ impl Terminal { } self.draw_differences()?; + self.update_cursor()?; self.out.flush()?; mem::swap(&mut self.prev_buffer, &mut self.curr_buffer); + self.curr_buffer.reset(); Ok(()) } @@ -80,7 +82,23 @@ impl Terminal { .queue(MoveTo(x, y))? .queue(PrintStyledContent(content))?; } + Ok(()) + } + fn update_cursor(&mut self) -> io::Result<()> { + if let Some(pos) = self.curr_buffer.cursor() { + let size = self.curr_buffer.size(); + let x_in_bounds = 0 <= pos.x && pos.x < size.width as i32; + let y_in_bounds = 0 <= pos.y && pos.y < size.height as i32; + if x_in_bounds && y_in_bounds { + self.out + .queue(Show)? + .queue(MoveTo(pos.x as u16, pos.y as u16))?; + return Ok(()); + } + } + + self.out.queue(Hide)?; Ok(()) } }