From 6abfc6aa54f6e5f21ab7baa2be03407e14c6b5ad Mon Sep 17 00:00:00 2001 From: Joe Bellus Date: Thu, 18 Apr 2024 15:07:21 -0400 Subject: [PATCH] Aded doc tests throughout --- src/app.rs | 18 +++++++- src/geometry.rs | 57 ++++++++++++++++++++++- src/runes.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++---- src/view.rs | 11 +++++ 4 files changed, 194 insertions(+), 11 deletions(-) diff --git a/src/app.rs b/src/app.rs index 68b9d20..f9c85a7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -34,7 +34,21 @@ impl Renderer { } /// The app is the core container for the application logic, resources, -/// state, and run loop. +/// state, and run loop. +/// +/// Setting up a basic application: +/// +/// ``` +/// use arkham::prelude::*; +/// +/// fn main() { +/// App::new(root_view).run(); +/// } +/// +/// fn root_view(ctx: &mut ViewContext) { +/// ctx.insert((2,2), "Hello World"); +/// } +/// ``` pub struct App where F: Callable, @@ -147,12 +161,14 @@ where pub fn run(&mut self) -> anyhow::Result<()> { self.container.borrow_mut().bind(Res::new(Terminal)); self.container.borrow_mut().bind(Res::new(Keyboard::new())); + let _ = ctrlc::set_handler(|| { let mut out = std::io::stdout(); let _ = terminal::disable_raw_mode(); let _ = execute!(out, terminal::LeaveAlternateScreen, cursor::Show); std::process::exit(0); }); + let mut out = std::io::stdout(); execute!(out, terminal::EnterAlternateScreen, cursor::Hide)?; terminal::enable_raw_mode()?; diff --git a/src/geometry.rs b/src/geometry.rs index bfc9ee9..d569b10 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -1,6 +1,9 @@ use std::ops::{Add, AddAssign, Sub}; /// Pos represents a coordinate position within the termianl screen. +/// +/// *NOTE* Most functions accept a value that can be converted into a Pos. +/// For these a simple tuple of coordinates is sufficient. #[derive(Debug, Clone, Copy)] pub struct Pos { pub x: usize, @@ -8,6 +11,16 @@ pub struct Pos { } impl Pos { + /// Generate a new Pos from a given set of coordinates. + /// + /// Example: + /// + /// ``` + /// use arkham::prelude::*; + /// let pos = Pos::new(3,1); + /// assert_eq!(pos.x, 3); + /// assert_eq!(pos.y, 1); + /// ``` pub fn new(x: usize, y: usize) -> Self { Self { x, y } } @@ -45,7 +58,27 @@ impl AddAssign for Pos { } } -// An area that can be operated on. +/// An area that can be operated on. +/// +/// ``` +/// use arkham::prelude::*; +/// +/// let s = Size::new(3,3); +/// assert_eq!(s.width, 3); +/// assert_eq!(s.height, 3); +/// ``` +/// +/// Sizes can be added and subtracted to mutate them easily: +/// +/// ``` +/// use arkham::prelude::*; +/// +/// let s1 = Size::new(3,3); +/// let s2 = Size::new(0,1); +/// let s = s1 - s2; +/// assert_eq!(s.width, 3); +/// assert_eq!(s.height, 2); +/// ``` #[derive(Debug, Clone, Copy)] pub struct Size { pub width: usize, @@ -172,11 +205,33 @@ impl Rect { } } + /// Move the Rect's origin, without chaging its size. + /// + /// Example: + /// + /// ``` + /// use arkham::prelude::*; + /// + /// let mut rect = Rect::new((0,0), (15,5)); + /// rect.translate(5,0); + /// assert_eq!(rect.pos.x, 5); + /// ``` pub fn translate(&mut self, x: i32, y: i32) { self.pos.x = (self.pos.x as i32 + x).max(0) as usize; self.pos.y = (self.pos.y as i32 + y).max(0) as usize; } + /// Change the Rect's size without altering its position. + /// + /// Example: + /// + /// ``` + /// use arkham::prelude::*; + /// + /// let mut rect = Rect::new((0,0), (15,5)); + /// rect.expand(5,0); + /// assert_eq!(rect.size.width, 20); + /// ``` pub fn expand(&mut self, width: i32, height: i32) { self.size.width = (self.size.width as i32 + width).max(1) as usize; self.size.height = (self.size.height as i32 + height).max(1) as usize; diff --git a/src/runes.rs b/src/runes.rs index 0d6408c..c187c9b 100644 --- a/src/runes.rs +++ b/src/runes.rs @@ -52,29 +52,71 @@ impl From for Rune { } impl Rune { + /// Create a new empty Rune. This can be used with the settings functions as a _builder_ pattern + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let rune:Rune = Rune::new().bg(Color::Blue).fg(Color::White).bold(); + /// ``` pub fn new() -> Self { Self::default() } + + /// Set the content of the rune. The rune's content is a single character. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let rune = Rune::new().content('A'); + /// assert_eq!(rune.content, Some('A')); + /// ``` pub fn content(mut self, content: char) -> Self { self.content = Some(content); self } + + /// Set the background color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let rune = Rune::new().bg(Color::Green); + /// assert_eq!(rune.bg, Some(Color::Green)); + /// ``` pub fn bg(mut self, bg: Color) -> Self { self.bg = Some(bg); self } + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let rune = Rune::new().fg(Color::Green); + /// assert_eq!(rune.fg, Some(Color::Green)); + /// ``` pub fn fg(mut self, fg: Color) -> Self { self.fg = Some(fg); self } + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let rune = Rune::new().fg(Color::Green); + /// assert_eq!(rune.fg, Some(Color::Green)); + /// ``` pub fn bold(mut self) -> Self { self.bold = true; self } - pub fn render(self, out: &mut W) -> anyhow::Result<()> + /// Renders a Print command into the terminal's output queue + pub(crate) fn render(self, out: &mut W) -> anyhow::Result<()> where W: std::io::Write, { @@ -95,10 +137,17 @@ impl Rune { } } -/// Runes represetns a series of runes. This is generally used to convert +/// Runes represents a series of runes. This is generally used to convert /// strings into Runes and apply styling information to them. +/// +/// Building runes from a string: +/// +/// ``` +/// use arkham::prelude::*; +/// let runes = "This is a test string".to_runes().fg(Color::White); +/// ``` #[derive(Clone, Debug, Default)] -pub struct Runes(Vec); +pub struct Runes(pub(crate) Vec); impl std::ops::Deref for Runes { type Target = Vec; @@ -127,26 +176,70 @@ impl From for Runes { } impl Runes { + /// Create a new runes collection from a vector of Rune. pub fn new(runes: Vec) -> Self { Self(runes) } - pub fn fg(self, color: Color) -> Self { - self.set_fg(Some(color)) - } - - pub fn set_fg(mut self, color: Option) -> Self { + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let runes = "blue".to_runes().fg(Color::Blue); + /// assert!(runes.iter().all(|r| r.fg == Some(Color::Blue))) + /// ``` + pub fn fg(mut self, color: Color) -> Self { for r in self.0.iter_mut() { - r.fg = color; + r.fg = Some(color); } self } + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let mut runes = "on blue".to_runes().bg(Color::Blue); + /// let runes = runes.clear_fg(); + /// assert!(runes.iter().all(|r| r.fg == None)) + pub fn clear_fg(mut self) -> Self { + for r in self.0.iter_mut() { + r.fg = None; + } + self + } + + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let runes = "on blue".to_runes().bg(Color::Blue); + /// assert!(runes.iter().all(|r| r.bg == Some(Color::Blue))) + /// ``` pub fn bg(mut self, color: Color) -> Self { for r in self.0.iter_mut() { r.bg = Some(color); } self } + + /// Set the text color of the rune. + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let mut runes = "on blue".to_runes().bg(Color::Blue); + /// let runes = runes.clear_bg(); + /// assert!(runes.iter().all(|r| r.bg == None)) + pub fn clear_bg(mut self) -> Self { + for r in self.0.iter_mut() { + r.bg = None; + } + self + } + pub fn bold(mut self) -> Self { for r in self.0.iter_mut() { r.bold = true; @@ -154,6 +247,14 @@ impl Runes { self } + /// Append runes or a string displayable object to the Runes + /// + /// Example: + /// ``` + /// use arkham::prelude::*; + /// let mut runes = "This is a test string. ".to_runes(); + /// runes.add("This is a colored string".to_runes().fg(Color::Blue)); + /// runes.add("This is another basic string"); pub fn add(&mut self, runes: R) where R: Into, diff --git a/src/view.rs b/src/view.rs index 6aac287..2969966 100644 --- a/src/view.rs +++ b/src/view.rs @@ -148,6 +148,8 @@ impl View { #[cfg(test)] mod tests { + use crossterm::style::Color; + use crate::{geometry::Rect, runes::Rune}; use super::View; @@ -242,4 +244,13 @@ mod tests { assert_eq!(view.0[2][1].content, Some('X')); assert_eq!(view.0[2][2].content, Some('X')); } + + #[test] + pub fn test_color_fill() { + let mut view = View::new((3, 3)); + view.fill_all(Color::Red); + assert!(view + .iter() + .all(|rs| rs.iter().all(|r| r.bg == Some(Color::Red)))); + } }