extern crate codegen;
extern crate inflector;
use codegen::Module;
use codegen::Scope;
use codegen::Type;
use inflector::Inflector;
use std::fmt;
use std::fs::File;
use std::fs::{self};
use std::io;
use std::io::prelude::*;
mod mi;
mod resources;
pub use crate::resources::GetResourcesError;
mod errors;
pub mod fa;
use crate::fa::IconType;
pub use crate::errors::GenIconsErr;
mod registry;
use crate::registry::write_registry;
pub fn get_fa_resources(target_dir: &str) -> Result<(), GetResourcesError> {
resources::download_fa(fa::FA_RELEASE, target_dir)
}
pub fn get_mi_resources(target_dir: &str)-> Result<(), GetResourcesError> {
resources::download_mi(mi::MI_RELEASE, target_dir)
}
impl fmt::Display for IconType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub trait IconSource {
fn closure_view_call(&self) -> String;
fn closure_view_with_classes_call(&self) -> String;
fn full_module_name(&self) -> String;
fn name(&self) -> String;
}
pub struct IconsCollectionSource {
pub icons: Vec<Box<dyn crate::IconSource>>,
pub function_prefix: String,
}
fn add_imports(module: &mut Module, enable_styles: bool) {
module.import("seed", "*");
module.import("seed::prelude", "*");
if enable_styles {
module.import("seed_style", "*");
}
}
fn add_functions(
module: &mut Module,
classes: String,
enable_styles: bool,
content: Option<&String>,
) {
let content = match content {
None => "".to_string(),
Some(text) => format!(r#", "{}""#, *text),
};
module
.new_fn("i")
.vis("pub")
.generic("T")
.ret("Node<T>")
.line(format!(r#"i![C![{}]{}]"#, classes, content));
module
.new_fn("i_c")
.vis("pub")
.generic("T")
.ret("Node<T>")
.arg("classes", Type::new("Vec<&str>"))
.line(format!(r#"i![C![{}, classes]{}]"#, classes, content));
if enable_styles {
module
.new_fn("i_sc")
.vis("pub")
.generic("T")
.ret("Node<T>")
.arg("style", Type::new("seed_style::Style"))
.arg("classes", Type::new("Vec<&str>"))
.line(format!(r#"i![style, C![{}, classes]{}]"#, classes, content));
module
.new_fn("i_s")
.vis("pub")
.generic("T")
.ret("Node<T>")
.arg("style", Type::new("seed_style::Style"))
.line(format!(r#"i![style, C![{}]{}]"#, classes, content));
}
}
pub fn write_all(
out_dir: &str,
enable_styles: bool,
enable_fa: bool,
enable_mi: bool,
) -> Result<(), GenIconsErr> {
prepare_structure(out_dir)?;
let mut scope = Scope::new();
println!("cargo:rerun-if-env-changed=SEED_ICONS_FILTER_NAMES");
let maybe_filter: Option<Vec<String>> = std::env::var("SEED_ICONS_FILTER_NAMES")
.map(|names_string| {
let res: Vec<String> = names_string
.split(";")
.map(|name| name.to_string())
.collect();
res
})
.ok();
if enable_fa {
fa::write_font_awesome_icons(&mut scope, enable_styles, maybe_filter.clone())?;
}
if enable_mi {
mi::write_material_icons(&mut scope, enable_styles, maybe_filter.clone())?;
}
let filename = format!("{}/fa/icons.rs", out_dir);
dump_to_file(filename, &scope)?;
let mut collections: Vec<IconsCollectionSource> = vec![];
if enable_fa {
fa::registry_icons(&mut collections, &maybe_filter)?;
}
if enable_mi {
mi::registry_icons(&mut collections, &maybe_filter)?;
}
write_registry(collections, out_dir)?;
Ok(())
}
fn dump_to_file(filename: String, scope: &Scope) -> Result<(), GenIconsErr> {
let mut file = File::create(filename)?;
file.write_all(scope.to_string().as_bytes())?;
Ok(())
}
fn prepare_structure(out_dir: &str) -> Result<(), io::Error> {
fs::create_dir_all(&format!("{}/fa", out_dir))?;
Ok(())
}
fn module_name(icon_name: &String) -> String {
let starts_with_digit = icon_name != "" && icon_name.as_bytes()[0].is_ascii_digit();
let is_keyword = match icon_name.as_str() {
"box" => true,
"loop" => true,
"as" => true,
"async" => true,
"await" => true,
"break" => true,
"const" => true,
"continue" => true,
"crate" => true,
"dyn" => true,
"else" => true,
"enum" => true,
"extern" => true,
"false" => true,
"fn" => true,
"for" => true,
"if" => true,
"impl" => true,
"in" => true,
"let" => true,
"match" => true,
"mod" => true,
"move" => true,
"mut" => true,
"pub" => true,
"ref" => true,
"return" => true,
"Self" => true,
"self" => true,
"static" => true,
"struct" => true,
"super" => true,
"trait" => true,
"true" => true,
"type" => true,
"union" => true,
"unsafe" => true,
"use" => true,
"where" => true,
"while" => true,
"abstract" => true,
"become" => true,
"do" => true,
"final" => true,
"macro" => true,
"override" => true,
"priv" => true,
"try" => true,
"typeof" => true,
"unsized" => true,
"virtual" => true,
"yield" => true,
_ => false,
};
let module_name: String = if starts_with_digit || is_keyword {
format!("a_{}", icon_name)
} else {
icon_name.to_snake_case()
};
module_name
}