use std::io::IsTerminal;
use std::time::Duration;
use terminal_colorsaurus::{QueryOptions, ThemeMode, theme_mode};
use crate::theme::Appearance;
fn appearance_of(mode: ThemeMode) -> Appearance {
match mode {
ThemeMode::Light => Appearance::Light,
ThemeMode::Dark => Appearance::Dark,
}
}
fn gate_allows(stderr_is_tty: bool, in_foreground: bool) -> bool {
stderr_is_tty && in_foreground
}
#[cfg(unix)]
fn in_foreground_pgrp() -> bool {
use std::os::fd::AsRawFd;
let fd = std::io::stderr().as_raw_fd();
unsafe { libc::tcgetpgrp(fd) == libc::getpgrp() }
}
#[cfg(not(unix))]
fn in_foreground_pgrp() -> bool {
true
}
pub fn probe(timeout: Duration) -> Option<Appearance> {
if !gate_allows(std::io::stderr().is_terminal(), in_foreground_pgrp()) {
return None;
}
let mut options = QueryOptions::default();
options.timeout = timeout;
match theme_mode(options) {
Ok(mode) => Some(appearance_of(mode)),
Err(err) => {
if std::env::var_os("RAT_DEBUG_APPEARANCE").is_some() {
eprintln!("rat: appearance query failed: {err}");
}
None
}
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
#[test]
fn the_gate_needs_a_terminal_on_stderr_and_the_foreground() {
assert!(gate_allows(true, true));
assert!(!gate_allows(false, true));
assert!(!gate_allows(true, false));
assert!(!gate_allows(false, false));
}
#[test]
fn theme_modes_map_onto_appearances() {
assert_eq!(
appearance_of(terminal_colorsaurus::ThemeMode::Light),
Appearance::Light
);
assert_eq!(
appearance_of(terminal_colorsaurus::ThemeMode::Dark),
Appearance::Dark
);
}
#[test]
fn probe_has_the_expected_shape() {
let f: fn(Duration) -> Option<Appearance> = probe;
let _ = f;
}
}