Aded doc tests throughout

This commit is contained in:
Joe Bellus 2024-04-18 15:07:21 -04:00
parent 972ddb57ca
commit 6abfc6aa54
4 changed files with 194 additions and 11 deletions

View File

@ -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<F, Args>
where
F: Callable<Args>,
@ -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()?;

View File

@ -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<Pos> 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;

View File

@ -52,29 +52,71 @@ impl From<Color> 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<W>(self, out: &mut W) -> anyhow::Result<()>
/// Renders a Print command into the terminal's output queue
pub(crate) fn render<W>(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<Rune>);
pub struct Runes(pub(crate) Vec<Rune>);
impl std::ops::Deref for Runes {
type Target = Vec<Rune>;
@ -127,26 +176,70 @@ impl<T: ToString> From<T> for Runes {
}
impl Runes {
/// Create a new runes collection from a vector of Rune.
pub fn new(runes: Vec<Rune>) -> Self {
Self(runes)
}
pub fn fg(self, color: Color) -> Self {
self.set_fg(Some(color))
}
pub fn set_fg(mut self, color: Option<Color>) -> 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<R>(&mut self, runes: R)
where
R: Into<Runes>,

View File

@ -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))));
}
}