]> git.proxmox.com Git - rustc.git/blame - src/libterm/win.rs
Imported Upstream version 1.0.0~0alpha
[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
17use std::io::IoResult;
18
19use attr;
20use color;
21use {Terminal,UnwrappableTerminal};
22
23/// A Terminal implementation which uses the Win32 Console API.
24pub struct WinConsole<T> {
25 buf: T,
26 def_foreground: color::Color,
27 def_background: color::Color,
28 foreground: color::Color,
29 background: color::Color,
30}
31
32#[allow(non_snake_case)]
33#[repr(C)]
34struct CONSOLE_SCREEN_BUFFER_INFO {
35 dwSize: [libc::c_short; 2],
36 dwCursorPosition: [libc::c_short; 2],
37 wAttributes: libc::WORD,
38 srWindow: [libc::c_short; 4],
39 dwMaximumWindowSize: [libc::c_short; 2],
40}
41
42#[allow(non_snake_case)]
43#[link(name = "kernel32")]
44extern "system" {
45 fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
46 fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
47 fn GetConsoleScreenBufferInfo(handle: libc::HANDLE,
48 info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> libc::BOOL;
49}
50
51fn color_to_bits(color: color::Color) -> u16 {
52 // magic numbers from mingw-w64's wincon.h
53
54 let bits = match color % 8 {
55 color::BLACK => 0,
56 color::BLUE => 0x1,
57 color::GREEN => 0x2,
58 color::RED => 0x4,
59 color::YELLOW => 0x2 | 0x4,
60 color::MAGENTA => 0x1 | 0x4,
61 color::CYAN => 0x1 | 0x2,
62 color::WHITE => 0x1 | 0x2 | 0x4,
63 _ => unreachable!()
64 };
65
66 if color >= 8 {
67 bits | 0x8
68 } else {
69 bits
70 }
71}
72
73fn bits_to_color(bits: u16) -> color::Color {
74 let color = match bits & 0x7 {
75 0 => color::BLACK,
76 0x1 => color::BLUE,
77 0x2 => color::GREEN,
78 0x4 => color::RED,
79 0x6 => color::YELLOW,
80 0x5 => color::MAGENTA,
81 0x3 => color::CYAN,
82 0x7 => color::WHITE,
83 _ => unreachable!()
84 };
85
86 color | (bits & 0x8) // copy the hi-intensity bit
87}
88
89impl<T: Writer+Send> WinConsole<T> {
90 fn apply(&mut self) {
91 let _unused = self.buf.flush();
92 let mut accum: libc::WORD = 0;
93 accum |= color_to_bits(self.foreground);
94 accum |= color_to_bits(self.background) << 4;
95
96 unsafe {
97 // Magic -11 means stdout, from
98 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
99 //
100 // You may be wondering, "but what about stderr?", and the answer
101 // to that is that setting terminal attributes on the stdout
102 // handle also sets them for stderr, since they go to the same
103 // terminal! Admittedly, this is fragile, since stderr could be
104 // redirected to a different console. This is good enough for
105 // rustc though. See #13400.
106 let out = GetStdHandle(-11);
107 SetConsoleTextAttribute(out, accum);
108 }
109 }
110
111 /// Returns `None` whenever the terminal cannot be created for some
112 /// reason.
113 pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
114 let fg;
115 let bg;
116 unsafe {
117 let mut buffer_info = ::std::mem::uninitialized();
118 if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 {
119 fg = bits_to_color(buffer_info.wAttributes);
120 bg = bits_to_color(buffer_info.wAttributes >> 4);
121 } else {
122 fg = color::WHITE;
123 bg = color::BLACK;
124 }
125 }
126 Some(box WinConsole { buf: out,
127 def_foreground: fg, def_background: bg,
128 foreground: fg, background: bg } as Box<Terminal<T>+Send>)
129 }
130}
131
132impl<T: Writer> Writer for WinConsole<T> {
133 fn write(&mut self, buf: &[u8]) -> IoResult<()> {
134 self.buf.write(buf)
135 }
136
137 fn flush(&mut self) -> IoResult<()> {
138 self.buf.flush()
139 }
140}
141
142impl<T: Writer+Send> Terminal<T> for WinConsole<T> {
143 fn fg(&mut self, color: color::Color) -> IoResult<bool> {
144 self.foreground = color;
145 self.apply();
146
147 Ok(true)
148 }
149
150 fn bg(&mut self, color: color::Color) -> IoResult<bool> {
151 self.background = color;
152 self.apply();
153
154 Ok(true)
155 }
156
157 fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
158 match attr {
159 attr::ForegroundColor(f) => {
160 self.foreground = f;
161 self.apply();
162 Ok(true)
163 },
164 attr::BackgroundColor(b) => {
165 self.background = b;
166 self.apply();
167 Ok(true)
168 },
169 _ => Ok(false)
170 }
171 }
172
173 fn supports_attr(&self, attr: attr::Attr) -> bool {
174 // it claims support for underscore and reverse video, but I can't get
175 // it to do anything -cmr
176 match attr {
177 attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
178 _ => false
179 }
180 }
181
182 fn reset(&mut self) -> IoResult<()> {
183 self.foreground = self.def_foreground;
184 self.background = self.def_background;
185 self.apply();
186
187 Ok(())
188 }
189
190 fn get_ref<'a>(&'a self) -> &'a T { &self.buf }
191
192 fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
193}
194
195impl<T: Writer+Send> UnwrappableTerminal<T> for WinConsole<T> {
196 fn unwrap(self) -> T { self.buf }
197}