#[allow(clippy::enum_glob_use)]
use anstyle::AnsiColor::*;
use anstyle::Color::Ansi;
use clap::builder::styling::Styles;
use colorchoice::ColorChoice;
use std::borrow::Cow;
use std::io::IsTerminal;
use std::sync::LazyLock;
const _ERROR: anstyle::Style = anstyle::Style::new().bold().fg_color(Some(Ansi(Red)));
const _WARNING: anstyle::Style = anstyle::Style::new().bold().fg_color(Some(Ansi(Yellow)));
const _INFO: anstyle::Style = anstyle::Style::new().fg_color(Some(Ansi(Cyan)));
const _SUCCESS: anstyle::Style = anstyle::Style::new().fg_color(Some(Ansi(Green)));
const _HEADER: anstyle::Style = anstyle::Style::new()
.underline()
.fg_color(Some(Ansi(Yellow)));
pub(crate) const CLAP_STYLES: Styles = Styles::styled()
.usage(_HEADER)
.header(_HEADER)
.literal(anstyle::Style::new().bold())
.invalid(_WARNING)
.error(_ERROR)
.valid(_INFO.bold().underline())
.placeholder(_INFO);
macro_rules! wrap {
($func:ident, $def:ident) => {
#[allow(clippy::missing_const_for_fn)]
#[allow(dead_code)] #[must_use]
#[doc = stringify!($func)]
pub fn $func() -> anstyle::Style {
if use_colours() {
$def
} else {
anstyle::Style::new()
}
}
};
}
wrap!(error, _ERROR);
wrap!(warning, _WARNING);
wrap!(info, _INFO);
wrap!(success, _SUCCESS);
wrap!(header, _HEADER);
#[must_use]
pub(crate) fn reset() -> impl core::fmt::Display + Copy {
error().render_reset()
}
pub(crate) static TABLE_STYLE: LazyLock<tabled::settings::Theme> = LazyLock::new(|| {
use tabled::settings::style::Style;
if cfg!(windows) {
Style::psql().into()
} else {
Style::sharp().into()
}
});
#[must_use]
pub fn use_colours() -> bool {
console::colors_enabled()
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
clap::ValueEnum,
strum_macros::EnumString,
strum_macros::VariantNames,
serde::Serialize,
enumscribe::EnumDeserialize,
)]
#[serde(rename_all = "lowercase")]
#[strum(ascii_case_insensitive)]
#[enumscribe(case_insensitive)]
pub enum ColourMode {
#[value(alias = "on", alias = "yes")]
Always,
#[value(alias = "off", alias = "no", alias = "none")]
Never,
Auto,
}
pub(crate) fn autodetect_colour() -> bool {
let clicolor_force = std::env::var("CLICOLOR_FORCE").unwrap_or_default();
let no_color = std::env::var("NO_COLOR").unwrap_or_default();
if !no_color.is_empty() {
false
} else if !clicolor_force.is_empty() {
true
} else {
std::io::stdout().is_terminal()
}
}
pub fn configure_colours<CM>(mode: CM)
where
CM: Into<Option<ColourMode>> + std::fmt::Debug,
{
let state = match mode.into() {
Some(ColourMode::Always) => true,
Some(ColourMode::Never) => false,
None | Some(ColourMode::Auto) => autodetect_colour(),
};
console::set_colors_enabled(state);
console::set_colors_enabled_stderr(state);
if state {
ColorChoice::Always
} else {
ColorChoice::Never
}
.write_global();
}
pub(crate) fn maybe_strip_color(s: &str) -> Cow<'_, str> {
if use_colours() {
s.into()
} else {
console::strip_ansi_codes(s)
}
}