aboutsummaryrefslogtreecommitdiff
path: root/vendor/console/src/windows_term
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
committerValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
commita990de90fe41456a23e58bd087d2f107d321f3a1 (patch)
tree15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/console/src/windows_term
parent3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff)
downloadfparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz
fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip
Deleted vendor folder
Diffstat (limited to 'vendor/console/src/windows_term')
-rw-r--r--vendor/console/src/windows_term/colors.rs451
-rw-r--r--vendor/console/src/windows_term/mod.rs563
2 files changed, 0 insertions, 1014 deletions
diff --git a/vendor/console/src/windows_term/colors.rs b/vendor/console/src/windows_term/colors.rs
deleted file mode 100644
index dc8209d..0000000
--- a/vendor/console/src/windows_term/colors.rs
+++ /dev/null
@@ -1,451 +0,0 @@
-use std::io;
-use std::mem;
-use std::os::windows::io::AsRawHandle;
-use std::str::Bytes;
-
-use windows_sys::Win32::Foundation::HANDLE;
-use windows_sys::Win32::System::Console::{
- 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::Term;
-
-type WORD = u16;
-
-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: HANDLE) -> io::Result<ScreenBufferInfo> {
- unsafe {
- let mut info: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
- let rc = GetConsoleScreenBufferInfo(h, &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: HANDLE, attributes: u16) -> io::Result<()> {
- if unsafe { SetConsoleTextAttribute(h, attributes) } == 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 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
- }
-}
-
-/// 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.
-#[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) -> HANDLE {
- match *self {
- HandleKind::Stdout => io::stdout().as_raw_handle() as HANDLE,
- HandleKind::Stderr => io::stderr().as_raw_handle() as HANDLE,
- }
- }
-}
-
-impl Console {
- /// Get a console for a standard I/O stream.
- fn create_for_stream(kind: HandleKind) -> io::Result<Console> {
- 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<Console> {
- 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<Console> {
- 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()
- }
-}
-
-/// 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,
- }
- }
-}
-
-pub fn console_colors(out: &Term, mut con: Console, bytes: &[u8]) -> io::Result<()> {
- use crate::ansi::AnsiCodeIterator;
- use std::str::from_utf8;
-
- let s = from_utf8(bytes).expect("data to be printed is not an ansi string");
- let mut iter = AnsiCodeIterator::new(s);
-
- while !iter.rest_slice().is_empty() {
- if let Some((part, is_esc)) = iter.next() {
- if !is_esc {
- out.write_through_common(part.as_bytes())?;
- } else if part == "\x1b[0m" {
- con.reset()?;
- } else if let Some((intense, color, fg_bg)) = driver(parse_color, part) {
- match fg_bg {
- FgBg::Foreground => con.fg(intense, color),
- FgBg::Background => con.bg(intense, color),
- }?;
- } else if driver(parse_attr, part).is_none() {
- out.write_through_common(part.as_bytes())?;
- }
- }
- }
-
- Ok(())
-}
-
-#[derive(Debug, PartialEq, Eq)]
-enum FgBg {
- Foreground,
- Background,
-}
-
-impl FgBg {
- fn new(byte: u8) -> Option<Self> {
- match byte {
- b'3' => Some(Self::Foreground),
- b'4' => Some(Self::Background),
- _ => None,
- }
- }
-}
-
-fn driver<Out>(parse: fn(Bytes<'_>) -> Option<Out>, part: &str) -> Option<Out> {
- let mut bytes = part.bytes();
-
- loop {
- while bytes.next()? != b'\x1b' {}
-
- if let ret @ Some(_) = (parse)(bytes.clone()) {
- return ret;
- }
- }
-}
-
-// `driver(parse_color, s)` parses the equivalent of the regex
-// \x1b\[(3|4)8;5;(8|9|1[0-5])m
-// for intense or
-// \x1b\[(3|4)([0-7])m
-// for normal
-fn parse_color(mut bytes: Bytes<'_>) -> Option<(Intense, Color, FgBg)> {
- parse_prefix(&mut bytes)?;
-
- let fg_bg = FgBg::new(bytes.next()?)?;
- let (intense, color) = match bytes.next()? {
- b @ b'0'..=b'7' => (Intense::No, normal_color_ansi_from_byte(b)?),
- b'8' => {
- if &[bytes.next()?, bytes.next()?, bytes.next()?] != b";5;" {
- return None;
- }
- (Intense::Yes, parse_intense_color_ansi(&mut bytes)?)
- }
- _ => return None,
- };
-
- parse_suffix(&mut bytes)?;
- Some((intense, color, fg_bg))
-}
-
-// `driver(parse_attr, s)` parses the equivalent of the regex
-// \x1b\[([1-8])m
-fn parse_attr(mut bytes: Bytes<'_>) -> Option<u8> {
- parse_prefix(&mut bytes)?;
- let attr = match bytes.next()? {
- attr @ b'1'..=b'8' => attr,
- _ => return None,
- };
- parse_suffix(&mut bytes)?;
- Some(attr)
-}
-
-fn parse_prefix(bytes: &mut Bytes<'_>) -> Option<()> {
- if bytes.next()? == b'[' {
- Some(())
- } else {
- None
- }
-}
-
-fn parse_intense_color_ansi(bytes: &mut Bytes<'_>) -> Option<Color> {
- let color = match bytes.next()? {
- b'8' => Color::Black,
- b'9' => Color::Red,
- b'1' => match bytes.next()? {
- b'0' => Color::Green,
- b'1' => Color::Yellow,
- b'2' => Color::Blue,
- b'3' => Color::Magenta,
- b'4' => Color::Cyan,
- b'5' => Color::White,
- _ => return None,
- },
- _ => return None,
- };
- Some(color)
-}
-
-fn normal_color_ansi_from_byte(b: u8) -> Option<Color> {
- let color = match b {
- b'0' => Color::Black,
- b'1' => Color::Red,
- b'2' => Color::Green,
- b'3' => Color::Yellow,
- b'4' => Color::Blue,
- b'5' => Color::Magenta,
- b'6' => Color::Cyan,
- b'7' => Color::White,
- _ => return None,
- };
- Some(color)
-}
-
-fn parse_suffix(bytes: &mut Bytes<'_>) -> Option<()> {
- if bytes.next()? == b'm' {
- Some(())
- } else {
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn color_parsing() {
- let intense_color = "leading bytes \x1b[38;5;10m trailing bytes";
- let parsed = driver(parse_color, intense_color).unwrap();
- assert_eq!(parsed, (Intense::Yes, Color::Green, FgBg::Foreground));
-
- let normal_color = "leading bytes \x1b[40m trailing bytes";
- let parsed = driver(parse_color, normal_color).unwrap();
- assert_eq!(parsed, (Intense::No, Color::Black, FgBg::Background));
- }
-
- #[test]
- fn attr_parsing() {
- let attr = "leading bytes \x1b[1m trailing bytes";
- let parsed = driver(parse_attr, attr).unwrap();
- assert_eq!(parsed, b'1');
- }
-}
diff --git a/vendor/console/src/windows_term/mod.rs b/vendor/console/src/windows_term/mod.rs
deleted file mode 100644
index c4ec193..0000000
--- a/vendor/console/src/windows_term/mod.rs
+++ /dev/null
@@ -1,563 +0,0 @@
-use std::cmp;
-use std::env;
-use std::ffi::OsStr;
-use std::fmt::Display;
-use std::io;
-use std::iter::once;
-use std::mem;
-use std::os::raw::c_void;
-use std::os::windows::ffi::OsStrExt;
-use std::os::windows::io::AsRawHandle;
-use std::slice;
-use std::{char, mem::MaybeUninit};
-
-use encode_unicode::error::InvalidUtf16Tuple;
-use encode_unicode::CharExt;
-use windows_sys::Win32::Foundation::{CHAR, HANDLE, INVALID_HANDLE_VALUE, MAX_PATH};
-use windows_sys::Win32::Storage::FileSystem::{
- FileNameInfo, GetFileInformationByHandleEx, FILE_NAME_INFO,
-};
-use windows_sys::Win32::System::Console::{
- FillConsoleOutputAttribute, FillConsoleOutputCharacterA, GetConsoleCursorInfo, GetConsoleMode,
- GetConsoleScreenBufferInfo, GetNumberOfConsoleInputEvents, GetStdHandle, ReadConsoleInputW,
- SetConsoleCursorInfo, SetConsoleCursorPosition, SetConsoleMode, SetConsoleTitleW,
- CONSOLE_CURSOR_INFO, CONSOLE_SCREEN_BUFFER_INFO, COORD, INPUT_RECORD, KEY_EVENT,
- KEY_EVENT_RECORD, STD_ERROR_HANDLE, STD_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
-};
-use windows_sys::Win32::UI::Input::KeyboardAndMouse::VIRTUAL_KEY;
-
-use crate::common_term;
-use crate::kb::Key;
-use crate::term::{Term, TermTarget};
-
-#[cfg(feature = "windows-console-colors")]
-mod colors;
-
-#[cfg(feature = "windows-console-colors")]
-pub use self::colors::*;
-
-const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x4;
-pub const DEFAULT_WIDTH: u16 = 79;
-
-pub fn as_handle(term: &Term) -> HANDLE {
- // convert between windows_sys::Win32::Foundation::HANDLE and std::os::windows::raw::HANDLE
- term.as_raw_handle() as HANDLE
-}
-
-pub fn is_a_terminal(out: &Term) -> bool {
- let (fd, others) = match out.target() {
- TermTarget::Stdout => (STD_OUTPUT_HANDLE, [STD_INPUT_HANDLE, STD_ERROR_HANDLE]),
- TermTarget::Stderr => (STD_ERROR_HANDLE, [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE]),
- };
-
- if unsafe { console_on_any(&[fd]) } {
- // False positives aren't possible. If we got a console then
- // we definitely have a tty on stdin.
- return true;
- }
-
- // At this point, we *could* have a false negative. We can determine that
- // this is true negative if we can detect the presence of a console on
- // any of the other streams. If another stream has a console, then we know
- // we're in a Windows console and can therefore trust the negative.
- if unsafe { console_on_any(&others) } {
- return false;
- }
-
- msys_tty_on(out)
-}
-
-pub fn is_a_color_terminal(out: &Term) -> bool {
- if !is_a_terminal(out) {
- return false;
- }
- if msys_tty_on(out) {
- return match env::var("TERM") {
- Ok(term) => term != "dumb",
- Err(_) => true,
- };
- }
- enable_ansi_on(out)
-}
-
-fn enable_ansi_on(out: &Term) -> bool {
- unsafe {
- let handle = as_handle(out);
-
- let mut dw_mode = 0;
- if GetConsoleMode(handle, &mut dw_mode) == 0 {
- return false;
- }
-
- dw_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
- if SetConsoleMode(handle, dw_mode) == 0 {
- return false;
- }
-
- true
- }
-}
-
-unsafe fn console_on_any(fds: &[STD_HANDLE]) -> bool {
- for &fd in fds {
- let mut out = 0;
- let handle = GetStdHandle(fd);
- if GetConsoleMode(handle, &mut out) != 0 {
- return true;
- }
- }
- false
-}
-
-pub fn terminal_size(out: &Term) -> Option<(u16, u16)> {
- use windows_sys::Win32::System::Console::SMALL_RECT;
-
- // convert between windows_sys::Win32::Foundation::HANDLE and std::os::windows::raw::HANDLE
- let handle = out.as_raw_handle();
- let hand = handle as windows_sys::Win32::Foundation::HANDLE;
-
- if hand == INVALID_HANDLE_VALUE {
- return None;
- }
-
- let zc = COORD { X: 0, Y: 0 };
- let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
- dwSize: zc,
- dwCursorPosition: zc,
- wAttributes: 0,
- srWindow: SMALL_RECT {
- Left: 0,
- Top: 0,
- Right: 0,
- Bottom: 0,
- },
- dwMaximumWindowSize: zc,
- };
- if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } == 0 {
- return None;
- }
-
- let rows = (csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16;
- let columns = (csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16;
-
- Some((rows, columns))
-}
-
-pub fn move_cursor_to(out: &Term, x: usize, y: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::move_cursor_to(out, x, y);
- }
- if let Some((hand, _)) = get_console_screen_buffer_info(as_handle(out)) {
- unsafe {
- SetConsoleCursorPosition(
- hand,
- COORD {
- X: x as i16,
- Y: y as i16,
- },
- );
- }
- }
- Ok(())
-}
-
-pub fn move_cursor_up(out: &Term, n: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::move_cursor_up(out, n);
- }
-
- if let Some((_, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- move_cursor_to(out, 0, csbi.dwCursorPosition.Y as usize - n)?;
- }
- Ok(())
-}
-
-pub fn move_cursor_down(out: &Term, n: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::move_cursor_down(out, n);
- }
-
- if let Some((_, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- move_cursor_to(out, 0, csbi.dwCursorPosition.Y as usize + n)?;
- }
- Ok(())
-}
-
-pub fn move_cursor_left(out: &Term, n: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::move_cursor_left(out, n);
- }
-
- if let Some((_, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- move_cursor_to(
- out,
- csbi.dwCursorPosition.X as usize - n,
- csbi.dwCursorPosition.Y as usize,
- )?;
- }
- Ok(())
-}
-
-pub fn move_cursor_right(out: &Term, n: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::move_cursor_right(out, n);
- }
-
- if let Some((_, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- move_cursor_to(
- out,
- csbi.dwCursorPosition.X as usize + n,
- csbi.dwCursorPosition.Y as usize,
- )?;
- }
- Ok(())
-}
-
-pub fn clear_line(out: &Term) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::clear_line(out);
- }
- if let Some((hand, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- unsafe {
- let width = csbi.srWindow.Right - csbi.srWindow.Left;
- let pos = COORD {
- X: 0,
- Y: csbi.dwCursorPosition.Y,
- };
- let mut written = 0;
- FillConsoleOutputCharacterA(hand, b' ' as CHAR, width as u32, pos, &mut written);
- FillConsoleOutputAttribute(hand, csbi.wAttributes, width as u32, pos, &mut written);
- SetConsoleCursorPosition(hand, pos);
- }
- }
- Ok(())
-}
-
-pub fn clear_chars(out: &Term, n: usize) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::clear_chars(out, n);
- }
- if let Some((hand, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- unsafe {
- let width = cmp::min(csbi.dwCursorPosition.X, n as i16);
- let pos = COORD {
- X: csbi.dwCursorPosition.X - width,
- Y: csbi.dwCursorPosition.Y,
- };
- let mut written = 0;
- FillConsoleOutputCharacterA(hand, b' ' as CHAR, width as u32, pos, &mut written);
- FillConsoleOutputAttribute(hand, csbi.wAttributes, width as u32, pos, &mut written);
- SetConsoleCursorPosition(hand, pos);
- }
- }
- Ok(())
-}
-
-pub fn clear_screen(out: &Term) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::clear_screen(out);
- }
- if let Some((hand, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- unsafe {
- let cells = csbi.dwSize.X as u32 * csbi.dwSize.Y as u32; // as u32, or else this causes stack overflows.
- let pos = COORD { X: 0, Y: 0 };
- let mut written = 0;
- FillConsoleOutputCharacterA(hand, b' ' as CHAR, cells, pos, &mut written); // cells as u32 no longer needed.
- FillConsoleOutputAttribute(hand, csbi.wAttributes, cells, pos, &mut written);
- SetConsoleCursorPosition(hand, pos);
- }
- }
- Ok(())
-}
-
-pub fn clear_to_end_of_screen(out: &Term) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::clear_to_end_of_screen(out);
- }
- if let Some((hand, csbi)) = get_console_screen_buffer_info(as_handle(out)) {
- unsafe {
- let bottom = csbi.srWindow.Right as u32 * csbi.srWindow.Bottom as u32;
- let cells = bottom - (csbi.dwCursorPosition.X as u32 * csbi.dwCursorPosition.Y as u32); // as u32, or else this causes stack overflows.
- let pos = COORD {
- X: 0,
- Y: csbi.dwCursorPosition.Y,
- };
- let mut written = 0;
- FillConsoleOutputCharacterA(hand, b' ' as CHAR, cells, pos, &mut written); // cells as u32 no longer needed.
- FillConsoleOutputAttribute(hand, csbi.wAttributes, cells, pos, &mut written);
- SetConsoleCursorPosition(hand, pos);
- }
- }
- Ok(())
-}
-
-pub fn show_cursor(out: &Term) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::show_cursor(out);
- }
- if let Some((hand, mut cci)) = get_console_cursor_info(as_handle(out)) {
- unsafe {
- cci.bVisible = 1;
- SetConsoleCursorInfo(hand, &cci);
- }
- }
- Ok(())
-}
-
-pub fn hide_cursor(out: &Term) -> io::Result<()> {
- if out.is_msys_tty {
- return common_term::hide_cursor(out);
- }
- if let Some((hand, mut cci)) = get_console_cursor_info(as_handle(out)) {
- unsafe {
- cci.bVisible = 0;
- SetConsoleCursorInfo(hand, &cci);
- }
- }
- Ok(())
-}
-
-fn get_console_screen_buffer_info(hand: HANDLE) -> Option<(HANDLE, CONSOLE_SCREEN_BUFFER_INFO)> {
- let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
- match unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } {
- 0 => None,
- _ => Some((hand, csbi)),
- }
-}
-
-fn get_console_cursor_info(hand: HANDLE) -> Option<(HANDLE, CONSOLE_CURSOR_INFO)> {
- let mut cci: CONSOLE_CURSOR_INFO = unsafe { mem::zeroed() };
- match unsafe { GetConsoleCursorInfo(hand, &mut cci) } {
- 0 => None,
- _ => Some((hand, cci)),
- }
-}
-
-pub fn key_from_key_code(code: VIRTUAL_KEY) -> Key {
- use windows_sys::Win32::UI::Input::KeyboardAndMouse;
-
- match code {
- KeyboardAndMouse::VK_LEFT => Key::ArrowLeft,
- KeyboardAndMouse::VK_RIGHT => Key::ArrowRight,
- KeyboardAndMouse::VK_UP => Key::ArrowUp,
- KeyboardAndMouse::VK_DOWN => Key::ArrowDown,
- KeyboardAndMouse::VK_RETURN => Key::Enter,
- KeyboardAndMouse::VK_ESCAPE => Key::Escape,
- KeyboardAndMouse::VK_BACK => Key::Backspace,
- KeyboardAndMouse::VK_TAB => Key::Tab,
- KeyboardAndMouse::VK_HOME => Key::Home,
- KeyboardAndMouse::VK_END => Key::End,
- KeyboardAndMouse::VK_DELETE => Key::Del,
- KeyboardAndMouse::VK_SHIFT => Key::Shift,
- KeyboardAndMouse::VK_MENU => Key::Alt,
- _ => Key::Unknown,
- }
-}
-
-pub fn read_secure() -> io::Result<String> {
- let mut rv = String::new();
- loop {
- match read_single_key()? {
- Key::Enter => {
- break;
- }
- Key::Char('\x08') => {
- if !rv.is_empty() {
- let new_len = rv.len() - 1;
- rv.truncate(new_len);
- }
- }
- Key::Char(c) => {
- rv.push(c);
- }
- _ => {}
- }
- }
- Ok(rv)
-}
-
-pub fn read_single_key() -> io::Result<Key> {
- let key_event = read_key_event()?;
-
- let unicode_char = unsafe { key_event.uChar.UnicodeChar };
- if unicode_char == 0 {
- Ok(key_from_key_code(key_event.wVirtualKeyCode))
- } else {
- // This is a unicode character, in utf-16. Try to decode it by itself.
- match char::from_utf16_tuple((unicode_char, None)) {
- Ok(c) => {
- // Maintain backward compatibility. The previous implementation (_getwch()) would return
- // a special keycode for `Enter`, while ReadConsoleInputW() prefers to use '\r'.
- if c == '\r' {
- Ok(Key::Enter)
- } else if c == '\x08' {
- Ok(Key::Backspace)
- } else if c == '\x1B' {
- Ok(Key::Escape)
- } else {
- Ok(Key::Char(c))
- }
- }
- // This is part of a surrogate pair. Try to read the second half.
- Err(InvalidUtf16Tuple::MissingSecond) => {
- // Confirm that there is a next character to read.
- if get_key_event_count()? == 0 {
- let message = format!(
- "Read invlid utf16 {}: {}",
- unicode_char,
- InvalidUtf16Tuple::MissingSecond
- );
- return Err(io::Error::new(io::ErrorKind::InvalidData, message));
- }
-
- // Read the next character.
- let next_event = read_key_event()?;
- let next_surrogate = unsafe { next_event.uChar.UnicodeChar };
-
- // Attempt to decode it.
- match char::from_utf16_tuple((unicode_char, Some(next_surrogate))) {
- Ok(c) => Ok(Key::Char(c)),
-
- // Return an InvalidData error. This is the recommended value for UTF-related I/O errors.
- // (This error is given when reading a non-UTF8 file into a String, for example.)
- Err(e) => {
- let message = format!(
- "Read invalid surrogate pair ({}, {}): {}",
- unicode_char, next_surrogate, e
- );
- Err(io::Error::new(io::ErrorKind::InvalidData, message))
- }
- }
- }
-
- // Return an InvalidData error. This is the recommended value for UTF-related I/O errors.
- // (This error is given when reading a non-UTF8 file into a String, for example.)
- Err(e) => {
- let message = format!("Read invalid utf16 {}: {}", unicode_char, e);
- Err(io::Error::new(io::ErrorKind::InvalidData, message))
- }
- }
- }
-}
-
-fn get_stdin_handle() -> io::Result<HANDLE> {
- let handle = unsafe { GetStdHandle(STD_INPUT_HANDLE) };
- if handle == INVALID_HANDLE_VALUE {
- Err(io::Error::last_os_error())
- } else {
- Ok(handle)
- }
-}
-
-/// Get the number of pending events in the ReadConsoleInput queue. Note that while
-/// these aren't necessarily key events, the only way that multiple events can be
-/// put into the queue simultaneously is if a unicode character spanning multiple u16's
-/// is read.
-///
-/// Therefore, this is accurate as long as at least one KEY_EVENT has already been read.
-fn get_key_event_count() -> io::Result<u32> {
- let handle = get_stdin_handle()?;
- let mut event_count: u32 = unsafe { mem::zeroed() };
-
- let success = unsafe { GetNumberOfConsoleInputEvents(handle, &mut event_count) };
- if success == 0 {
- Err(io::Error::last_os_error())
- } else {
- Ok(event_count)
- }
-}
-
-fn read_key_event() -> io::Result<KEY_EVENT_RECORD> {
- let handle = get_stdin_handle()?;
- let mut buffer: INPUT_RECORD = unsafe { mem::zeroed() };
-
- let mut events_read: u32 = unsafe { mem::zeroed() };
-
- let mut key_event: KEY_EVENT_RECORD;
- loop {
- let success = unsafe { ReadConsoleInputW(handle, &mut buffer, 1, &mut events_read) };
- if success == 0 {
- return Err(io::Error::last_os_error());
- }
- if events_read == 0 {
- return Err(io::Error::new(
- io::ErrorKind::Other,
- "ReadConsoleInput returned no events, instead of waiting for an event",
- ));
- }
-
- if events_read == 1 && buffer.EventType != KEY_EVENT as u16 {
- // This isn't a key event; ignore it.
- continue;
- }
-
- key_event = unsafe { mem::transmute(buffer.Event) };
-
- if key_event.bKeyDown == 0 {
- // This is a key being released; ignore it.
- continue;
- }
-
- return Ok(key_event);
- }
-}
-
-pub fn wants_emoji() -> bool {
- // If WT_SESSION is set, we can assume we're running in the nne
- // Windows Terminal. The correct way to detect this is not available
- // yet. See https://github.com/microsoft/terminal/issues/1040
- env::var("WT_SESSION").is_ok()
-}
-
-/// Returns true if there is an MSYS tty on the given handle.
-pub fn msys_tty_on(term: &Term) -> bool {
- let handle = term.as_raw_handle();
- unsafe {
- // Check whether the Windows 10 native pty is enabled
- {
- let mut out = MaybeUninit::uninit();
- let res = GetConsoleMode(handle as HANDLE, out.as_mut_ptr());
- if res != 0 // If res is true then out was initialized.
- && (out.assume_init() & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- == ENABLE_VIRTUAL_TERMINAL_PROCESSING
- {
- return true;
- }
- }
-
- let size = mem::size_of::<FILE_NAME_INFO>();
- let mut name_info_bytes = vec![0u8; size + MAX_PATH as usize * mem::size_of::<u16>()];
- let res = GetFileInformationByHandleEx(
- handle as HANDLE,
- FileNameInfo,
- &mut *name_info_bytes as *mut _ as *mut c_void,
- name_info_bytes.len() as u32,
- );
- if res == 0 {
- return false;
- }
- let name_info: &FILE_NAME_INFO = &*(name_info_bytes.as_ptr() as *const FILE_NAME_INFO);
- let s = slice::from_raw_parts(
- name_info.FileName.as_ptr(),
- name_info.FileNameLength as usize / 2,
- );
- let name = String::from_utf16_lossy(s);
- // This checks whether 'pty' exists in the file name, which indicates that
- // a pseudo-terminal is attached. To mitigate against false positives
- // (e.g., an actual file name that contains 'pty'), we also require that
- // either the strings 'msys-' or 'cygwin-' are in the file name as well.)
- let is_msys = name.contains("msys-") || name.contains("cygwin-");
- let is_pty = name.contains("-pty");
- is_msys && is_pty
- }
-}
-
-pub fn set_title<T: Display>(title: T) {
- let buffer: Vec<u16> = OsStr::new(&format!("{}", title))
- .encode_wide()
- .chain(once(0))
- .collect();
- unsafe {
- SetConsoleTitleW(buffer.as_ptr());
- }
-}