Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
405
third-party/vendor/winapi-util/src/console.rs
vendored
Normal file
405
third-party/vendor/winapi-util/src/console.rs
vendored
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
use std::{io, mem};
|
||||
|
||||
use winapi::{
|
||||
shared::minwindef::WORD,
|
||||
um::{
|
||||
consoleapi::{GetConsoleMode, SetConsoleMode},
|
||||
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: AsHandleRef>(
|
||||
h: H,
|
||||
) -> io::Result<ScreenBufferInfo> {
|
||||
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: AsHandleRef>(
|
||||
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: AsHandleRef>(h: H) -> io::Result<u32> {
|
||||
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: AsHandleRef>(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<Console> {
|
||||
let h = kind.handle();
|
||||
let info = screen_buffer_info(&h)?;
|
||||
let attr = TextAttributes::from_word(info.attributes());
|
||||
Ok(Console { 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()
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue