From 9618ac7957ca17f53c8aa4b693c39a9e4a841118 Mon Sep 17 00:00:00 2001 From: Xyverle Date: Sat, 15 Mar 2025 20:36:10 -0400 Subject: [PATCH] make clippy happy, add docs, add asserts, etc. --- src/ansi.rs | 35 ++++++++++++++++++++---- src/input.rs | 6 +++++ src/os.rs | 34 ++++++----------------- src/unix.rs | 39 +++++++++++++++++++++++++++ src/windows.rs | 73 ++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 139 insertions(+), 48 deletions(-) diff --git a/src/ansi.rs b/src/ansi.rs index b26500c..893ae4e 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -2,9 +2,10 @@ //! //! These should work on *most* terminals (i.e. Xterm compatible terminals) //! -//! For these to work on Windows you need to run the enable_ansi function in the os module +//! For these to work on Windows you need to run the `enable_ansi` function in the os module /// Sets the terminal to an arbitrary 12-bit/truecolor color +#[must_use] pub fn rgb_color_code(red: u8, green: u8, blue: u8) -> String { format!("\x1b[38;2;{red};{green};{blue}m") } @@ -13,10 +14,11 @@ pub fn rgb_color_code(red: u8, green: u8, blue: u8) -> String { /// /// The title must be only in ASCII characters or **weird** things will happen /// -/// Panics: +/// # Panics /// /// When the title is more than 255 characters -pub fn set_window_title(title: String) -> String { +#[must_use] +pub fn set_window_title(title: &str) -> String { assert!( title.len() <= 255, "Title length longer than maximum of 255" @@ -25,21 +27,25 @@ pub fn set_window_title(title: String) -> String { } /// Moves the cursor up {num} characters +#[must_use] pub fn move_cursor_up(num: u16) -> String { format!("\x1b[{num}A") } /// Moves the cursor down {num} characters +#[must_use] pub fn move_cursor_down(num: u16) -> String { format!("\x1b[{num}B") } /// Moves the cursor right {num} characters +#[must_use] pub fn move_cursor_right(num: u16) -> String { format!("\x1b[{num}C") } /// Moves the cursor left {num} characters +#[must_use] pub fn move_cursor_left(num: u16) -> String { format!("\x1b[{num}A") } @@ -47,21 +53,40 @@ pub fn move_cursor_left(num: u16) -> String { /// Moves the cursor to {row} /// /// Origin is 1, 1 -pub fn move_cursor_to_row(row: u16) -> String { - format!("\x1b[{row}d") +#[must_use] +pub fn move_cursor_to_row(line: u16) -> String { + debug_assert!( + line != 0, + "Tried to go to line 0, when position is (1, 1)-based" + ); + format!("\x1b[{line}d") } /// Moves the cursor to {column} /// /// Origin is 1, 1 +#[must_use] pub fn move_cursor_to_column(column: u16) -> String { + debug_assert!( + column != 0, + "Tried to go to column 0, when position is (1, 1)-based" + ); format!("\x1b[{column}G") } /// Moves the cursor to Position {x}, {y} /// /// Origin is 1, 1 +#[must_use] pub fn move_cursor_to_position(column: u16, line: u16) -> String { + debug_assert!( + line != 0, + "Tried to go to line 0, when position is (1, 1)-based" + ); + debug_assert!( + column != 0, + "Tried to go to column 0, when position is (1, 1)-based" + ); format!("\x1b[{line};{column}H") } diff --git a/src/input.rs b/src/input.rs index ea6b78c..39b9ada 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,3 +1,7 @@ +//! Various input functions, structs, etc. +//! +//! Very incomplete currently + use std::io::{self, Read}; use std::sync::mpsc; use std::thread; @@ -6,6 +10,8 @@ use std::thread; /// /// This acts as any other stream, with the exception that reading from it won't block. Instead, /// the buffer will only be partially updated based on how much the internal buffer holds. +/// +/// Taken from the Termion crate pub struct AsyncReader { recv: mpsc::Receiver>, } diff --git a/src/os.rs b/src/os.rs index b25579f..fd3ff13 100644 --- a/src/os.rs +++ b/src/os.rs @@ -1,36 +1,18 @@ +//! Collection of functions that help control the terminal +//! +//! These are built to work at least on these platforms: +//! Windows, Linux, and Mac, but are likely to work on more + #[cfg(unix)] #[path = "unix.rs"] mod unix; #[cfg(unix)] -use unix as os; +pub use unix::*; #[cfg(windows)] #[path = "windows.rs"] -mod windows; +mod unix; #[cfg(windows)] -use windows as os; - -/// Checks if stdout is a terminal -pub use os::is_terminal; - -/// Enables ANSI support on Windows terminals -/// -/// ANSI is on by default on *nix machines but still exists on them for simpler usage -pub use os::enable_ansi; - -/// Gets the size of the terminal -/// -/// Returns in (width, height) format -pub use os::get_terminal_size; - -/// Enables raw mode -/// -/// Disables input echoing, line feeding, etc. -pub use os::enable_raw_mode; - -/// Disables raw mode -/// -/// Enables input echoing, line feeding, etc. -pub use os::disable_raw_mode; +pub use windows::*; diff --git a/src/unix.rs b/src/unix.rs index 91a86d2..7730f24 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -46,17 +46,38 @@ struct Termios { cc: [u8; NCCS], } +/// Checks if stdout is a terminal #[must_use] pub fn is_terminal() -> bool { unsafe { isatty(1) != 0 } } +/// Enables ANSI support on Windows terminals +/// +/// ANSI is on by default on *nix machines but still exists on them for simpler usage +/// +/// # Errors +/// +/// Never on *nix +/// +/// If There is no stdout, +/// if stdout isn't a TTY, or +/// if it cannot change terminal properties on Windows pub fn enable_ansi() -> io::Result<()> { // ANSI is on by default on unix platforms // This is here for compatibility with the windows version of this API Ok(()) } +/// Gets the size of the terminal +/// +/// Returns in (width, height) format +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to retrieve the terminal size pub fn get_terminal_size() -> io::Result<(u16, u16)> { let mut winsize = unsafe { std::mem::zeroed::() }; let ioctl_result = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, (&raw mut winsize).cast::()) }; @@ -68,6 +89,15 @@ pub fn get_terminal_size() -> io::Result<(u16, u16)> { } } +/// Enables raw mode +/// +/// Disables input echoing, line feeding, etc. +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to get or set terminal settings pub fn enable_raw_mode() -> io::Result<()> { let mut termios = unsafe { std::mem::zeroed::() }; get_attributes(STDIN_FILENO, &mut termios)?; @@ -76,6 +106,15 @@ pub fn enable_raw_mode() -> io::Result<()> { Ok(()) } +/// Disables raw mode +/// +/// Enables input echoing, line feeding, etc. +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to get or set terminal settings pub fn disable_raw_mode() -> io::Result<()> { let mut termios = unsafe { std::mem::zeroed::() }; get_attributes(STDIN_FILENO, &mut termios)?; diff --git a/src/windows.rs b/src/windows.rs index 82bb960..811fdeb 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,14 +2,6 @@ use std::io; -const STD_INPUT_HANDLE: u32 = 0xFFFF_FFF6; -const STD_OUTPUT_HANDLE: u32 = 0xFFFF_FFF5; -const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 4; -const ENABLE_ECHO_INPUT: u32 = 4; -const ENABLE_LINE_INPUT: u32 = 2; -const ENABLE_PROCESSED_INPUT: u32 = 1; -const INVALID_HANDLE_VALUE: usize = usize::MAX - 1; - unsafe extern "system" { fn GetStdHandle(nStdHandle: u32) -> usize; fn GetConsoleMode(hConsoleHandle: usize, dwMode: *mut u32) -> u32; @@ -20,6 +12,14 @@ unsafe extern "system" { ) -> u32; } +const STD_INPUT_HANDLE: u32 = 0xFFFF_FFF6; +const STD_OUTPUT_HANDLE: u32 = 0xFFFF_FFF5; +const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 4; +const ENABLE_ECHO_INPUT: u32 = 4; +const ENABLE_LINE_INPUT: u32 = 2; +const ENABLE_PROCESSED_INPUT: u32 = 1; +const INVALID_HANDLE_VALUE: usize = usize::MAX - 1; + #[repr(C)] #[derive(Default)] struct ConsoleScreenBufferInfo { @@ -36,6 +36,7 @@ struct ConsoleScreenBufferInfo { dwMaximumWindowSizeY: u16, } +/// Checks if stdout is a terminal #[must_use] pub fn is_terminal() -> bool { let handle = get_std_handle(STD_OUTPUT_HANDLE); @@ -48,6 +49,35 @@ pub fn is_terminal() -> bool { } } +/// Enables ANSI support on Windows terminals +/// +/// ANSI is on by default on *nix machines but still exists on them for simpler usage +/// +/// # Errors +/// +/// Never on *nix +/// +/// On Windows, if There is no stdout, +/// if stdout isn't a TTY, or +/// if it cannot change terminal properties +pub fn enable_ansi() -> io::Result<()> { + let handle = get_std_handle(STD_OUTPUT_HANDLE)?; + let mut dwMode = 0; + get_console_mode(handle, &raw mut dwMode)?; + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + set_console_mode(handle, &raw mut dwMode)?; + Ok(()) +} + +/// Gets the size of the terminal +/// +/// Returns in (width, height) format +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to retrieve the terminal size pub fn get_terminal_size() -> io::Result<(u16, u16)> { let handle = get_std_handle(STD_OUTPUT_HANDLE)?; let mut csbi = ConsoleScreenBufferInfo::default(); @@ -59,15 +89,15 @@ pub fn get_terminal_size() -> io::Result<(u16, u16)> { Err(io::Error::last_os_error()) } -pub fn enable_ansi() -> io::Result<()> { - let handle = get_std_handle(STD_OUTPUT_HANDLE)?; - let mut dwMode = 0; - get_console_mode(handle, &raw mut dwMode)?; - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - set_console_mode(handle, &raw mut dwMode)?; - Ok(()) -} - +/// Enables raw mode +/// +/// Disables input echoing, line feeding, etc. +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to get or set terminal settings pub fn enable_raw_mode() -> io::Result<()> { let handle = get_std_handle(STD_INPUT_HANDLE)?; let mut dwMode = 0; @@ -77,6 +107,15 @@ pub fn enable_raw_mode() -> io::Result<()> { Ok(()) } +/// Disables raw mode +/// +/// Enables input echoing, line feeding, etc. +/// +/// # Errors +/// +/// If there is no stdout, +/// if stdout isn't a TTY, or +/// if it fails to get or set terminal settings pub fn disable_raw_mode() -> io::Result<()> { let handle = get_std_handle(STD_INPUT_HANDLE)?; let mut dwMode = 0;