From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/winapi-util/src/console.rs | 402 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 vendor/winapi-util/src/console.rs (limited to 'vendor/winapi-util/src/console.rs') diff --git a/vendor/winapi-util/src/console.rs b/vendor/winapi-util/src/console.rs new file mode 100644 index 000000000..233d5c969 --- /dev/null +++ b/vendor/winapi-util/src/console.rs @@ -0,0 +1,402 @@ +use std::io; +use std::mem; + +use winapi::shared::minwindef::WORD; +use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; +use winapi::um::wincon::{ + self, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, + CONSOLE_SCREEN_BUFFER_INFO, FOREGROUND_BLUE as FG_BLUE, + FOREGROUND_GREEN as FG_GREEN, FOREGROUND_INTENSITY as FG_INTENSITY, + FOREGROUND_RED as FG_RED, +}; + +use crate::{AsHandleRef, HandleRef}; + +const FG_CYAN: WORD = FG_BLUE | FG_GREEN; +const FG_MAGENTA: WORD = FG_BLUE | FG_RED; +const FG_YELLOW: WORD = FG_GREEN | FG_RED; +const FG_WHITE: WORD = FG_BLUE | FG_GREEN | FG_RED; + +/// Query the given handle for information about the console's screen buffer. +/// +/// The given handle should represent a console. Otherwise, an error is +/// returned. +/// +/// This corresponds to calling [`GetConsoleScreenBufferInfo`]. +/// +/// [`GetConsoleScreenBufferInfo`]: https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo +pub fn screen_buffer_info( + h: H, +) -> io::Result { + unsafe { + let mut info: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed(); + let rc = GetConsoleScreenBufferInfo(h.as_raw(), &mut info); + if rc == 0 { + return Err(io::Error::last_os_error()); + } + Ok(ScreenBufferInfo(info)) + } +} + +/// Set the text attributes of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleTextAttribute`]. +/// +/// [`SetConsoleTextAttribute`]: https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute +pub fn set_text_attributes( + h: H, + attributes: u16, +) -> io::Result<()> { + if unsafe { SetConsoleTextAttribute(h.as_raw(), attributes) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Query the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`GetConsoleMode`], which describes the return +/// value. +/// +/// [`GetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/getconsolemode +pub fn mode(h: H) -> io::Result { + let mut mode = 0; + if unsafe { GetConsoleMode(h.as_raw(), &mut mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(mode) + } +} + +/// Set the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleMode`], which describes the format +/// of the mode parameter. +/// +/// [`SetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/setconsolemode +pub fn set_mode(h: H, mode: u32) -> io::Result<()> { + if unsafe { SetConsoleMode(h.as_raw(), mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Represents console screen buffer information such as size, cursor position +/// and styling attributes. +/// +/// This wraps a [`CONSOLE_SCREEN_BUFFER_INFO`]. +/// +/// [`CONSOLE_SCREEN_BUFFER_INFO`]: https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str +#[derive(Clone)] +pub struct ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO); + +impl ScreenBufferInfo { + /// Returns the size of the console screen buffer, in character columns and + /// rows. + /// + /// This corresponds to `dwSize`. + pub fn size(&self) -> (i16, i16) { + (self.0.dwSize.X, self.0.dwSize.Y) + } + + /// Returns the position of the cursor in terms of column and row + /// coordinates of the console screen buffer. + /// + /// This corresponds to `dwCursorPosition`. + pub fn cursor_position(&self) -> (i16, i16) { + (self.0.dwCursorPosition.X, self.0.dwCursorPosition.Y) + } + + /// Returns the character attributes associated with this console. + /// + /// This corresponds to `wAttributes`. + /// + /// See [`char info`] for more details. + /// + /// [`char info`]: https://docs.microsoft.com/en-us/windows/console/char-info-str + pub fn attributes(&self) -> u16 { + self.0.wAttributes + } + + /// Returns the maximum size of the console window, in character columns + /// and rows, given the current screen buffer size and font and the screen + /// size. + pub fn max_window_size(&self) -> (i16, i16) { + (self.0.dwMaximumWindowSize.X, self.0.dwMaximumWindowSize.Y) + } + + /// Returns the console screen buffer coordinates of the upper-left and + /// lower-right corners of the display window. + /// + /// This corresponds to `srWindow`. + pub fn window_rect(&self) -> SmallRect { + SmallRect { + left: self.0.srWindow.Left, + top: self.0.srWindow.Top, + right: self.0.srWindow.Right, + bottom: self.0.srWindow.Bottom, + } + } +} + +/// Defines the coordinates of the upper left and lower right corners of a rectangle. +/// +/// This corresponds to [`SMALL_RECT`]. +/// +/// [`SMALL_RECT`]: https://docs.microsoft.com/en-us/windows/console/small-rect-str +pub struct SmallRect { + pub left: i16, + pub top: i16, + pub right: i16, + pub bottom: i16, +} + +/// A Windows console. +/// +/// This represents a very limited set of functionality available to a Windows +/// console. In particular, it can only change text attributes such as color +/// and intensity. This may grow over time. If you need more routines, please +/// file an issue and/or PR. +/// +/// There is no way to "write" to this console. Simply write to +/// stdout or stderr instead, while interleaving instructions to the console +/// to change text attributes. +/// +/// A common pitfall when using a console is to forget to flush writes to +/// stdout before setting new text attributes. +/// +/// # Example +/// ```no_run +/// # #[cfg(windows)] +/// # { +/// use winapi_util::console::{Console, Color, Intense}; +/// +/// let mut con = Console::stdout().unwrap(); +/// con.fg(Intense::Yes, Color::Cyan).unwrap(); +/// println!("This text will be intense cyan."); +/// con.reset().unwrap(); +/// println!("This text will be normal."); +/// # } +/// ``` +#[derive(Debug)] +pub struct Console { + kind: HandleKind, + start_attr: TextAttributes, + cur_attr: TextAttributes, +} + +#[derive(Clone, Copy, Debug)] +enum HandleKind { + Stdout, + Stderr, +} + +impl HandleKind { + fn handle(&self) -> HandleRef { + match *self { + HandleKind::Stdout => HandleRef::stdout(), + HandleKind::Stderr => HandleRef::stderr(), + } + } +} + +impl Console { + /// Get a console for a standard I/O stream. + fn create_for_stream(kind: HandleKind) -> io::Result { + let h = kind.handle(); + let info = screen_buffer_info(&h)?; + let attr = TextAttributes::from_word(info.attributes()); + Ok(Console { kind: kind, start_attr: attr, cur_attr: attr }) + } + + /// Create a new Console to stdout. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stdout() -> io::Result { + Self::create_for_stream(HandleKind::Stdout) + } + + /// Create a new Console to stderr. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stderr() -> io::Result { + Self::create_for_stream(HandleKind::Stderr) + } + + /// Applies the current text attributes. + fn set(&mut self) -> io::Result<()> { + set_text_attributes(self.kind.handle(), self.cur_attr.to_word()) + } + + /// Apply the given intensity and color attributes to the console + /// foreground. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.fg_color = color; + self.cur_attr.fg_intense = intense; + self.set() + } + + /// Apply the given intensity and color attributes to the console + /// background. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.bg_color = color; + self.cur_attr.bg_intense = intense; + self.set() + } + + /// Reset the console text attributes to their original settings. + /// + /// The original settings correspond to the text attributes on the console + /// when this `Console` value was created. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn reset(&mut self) -> io::Result<()> { + self.cur_attr = self.start_attr; + self.set() + } + + /// Toggle virtual terminal processing. + /// + /// This method attempts to toggle virtual terminal processing for this + /// console. If there was a problem toggling it, then an error returned. + /// On success, the caller may assume that toggling it was successful. + /// + /// When virtual terminal processing is enabled, characters emitted to the + /// console are parsed for VT100 and similar control character sequences + /// that control color and other similar operations. + pub fn set_virtual_terminal_processing( + &mut self, + yes: bool, + ) -> io::Result<()> { + let vt = wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + let handle = self.kind.handle(); + let old_mode = mode(&handle)?; + let new_mode = if yes { old_mode | vt } else { old_mode & !vt }; + if old_mode == new_mode { + return Ok(()); + } + set_mode(&handle, new_mode) + } +} + +/// A representation of text attributes for the Windows console. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct TextAttributes { + fg_color: Color, + fg_intense: Intense, + bg_color: Color, + bg_intense: Intense, +} + +impl TextAttributes { + fn to_word(&self) -> WORD { + let mut w = 0; + w |= self.fg_color.to_fg(); + w |= self.fg_intense.to_fg(); + w |= self.bg_color.to_bg(); + w |= self.bg_intense.to_bg(); + w + } + + fn from_word(word: WORD) -> TextAttributes { + TextAttributes { + fg_color: Color::from_fg(word), + fg_intense: Intense::from_fg(word), + bg_color: Color::from_bg(word), + bg_intense: Intense::from_bg(word), + } + } +} + +/// Whether to use intense colors or not. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Intense { + Yes, + No, +} + +impl Intense { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Intense { + Intense::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Intense::No => 0, + Intense::Yes => FG_INTENSITY, + } + } + + fn from_fg(word: WORD) -> Intense { + if word & FG_INTENSITY > 0 { + Intense::Yes + } else { + Intense::No + } + } +} + +/// The set of available colors for use with a Windows console. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Color { + Black, + Blue, + Green, + Red, + Cyan, + Magenta, + Yellow, + White, +} + +impl Color { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Color { + Color::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Color::Black => 0, + Color::Blue => FG_BLUE, + Color::Green => FG_GREEN, + Color::Red => FG_RED, + Color::Cyan => FG_CYAN, + Color::Magenta => FG_MAGENTA, + Color::Yellow => FG_YELLOW, + Color::White => FG_WHITE, + } + } + + fn from_fg(word: WORD) -> Color { + match word & 0b111 { + FG_BLUE => Color::Blue, + FG_GREEN => Color::Green, + FG_RED => Color::Red, + FG_CYAN => Color::Cyan, + FG_MAGENTA => Color::Magenta, + FG_YELLOW => Color::Yellow, + FG_WHITE => Color::White, + _ => Color::Black, + } + } +} -- cgit v1.2.3