use colored::*;
use std::env;
#[derive(Debug, Clone, PartialEq)]
pub enum IconType {
Local,
Ascii,
}
#[derive(Debug, Clone, PartialEq)]
pub enum IconStyle {
Default,
Success,
Failure,
Warning,
Info,
}
pub struct IconManager {
icon_type: IconType,
supports_color: bool,
}
impl IconManager {
pub fn new() -> Self {
let icon_type = Self::detect_icon_support();
let supports_color = Self::detect_color_support();
Self {
icon_type,
supports_color,
}
}
fn detect_icon_support() -> IconType {
if env::var("DEVMODE_NO_ICONS").is_ok() {
return IconType::Ascii;
}
if env::var("DEVMODE_FORCE_LOCAL_ICONS").is_ok() {
return IconType::Local;
}
IconType::Local
}
fn detect_color_support() -> bool {
if env::var("NO_COLOR").is_ok() || env::var("DEVMODE_NO_COLOR").is_ok() {
return false;
}
if env::var("FORCE_COLOR").is_ok() || env::var("DEVMODE_FORCE_COLOR").is_ok() {
return true;
}
let term = env::var("TERM").unwrap_or_default();
let term_program = env::var("TERM_PROGRAM").unwrap_or_default();
term.contains("xterm")
|| term.contains("screen")
|| term.contains("tmux")
|| term_program.contains("iTerm")
|| term_program.contains("Terminal")
|| term_program.contains("vscode")
|| term_program.contains("Alacritty")
|| term_program.contains("Kitty")
|| term_program.contains("WezTerm")
|| term_program.contains("Hyper")
|| term_program.contains("Terminus")
|| term_program.contains("Terminator")
|| term_program.contains("Gnome")
|| term_program.contains("Konsole")
|| term_program.contains("Xfce")
}
#[cfg(test)]
pub fn icon_type(&self) -> &IconType {
&self.icon_type
}
fn apply_style(&self, icon: &str, style: IconStyle) -> String {
if !self.supports_color {
return icon.to_string();
}
match style {
IconStyle::Success => icon.green().bold().to_string(),
IconStyle::Failure => icon.red().to_string(),
IconStyle::Warning => icon.yellow().to_string(),
IconStyle::Info => icon.blue().to_string(),
IconStyle::Default => icon.to_string(),
}
}
pub fn rocket(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "🚀";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => ">".to_string(),
}
}
pub fn clipboard(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "📋";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "[*]".to_string(),
}
}
pub fn success(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "✓";
self.apply_style(icon, IconStyle::Success)
}
IconType::Ascii => "✓".to_string(),
}
}
pub fn failure(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "✗";
self.apply_style(icon, IconStyle::Failure)
}
IconType::Ascii => "✗".to_string(),
}
}
pub fn warning(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "⚠";
self.apply_style(icon, IconStyle::Warning)
}
IconType::Ascii => "⚠".to_string(),
}
}
pub fn info(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "ℹ";
self.apply_style(icon, IconStyle::Info)
}
IconType::Ascii => "ℹ".to_string(),
}
}
pub fn package(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "📦";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "📦".to_string(),
}
}
pub fn rust(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "🦀";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "🦀".to_string(),
}
}
pub fn wrench(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "🔧";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "🔧".to_string(),
}
}
pub fn pause(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "⏸";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "⏸".to_string(),
}
}
pub fn tools(&self) -> String {
match self.icon_type {
IconType::Local => {
let icon = "🛠";
self.apply_style(icon, IconStyle::Default)
}
IconType::Ascii => "🛠".to_string(),
}
}
}
impl Default for IconManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icon_manager_creation() {
let manager = IconManager::new();
assert!(matches!(
manager.icon_type(),
IconType::Local | IconType::Ascii
));
}
#[test]
fn test_icon_consistency() {
let manager = IconManager::new();
let _ = manager.rocket();
let _ = manager.clipboard();
let _ = manager.success();
let _ = manager.failure();
let _ = manager.warning();
let _ = manager.info();
let _ = manager.package();
let _ = manager.rust();
let _ = manager.wrench();
let _ = manager.pause();
let _ = manager.tools();
}
#[test]
fn test_ascii_fallback() {
env::set_var("DEVMODE_NO_ICONS", "1");
let manager = IconManager::new();
assert_eq!(manager.icon_type(), &IconType::Ascii);
env::remove_var("DEVMODE_NO_ICONS");
}
}