use console::{Emoji, style};
use std::env;
pub struct Icons {
use_unicode: bool,
}
pub struct SafeIcons;
impl SafeIcons {
pub const CHECK: Emoji<'static, 'static> = Emoji("✓", "+");
pub const CROSS: Emoji<'static, 'static> = Emoji("✗", "x");
pub const LIGHTNING: Emoji<'static, 'static> = Emoji("⚡", "*");
pub const SEARCH: Emoji<'static, 'static> = Emoji("🔍", "?");
pub const WARNING: Emoji<'static, 'static> = Emoji("⚠️", "!");
pub const FIRE: Emoji<'static, 'static> = Emoji("🔥", "!");
pub const FOLDER: Emoji<'static, 'static> = Emoji("📁", "[D]");
pub const FILE: Emoji<'static, 'static> = Emoji("📄", "[F]");
pub const LINK: Emoji<'static, 'static> = Emoji("🔗", "->");
}
impl Default for Icons {
fn default() -> Self {
Self::new()
}
}
impl Icons {
pub fn new() -> Self {
let use_unicode = Self::detect_unicode_support();
Self { use_unicode }
}
fn detect_unicode_support() -> bool {
if let Ok(force_ascii) = env::var("ZIRO_ASCII_ICONS") {
return force_ascii != "1" && force_ascii.to_lowercase() != "true";
}
if let Ok(force_unicode) = env::var("ZIRO_UNICODE_ICONS") {
return force_unicode == "1" || force_unicode.to_lowercase() == "true";
}
if let Ok(term) = env::var("TERM") {
if term.contains("xterm")
|| term.contains("screen")
|| term.contains("tmux")
|| term.contains("alacritty")
|| term.contains("kitty")
{
return true;
}
}
if cfg!(target_os = "windows") {
if let Ok(wt_session) = env::var("WT_SESSION") {
return !wt_session.is_empty(); }
if let Ok(program_files) = env::var("ProgramFiles") {
let wt_path = std::path::Path::new(&program_files)
.join("WindowsApps")
.join("Microsoft.WindowsTerminal");
if wt_path.exists() {
return true;
}
}
}
#[cfg(target_os = "windows")]
{
false
}
#[cfg(not(target_os = "windows"))]
{
true
}
}
pub fn check(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::CHECK, self.use_unicode)
}
pub fn cross(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::CROSS, self.use_unicode)
}
pub fn lightning(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::LIGHTNING, self.use_unicode)
}
pub fn search(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::SEARCH, self.use_unicode)
}
pub fn warning(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::WARNING, self.use_unicode)
}
pub fn fire(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::FIRE, self.use_unicode)
}
pub fn folder(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::FOLDER, self.use_unicode)
}
pub fn file(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::FILE, self.use_unicode)
}
pub fn link(&self) -> StyledEmoji {
StyledEmoji::new(SafeIcons::LINK, self.use_unicode)
}
}
pub struct StyledEmoji {
emoji: Emoji<'static, 'static>,
use_unicode: bool,
}
impl StyledEmoji {
fn new(emoji: Emoji<'static, 'static>, use_unicode: bool) -> Self {
Self { emoji, use_unicode }
}
pub fn as_str(&self) -> &str {
if self.use_unicode {
self.emoji.0
} else {
self.emoji.1
}
}
#[allow(dead_code)]
pub fn yellow(&self) -> String {
style(self.as_str()).yellow().to_string()
}
#[allow(dead_code)]
pub fn magenta(&self) -> String {
style(self.as_str()).magenta().to_string()
}
#[allow(dead_code)]
pub fn bold(&self) -> String {
style(self.as_str()).bold().to_string()
}
#[allow(dead_code)]
pub fn display(&self) -> &str {
self.as_str()
}
}
impl std::fmt::Display for StyledEmoji {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub fn icons() -> Icons {
Icons::new()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icon_creation() {
let icons = Icons::new();
let check = icons.check();
assert!(!check.as_str().is_empty());
}
}