summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-11-20 15:44:19 -0500
committerAndrew Gallant <jamslam@gmail.com>2016-11-20 15:44:19 -0500
commitdf72d8d1e0016b2235504b17451348e68522e187 (patch)
tree0466e50e7045ac8d8ddf9e3da4f97012eb81589a
parentd06f84ced349b97a5181abf5d9e3029e18ee2b1c (diff)
Make wincolor crate compilable on non-Windows platforms.wincolor-0.1.0termcolor-0.1.0
-rw-r--r--wincolor/src/lib.rs229
-rw-r--r--wincolor/src/win.rs223
2 files changed, 231 insertions, 221 deletions
diff --git a/wincolor/src/lib.rs b/wincolor/src/lib.rs
index a210b4b2..d5a98f93 100644
--- a/wincolor/src/lib.rs
+++ b/wincolor/src/lib.rs
@@ -3,6 +3,8 @@ This crate provides a safe and simple Windows specific API to control
text attributes in the Windows console. Text attributes are limited to
foreground/background colors, as well as whether to make colors intense or not.
+Note that on non-Windows platforms, this crate is empty but will compile.
+
# Example
```no_run
@@ -15,228 +17,13 @@ con.reset().unwrap();
println!("This text will be normal.");
```
*/
+#[cfg(windows)]
extern crate kernel32;
+#[cfg(windows)]
extern crate winapi;
-use std::io;
-use std::mem;
-
-use winapi::{DWORD, HANDLE, WORD};
-use winapi::winbase::STD_OUTPUT_HANDLE;
-use winapi::wincon::{
- FOREGROUND_BLUE as FG_BLUE,
- FOREGROUND_GREEN as FG_GREEN,
- FOREGROUND_RED as FG_RED,
- FOREGROUND_INTENSITY as FG_INTENSITY,
-};
-
-const FG_CYAN: DWORD = FG_BLUE | FG_GREEN;
-const FG_MAGENTA: DWORD = FG_BLUE | FG_RED;
-const FG_YELLOW: DWORD = FG_GREEN | FG_RED;
-const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED;
-
-/// A Windows console.
-///
-/// This represents a very limited set of functionality available to a Windows
-/// console. In particular, it can only change text attributes such as color
-/// and intensity.
-///
-/// There is no way to "write" to this console. Simply write to
-/// stdout or stderr instead, while interleaving instructions to the console
-/// to change text attributes.
-///
-/// A common pitfall when using a console is to forget to flush writes to
-/// stdout before setting new text attributes.
-#[derive(Debug)]
-pub struct Console {
- handle: HANDLE,
- start_attr: TextAttributes,
- cur_attr: TextAttributes,
-}
-
-unsafe impl Send for Console {}
-
-impl Drop for Console {
- fn drop(&mut self) {
- unsafe { kernel32::CloseHandle(self.handle); }
- }
-}
-
-impl Console {
- /// Create a new Console to stdout.
- ///
- /// If there was a problem creating the console, then an error is returned.
- pub fn stdout() -> io::Result<Console> {
- let mut info = unsafe { mem::zeroed() };
- let (handle, res) = unsafe {
- let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE);
- (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
- };
- if res == 0 {
- return Err(io::Error::last_os_error());
- }
- let attr = TextAttributes::from_word(info.wAttributes);
- Ok(Console {
- handle: handle,
- start_attr: attr,
- cur_attr: attr,
- })
- }
-
- /// Applies the current text attributes.
- fn set(&mut self) -> io::Result<()> {
- let attr = self.cur_attr.to_word();
- let res = unsafe {
- kernel32::SetConsoleTextAttribute(self.handle, attr)
- };
- if res == 0 {
- return Err(io::Error::last_os_error());
- }
- Ok(())
- }
-
- /// Apply the given intensity and color attributes to the console
- /// foreground.
- ///
- /// If there was a problem setting attributes on the console, then an error
- /// is returned.
- pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
- self.cur_attr.fg_color = color;
- self.cur_attr.fg_intense = intense;
- self.set()
- }
-
- /// Apply the given intensity and color attributes to the console
- /// background.
- ///
- /// If there was a problem setting attributes on the console, then an error
- /// is returned.
- pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
- self.cur_attr.bg_color = color;
- self.cur_attr.bg_intense = intense;
- self.set()
- }
-
- /// Reset the console text attributes to their original settings.
- ///
- /// The original settings correspond to the text attributes on the console
- /// when this `Console` value was created.
- ///
- /// If there was a problem setting attributes on the console, then an error
- /// is returned.
- pub fn reset(&mut self) -> io::Result<()> {
- self.cur_attr = self.start_attr;
- self.set()
- }
-}
-
-/// A representation of text attributes for the Windows console.
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-struct TextAttributes {
- fg_color: Color,
- fg_intense: Intense,
- bg_color: Color,
- bg_intense: Intense,
-}
-
-impl TextAttributes {
- fn to_word(&self) -> WORD {
- let mut w = 0;
- w |= self.fg_color.to_fg();
- w |= self.fg_intense.to_fg();
- w |= self.bg_color.to_bg();
- w |= self.bg_intense.to_bg();
- w as WORD
- }
-
- fn from_word(word: WORD) -> TextAttributes {
- let attr = word as DWORD;
- TextAttributes {
- fg_color: Color::from_fg(attr),
- fg_intense: Intense::from_fg(attr),
- bg_color: Color::from_bg(attr),
- bg_intense: Intense::from_bg(attr),
- }
- }
-}
-
-/// Whether to use intense colors or not.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Intense {
- Yes,
- No,
-}
-
-impl Intense {
- fn to_bg(&self) -> DWORD {
- self.to_fg() << 4
- }
-
- fn from_bg(word: DWORD) -> Intense {
- Intense::from_fg(word >> 4)
- }
-
- fn to_fg(&self) -> DWORD {
- match *self {
- Intense::No => 0,
- Intense::Yes => FG_INTENSITY,
- }
- }
-
- fn from_fg(word: DWORD) -> Intense {
- if word & FG_INTENSITY > 0 {
- Intense::Yes
- } else {
- Intense::No
- }
- }
-}
-
-/// The set of available colors for use with a Windows console.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Color {
- Black,
- Blue,
- Green,
- Red,
- Cyan,
- Magenta,
- Yellow,
- White,
-}
-
-impl Color {
- fn to_bg(&self) -> DWORD {
- self.to_fg() << 4
- }
-
- fn from_bg(word: DWORD) -> Color {
- Color::from_fg(word >> 4)
- }
-
- fn to_fg(&self) -> DWORD {
- match *self {
- Color::Black => 0,
- Color::Blue => FG_BLUE,
- Color::Green => FG_GREEN,
- Color::Red => FG_RED,
- Color::Cyan => FG_CYAN,
- Color::Magenta => FG_MAGENTA,
- Color::Yellow => FG_YELLOW,
- Color::White => FG_WHITE,
- }
- }
+#[cfg(windows)]
+pub use win::*;
- fn from_fg(word: DWORD) -> Color {
- match word & 0b111 {
- FG_BLUE => Color::Blue,
- FG_GREEN => Color::Green,
- FG_RED => Color::Red,
- FG_CYAN => Color::Cyan,
- FG_MAGENTA => Color::Magenta,
- FG_YELLOW => Color::Yellow,
- FG_WHITE => Color::White,
- _ => Color::Black,
- }
- }
-}
+#[cfg(windows)]
+mod win;
diff --git a/wincolor/src/win.rs b/wincolor/src/win.rs
new file mode 100644
index 00000000..9c3cf76c
--- /dev/null
+++ b/wincolor/src/win.rs
@@ -0,0 +1,223 @@
+use std::io;
+use std::mem;
+
+use kernel32;
+use winapi::{DWORD, HANDLE, WORD};
+use winapi::winbase::STD_OUTPUT_HANDLE;
+use winapi::wincon::{
+ FOREGROUND_BLUE as FG_BLUE,
+ FOREGROUND_GREEN as FG_GREEN,
+ FOREGROUND_RED as FG_RED,
+ FOREGROUND_INTENSITY as FG_INTENSITY,
+};
+
+const FG_CYAN: DWORD = FG_BLUE | FG_GREEN;
+const FG_MAGENTA: DWORD = FG_BLUE | FG_RED;
+const FG_YELLOW: DWORD = FG_GREEN | FG_RED;
+const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED;
+
+/// A Windows console.
+///
+/// This represents a very limited set of functionality available to a Windows
+/// console. In particular, it can only change text attributes such as color
+/// and intensity.
+///
+/// There is no way to "write" to this console. Simply write to
+/// stdout or stderr instead, while interleaving instructions to the console
+/// to change text attributes.
+///
+/// A common pitfall when using a console is to forget to flush writes to
+/// stdout before setting new text attributes.
+#[derive(Debug)]
+pub struct Console {
+ handle: HANDLE,
+ start_attr: TextAttributes,
+ cur_attr: TextAttributes,
+}
+
+unsafe impl Send for Console {}
+
+impl Drop for Console {
+ fn drop(&mut self) {
+ unsafe { kernel32::CloseHandle(self.handle); }
+ }
+}
+
+impl Console {
+ /// Create a new Console to stdout.
+ ///
+ /// If there was a problem creating the console, then an error is returned.
+ pub fn stdout() -> io::Result<Console> {
+ let mut info = unsafe { mem::zeroed() };
+ let (handle, res) = unsafe {
+ let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE);
+ (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
+ };
+ if res == 0 {
+ return Err(io::Error::last_os_error());
+ }
+ let attr = TextAttributes::from_word(info.wAttributes);
+ Ok(Console {
+ handle: handle,
+ start_attr: attr,
+ cur_attr: attr,
+ })
+ }
+
+ /// Applies the current text attributes.
+ fn set(&mut self) -> io::Result<()> {
+ let attr = self.cur_attr.to_word();
+ let res = unsafe {
+ kernel32::SetConsoleTextAttribute(self.handle, attr)
+ };
+ if res == 0 {
+ return Err(io::Error::last_os_error());
+ }
+ Ok(())
+ }
+
+ /// Apply the given intensity and color attributes to the console
+ /// foreground.
+ ///
+ /// If there was a problem setting attributes on the console, then an error
+ /// is returned.
+ pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
+ self.cur_attr.fg_color = color;
+ self.cur_attr.fg_intense = intense;
+ self.set()
+ }
+
+ /// Apply the given intensity and color attributes to the console
+ /// background.
+ ///
+ /// If there was a problem setting attributes on the console, then an error
+ /// is returned.
+ pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
+ self.cur_attr.bg_color = color;
+ self.cur_attr.bg_intense = intense;
+ self.set()
+ }
+
+ /// Reset the console text attributes to their original settings.
+ ///
+ /// The original settings correspond to the text attributes on the console
+ /// when this `Console` value was created.
+ ///
+ /// If there was a problem setting attributes on the console, then an error
+ /// is returned.
+ pub fn reset(&mut self) -> io::Result<()> {
+ self.cur_attr = self.start_attr;
+ self.set()
+ }
+}
+
+/// A representation of text attributes for the Windows console.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+struct TextAttributes {
+ fg_color: Color,
+ fg_intense: Intense,
+ bg_color: Color,
+ bg_intense: Intense,
+}
+
+impl TextAttributes {
+ fn to_word(&self) -> WORD {
+ let mut w = 0;
+ w |= self.fg_color.to_fg();
+ w |= self.fg_intense.to_fg();
+ w |= self.bg_color.to_bg();
+ w |= self.bg_intense.to_bg();
+ w as WORD
+ }
+
+ fn from_word(word: WORD) -> TextAttributes {
+ let attr = word as DWORD;
+ TextAttributes {
+ fg_color: Color::from_fg(attr),
+ fg_intense: Intense::from_fg(attr),
+ bg_color: Color::from_bg(attr),
+ bg_intense: Intense::from_bg(attr),
+ }
+ }
+}
+
+/// Whether to use intense colors or not.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum Intense {
+ Yes,
+ No,
+}
+
+impl Intense {
+ fn to_bg(&self) -> DWORD {
+ self.to_fg() << 4
+ }
+
+ fn from_bg(word: DWORD) -> Intense {
+ Intense::from_fg(word >> 4)
+ }
+
+ fn to_fg(&self) -> DWORD {
+ match *self {
+ Intense::No => 0,
+ Intense::Yes => FG_INTENSITY,
+ }
+ }
+
+ fn from_fg(word: DWORD) -> Intense {
+ if word & FG_INTENSITY > 0 {
+ Intense::Yes
+ } else {
+ Intense::No
+ }
+ }
+}
+
+/// The set of available colors for use with a Windows console.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum Color {
+ Black,
+ Blue,
+ Green,
+ Red,
+ Cyan,
+ Magenta,
+ Yellow,
+ White,
+}
+
+impl Color {
+ fn to_bg(&self) -> DWORD {
+ self.to_fg() << 4
+ }
+
+ fn from_bg(word: DWORD) -> Color {
+ Color::from_fg(word >> 4)
+ }
+
+ fn to_fg(&self) -> DWORD {
+ match *self {
+ Color::Black => 0,
+ Color::Blue => FG_BLUE,
+ Color::Green => FG_GREEN,
+ Color::Red => FG_RED,
+ Color::Cyan => FG_CYAN,
+ Color::Magenta => FG_MAGENTA,
+ Color::Yellow => FG_YELLOW,
+ Color::White => FG_WHITE,
+ }
+ }
+
+ fn from_fg(word: DWORD) -> Color {
+ match word & 0b111 {
+ FG_BLUE => Color::Blue,
+ FG_GREEN => Color::Green,
+ FG_RED => Color::Red,
+ FG_CYAN => Color::Cyan,
+ FG_MAGENTA => Color::Magenta,
+ FG_YELLOW => Color::Yellow,
+ FG_WHITE => Color::White,
+ _ => Color::Black,
+ }
+ }
+}