aver/
colors.rs

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/// creates the console color, preserving the pervious color settings if an arg is set to -1
28#[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);