diff --git a/src/attr.rs b/src/attr.rs index 1bf4aa4..d91cf7b 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -36,15 +36,6 @@ impl Default for Attr { } impl Attr { - /// Convert attributes to ANSI escape codes - /// - /// Returns a string containing the ANSI escape codes for the active attributes. - pub fn to_ansi(&self) -> String { - let mut buf = String::with_capacity(24); - self.write_ansi(&mut buf); - buf - } - /// Write ANSI escape codes directly into an existing buffer, avoiding allocation. pub fn write_ansi(&self, buf: &mut String) { if self.is_empty() { @@ -92,16 +83,4 @@ mod tests { let attr = Attr::default(); assert_eq!(attr, Attr::NORMAL); } - - #[test] - fn test_attr_to_ansi() { - let attr = Attr::BOLD | Attr::UNDERLINE; - assert_eq!(attr.to_ansi(), "\x1B[1;4m"); - - let attr = Attr::empty(); - assert_eq!(attr.to_ansi(), "\x1B[0m"); - - let attr = Attr::all(); - assert_eq!(attr.to_ansi(), "\x1B[0;1;2;3;4;5;6;7;8;9;10m"); - } } diff --git a/src/color.rs b/src/color.rs index b750cf1..6500761 100644 --- a/src/color.rs +++ b/src/color.rs @@ -16,15 +16,6 @@ pub enum Color { } impl Color { - /// Convert the color to an ANSI escape code. - /// - /// Returns an ANSI escape code string for the color. - pub fn to_ansi(&self, fg: bool) -> String { - let mut buf = String::with_capacity(20); - self.write_ansi(fg, &mut buf); - buf - } - /// Write ANSI escape code directly into an existing buffer, avoiding allocation. pub fn write_ansi(&self, fg: bool, buf: &mut String) { use std::fmt::Write; @@ -77,14 +68,4 @@ mod tests { let color = Color::default(); assert_eq!(color, Color::None); } - - #[test] - fn test_color_to_ansi() { - assert!(Color::Black.to_ansi(true).contains("30m")); - assert!(Color::Red.to_ansi(false).contains("41m")); - assert!(Color::RGB(255, 0, 0).to_ansi(true).contains("38;2;255;0;0")); - assert!(Color::HSV(0, 255, 255) - .to_ansi(true) - .contains("38;2;255;0;0")); - } } diff --git a/src/framebuffer.rs b/src/framebuffer.rs index b183a2e..42b34c7 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -9,20 +9,20 @@ const CHUNK_SIZE: usize = 1024; #[derive(Clone, Copy, PartialEq, Debug)] struct Cell { /// The character displayed in the cell. - pub ch: char, + ch: char, /// Text attributes (bold, italic, underline, etc.) - pub attrs: Attr, + attrs: Attr, /// Foreground color as RGB values (0-255 each) - pub fg: Color, + fg: Color, /// Background color as RGB values (0-255 each) - pub bg: Color, + bg: Color, } impl Cell { /// Create a new cell with default values. /// /// Returns a `Cell` instance with default attributes and colors. - pub fn new() -> Self { + fn new() -> Self { Self { ch: ' ', attrs: Attr::default(), @@ -52,7 +52,7 @@ pub struct Framebuffer { pub width: usize, /// The height of the framebuffer. pub height: usize, - buffer: Vec, + buffer: Box<[Cell]>, } impl Framebuffer { @@ -63,7 +63,7 @@ impl Framebuffer { /// /// Returns a new `Framebuffer` instance. pub fn new(width: usize, height: usize) -> Self { - let buffer = vec![Cell::default(); width * height]; + let buffer = vec![Cell::default(); width * height].into_boxed_slice(); Self { width, height, diff --git a/src/lib.rs b/src/lib.rs index d84cca7..5cb9745 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,10 +18,8 @@ The library is organized into several core modules: - [`framebuffer`] - Character grid for efficient rendering - [`window`] - High-level windowing abstraction with thread management - [`input`] - Non-blocking keyboard and mouse input handling -- [`term`] - Terminal colors, attributes, and ANSI escape sequences - [`attr`] - Text attributes and styling - [`color`] - Color manipulation and conversion utilities -- [`render`] - Rendering utilities and drawing primitives ## Performance @@ -43,22 +41,22 @@ pub mod framebuffer; /// A module for handling user input. #[cfg(target_os = "linux")] pub mod input; -/// A module for a rendering context. -#[cfg(target_os = "linux")] -pub mod render; -/// A module for handling terminal colors and attributes. -#[cfg(target_os = "linux")] -pub mod term; /// A module for handling windowing. #[cfg(target_os = "linux")] pub mod window; -mod macros; +/// A module for a rendering context. +#[cfg(target_os = "linux")] +pub(crate) mod render; +/// A module for handling terminal colors and attributes. +#[cfg(target_os = "linux")] +pub(crate) mod term; pub use attr::*; pub use color::*; pub use framebuffer::*; pub use input::*; -pub use render::*; -pub use term::*; pub use window::*; + +pub(crate) use render::*; +pub(crate) use term::*; diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index ecda57a..0000000 --- a/src/macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -/// Create a CSI (Control Sequence Introducer) escape sequence -#[macro_export] -#[doc(hidden)] -macro_rules! csi { - ($x:expr) => { - String::from("\x1B[") + $x - }; -} - -#[cfg(test)] -mod tests { - #[test] - fn test_csi_macro() { - assert_eq!(csi!("?25h"), "\x1B[?25h"); - } -} diff --git a/src/render.rs b/src/render.rs index f8837b4..9559ca2 100644 --- a/src/render.rs +++ b/src/render.rs @@ -9,7 +9,7 @@ use std::time; use crate::Framebuffer; /// Represents a render thread for rendering frames. -pub struct RenderThread { +pub(crate) struct RenderThread { /// The thread handle for the render thread. handle: Option>, /// The stop signal sender for the render thread. @@ -26,7 +26,7 @@ impl RenderThread { /// * `rendering_rate` - The rate at which to render frames. /// /// Returns `RenderThread` instance. - pub fn new( + pub(crate) fn new( front_fb: Arc>, back_fb: Arc>, rendering_rate: time::Duration, @@ -64,9 +64,7 @@ impl RenderThread { } } Err(TryLockError::WouldBlock) => { - // back_fb is locked by draw(); retry immediately without - // resetting the frame timer so the next iteration does not - // sleep a full rendering_rate before retrying. + thread::yield_now(); // Yield to other threads if the back framebuffer is currently locked continue; } Err(_) => { @@ -98,14 +96,14 @@ impl RenderThread { /// Try to receive the current FPS /// /// Returns the current FPS if available, or an error if not. - pub fn try_recv_fps(&self) -> Result { + pub(crate) fn try_recv_fps(&self) -> Result { self.fps_rx.try_recv() } /// Stop the render thread /// /// Returns `Ok(())` if the thread was stopped successfully, or an error if it failed. - pub fn stop(&mut self) -> Result<(), Box> { + pub(crate) fn stop(&mut self) -> Result<(), Box> { if let Some(tx) = self.stop_signal.take() { tx.send(())?; // Send stop signal } diff --git a/src/term.rs b/src/term.rs index 737bb7e..7648b22 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,4 +1,3 @@ -use crate::csi; use nix::libc; use nix::sys::termios::{self, ControlFlags, InputFlags, LocalFlags, OutputFlags, SetArg, Termios}; use std::os::unix::io::{BorrowedFd, RawFd}; @@ -11,8 +10,6 @@ use std::{ pub enum Cmd { ShowCursor, HideCursor, - MoveCursor(usize, usize), - MoveCursorToHome, ClearScreen, EnableAlternativeScreen, DisableAlternativeScreen, @@ -23,7 +20,7 @@ pub enum Cmd { } /// Represents a terminal. -pub struct Terminal { +pub(crate) struct Terminal { /// The file descriptor for the terminal. fd: RawFd, /// The original terminal settings. @@ -34,7 +31,7 @@ impl Terminal { /// Create a new terminal instance. /// /// Returns a new `Terminal` instance. - pub fn new() -> Self { + pub(crate) fn new() -> Self { let fd: RawFd = std::io::stdout().as_raw_fd(); Self { fd, original: None } } @@ -52,7 +49,7 @@ impl Terminal { /// Enable raw mode /// /// Returns a `Terminal` instance with raw mode enabled. - pub fn enable_raw_mode(&mut self) -> nix::Result<()> { + pub(crate) fn enable_raw_mode(&mut self) -> nix::Result<()> { let borrowed_fd = self.get_borrowed_fd()?; let original = termios::tcgetattr(borrowed_fd)?; let mut raw = original.clone(); @@ -90,7 +87,7 @@ impl Terminal { /// Disable raw mode /// /// Returns `Ok(())` if successful, or an error if it fails. - pub fn disable_raw_mode(&mut self) -> nix::Result<()> { + pub(crate) fn disable_raw_mode(&mut self) -> nix::Result<()> { if let Some(original) = &self.original { let borrowed_fd = self.get_borrowed_fd()?; termios::tcsetattr(borrowed_fd, SetArg::TCSANOW, original)?; @@ -102,7 +99,7 @@ impl Terminal { /// Set the terminal to non-blocking mode /// /// Returns `Ok(())` if successful, or an error if it fails. - pub fn set_nonblocking(&self) -> nix::Result<()> { + pub(crate) fn set_nonblocking(&self) -> nix::Result<()> { unsafe { let flags = libc::fcntl(self.fd, libc::F_GETFL); if flags == -1 { @@ -121,26 +118,25 @@ impl Terminal { /// * `cmd` - The command to execute. /// /// Returns `Ok(())` if successful, or an error if it fails. - pub fn exec(cmd: Cmd) -> io::Result<()> { - let ansi = match cmd { - Cmd::ShowCursor => csi!("?25h"), - Cmd::HideCursor => csi!("?25l"), - Cmd::MoveCursor(x, y) => csi!(&format!("{y};{x}H")), - Cmd::MoveCursorToHome => csi!("H"), - Cmd::ClearScreen => csi!("2J"), - Cmd::EnableAlternativeScreen => csi!("?1049h"), - Cmd::DisableAlternativeScreen => csi!("?1049l"), - Cmd::EnableMouseReporting => csi!("?1000h"), - Cmd::DisableMouseReporting => csi!("?1000l"), - Cmd::EnableSgrCoords => csi!("?1006h"), - Cmd::DisableSgrCoords => csi!("?1006l"), - }; - print!("{ansi}"); - io::stdout().flush() + pub(crate) fn exec(cmd: Cmd) -> io::Result<()> { + let stdout = io::stdout(); + let mut lock = stdout.lock(); + match cmd { + Cmd::ShowCursor => lock.write_all(b"\x1B[?25h")?, + Cmd::HideCursor => lock.write_all(b"\x1B[?25l")?, + Cmd::ClearScreen => lock.write_all(b"\x1B[2J")?, + Cmd::EnableAlternativeScreen => lock.write_all(b"\x1B[?1049h")?, + Cmd::DisableAlternativeScreen => lock.write_all(b"\x1B[?1049l")?, + Cmd::EnableMouseReporting => lock.write_all(b"\x1B[?1000h")?, + Cmd::DisableMouseReporting => lock.write_all(b"\x1B[?1000l")?, + Cmd::EnableSgrCoords => lock.write_all(b"\x1B[?1006h")?, + Cmd::DisableSgrCoords => lock.write_all(b"\x1B[?1006l")?, + } + lock.flush() } /// Get the terminal size - pub fn get_size(&self) -> io::Result<(usize, usize)> { + pub(crate) fn get_size(&self) -> io::Result<(usize, usize)> { let mut ws = libc::winsize { ws_row: 0, ws_col: 0, diff --git a/src/window.rs b/src/window.rs index 30101f4..f8d9dc9 100644 --- a/src/window.rs +++ b/src/window.rs @@ -173,7 +173,7 @@ impl Drop for Window { } /// A listener for window size changes -pub struct WindowSizeListener { +struct WindowSizeListener { /// The thread handle for the listener handle: Option>, /// The stop signal for the listener @@ -188,7 +188,7 @@ impl WindowSizeListener { /// * `rate`: The rate at which to check for window size changes /// /// Returns `WindowSizeListener` instance. - pub fn new(terminal: Terminal, rate: Duration) -> Self { + fn new(terminal: Terminal, rate: Duration) -> Self { #[allow(clippy::type_complexity)] let (size_tx, size_rx): (SyncSender<(usize, usize)>, Receiver<(usize, usize)>) = mpsc::sync_channel(1); @@ -227,14 +227,14 @@ impl WindowSizeListener { /// Try to receive a window size change event /// /// Returns the new window size if available, or an error if not. - pub fn try_recv(&self) -> Result<(usize, usize), mpsc::TryRecvError> { + fn try_recv(&self) -> Result<(usize, usize), mpsc::TryRecvError> { self.size_rx.try_recv() } /// Stop the window size listener /// /// Returns `Ok(())` if the listener was stopped successfully, or an error if it failed. - pub fn stop(&mut self) -> Result<(), Box> { + fn stop(&mut self) -> Result<(), Box> { if let Some(tx) = self.stop_signal.take() { tx.send(())?; // Send stop signal }