crossterm 0.17.7

An crossplatform terminal library for manipulating terminals.
Documentation
use crossterm_winapi::ConsoleMode;
use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;

use lazy_static::lazy_static;

use crate::Result;

/// Toggle virtual terminal processing.
///
/// This method attempts to toggle virtual terminal processing for this
/// console. If there was a problem toggling it, then an error returned.
/// On success, the caller may assume that toggling it was successful.
///
/// When virtual terminal processing is enabled, characters emitted to the
/// console are parsed for VT100 and similar control character sequences
/// that control color and other similar operations.
pub(crate) fn set_virtual_terminal_processing(yes: bool) -> Result<()> {
    let mask = ENABLE_VIRTUAL_TERMINAL_PROCESSING;

    let console_mode = ConsoleMode::new()?;
    let old_mode = console_mode.mode()?;

    let new_mode = if yes {
        old_mode | mask
    } else {
        old_mode & !mask
    };

    if old_mode != new_mode {
        console_mode.set_mode(new_mode)?;
    }

    Ok(())
}

lazy_static! {
    static ref SUPPORTS_ANSI_ESCAPE_CODES: bool = {
        // Some terminals on windows like GitBash can't use WinaApi calls directly
        // so when we try to enable the ANSI-flag for windows this won't work.
        // Because of that we should check first if the TERM-variable is set
        // and see if the current terminal is a terminal who does support ANSI.
        if is_specific_term() {
            true
        } else {
            // if it is not listed we should try with WinApi to check if we do support ANSI-codes.
            set_virtual_terminal_processing(true)
                .map(|_| true)
                .unwrap_or(false)
        }
    };
}

pub fn supports_ansi() -> bool {
    *SUPPORTS_ANSI_ESCAPE_CODES
}

// Checks if the 'TERM' environment variable is set to check if the terminal supports ANSI-codes.
// I got the list of terminals from here: https://github.com/keqingrong/supports-ansi/blob/master/index.js
fn is_specific_term() -> bool {
    const TERMS: [&str; 15] = [
        "xterm",  // xterm, PuTTY, Mintty
        "rxvt",   // RXVT
        "eterm",  // Eterm
        "screen", // GNU screen, tmux
        "tmux",   // tmux
        "vt100", "vt102", "vt220", "vt320",   // DEC VT series
        "ansi",    // ANSI
        "scoansi", // SCO ANSI
        "cygwin",  // Cygwin, MinGW
        "linux",   // Linux console
        "konsole", // Konsole
        "bvterm",  // Bitvise SSH Client
    ];

    match std::env::var("TERM") {
        Ok(val) => val != "dumb" || TERMS.contains(&val.as_str()),
        Err(_) => false,
    }
}