use owo_colors::{OwoColorize, Style};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Badge {
Bridge,
Api,
Recent,
HighChurn,
Crystal,
Rotting,
Emergent,
Evolving,
}
impl Badge {
pub fn label(&self) -> &'static str {
match self {
Badge::Bridge => "bridge",
Badge::Api => "api",
Badge::Recent => "recent",
Badge::HighChurn => "high-churn",
Badge::Crystal => "crystal",
Badge::Rotting => "rotting",
Badge::Emergent => "emergent",
Badge::Evolving => "evolving",
}
}
pub fn style(&self) -> Style {
match self {
Badge::Bridge => Style::new().bright_red().bold(),
Badge::Api => Style::new().bright_blue().bold(),
Badge::Recent => Style::new().yellow(),
Badge::HighChurn => Style::new().bright_yellow(),
Badge::Crystal => Style::new().bright_cyan().dimmed(),
Badge::Rotting => Style::new().bright_magenta(),
Badge::Emergent => Style::new().green(),
Badge::Evolving => Style::new().dimmed(),
}
}
pub fn render(&self) -> String {
format!("[{}]", self.label().style(self.style()))
}
}
impl fmt::Display for Badge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.render())
}
}
pub struct Colorizer;
impl Colorizer {
pub fn file_path(s: &str) -> String {
s.bright_blue().bold().to_string()
}
pub fn class_name(s: &str) -> String {
s.magenta().to_string()
}
pub fn function_name(s: &str) -> String {
s.green().to_string()
}
pub fn constant_name(s: &str) -> String {
s.bright_cyan().to_string()
}
pub fn type_name(s: &str) -> String {
s.cyan().to_string()
}
pub fn field_name(s: &str) -> String {
s.to_string()
}
pub fn decorator(s: &str) -> String {
s.yellow().dimmed().to_string()
}
pub fn badge_group(badges: &[Badge]) -> String {
if badges.is_empty() {
return String::new();
}
let rendered: Vec<_> = badges.iter().map(|b| b.render()).collect();
rendered.join(" ")
}
pub fn coupling_label() -> String {
"⇄ changes with:".dimmed().to_string()
}
pub fn coupling_entry(file: &str, percentage: f64) -> String {
format!("{}({}%)", file.cyan(), (percentage * 100.0) as u32)
}
pub fn dim(s: &str) -> String {
s.dimmed().to_string()
}
}
pub fn colorize(node_type: &str, name: &str) -> String {
match node_type {
"class" | "class_definition" | "struct" | "struct_item" => Colorizer::class_name(name),
"function" | "function_definition" | "method" | "method_definition" => {
Colorizer::function_name(name)
}
"constant" | "const_item" => Colorizer::constant_name(name),
"type" | "type_alias" | "type_definition" => Colorizer::type_name(name),
"decorator" | "attribute" => Colorizer::decorator(name),
_ => name.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_badge_labels() {
assert_eq!(Badge::Bridge.label(), "bridge");
assert_eq!(Badge::Api.label(), "api");
assert_eq!(Badge::Recent.label(), "recent");
assert_eq!(Badge::HighChurn.label(), "high-churn");
assert_eq!(Badge::Crystal.label(), "crystal");
assert_eq!(Badge::Rotting.label(), "rotting");
assert_eq!(Badge::Emergent.label(), "emergent");
assert_eq!(Badge::Evolving.label(), "evolving");
}
#[test]
fn test_badge_render() {
let badges = vec![
Badge::Bridge,
Badge::Api,
Badge::Recent,
Badge::HighChurn,
Badge::Crystal,
Badge::Rotting,
Badge::Emergent,
Badge::Evolving,
];
for badge in badges {
let rendered = badge.render();
assert!(rendered.contains(badge.label()));
}
}
#[test]
fn test_colorize_node_types() {
colorize("class", "MyClass");
colorize("function", "my_func");
colorize("constant", "MAX_SIZE");
colorize("type", "UserId");
colorize("unknown", "something");
}
}