use std::io::IsTerminal;
use std::sync::OnceLock;
use anstyle::{AnsiColor, Color, Style};
use gitcortex_core::schema::NodeKind;
fn kind_color(k: &NodeKind) -> Option<Color> {
Some(Color::Ansi(match k {
NodeKind::Struct => AnsiColor::Green,
NodeKind::Enum => AnsiColor::Cyan,
NodeKind::Trait => AnsiColor::Yellow,
NodeKind::Interface => AnsiColor::BrightCyan,
NodeKind::Function => AnsiColor::Blue,
NodeKind::Method => AnsiColor::BrightBlue,
NodeKind::Constant => AnsiColor::Yellow,
NodeKind::TypeAlias => AnsiColor::Red,
NodeKind::Module => AnsiColor::Magenta,
NodeKind::Macro => AnsiColor::BrightWhite,
NodeKind::Property => AnsiColor::Magenta,
NodeKind::Annotation => AnsiColor::Red,
NodeKind::EnumMember => AnsiColor::BrightGreen,
NodeKind::File | NodeKind::Folder => AnsiColor::BrightBlack,
}))
}
pub fn kind_style(k: &NodeKind) -> Style {
Style::new().fg_color(kind_color(k))
}
pub fn kind_style_from_str(k: &str) -> Style {
let ansi = match k {
"struct" => AnsiColor::Green,
"enum" => AnsiColor::Cyan,
"trait" => AnsiColor::Yellow,
"interface" => AnsiColor::BrightCyan,
"function" => AnsiColor::Blue,
"method" => AnsiColor::BrightBlue,
"constant" => AnsiColor::Yellow,
"type_alias" => AnsiColor::Red,
"module" => AnsiColor::Magenta,
"macro" => AnsiColor::BrightWhite,
"property" => AnsiColor::Magenta,
"annotation" => AnsiColor::Red,
"enum_member" => AnsiColor::BrightGreen,
"file" | "folder" => AnsiColor::BrightBlack,
_ => return Style::new(),
};
Style::new().fg_color(Some(Color::Ansi(ansi)))
}
pub fn name_style() -> Style {
Style::new().bold()
}
pub fn path_style() -> Style {
Style::new().fg_color(Some(Color::Ansi(AnsiColor::BrightBlack)))
}
pub fn header_style() -> Style {
Style::new().bold().underline()
}
pub fn arrow_style() -> Style {
Style::new().fg_color(Some(Color::Ansi(AnsiColor::BrightBlack)))
}
pub fn hint_style() -> Style {
Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::BrightBlack)))
.italic()
}
pub fn risk_style(level: &str) -> Style {
let c = match level {
"LOW" => AnsiColor::Green,
"MEDIUM" => AnsiColor::Yellow,
"HIGH" => AnsiColor::Red,
"CRITICAL" => AnsiColor::BrightRed,
_ => AnsiColor::BrightBlack,
};
Style::new().fg_color(Some(Color::Ansi(c))).bold()
}
pub fn score_style() -> Style {
Style::new().fg_color(Some(Color::Ansi(AnsiColor::BrightYellow)))
}
#[derive(Clone, Copy, Debug, clap::ValueEnum)]
pub enum ColorMode {
Auto,
Always,
Never,
}
static ENABLED: OnceLock<bool> = OnceLock::new();
pub fn init(mode: ColorMode) {
let on = match mode {
ColorMode::Always => true,
ColorMode::Never => false,
ColorMode::Auto => detect_tty_color(),
};
let _ = ENABLED.set(on);
}
fn detect_tty_color() -> bool {
if std::env::var_os("NO_COLOR").is_some() {
return false;
}
if matches!(std::env::var("CLICOLOR").as_deref(), Ok("0")) {
return false;
}
if matches!(std::env::var("TERM").as_deref(), Ok("dumb")) {
return false;
}
std::io::stdout().is_terminal()
}
#[inline]
pub fn enabled() -> bool {
*ENABLED.get().unwrap_or(&false)
}
pub fn paint(style: Style, text: &str) -> String {
if enabled() {
format!("{style}{text}{style:#}")
} else {
text.to_owned()
}
}
use gitcortex_core::graph::Node;
pub fn node_line(n: &Node) -> String {
format!(
"{} {} {}{}{}",
paint(name_style(), &n.name),
paint(kind_style(&n.kind), &format!("({})", n.kind)),
paint(path_style(), &n.file.display().to_string()),
paint(path_style(), ":"),
paint(path_style(), &n.span.start_line.to_string()),
)
}
pub fn node_line_indented(n: &Node, prefix: &str) -> String {
format!("{prefix}{}", node_line(n))
}
pub fn arrow() -> String {
paint(arrow_style(), "→")
}