From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001
From: Valentin Popov <valentin@popov.link>
Date: Mon, 8 Jan 2024 01:21:28 +0400
Subject: Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
---
 vendor/anstyle-wincon/src/windows.rs | 263 +++++++++++++++++++++++++++++++++++
 1 file changed, 263 insertions(+)
 create mode 100644 vendor/anstyle-wincon/src/windows.rs

(limited to 'vendor/anstyle-wincon/src/windows.rs')

diff --git a/vendor/anstyle-wincon/src/windows.rs b/vendor/anstyle-wincon/src/windows.rs
new file mode 100644
index 0000000..bf1cf56
--- /dev/null
+++ b/vendor/anstyle-wincon/src/windows.rs
@@ -0,0 +1,263 @@
+//! Low-level wincon-styling
+
+use std::os::windows::io::AsHandle;
+use std::os::windows::io::AsRawHandle;
+
+type StdioColorResult = std::io::Result<(anstyle::AnsiColor, anstyle::AnsiColor)>;
+type StdioColorInnerResult = Result<(anstyle::AnsiColor, anstyle::AnsiColor), inner::IoError>;
+
+/// Cached [`get_colors`] call for [`std::io::stdout`]
+pub fn stdout_initial_colors() -> StdioColorResult {
+    static INITIAL: std::sync::OnceLock<StdioColorInnerResult> = std::sync::OnceLock::new();
+    INITIAL
+        .get_or_init(|| get_colors_(&std::io::stdout()))
+        .clone()
+        .map_err(Into::into)
+}
+
+/// Cached [`get_colors`] call for [`std::io::stderr`]
+pub fn stderr_initial_colors() -> StdioColorResult {
+    static INITIAL: std::sync::OnceLock<StdioColorInnerResult> = std::sync::OnceLock::new();
+    INITIAL
+        .get_or_init(|| get_colors_(&std::io::stderr()))
+        .clone()
+        .map_err(Into::into)
+}
+
+/// Apply colors to future writes
+///
+/// **Note:** Make sure any buffers are first flushed or else these colors will apply
+pub fn set_colors<S: AsHandle>(
+    stream: &mut S,
+    fg: anstyle::AnsiColor,
+    bg: anstyle::AnsiColor,
+) -> std::io::Result<()> {
+    set_colors_(stream, fg, bg).map_err(Into::into)
+}
+
+fn set_colors_<S: AsHandle>(
+    stream: &mut S,
+    fg: anstyle::AnsiColor,
+    bg: anstyle::AnsiColor,
+) -> Result<(), inner::IoError> {
+    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)
+}
+
+/// Get the colors currently active on the console
+pub fn get_colors<S: AsHandle>(stream: &S) -> StdioColorResult {
+    get_colors_(stream).map_err(Into::into)
+}
+
+fn get_colors_<S: AsHandle>(stream: &S) -> StdioColorInnerResult {
+    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))
+}
+
+pub(crate) fn write_colored<S: AsHandle + std::io::Write>(
+    stream: &mut S,
+    fg: Option<anstyle::AnsiColor>,
+    bg: Option<anstyle::AnsiColor>,
+    data: &[u8],
+    initial: StdioColorResult,
+) -> std::io::Result<usize> {
+    let (initial_fg, initial_bg) = initial?;
+    let non_default = fg.is_some() || bg.is_some();
+
+    if non_default {
+        let fg = fg.unwrap_or(initial_fg);
+        let bg = bg.unwrap_or(initial_bg);
+        // Ensure everything is written with the last set of colors before applying the next set
+        stream.flush()?;
+        set_colors(stream, fg, bg)?;
+    }
+    let written = stream.write(data)?;
+    if non_default {
+        // Ensure everything is written with the last set of colors before applying the next set
+        stream.flush()?;
+        set_colors(stream, initial_fg, initial_bg)?;
+    }
+    Ok(written)
+}
+
+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;
+
+    use std::os::windows::io::RawHandle;
+
+    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;
+
+    #[derive(Copy, Clone, Debug)]
+    pub(crate) enum IoError {
+        BrokenPipe,
+        RawOs(i32),
+    }
+
+    impl From<IoError> for std::io::Error {
+        fn from(io: IoError) -> Self {
+            match io {
+                IoError::BrokenPipe => {
+                    std::io::Error::new(std::io::ErrorKind::BrokenPipe, "console is detached")
+                }
+                IoError::RawOs(code) => std::io::Error::from_raw_os_error(code),
+            }
+        }
+    }
+
+    impl IoError {
+        fn last_os_error() -> Self {
+            Self::RawOs(std::io::Error::last_os_error().raw_os_error().unwrap())
+        }
+    }
+
+    pub(crate) fn get_screen_buffer_info(
+        handle: RawHandle,
+    ) -> Result<CONSOLE_SCREEN_BUFFER_INFO, IoError> {
+        unsafe {
+            let handle = std::mem::transmute(handle);
+            if handle == 0 {
+                return Err(IoError::BrokenPipe);
+            }
+
+            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(IoError::last_os_error())
+            }
+        }
+    }
+
+    pub(crate) fn set_console_text_attributes(
+        handle: RawHandle,
+        attributes: CONSOLE_CHARACTER_ATTRIBUTES,
+    ) -> Result<(), IoError> {
+        unsafe {
+            let handle = std::mem::transmute(handle);
+            if handle == 0 {
+                return Err(IoError::BrokenPipe);
+            }
+
+            if windows_sys::Win32::System::Console::SetConsoleTextAttribute(handle, attributes) != 0
+            {
+                Ok(())
+            } else {
+                Err(IoError::last_os_error())
+            }
+        }
+    }
+
+    pub(crate) 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(crate) 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
+        }
+        .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;
+        }
+        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);
+        }
+    }
+}
-- 
cgit v1.2.3