tooey/
lib.rs

1#![no_std]
2#![warn(missing_docs)]
3//! # Tooey
4//!
5//! ## The barebones no-std TUI library.
6//!
7//! For a quick example that you can locally test on your machine, add `tooey` to your crate
8//! with the `std` feature (the standard library is not included by default).
9//!
10//!
11//! ```toml
12//! tooey = { version = "0.7", features = ["std"] }
13//! ```
14//!
15//! For embedded users, you will have to implement displaying Tooey's characters yourself.
16//!
17//! <sub>*Including the stdlib does not add additional
18//! features, but it allows Tooey to implement its traits for stdlib types.</sub>
19//!
20//! ```
21//! use tooey::types::Terminal;
22//! use tooey::types::ColourChar;
23//!
24//! use tooey::objects::ColourPrompt;
25//!
26//! use std::io::stdout;
27//!
28//! let mut terminal: Terminal<ColourChar> = Terminal::new(30, 20);
29//!
30//! terminal.push_object(ColourPrompt::new("Hello world!"));
31//!
32//! terminal.frame();
33//!
34//! #[cfg(feature="std")]
35//! terminal.draw(stdout()).expect("Failed to draw the terminal :(");
36//! ```
37extern crate alloc;
38
39/// Tooey's premade objects, ready for use in your projects.
40#[cfg(feature = "objects")]
41pub mod objects;
42/// These are the types and traits provided by Tooey for users
43pub mod types;
44
45#[cfg(feature = "std")]
46/// This enables implementations for standard library components (like a TooeyDrawable impl for
47/// std::io::Stdout)
48pub mod std_features {
49    extern crate std;
50
51    use core::fmt::Display;
52
53    use std::io;
54    use std::io::Stdout;
55    use std::io::Write;
56
57    use crate::types::TerminalScreen;
58
59    use crate::types::Character;
60    use crate::types::TooeyDrawable;
61
62    impl<T: Character + Display> TooeyDrawable<T> for Stdout {
63        type Error = io::Error;
64
65        fn draw_terminal(&mut self, characters: &TerminalScreen<T>) -> Result<(), Self::Error> {
66            for row in characters.rows() {
67                for character in row {
68                    write!(self, "{character}")?;
69                }
70                writeln!(self)?;
71            }
72
73            Ok(())
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::{
81        objects::{Background, ColourPrompt},
82        types::{Colour, ColourChar, Terminal},
83    };
84
85    #[test]
86    fn prompt() {
87        let mut terminal: Terminal<ColourChar> = Terminal::new(128, 128);
88
89        let prompt = ColourPrompt::new("Hello world!").fg_rgb(255, 0, 0);
90
91        terminal.push_object(prompt);
92
93        terminal.frame();
94    }
95
96    #[test]
97    fn very_large_prompt() {
98        let mut terminal: Terminal<ColourChar> = Terminal::new(12, 12);
99
100        let prompt = ColourPrompt::new(
101            "Hello, world! I contain exceedingly long repeated
102        text because I am designed to make the terminal overflow
103        so that the prompt's ability to withstand these conditions can be tested.
104        I need to have over 144 characters in order to fulfill my purpose as a test!
105        That is why I am this long. I like being long. It is me. It is who I am. It is what I am.
106        I am the prompt. And this message... you should hopefully not see.",
107        )
108        .bg_rgb(0, 255, 0);
109
110        terminal.push_object(prompt);
111
112        terminal.frame();
113    }
114
115    #[test]
116    fn background_colour() {
117        let mut terminal: Terminal<ColourChar> = Terminal::new(12, 12);
118
119        let background = Background(Colour::Rgb(0, 0, 255));
120
121        terminal.push_object(background);
122
123        terminal.frame();
124
125        assert_eq!(terminal.characters[(0, 0)].bg_colour, Colour::Rgb(0, 0, 255), "We are ensuring that the Background object changes the background colour of items in the terminal.");
126    }
127
128    #[test]
129    fn multi_layer() {
130        let mut terminal: Terminal<ColourChar> = Terminal::new(12, 12);
131
132        let prompt = ColourPrompt::new(
133            "Hello, world! I contain exceedingly long repeated
134        text because I am designed to make the terminal overflow
135        so that the prompt's ability to withstand these conditions can be tested.
136        I need to have over 144 characters in order to fulfill my purpose as a test!
137        That is why I am this long. I like being long. It is me. It is who I am. It is what I am.
138        I am the prompt. And this message... you should hopefully not see.",
139        )
140        .bg_rgb(0, 255, 0);
141
142        let background = Background(Colour::Rgb(0, 0, 255));
143
144        terminal.push_object(background);
145        terminal.push_object(prompt);
146
147        terminal.frame();
148
149        assert_eq!(
150            terminal.characters[(0, 0)].bg_colour,
151            Colour::Rgb(0, 255, 0),
152            "We are ensuring that the prompt overwrites the Background object."
153        );
154    }
155}