#![deny(unsafe_code)]
#![deny(
rustdoc::broken_intra_doc_links,
rustdoc::bare_urls,
rustdoc::private_intra_doc_links
)]
#![deny(clippy::perf, clippy::complexity, clippy::cargo)]
#![allow(clippy::new_without_default)]
#![allow(clippy::multiple_crate_versions)]
pub mod component;
pub mod components;
pub mod input;
pub mod post_office;
pub mod render;
pub mod test;
pub mod ui;
pub mod util;
pub use component::Component;
pub use input::Input;
pub use render::Renderer;
pub use ui::MUI;
pub use makeup_ansi::prelude::*;
pub type Coordinate = u64;
pub type Coordinates = (Coordinate, Coordinate);
pub type Dimension = u64;
pub type Dimensions = (Dimension, Dimension);
pub type RelativeCoordinate = i64;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, strum::Display)]
pub enum DrawCommand {
TextUnderCursor(String),
CharUnderCursor(char),
EraseCurrentLine(LineEraseMode),
MoveCursorAbsolute { x: Coordinate, y: Coordinate },
MoveCursorRelative {
x: RelativeCoordinate,
y: RelativeCoordinate,
},
HideCursor,
ShowCursor,
Style(DrawStyle),
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, strum::Display)]
pub enum DrawStyle {
Coloured {
foreground: Option<u32>,
background: Option<u32>,
},
Foreground(u32),
Background(u32),
Coloured8Bit {
foreground: Option<Colour>,
background: Option<Colour>,
},
Foreground8Bit(Colour),
Background8Bit(Colour),
Default,
Bold,
Italic,
Underline,
}
#[cfg(test)]
mod tests {
use crate::component::{DrawCommandBatch, Key, MakeupUpdate, RenderContext};
use crate::input::TerminalInput;
use crate::render::MemoryRenderer;
use crate::{Component, Dimensions, DrawCommand, MUI};
use async_trait::async_trait;
use eyre::Result;
#[derive(Debug)]
struct BasicComponent {
#[allow(dead_code)]
state: (),
children: Vec<Box<dyn Component<Message = ()>>>,
key: Key,
}
#[async_trait]
impl Component for BasicComponent {
type Message = ();
fn children(&self) -> Option<Vec<&Box<dyn Component<Message = Self::Message>>>> {
Some(self.children.iter().collect())
}
fn children_mut(
&mut self,
) -> Option<Vec<&mut Box<dyn Component<Message = Self::Message>>>> {
Some(self.children.iter_mut().collect())
}
async fn update(&mut self, _ctx: &mut MakeupUpdate<Self>) -> Result<()> {
Ok(())
}
async fn render(&self, _ctx: &RenderContext) -> Result<DrawCommandBatch> {
Ok((
self.key,
vec![DrawCommand::TextUnderCursor("henol world".into())],
))
}
fn key(&self) -> Key {
self.key
}
fn dimensions(&self) -> Result<Option<Dimensions>> {
Ok(Some((11, 1)))
}
}
#[tokio::test]
async fn test_it_works() -> Result<()> {
let mut root = BasicComponent {
state: (),
children: vec![],
key: crate::component::generate_key(),
};
let renderer = MemoryRenderer::new(128, 128);
let input = TerminalInput::new().await?;
let ui = MUI::new(&mut root, Box::new(renderer), input)?;
ui.render_once().await?;
let expected = "henol world".to_string();
ui.render_once().await?;
ui.move_cursor(0, 0).await?;
assert_eq!(expected, ui.read_at_cursor(expected.len() as u64).await?);
Ok(())
}
}