yansi/
windows.rs

1#[cfg(windows)]
2#[allow(non_camel_case_types, non_snake_case)]
3mod windows_console {
4    use core::ffi::c_void;
5
6    type c_ulong = u32;
7    type c_int = i32;
8    type wchar_t = u16;
9
10    type DWORD = c_ulong;
11    type LPDWORD = *mut DWORD;
12    type HANDLE = *mut c_void;
13    type BOOL = c_int;
14    type LPCWSTR = *const WCHAR;
15    type WCHAR = wchar_t;
16    type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
17    type LPVOID = *mut c_void;
18
19    #[repr(C)]
20    pub struct SECURITY_ATTRIBUTES {
21        pub nLength: DWORD,
22        pub lpSecurityDescriptor: LPVOID,
23        pub bInheritHandle: BOOL,
24    }
25
26    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: DWORD = 0x0004;
27    const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
28    const FALSE: BOOL = 0;
29    const TRUE: BOOL = 1;
30
31    const GENERIC_READ: DWORD = 0x80000000;
32    const GENERIC_WRITE: DWORD = 0x40000000;
33
34    const FILE_SHARE_READ: DWORD = 0x00000001;
35    const FILE_SHARE_WRITE: DWORD = 0x00000002;
36    const OPEN_EXISTING: DWORD = 3;
37
38    // This is the win32 console API, taken from the 'winapi' crate.
39    extern "system" {
40        fn CreateFileW(
41            lpFileName: LPCWSTR,
42            dwDesiredAccess: DWORD,
43            dwShareMode: DWORD,
44            lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
45            dwCreationDisposition: DWORD,
46            dwFlagsAndAttributes: DWORD,
47            hTemplateFile: HANDLE
48        ) -> HANDLE;
49
50        fn GetLastError() -> DWORD;
51        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
52        fn SetConsoleMode(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL;
53    }
54
55    fn get_output_handle() -> Result<HANDLE, DWORD> {
56        // This is "CONOUT$\0" UTF-16 encoded.
57        const CONOUT: &[u16] = &[0x43, 0x4F, 0x4E, 0x4F, 0x55, 0x54, 0x24, 0x00];
58
59        let raw_handle = unsafe {
60            CreateFileW(
61                CONOUT.as_ptr(),
62                GENERIC_READ | GENERIC_WRITE,
63                FILE_SHARE_READ | FILE_SHARE_WRITE,
64                core::ptr::null_mut(),
65                OPEN_EXISTING,
66                0,
67                core::ptr::null_mut(),
68            )
69        };
70
71        if raw_handle == INVALID_HANDLE_VALUE {
72            return Err(6);
73        }
74
75        Ok(raw_handle)
76    }
77
78    unsafe fn enable_vt(handle: HANDLE) -> Result<(), DWORD> {
79        let mut dw_mode: DWORD = 0;
80        if GetConsoleMode(handle, &mut dw_mode) == FALSE {
81            return Err(GetLastError());
82        }
83
84        dw_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
85        match SetConsoleMode(handle, dw_mode) {
86            result if result == TRUE => Ok(()),
87            _ => Err(GetLastError())
88        }
89    }
90
91    unsafe fn enable_ansi_colors_raw() -> Result<bool, DWORD> {
92        enable_vt(get_output_handle()?)?;
93        Ok(true)
94    }
95
96    #[inline(always)]
97    pub fn enable() -> bool {
98        unsafe { enable_ansi_colors_raw().unwrap_or(false) }
99    }
100
101    // Try to enable colors on Windows, and try to do it at most once.
102    pub fn cache_enable() -> bool {
103        use crate::condition::CachedBool;
104
105        static ENABLED: CachedBool = CachedBool::new();
106        ENABLED.get_or_init(enable)
107    }
108}
109
110#[cfg(not(windows))]
111mod windows_console {
112    #[inline(always)]
113    #[allow(dead_code)]
114    pub fn enable() -> bool { true }
115
116    #[inline(always)]
117    pub fn cache_enable() -> bool { true }
118}
119
120// pub use self::windows_console::enable;
121pub use self::windows_console::cache_enable;