use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum OutputMode {
#[default]
Normal,
Stream { no_prefix: bool },
File { path: PathBuf, no_prefix: bool },
Tui,
}
impl OutputMode {
pub fn from_args(stream: bool, output_dir: Option<PathBuf>) -> Self {
Self::from_args_with_no_prefix(stream, output_dir, false)
}
pub fn from_args_with_no_prefix(
stream: bool,
output_dir: Option<PathBuf>,
no_prefix: bool,
) -> Self {
if let Some(dir) = output_dir {
OutputMode::File {
path: dir,
no_prefix,
}
} else if stream {
OutputMode::Stream { no_prefix }
} else if is_tty() {
OutputMode::Tui
} else {
OutputMode::Normal
}
}
pub fn from_args_explicit(stream: bool, output_dir: Option<PathBuf>, enable_tui: bool) -> Self {
Self::from_args_explicit_with_no_prefix(stream, output_dir, enable_tui, false)
}
pub fn from_args_explicit_with_no_prefix(
stream: bool,
output_dir: Option<PathBuf>,
enable_tui: bool,
no_prefix: bool,
) -> Self {
if let Some(dir) = output_dir {
OutputMode::File {
path: dir,
no_prefix,
}
} else if stream {
OutputMode::Stream { no_prefix }
} else if enable_tui && is_tty() {
OutputMode::Tui
} else {
OutputMode::Normal
}
}
pub fn is_normal(&self) -> bool {
matches!(self, OutputMode::Normal)
}
pub fn is_stream(&self) -> bool {
matches!(self, OutputMode::Stream { .. })
}
pub fn is_file(&self) -> bool {
matches!(self, OutputMode::File { .. })
}
pub fn is_tui(&self) -> bool {
matches!(self, OutputMode::Tui)
}
pub fn output_dir(&self) -> Option<&PathBuf> {
match self {
OutputMode::File { path, .. } => Some(path),
_ => None,
}
}
pub fn is_no_prefix(&self) -> bool {
match self {
OutputMode::Stream { no_prefix } => *no_prefix,
OutputMode::File { no_prefix, .. } => *no_prefix,
_ => false,
}
}
}
pub fn is_tty() -> bool {
use std::io::IsTerminal;
let is_terminal = std::io::stdout().is_terminal();
let is_ci = 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("TRAVIS").is_ok();
is_terminal && !is_ci
}
pub fn should_use_colors() -> bool {
if !is_tty() {
return false;
}
if std::env::var("NO_COLOR").is_ok() {
return false;
}
if let Ok(term) = std::env::var("TERM") {
if term == "dumb" {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_output_mode_from_args() {
let mode = OutputMode::from_args(false, None);
assert!(mode.is_normal());
let mode = OutputMode::from_args(true, None);
assert!(mode.is_stream());
let dir = PathBuf::from("/tmp/output");
let mode = OutputMode::from_args(true, Some(dir.clone()));
assert!(mode.is_file());
assert_eq!(mode.output_dir(), Some(&dir));
}
#[test]
fn test_output_mode_checks() {
let normal = OutputMode::Normal;
assert!(normal.is_normal());
assert!(!normal.is_stream());
assert!(!normal.is_file());
let stream = OutputMode::Stream { no_prefix: false };
assert!(!stream.is_normal());
assert!(stream.is_stream());
assert!(!stream.is_file());
let file = OutputMode::File {
path: PathBuf::from("/tmp"),
no_prefix: false,
};
assert!(!file.is_normal());
assert!(!file.is_stream());
assert!(file.is_file());
}
#[test]
fn test_default_output_mode() {
let mode = OutputMode::default();
assert!(mode.is_normal());
}
#[test]
fn test_no_prefix_option() {
let mode = OutputMode::from_args_with_no_prefix(true, None, true);
assert!(mode.is_stream());
assert!(mode.is_no_prefix());
let mode = OutputMode::from_args_with_no_prefix(true, None, false);
assert!(mode.is_stream());
assert!(!mode.is_no_prefix());
let dir = PathBuf::from("/tmp/output");
let mode = OutputMode::from_args_with_no_prefix(false, Some(dir.clone()), true);
assert!(mode.is_file());
assert!(mode.is_no_prefix());
assert_eq!(mode.output_dir(), Some(&dir));
let mode = OutputMode::Normal;
assert!(!mode.is_no_prefix());
}
}