use std::env;
use std::io::{self, IsTerminal};
use crossterm::terminal;
use crate::ui::terminal_supports_cursor;
pub(crate) const RESET: &str = "\x1b[0m";
pub(crate) const WARM_WHITE_BOLD: &str = "\x1b[1;38;2;255;244;226m";
pub(crate) const MUTED: &str = "\x1b[38;2;178;160;142m";
pub(crate) const ACCENT: &str = "\x1b[38;2;255;165;0m";
pub(crate) const ACCENT_BOLD: &str = "\x1b[1;38;2;255;165;0m";
pub(crate) const INFO_BLUE: &str = "\x1b[1;38;2;96;165;250m";
pub(crate) const SUCCESS_GREEN: &str = "\x1b[1;38;2;74;222;128m";
pub(crate) const WARNING_AMBER: &str = "\x1b[1;38;2;251;191;36m";
pub(crate) const WARNING_AMBER_PLAIN: &str = "\x1b[38;2;251;191;36m";
pub(crate) const ERROR_RED: &str = "\x1b[1;38;2;248;113;113m";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct Theme {
pub(crate) reset: &'static str,
pub(crate) title: &'static str,
pub(crate) accent_bold: &'static str,
pub(crate) muted: &'static str,
pub(crate) accent: &'static str,
pub(crate) info: &'static str,
pub(crate) success: &'static str,
pub(crate) warning: &'static str,
pub(crate) warning_plain: &'static str,
pub(crate) error: &'static str,
}
impl Default for Theme {
fn default() -> Self {
Self {
reset: RESET,
title: WARM_WHITE_BOLD,
accent_bold: ACCENT_BOLD,
muted: MUTED,
accent: ACCENT,
info: INFO_BLUE,
success: SUCCESS_GREEN,
warning: WARNING_AMBER,
warning_plain: WARNING_AMBER_PLAIN,
error: ERROR_RED,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct RenderOptions {
pub(crate) color: bool,
pub(crate) width: usize,
pub(crate) cursor: bool,
pub(crate) theme: Theme,
}
impl Default for RenderOptions {
fn default() -> Self {
Self::stdout()
}
}
impl RenderOptions {
#[cfg(test)]
pub(crate) fn no_color() -> Self {
Self {
color: false,
cursor: false,
..Self::default()
}
}
pub(crate) fn stdout() -> Self {
let tty = io::stdout().is_terminal();
Self {
color: color_enabled(tty),
width: terminal_width(tty),
cursor: tty && terminal_supports_cursor(),
theme: Theme::default(),
}
}
pub(crate) fn stderr() -> Self {
let tty = io::stderr().is_terminal();
Self {
color: color_enabled(tty),
width: terminal_width(tty),
cursor: tty && terminal_supports_cursor(),
theme: Theme::default(),
}
}
}
pub(crate) fn color_enabled(is_terminal: bool) -> bool {
is_terminal && env::var_os("NO_COLOR").is_none() && terminal_supports_cursor()
}
pub(crate) fn terminal_width(is_terminal: bool) -> usize {
if is_terminal {
terminal::size()
.ok()
.map_or(100, |(width, _)| usize::from(width))
} else {
100
}
.max(20)
}