1 //! Windows console handling
3 // FIXME (#13400): this is only a tiny fraction of the Windows console api
8 use std::io::prelude::*;
14 /// A Terminal implementation that uses the Win32 Console API.
15 pub struct WinConsole<T> {
17 def_foreground: color::Color,
18 def_background: color::Color,
19 foreground: color::Color,
20 background: color::Color,
26 type HANDLE = *mut u8;
28 #[allow(non_snake_case)]
30 struct CONSOLE_SCREEN_BUFFER_INFO {
31 dwSize: [libc::c_short; 2],
32 dwCursorPosition: [libc::c_short; 2],
34 srWindow: [libc::c_short; 4],
35 dwMaximumWindowSize: [libc::c_short; 2],
38 #[allow(non_snake_case)]
39 #[link(name = "kernel32")]
41 fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
42 fn GetStdHandle(which: DWORD) -> HANDLE;
43 fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
46 fn color_to_bits(color: color::Color) -> u16 {
47 // magic numbers from mingw-w64's wincon.h
49 let bits = match color % 8 {
54 color::YELLOW => 0x2 | 0x4,
55 color::MAGENTA => 0x1 | 0x4,
56 color::CYAN => 0x1 | 0x2,
57 color::WHITE => 0x1 | 0x2 | 0x4,
68 fn bits_to_color(bits: u16) -> color::Color {
69 let color = match bits & 0x7 {
75 0x5 => color::MAGENTA,
81 color | (bits & 0x8) // copy the hi-intensity bit
84 impl<T: Write + Send + 'static> WinConsole<T> {
86 let _unused = self.buf.flush();
87 let mut accum: WORD = 0;
88 accum |= color_to_bits(self.foreground);
89 accum |= color_to_bits(self.background) << 4;
92 // Magic -11 means stdout, from
93 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
95 // You may be wondering, "but what about stderr?", and the answer
96 // to that is that setting terminal attributes on the stdout
97 // handle also sets them for stderr, since they go to the same
98 // terminal! Admittedly, this is fragile, since stderr could be
99 // redirected to a different console. This is good enough for
100 // rustc though. See #13400.
101 let out = GetStdHandle(-11i32 as DWORD);
102 SetConsoleTextAttribute(out, accum);
106 /// Returns `None` whenever the terminal cannot be created for some reason.
107 pub fn new(out: T) -> io::Result<WinConsole<T>> {
112 let mut buffer_info = ::std::mem::uninitialized();
113 if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD), &mut buffer_info) != 0 {
114 fg = bits_to_color(buffer_info.wAttributes);
115 bg = bits_to_color(buffer_info.wAttributes >> 4);
131 impl<T: Write> Write for WinConsole<T> {
132 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
136 fn flush(&mut self) -> io::Result<()> {
141 impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
144 fn fg(&mut self, color: color::Color) -> io::Result<bool> {
145 self.foreground = color;
151 fn bg(&mut self, color: color::Color) -> io::Result<bool> {
152 self.background = color;
158 fn attr(&mut self, attr: Attr) -> io::Result<bool> {
160 Attr::ForegroundColor(f) => {
165 Attr::BackgroundColor(b) => {
174 fn supports_attr(&self, attr: Attr) -> bool {
175 // it claims support for underscore and reverse video, but I can't get
176 // it to do anything -cmr
178 Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
183 fn reset(&mut self) -> io::Result<bool> {
184 self.foreground = self.def_foreground;
185 self.background = self.def_background;
191 fn get_ref(&self) -> &T {
195 fn get_mut(&mut self) -> &mut T {
199 fn into_inner(self) -> T