1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
// Copyright 2017 Lyndon Brown // // Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not // copy, modify, or distribute this file except in compliance with said license. You can find copies // of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at // <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0> // respectively. //! Formatted output support helpers /// Are ANSI format sequences supported on stdout? /// /// - On Unix this is reliable, returning `true` only if **stdout** is connected to a tty (as /// opposed to being redirected to a file or other program). /// - On Windows, this gives an answer on the same principle, however even if returning `true` such /// that we know we are connected to a terminal, this does not mean that the terminal actually /// supports ANSI control sequences. Before Windows 10 you should assume not. On Windows 10+ you /// must use the [`enable_ansi_support()`] function to turn on support. #[inline(always)] pub fn fmt_supported_stdout() -> bool { atty::is(atty::Stream::Stdout) } /// Are ANSI format sequences supported on stderr? /// /// - On Unix this is reliable, returning `true` only if **stderr** is connected to a tty (as /// opposed to being redirected to a file or other program). /// - On Windows, this gives an answer on the same principle, however even if returning `true` such /// that we know we are connected to a terminal, this does not mean that the terminal actually /// supports ANSI control sequences. Before Windows 10 you should assume not. On Windows 10+ you /// must use the [`enable_ansi_support()`] function to turn on support. #[inline(always)] pub fn fmt_supported_stderr() -> bool { atty::is(atty::Stream::Stderr) } /// Should I use formatting on stdout? /// /// Convenience helper, taking user preference, and checking support. Combines them to give an /// answer of `true` for yes, `false` for no. #[inline(always)] pub fn use_fmt_stdout(user_pref: bool) -> bool { user_pref && fmt_supported_stdout() } /// Should I use formatting on stderr? /// /// Convenience helper, taking user preference, and checking support. Combines them to give an /// answer of `true` for yes, `false` for no. #[inline(always)] pub fn use_fmt_stderr(user_pref: bool) -> bool { user_pref && fmt_supported_stderr() } /* Copied and slightly modified from the `ansi_term` crate (MIT licensed). */ /// Enables ANSI code support on Windows 10. /// /// This uses Windows API calls to alter the properties of the console that /// the program is running in. /// /// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx /// /// Returns a `Result` with the Windows error code if unsuccessful. #[cfg(windows)] pub fn enable_ansi_support() -> Result<(), u32> { use winapi::um::processenv::GetStdHandle; use winapi::um::errhandlingapi::GetLastError; use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; const STD_OUT_HANDLE: u32 = -11i32 as u32; const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; macro_rules! handle_error { ( $result:expr ) => { match GetLastError() { 0 => Ok($result), e => Err(e), } }; } unsafe { // https://docs.microsoft.com/en-us/windows/console/getstdhandle let std_out_handle = handle_error!(GetStdHandle(STD_OUT_HANDLE))?; // https://docs.microsoft.com/en-us/windows/console/getconsolemode let mut console_mode: u32 = 0; handle_error!(GetConsoleMode(std_out_handle, &mut console_mode))?; // VT processing not already enabled? if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { // https://docs.microsoft.com/en-us/windows/console/setconsolemode handle_error!(SetConsoleMode(std_out_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING))?; } } Ok(()) }