1#[cfg(windows)] extern crate winapi;
2#[cfg(windows)] use std::io::Write;
3
4#[cfg(windows)]
5static mut CONSOLE_CONFIG: winapi::shared::minwindef::WORD = 0;
6
7#[cfg(windows)]
8fn get_handle() -> std::io::Result<winapi::um::winnt::HANDLE> {
9 use winapi::um::winnt::{ FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE };
10
11 let handle = unsafe {
12 winapi::um::fileapi::CreateFileA(
13 b"CONOUT$\0".as_ptr() as *const i8,
14 GENERIC_READ | GENERIC_WRITE,
15 FILE_SHARE_WRITE,
16 std::ptr::null_mut(),
17 winapi::um::fileapi::OPEN_EXISTING,
18 0,
19 std::ptr::null_mut(),
20 )
21 };
22 if handle == winapi::um::handleapi::INVALID_HANDLE_VALUE {
23 Err(std::io::Error::last_os_error())
24 } else { Ok(handle) }
25}
26
27#[cfg(windows)]
29fn make_win_color(fg: i16, bg: i16) -> winapi::shared::minwindef::WORD {
30 unsafe {
31 let mut new_color: winapi::shared::minwindef::WORD = CONSOLE_CONFIG;
32 if fg != -1 {
33 new_color &= !(new_color & 0x0F);
34 new_color |= fg as winapi::shared::minwindef::WORD;
35 }
36 if bg != -1 {
37 new_color &= !(new_color & 0xF0);
38 new_color |= bg as winapi::shared::minwindef::WORD;
39 }
40 new_color
41 }
42}
43
44macro_rules! make_color_fns {
45 ($name:ident, $linux_code:expr, $win_code_fg:expr, $win_code_bg:expr) => {
46 #[cfg(not(windows))]
47 pub fn $name() -> String {
48 $linux_code.to_string()
49 }
50
51 #[cfg(windows)]
52 pub fn $name() -> String {
53 std::io::stdout().flush().expect("Flush stdout failed!");
54 unsafe {
55 CONSOLE_CONFIG = make_win_color($win_code_fg as i16, $win_code_bg as i16);
56 let handle = get_handle();
57 match handle {
58 Ok(h) => { winapi::um::wincon::SetConsoleTextAttribute(h, CONSOLE_CONFIG); }
59 Err(e) => { return format!("{}", e) }
60 };
61 }
62 "".to_string()
63 }
64 };
65}
66
67struct ColorString(String);
68
69impl std::fmt::Display for ColorString {
70 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
71 f.write_str(&self.0)?;
72 Ok(())
73 }
74}
75
76impl From<String> for ColorString {
77 #[inline]
78 fn from(s: String) -> Self {
79 Self {
80 0: s
81 }
82 }
83}
84
85impl ColorString {
86 pub fn new(s: &str) -> Self {
87 Self {
88 0: s.to_string()
89 }
90 }
91}
92
93
94make_color_fns!(reset, ColorString::new("\x1B[00m"), winapi::um::wincon::FOREGROUND_RED | winapi::um::wincon::FOREGROUND_GREEN | winapi::um::wincon::FOREGROUND_BLUE, 0);
95
96make_color_fns!(white, ColorString::new("\x1B[97m"), winapi::um::wincon::FOREGROUND_RED | winapi::um::wincon::FOREGROUND_GREEN | winapi::um::wincon::FOREGROUND_BLUE, -1);
97make_color_fns!(grey, ColorString::new("\x1B[37m"), 0 | winapi::um::wincon::FOREGROUND_INTENSITY, -1);
98make_color_fns!(black, ColorString::new("\x1B[30m"), 0, -1);
99make_color_fns!(red, ColorString::new("\x1B[31m"), winapi::um::wincon::FOREGROUND_RED, -1);
100make_color_fns!(yellow, ColorString::new("\x1B[33m"), winapi::um::wincon::FOREGROUND_RED | winapi::um::wincon::FOREGROUND_GREEN, -1);
101make_color_fns!(green, ColorString::new("\x1B[32m"), winapi::um::wincon::FOREGROUND_GREEN, -1);
102make_color_fns!(cyan, ColorString::new("\x1B[36m"), winapi::um::wincon::FOREGROUND_GREEN | winapi::um::wincon::FOREGROUND_BLUE, -1);
103make_color_fns!(blue, ColorString::new("\x1B[34m"), winapi::um::wincon::FOREGROUND_BLUE, -1);
104make_color_fns!(magenta, ColorString::new("\x1B[35m"), winapi::um::wincon::FOREGROUND_RED | winapi::um::wincon::FOREGROUND_BLUE, -1);
105
106make_color_fns!(on_white, ColorString::new("\x1B[107m"), -1, winapi::um::wincon::BACKGROUND_RED | winapi::um::wincon::BACKGROUND_GREEN | winapi::um::wincon::BACKGROUND_BLUE);
107make_color_fns!(on_grey, ColorString::new("\x1B[100m"), -1, 0 | winapi::um::wincon::BACKGROUND_INTENSITY);
108make_color_fns!(on_black, ColorString::new("\x1B[40m"), -1, 0);
109make_color_fns!(on_red, ColorString::new("\x1B[41m"), -1, winapi::um::wincon::BACKGROUND_RED);
110make_color_fns!(on_yellow, ColorString::new("\x1B[43m"), -1, winapi::um::wincon::BACKGROUND_RED | winapi::um::wincon::BACKGROUND_GREEN);
111make_color_fns!(on_green, ColorString::new("\x1B[42m"), -1, winapi::um::wincon::BACKGROUND_GREEN);
112make_color_fns!(on_cyan, ColorString::new("\x1B[46m"), -1, winapi::um::wincon::BACKGROUND_GREEN | winapi::um::wincon::BACKGROUND_BLUE);
113make_color_fns!(on_blue, ColorString::new("\x1B[44m"), -1, winapi::um::wincon::BACKGROUND_BLUE);
114make_color_fns!(on_magenta, ColorString::new("\x1B[45m"), -1, winapi::um::wincon::BACKGROUND_RED | winapi::um::wincon::BACKGROUND_BLUE);