diff --git a/crates/anstyle-wincon/src/lib.rs b/crates/anstyle-wincon/src/lib.rs index f61b6dc1..670ae7f7 100644 --- a/crates/anstyle-wincon/src/lib.rs +++ b/crates/anstyle-wincon/src/lib.rs @@ -14,7 +14,7 @@ mod console; mod lockable; mod stream; #[cfg(windows)] -mod windows; +pub mod windows; pub use console::Console; pub use lockable::Lockable; diff --git a/crates/anstyle-wincon/src/stream.rs b/crates/anstyle-wincon/src/stream.rs index 13d56909..dd16c7ef 100644 --- a/crates/anstyle-wincon/src/stream.rs +++ b/crates/anstyle-wincon/src/stream.rs @@ -100,18 +100,15 @@ impl WinconStream for std::fs::File { #[cfg(windows)] mod wincon { - use std::os::windows::io::{AsHandle, AsRawHandle}; + use std::os::windows::io::AsHandle; pub(super) fn set_colors( stream: &mut S, fg: Option, bg: Option, ) -> std::io::Result<()> { - let handle = stream.as_handle(); - let handle = handle.as_raw_handle(); if let (Some(fg), Some(bg)) = (fg, bg) { - let attributes = crate::windows::set_colors(fg, bg); - crate::windows::set_console_text_attributes(handle, attributes) + crate::windows::set_colors(stream, fg, bg) } else { Ok(()) } @@ -120,11 +117,7 @@ mod wincon { pub(super) fn get_colors( stream: &S, ) -> std::io::Result<(Option, Option)> { - let handle = stream.as_handle(); - let handle = handle.as_raw_handle(); - let info = crate::windows::get_screen_buffer_info(handle)?; - let (fg, bg) = crate::windows::get_colors(&info); - Ok((Some(fg), Some(bg))) + crate::windows::get_colors(stream).map(|(fg, bg)| (Some(fg), Some(bg))) } } diff --git a/crates/anstyle-wincon/src/windows.rs b/crates/anstyle-wincon/src/windows.rs index d2b9bc80..188a8e54 100644 --- a/crates/anstyle-wincon/src/windows.rs +++ b/crates/anstyle-wincon/src/windows.rs @@ -1,147 +1,183 @@ -use windows_sys::Win32::System::Console::CONSOLE_CHARACTER_ATTRIBUTES; -use windows_sys::Win32::System::Console::CONSOLE_SCREEN_BUFFER_INFO; -use windows_sys::Win32::System::Console::FOREGROUND_BLUE; -use windows_sys::Win32::System::Console::FOREGROUND_GREEN; -use windows_sys::Win32::System::Console::FOREGROUND_INTENSITY; -use windows_sys::Win32::System::Console::FOREGROUND_RED; +use std::os::windows::io::AsHandle; +use std::os::windows::io::AsRawHandle; -use std::os::windows::io::RawHandle; +pub fn set_colors( + stream: &mut S, + fg: anstyle::AnsiColor, + bg: anstyle::AnsiColor, +) -> std::io::Result<()> { + let handle = stream.as_handle(); + let handle = handle.as_raw_handle(); + let attributes = inner::set_colors(fg, bg); + inner::set_console_text_attributes(handle, attributes) +} + +pub fn get_colors( + stream: &S, +) -> std::io::Result<(anstyle::AnsiColor, anstyle::AnsiColor)> { + let handle = stream.as_handle(); + let handle = handle.as_raw_handle(); + let info = inner::get_screen_buffer_info(handle)?; + let (fg, bg) = inner::get_colors(&info); + Ok((fg, bg)) +} -const FOREGROUND_CYAN: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_GREEN; -const FOREGROUND_MAGENTA: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_RED; -const FOREGROUND_YELLOW: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_GREEN | FOREGROUND_RED; -const FOREGROUND_WHITE: CONSOLE_CHARACTER_ATTRIBUTES = - FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; +mod inner { + use windows_sys::Win32::System::Console::CONSOLE_CHARACTER_ATTRIBUTES; + use windows_sys::Win32::System::Console::CONSOLE_SCREEN_BUFFER_INFO; + use windows_sys::Win32::System::Console::FOREGROUND_BLUE; + use windows_sys::Win32::System::Console::FOREGROUND_GREEN; + use windows_sys::Win32::System::Console::FOREGROUND_INTENSITY; + use windows_sys::Win32::System::Console::FOREGROUND_RED; -pub fn get_screen_buffer_info(handle: RawHandle) -> std::io::Result { - unsafe { - let handle = std::mem::transmute(handle); - if handle == 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "console is detached", - )); - } + use std::os::windows::io::RawHandle; - let mut info: CONSOLE_SCREEN_BUFFER_INFO = std::mem::zeroed(); - if windows_sys::Win32::System::Console::GetConsoleScreenBufferInfo(handle, &mut info) != 0 { - Ok(info) - } else { - Err(std::io::Error::last_os_error()) + const FOREGROUND_CYAN: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_GREEN; + const FOREGROUND_MAGENTA: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_RED; + const FOREGROUND_YELLOW: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_GREEN | FOREGROUND_RED; + const FOREGROUND_WHITE: CONSOLE_CHARACTER_ATTRIBUTES = + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + + pub fn get_screen_buffer_info( + handle: RawHandle, + ) -> std::io::Result { + unsafe { + let handle = std::mem::transmute(handle); + if handle == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "console is detached", + )); + } + + let mut info: CONSOLE_SCREEN_BUFFER_INFO = std::mem::zeroed(); + if windows_sys::Win32::System::Console::GetConsoleScreenBufferInfo(handle, &mut info) + != 0 + { + Ok(info) + } else { + Err(std::io::Error::last_os_error()) + } } } -} -pub fn set_console_text_attributes( - handle: RawHandle, - attributes: CONSOLE_CHARACTER_ATTRIBUTES, -) -> std::io::Result<()> { - unsafe { - let handle = std::mem::transmute(handle); - if handle == 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "console is detached", - )); - } + pub fn set_console_text_attributes( + handle: RawHandle, + attributes: CONSOLE_CHARACTER_ATTRIBUTES, + ) -> std::io::Result<()> { + unsafe { + let handle = std::mem::transmute(handle); + if handle == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "console is detached", + )); + } - if windows_sys::Win32::System::Console::SetConsoleTextAttribute(handle, attributes) != 0 { - Ok(()) - } else { - Err(std::io::Error::last_os_error()) + if windows_sys::Win32::System::Console::SetConsoleTextAttribute(handle, attributes) != 0 + { + Ok(()) + } else { + Err(std::io::Error::last_os_error()) + } } } -} -pub fn get_colors(info: &CONSOLE_SCREEN_BUFFER_INFO) -> (anstyle::AnsiColor, anstyle::AnsiColor) { - let attributes = info.wAttributes; - let bg = from_nibble(attributes >> 4); - let fg = from_nibble(attributes); - (fg, bg) -} + pub fn get_colors( + info: &CONSOLE_SCREEN_BUFFER_INFO, + ) -> (anstyle::AnsiColor, anstyle::AnsiColor) { + let attributes = info.wAttributes; + let bg = from_nibble(attributes >> 4); + let fg = from_nibble(attributes); + (fg, bg) + } -pub fn set_colors(fg: anstyle::AnsiColor, bg: anstyle::AnsiColor) -> CONSOLE_CHARACTER_ATTRIBUTES { - to_nibble(bg) << 4 | to_nibble(fg) -} + pub fn set_colors( + fg: anstyle::AnsiColor, + bg: anstyle::AnsiColor, + ) -> CONSOLE_CHARACTER_ATTRIBUTES { + to_nibble(bg) << 4 | to_nibble(fg) + } -fn from_nibble(color: CONSOLE_CHARACTER_ATTRIBUTES) -> anstyle::AnsiColor { - if color & FOREGROUND_WHITE == FOREGROUND_WHITE { - // 3 bits high - anstyle::AnsiColor::White - } else if color & FOREGROUND_CYAN == FOREGROUND_CYAN { - // 2 bits high - anstyle::AnsiColor::Cyan - } else if color & FOREGROUND_YELLOW == FOREGROUND_YELLOW { - // 2 bits high - anstyle::AnsiColor::Yellow - } else if color & FOREGROUND_MAGENTA == FOREGROUND_MAGENTA { - // 2 bits high - anstyle::AnsiColor::Magenta - } else if color & FOREGROUND_RED == FOREGROUND_RED { - // 1 bit high - anstyle::AnsiColor::Red - } else if color & FOREGROUND_GREEN == FOREGROUND_GREEN { - // 1 bit high - anstyle::AnsiColor::Green - } else if color & FOREGROUND_BLUE == FOREGROUND_BLUE { - // 1 bit high - anstyle::AnsiColor::Blue - } else { - // 0 bits high - anstyle::AnsiColor::Black + fn from_nibble(color: CONSOLE_CHARACTER_ATTRIBUTES) -> anstyle::AnsiColor { + if color & FOREGROUND_WHITE == FOREGROUND_WHITE { + // 3 bits high + anstyle::AnsiColor::White + } else if color & FOREGROUND_CYAN == FOREGROUND_CYAN { + // 2 bits high + anstyle::AnsiColor::Cyan + } else if color & FOREGROUND_YELLOW == FOREGROUND_YELLOW { + // 2 bits high + anstyle::AnsiColor::Yellow + } else if color & FOREGROUND_MAGENTA == FOREGROUND_MAGENTA { + // 2 bits high + anstyle::AnsiColor::Magenta + } else if color & FOREGROUND_RED == FOREGROUND_RED { + // 1 bit high + anstyle::AnsiColor::Red + } else if color & FOREGROUND_GREEN == FOREGROUND_GREEN { + // 1 bit high + anstyle::AnsiColor::Green + } else if color & FOREGROUND_BLUE == FOREGROUND_BLUE { + // 1 bit high + anstyle::AnsiColor::Blue + } else { + // 0 bits high + anstyle::AnsiColor::Black + } + .bright(color & FOREGROUND_INTENSITY == FOREGROUND_INTENSITY) } - .bright(color & FOREGROUND_INTENSITY == FOREGROUND_INTENSITY) -} -fn to_nibble(color: anstyle::AnsiColor) -> CONSOLE_CHARACTER_ATTRIBUTES { - let mut attributes = 0; - attributes |= match color.bright(false) { - anstyle::AnsiColor::Black => 0, - anstyle::AnsiColor::Red => FOREGROUND_RED, - anstyle::AnsiColor::Green => FOREGROUND_GREEN, - anstyle::AnsiColor::Yellow => FOREGROUND_YELLOW, - anstyle::AnsiColor::Blue => FOREGROUND_BLUE, - anstyle::AnsiColor::Magenta => FOREGROUND_MAGENTA, - anstyle::AnsiColor::Cyan => FOREGROUND_CYAN, - anstyle::AnsiColor::White => FOREGROUND_WHITE, - anstyle::AnsiColor::BrightBlack - | anstyle::AnsiColor::BrightRed - | anstyle::AnsiColor::BrightGreen - | anstyle::AnsiColor::BrightYellow - | anstyle::AnsiColor::BrightBlue - | anstyle::AnsiColor::BrightMagenta - | anstyle::AnsiColor::BrightCyan - | anstyle::AnsiColor::BrightWhite => unreachable!("brights were toggled off"), - }; - if color.is_bright() { - attributes |= FOREGROUND_INTENSITY; + fn to_nibble(color: anstyle::AnsiColor) -> CONSOLE_CHARACTER_ATTRIBUTES { + let mut attributes = 0; + attributes |= match color.bright(false) { + anstyle::AnsiColor::Black => 0, + anstyle::AnsiColor::Red => FOREGROUND_RED, + anstyle::AnsiColor::Green => FOREGROUND_GREEN, + anstyle::AnsiColor::Yellow => FOREGROUND_YELLOW, + anstyle::AnsiColor::Blue => FOREGROUND_BLUE, + anstyle::AnsiColor::Magenta => FOREGROUND_MAGENTA, + anstyle::AnsiColor::Cyan => FOREGROUND_CYAN, + anstyle::AnsiColor::White => FOREGROUND_WHITE, + anstyle::AnsiColor::BrightBlack + | anstyle::AnsiColor::BrightRed + | anstyle::AnsiColor::BrightGreen + | anstyle::AnsiColor::BrightYellow + | anstyle::AnsiColor::BrightBlue + | anstyle::AnsiColor::BrightMagenta + | anstyle::AnsiColor::BrightCyan + | anstyle::AnsiColor::BrightWhite => unreachable!("brights were toggled off"), + }; + if color.is_bright() { + attributes |= FOREGROUND_INTENSITY; + } + attributes } - attributes -} -#[test] -fn to_from_nibble() { - const COLORS: [anstyle::AnsiColor; 16] = [ - anstyle::AnsiColor::Black, - anstyle::AnsiColor::Red, - anstyle::AnsiColor::Green, - anstyle::AnsiColor::Yellow, - anstyle::AnsiColor::Blue, - anstyle::AnsiColor::Magenta, - anstyle::AnsiColor::Cyan, - anstyle::AnsiColor::White, - anstyle::AnsiColor::BrightBlack, - anstyle::AnsiColor::BrightRed, - anstyle::AnsiColor::BrightGreen, - anstyle::AnsiColor::BrightYellow, - anstyle::AnsiColor::BrightBlue, - anstyle::AnsiColor::BrightMagenta, - anstyle::AnsiColor::BrightCyan, - anstyle::AnsiColor::BrightWhite, - ]; - for expected in COLORS { - let nibble = to_nibble(expected); - let actual = from_nibble(nibble); - assert_eq!(expected, actual, "Intermediate: {}", nibble); + #[test] + fn to_from_nibble() { + const COLORS: [anstyle::AnsiColor; 16] = [ + anstyle::AnsiColor::Black, + anstyle::AnsiColor::Red, + anstyle::AnsiColor::Green, + anstyle::AnsiColor::Yellow, + anstyle::AnsiColor::Blue, + anstyle::AnsiColor::Magenta, + anstyle::AnsiColor::Cyan, + anstyle::AnsiColor::White, + anstyle::AnsiColor::BrightBlack, + anstyle::AnsiColor::BrightRed, + anstyle::AnsiColor::BrightGreen, + anstyle::AnsiColor::BrightYellow, + anstyle::AnsiColor::BrightBlue, + anstyle::AnsiColor::BrightMagenta, + anstyle::AnsiColor::BrightCyan, + anstyle::AnsiColor::BrightWhite, + ]; + for expected in COLORS { + let nibble = to_nibble(expected); + let actual = from_nibble(nibble); + assert_eq!(expected, actual, "Intermediate: {}", nibble); + } } }