use std::{ collections::HashMap, fs::{exists, read_to_string, write}, sync::LazyLock, }; use tokio::sync::RwLock; use pathbufd::PathBufD; /// A container for all loaded icons. pub static ICONS: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); /// Pull an icon given its name and insert it into [`ICONS`]. pub async fn pull_icon(icon: &str, icons_dir: &str) { let writer = &mut ICONS.write().await; let icon_url = format!( "https://raw.githubusercontent.com/lucide-icons/lucide/refs/heads/main/icons/{icon}.svg" ); let file_path = PathBufD::current().extend(&[icons_dir, &format!("{icon}.svg")]); if exists(&file_path).unwrap_or(false) { writer.insert(icon.to_string(), read_to_string(&file_path).unwrap()); return; } println!("download icon: {icon}"); let svg = reqwest::get(icon_url) .await .unwrap() .text() .await .unwrap() .replace("\n", ""); write(&file_path, &svg).unwrap(); writer.insert(icon.to_string(), svg); } /// Read a string and pull all icons found within it. pub async fn pull_icons(mut input: String, icon_dir: &str) -> String { // icon (with class) let icon_with_class = regex::Regex::new("(\\{\\{)\\s*(icon)\\s*(.*?)\\s*c\\((.*?)\\)\\s*(\\}\\})").unwrap(); for cap in icon_with_class.captures_iter(&input.clone()) { let cap_str = &cap.get(3).unwrap().as_str().replace("\"", ""); let icon = &(if cap_str.contains(" }}") { cap_str.split(" }}").next().unwrap().to_string() } else { cap_str.to_string() }); pull_icon(icon, icon_dir).await; let reader = ICONS.read().await; let icon_text = reader.get(icon).unwrap().replace( "