Skip to main content

upgate_presentation/
theme.rs

1use std::io::IsTerminal;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4enum OutputMode {
5    Plain,
6    Styled { color: bool },
7}
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct OutputTheme {
11    mode: OutputMode,
12    pub verbose: bool,
13}
14
15impl OutputTheme {
16    pub fn from_environment(options: ThemeOptions) -> Self {
17        Self::from_terminal(
18            options,
19            TerminalCapabilities {
20                stdout_is_tty: std::io::stdout().is_terminal(),
21                no_color_env: std::env::var_os("NO_COLOR").is_some_and(|value| !value.is_empty()),
22                term_is_dumb: std::env::var_os("TERM").is_some_and(|value| value == "dumb"),
23            },
24        )
25    }
26    pub const fn from_terminal(options: ThemeOptions, capabilities: TerminalCapabilities) -> Self {
27        let plain = options.plain || !capabilities.stdout_is_tty;
28        let mode = if plain {
29            OutputMode::Plain
30        } else {
31            OutputMode::Styled {
32                color: !options.no_color
33                    && !capabilities.no_color_env
34                    && !capabilities.term_is_dumb,
35            }
36        };
37
38        Self {
39            mode,
40            verbose: options.verbose,
41        }
42    }
43    pub const fn is_plain(self) -> bool {
44        matches!(self.mode, OutputMode::Plain)
45    }
46    pub const fn color(self) -> bool {
47        match self.mode {
48            OutputMode::Plain => false,
49            OutputMode::Styled { color } => color,
50        }
51    }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
55pub struct ThemeOptions {
56    pub plain: bool,
57    pub no_color: bool,
58    pub verbose: bool,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct TerminalCapabilities {
63    pub stdout_is_tty: bool,
64    pub no_color_env: bool,
65    pub term_is_dumb: bool,
66}