]> git.proxmox.com Git - rustc.git/blame - src/libterm/win.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / libterm / win.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Windows console handling
12
13// FIXME (#13400): this is only a tiny fraction of the Windows console api
14
15extern crate libc;
16
c34b1796
AL
17use std::io;
18use std::io::prelude::*;
1a4d82fc 19
92a42be0 20use Attr;
1a4d82fc 21use color;
92a42be0 22use Terminal;
1a4d82fc
JJ
23
24/// A Terminal implementation which uses the Win32 Console API.
25pub struct WinConsole<T> {
26 buf: T,
27 def_foreground: color::Color,
28 def_background: color::Color,
29 foreground: color::Color,
30 background: color::Color,
31}
32
92a42be0
SL
33type WORD = u16;
34type DWORD = u32;
35type BOOL = i32;
36type HANDLE = *mut u8;
37
1a4d82fc
JJ
38#[allow(non_snake_case)]
39#[repr(C)]
40struct CONSOLE_SCREEN_BUFFER_INFO {
41 dwSize: [libc::c_short; 2],
42 dwCursorPosition: [libc::c_short; 2],
92a42be0 43 wAttributes: WORD,
1a4d82fc
JJ
44 srWindow: [libc::c_short; 4],
45 dwMaximumWindowSize: [libc::c_short; 2],
46}
47
48#[allow(non_snake_case)]
49#[link(name = "kernel32")]
50extern "system" {
92a42be0
SL
51 fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
52 fn GetStdHandle(which: DWORD) -> HANDLE;
53 fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
1a4d82fc
JJ
54}
55
56fn color_to_bits(color: color::Color) -> u16 {
57 // magic numbers from mingw-w64's wincon.h
58
59 let bits = match color % 8 {
92a42be0
SL
60 color::BLACK => 0,
61 color::BLUE => 0x1,
62 color::GREEN => 0x2,
63 color::RED => 0x4,
64 color::YELLOW => 0x2 | 0x4,
1a4d82fc 65 color::MAGENTA => 0x1 | 0x4,
92a42be0
SL
66 color::CYAN => 0x1 | 0x2,
67 color::WHITE => 0x1 | 0x2 | 0x4,
68 _ => unreachable!(),
1a4d82fc
JJ
69 };
70
71 if color >= 8 {
72 bits | 0x8
73 } else {
74 bits
75 }
76}
77
78fn bits_to_color(bits: u16) -> color::Color {
79 let color = match bits & 0x7 {
80 0 => color::BLACK,
81 0x1 => color::BLUE,
82 0x2 => color::GREEN,
83 0x4 => color::RED,
84 0x6 => color::YELLOW,
85 0x5 => color::MAGENTA,
86 0x3 => color::CYAN,
87 0x7 => color::WHITE,
92a42be0 88 _ => unreachable!(),
1a4d82fc
JJ
89 };
90
91 color | (bits & 0x8) // copy the hi-intensity bit
92}
93
c34b1796 94impl<T: Write+Send+'static> WinConsole<T> {
1a4d82fc
JJ
95 fn apply(&mut self) {
96 let _unused = self.buf.flush();
92a42be0 97 let mut accum: WORD = 0;
1a4d82fc
JJ
98 accum |= color_to_bits(self.foreground);
99 accum |= color_to_bits(self.background) << 4;
100
101 unsafe {
102 // Magic -11 means stdout, from
103 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
104 //
105 // You may be wondering, "but what about stderr?", and the answer
106 // to that is that setting terminal attributes on the stdout
107 // handle also sets them for stderr, since they go to the same
108 // terminal! Admittedly, this is fragile, since stderr could be
109 // redirected to a different console. This is good enough for
110 // rustc though. See #13400.
92a42be0 111 let out = GetStdHandle(-11i32 as DWORD);
1a4d82fc
JJ
112 SetConsoleTextAttribute(out, accum);
113 }
114 }
115
116 /// Returns `None` whenever the terminal cannot be created for some
117 /// reason.
92a42be0 118 pub fn new(out: T) -> io::Result<WinConsole<T>> {
1a4d82fc
JJ
119 let fg;
120 let bg;
121 unsafe {
122 let mut buffer_info = ::std::mem::uninitialized();
92a42be0 123 if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD), &mut buffer_info) != 0 {
1a4d82fc
JJ
124 fg = bits_to_color(buffer_info.wAttributes);
125 bg = bits_to_color(buffer_info.wAttributes >> 4);
126 } else {
127 fg = color::WHITE;
128 bg = color::BLACK;
129 }
130 }
92a42be0
SL
131 Ok(WinConsole {
132 buf: out,
133 def_foreground: fg,
134 def_background: bg,
135 foreground: fg,
136 background: bg,
137 })
1a4d82fc
JJ
138 }
139}
140
c34b1796
AL
141impl<T: Write> Write for WinConsole<T> {
142 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
143 self.buf.write(buf)
1a4d82fc
JJ
144 }
145
c34b1796 146 fn flush(&mut self) -> io::Result<()> {
1a4d82fc
JJ
147 self.buf.flush()
148 }
149}
150
92a42be0
SL
151impl<T: Write+Send+'static> Terminal for WinConsole<T> {
152 type Output = T;
153
c34b1796 154 fn fg(&mut self, color: color::Color) -> io::Result<bool> {
1a4d82fc
JJ
155 self.foreground = color;
156 self.apply();
157
158 Ok(true)
159 }
160
c34b1796 161 fn bg(&mut self, color: color::Color) -> io::Result<bool> {
1a4d82fc
JJ
162 self.background = color;
163 self.apply();
164
165 Ok(true)
166 }
167
92a42be0 168 fn attr(&mut self, attr: Attr) -> io::Result<bool> {
1a4d82fc 169 match attr {
92a42be0 170 Attr::ForegroundColor(f) => {
1a4d82fc
JJ
171 self.foreground = f;
172 self.apply();
173 Ok(true)
92a42be0
SL
174 }
175 Attr::BackgroundColor(b) => {
1a4d82fc
JJ
176 self.background = b;
177 self.apply();
178 Ok(true)
92a42be0
SL
179 }
180 _ => Ok(false),
1a4d82fc
JJ
181 }
182 }
183
92a42be0 184 fn supports_attr(&self, attr: Attr) -> bool {
1a4d82fc
JJ
185 // it claims support for underscore and reverse video, but I can't get
186 // it to do anything -cmr
187 match attr {
92a42be0
SL
188 Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
189 _ => false,
1a4d82fc
JJ
190 }
191 }
192
92a42be0 193 fn reset(&mut self) -> io::Result<bool> {
1a4d82fc
JJ
194 self.foreground = self.def_foreground;
195 self.background = self.def_background;
196 self.apply();
197
92a42be0 198 Ok(true)
1a4d82fc
JJ
199 }
200
92a42be0
SL
201 fn get_ref<'a>(&'a self) -> &'a T {
202 &self.buf
203 }
1a4d82fc 204
92a42be0
SL
205 fn get_mut<'a>(&'a mut self) -> &'a mut T {
206 &mut self.buf
207 }
1a4d82fc 208
92a42be0
SL
209 fn into_inner(self) -> T
210 where Self: Sized
211 {
212 self.buf
213 }
1a4d82fc 214}