]> git.lizzy.rs Git - rust.git/commitdiff
Restore original terminal colors after error messages on Windows.
authorVadim Chugunov <vadimcn@gmail.com>
Sat, 20 Sep 2014 22:22:11 +0000 (15:22 -0700)
committerVadim Chugunov <vadimcn@gmail.com>
Sat, 20 Sep 2014 22:23:23 +0000 (15:23 -0700)
src/libterm/win.rs

index cd61f9bb35ed12c2f16c2f22295c629b7206b908..0aae85503d07ddaf5647950e410a1762c029f871 100644 (file)
 /// A Terminal implementation which uses the Win32 Console API.
 pub struct WinConsole<T> {
     buf: T,
+    def_foreground: color::Color,
+    def_background: color::Color,
     foreground: color::Color,
     background: color::Color,
 }
 
+#[allow(non_snake_case)]
+#[repr(C)]
+struct CONSOLE_SCREEN_BUFFER_INFO {
+    dwSize: [libc::c_short, ..2],
+    dwCursorPosition: [libc::c_short, ..2],
+    wAttributes: libc::WORD,
+    srWindow: [libc::c_short, ..4],
+    dwMaximumWindowSize: [libc::c_short, ..2],
+}
+
 #[allow(non_snake_case)]
 #[link(name = "kernel32")]
 extern "system" {
     fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
     fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
+    fn GetConsoleScreenBufferInfo(handle: libc::HANDLE,
+                                  info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> libc::BOOL;
 }
 
 fn color_to_bits(color: color::Color) -> u16 {
@@ -56,6 +70,26 @@ fn color_to_bits(color: color::Color) -> u16 {
     }
 }
 
+fn bits_to_color(bits: u16) -> color::Color {
+    let color = match bits & 0x7 {
+        0 => color::BLACK,
+        0x1 => color::BLUE,
+        0x2 => color::GREEN,
+        0x4 => color::RED,
+        0x6 => color::YELLOW,
+        0x5 => color::MAGENTA,
+        0x3 => color::CYAN,
+        0x7 => color::WHITE,
+        _ => unreachable!()
+    };
+
+    if bits >= 8 {
+        color | 0x8
+    } else {
+        color
+    }
+}
+
 impl<T: Writer> WinConsole<T> {
     fn apply(&mut self) {
         let _unused = self.buf.flush();
@@ -91,7 +125,21 @@ fn flush(&mut self) -> IoResult<()> {
 
 impl<T: Writer> Terminal<T> for WinConsole<T> {
     fn new(out: T) -> Option<WinConsole<T>> {
-        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
+        let fg;
+        let bg;
+        unsafe {
+            let mut buffer_info = ::std::mem::uninitialized();
+            if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 {
+                fg = bits_to_color(buffer_info.wAttributes);
+                bg = bits_to_color(buffer_info.wAttributes >> 4);
+            } else {
+                fg = color::WHITE;
+                bg = color::BLACK;
+            }
+        }
+        Some(WinConsole { buf: out,
+                          def_foreground: fg, def_background: bg,
+                          foreground: fg, background: bg } )
     }
 
     fn fg(&mut self, color: color::Color) -> IoResult<bool> {
@@ -134,8 +182,8 @@ fn supports_attr(&self, attr: attr::Attr) -> bool {
     }
 
     fn reset(&mut self) -> IoResult<()> {
-        self.foreground = color::WHITE;
-        self.background = color::BLACK;
+        self.foreground = self.def_foreground;
+        self.background = self.def_background;
         self.apply();
 
         Ok(())