use std::io::IsTerminal;
#[derive(Debug, Clone)]
pub struct Environment {
pub is_ci: bool,
pub is_tty: bool,
pub stdin_is_tty: bool,
pub stderr_is_tty: bool,
pub width: Option<u16>,
pub height: Option<u16>,
}
impl Environment {
pub fn detect() -> Self {
let (width, height) = crossterm::terminal::size().ok().unzip();
Self {
is_ci: is_ci(),
is_tty: is_tty(),
stdin_is_tty: std::io::stdin().is_terminal(),
stderr_is_tty: std::io::stderr().is_terminal(),
width,
height,
}
}
pub fn should_disable_colors(&self) -> bool {
!self.is_tty
|| std::env::var("NO_COLOR").is_ok()
|| std::env::var("TERM").map(|t| t == "dumb").unwrap_or(false)
}
pub fn should_disable_interactive(&self) -> bool {
self.is_ci || !self.stdin_is_tty
}
}
impl Default for Environment {
fn default() -> Self {
Self::detect()
}
}
pub fn is_ci() -> bool {
std::env::var("CI").is_ok()
|| std::env::var("GITHUB_ACTIONS").is_ok()
|| std::env::var("GITLAB_CI").is_ok()
|| std::env::var("JENKINS_URL").is_ok()
|| std::env::var("BUILD_NUMBER").is_ok()
|| std::env::var("TRAVIS").is_ok()
|| std::env::var("CIRCLECI").is_ok()
|| std::env::var("TF_BUILD").is_ok()
|| std::env::var("BITBUCKET_BUILD_NUMBER").is_ok()
|| std::env::var("APPVEYOR").is_ok()
|| std::env::var("DRONE").is_ok()
|| std::env::var("BUILDKITE").is_ok()
|| std::env::var("TEAMCITY_VERSION").is_ok()
|| std::env::var("CI_NAME").map(|v| v == "codeship").unwrap_or(false)
}
pub fn is_tty() -> bool {
std::io::stdout().is_terminal()
}
#[allow(dead_code)]
pub fn terminal_size() -> (u16, u16) {
crossterm::terminal::size().unwrap_or((80, 24))
}
#[allow(dead_code)]
pub fn term_program() -> Option<String> {
std::env::var("TERM_PROGRAM").ok()
}
#[allow(dead_code)]
pub fn is_terminal_emulator(name: &str) -> bool {
term_program()
.map(|t| t.to_lowercase().contains(&name.to_lowercase()))
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_environment_detect() {
let env = Environment::detect();
let _ = env.is_ci;
let _ = env.is_tty;
}
#[test]
fn test_is_ci_returns_bool() {
let _ = is_ci();
}
#[test]
fn test_is_tty_returns_bool() {
let _ = is_tty();
}
#[test]
fn test_terminal_size_has_fallback() {
let (w, h) = terminal_size();
assert!(w > 0);
assert!(h > 0);
}
#[test]
fn test_should_disable_colors() {
let env = Environment {
is_ci: false,
is_tty: false, stdin_is_tty: false,
stderr_is_tty: false,
width: None,
height: None,
};
assert!(env.should_disable_colors());
}
}