nu_ansi_term/
windows.rs

1/// Enables ANSI code support on Windows 10.
2///
3/// This uses Windows API calls to alter the properties of the console that
4/// the program is running in.
5///
6/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
7///
8/// Returns a `Result` with the Windows error code if unsuccessful.
9#[cfg(windows)]
10pub fn enable_ansi_support() -> Result<(), u32> {
11    // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76%
12    use windows::w;
13    use windows::Win32::Foundation::GetLastError;
14    use windows::Win32::Foundation::INVALID_HANDLE_VALUE;
15    use windows::Win32::Storage::FileSystem::{CreateFileW, OPEN_EXISTING};
16    use windows::Win32::Storage::FileSystem::{
17        FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_SHARE_WRITE,
18    };
19    use windows::Win32::System::Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
20    use windows::Win32::System::Console::{GetConsoleMode, SetConsoleMode};
21
22    unsafe {
23        // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
24        // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
25        let console_handle = CreateFileW(
26            w!("CONOUT$"),
27            FILE_GENERIC_READ | FILE_GENERIC_WRITE,
28            FILE_SHARE_WRITE,
29            std::ptr::null_mut(), // SECURITY_ATTRIBUTES
30            OPEN_EXISTING,
31            0, // FILE_FLAGS_AND_ATTRIBUTES
32            0, // hTemplateFile: HANDLE
33        );
34        if console_handle == INVALID_HANDLE_VALUE {
35            return Err(GetLastError());
36        }
37
38        // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
39        let mut console_mode = 0;
40        if 0 == GetConsoleMode(console_handle, &mut console_mode) {
41            return Err(GetLastError());
42        }
43
44        // VT processing not already enabled?
45        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
46            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
47            if 0 == SetConsoleMode(
48                console_handle,
49                console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING,
50            ) {
51                return Err(GetLastError());
52            }
53        }
54
55        Ok(())
56    }
57}