1 //! Windows console handling
3 // FIXME (#13400): this is only a tiny fraction of the Windows console api
6 use std::io::prelude::*;
12 /// A Terminal implementation that uses the Win32 Console API.
13 pub struct WinConsole<T> {
15 def_foreground: color::Color,
16 def_background: color::Color,
17 foreground: color::Color,
18 background: color::Color,
25 type HANDLE = *mut u8;
27 #[allow(non_snake_case)]
36 #[allow(non_snake_case)]
43 #[allow(non_snake_case)]
45 struct CONSOLE_SCREEN_BUFFER_INFO {
47 dwCursorPosition: COORD,
50 dwMaximumWindowSize: COORD,
53 #[allow(non_snake_case)]
54 #[link(name = "kernel32")]
56 fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
57 fn GetStdHandle(which: DWORD) -> HANDLE;
58 fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
61 fn color_to_bits(color: color::Color) -> u16 {
62 // magic numbers from mingw-w64's wincon.h
64 let bits = match color % 8 {
69 color::YELLOW => 0x2 | 0x4,
70 color::MAGENTA => 0x1 | 0x4,
71 color::CYAN => 0x1 | 0x2,
72 color::WHITE => 0x1 | 0x2 | 0x4,
76 if color >= 8 { bits | 0x8 } else { bits }
79 fn bits_to_color(bits: u16) -> color::Color {
80 let color = match bits & 0x7 {
86 0x5 => color::MAGENTA,
92 color | (u32::from(bits) & 0x8) // copy the hi-intensity bit
95 impl<T: Write + Send + 'static> WinConsole<T> {
97 let _unused = self.buf.flush();
98 let mut accum: WORD = 0;
99 accum |= color_to_bits(self.foreground);
100 accum |= color_to_bits(self.background) << 4;
103 // Magic -11 means stdout, from
104 // https://docs.microsoft.com/en-us/windows/console/getstdhandle
106 // You may be wondering, "but what about stderr?", and the answer
107 // to that is that setting terminal attributes on the stdout
108 // handle also sets them for stderr, since they go to the same
109 // terminal! Admittedly, this is fragile, since stderr could be
110 // redirected to a different console. This is good enough for
111 // rustc though. See #13400.
112 let out = GetStdHandle(-11i32 as DWORD);
113 SetConsoleTextAttribute(out, accum);
117 /// Returns `None` whenever the terminal cannot be created for some reason.
118 pub fn new(out: T) -> io::Result<WinConsole<T>> {
119 use std::mem::MaybeUninit;
124 let mut buffer_info = MaybeUninit::<CONSOLE_SCREEN_BUFFER_INFO>::uninit();
125 if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD), buffer_info.as_mut_ptr())
128 let buffer_info = buffer_info.assume_init();
129 fg = bits_to_color(buffer_info.wAttributes);
130 bg = bits_to_color(buffer_info.wAttributes >> 4);
146 impl<T: Write> Write for WinConsole<T> {
147 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
151 fn flush(&mut self) -> io::Result<()> {
156 impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
159 fn fg(&mut self, color: color::Color) -> io::Result<bool> {
160 self.foreground = color;
166 fn bg(&mut self, color: color::Color) -> io::Result<bool> {
167 self.background = color;
173 fn attr(&mut self, attr: Attr) -> io::Result<bool> {
175 Attr::ForegroundColor(f) => {
180 Attr::BackgroundColor(b) => {
189 fn supports_attr(&self, attr: Attr) -> bool {
190 // it claims support for underscore and reverse video, but I can't get
191 // it to do anything -cmr
193 Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
198 fn reset(&mut self) -> io::Result<bool> {
199 self.foreground = self.def_foreground;
200 self.background = self.def_background;
206 fn get_ref(&self) -> &T {
210 fn get_mut(&mut self) -> &mut T {
214 fn into_inner(self) -> T