use std::env;
use std::fs;
use std::path::Path;
fn main() {
napi_build::setup();
println!("cargo::rerun-if-changed=fonts/glyphnames.json");
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let json_path = Path::new(&manifest_dir).join("fonts/glyphnames.json");
let json_data = fs::read_to_string(&json_path).expect("Failed to read glyphnames.json");
let raw: serde_json::Value = serde_json::from_str(&json_data).expect("Failed to parse glyphnames.json");
let mut icons: Vec<(u32, String, String)> = Vec::new();
let mut unknown_names: Vec<String> = Vec::new();
if let Some(obj) = raw.as_object() {
for (key, val) in obj {
if key == "METADATA" {
continue;
}
let code_str = val.get("code").and_then(|c| c.as_str()).unwrap_or("");
let codepoint = u32::from_str_radix(code_str, 16).unwrap_or(0);
if codepoint == 0 {
unknown_names.push(key.clone());
continue;
}
let (name, category) = classify_icon(key);
icons.push((codepoint, name, category));
}
}
icons.sort_by_key(|(cp, _, _)| *cp);
if !unknown_names.is_empty() {
println!(
"cargo::warning=Font build: {} entries without valid codepoint. First few: {:?}",
unknown_names.len(),
&unknown_names[..unknown_names.len().min(5)]
);
}
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir).join("builtin.rs");
let mut output = String::new();
output.push_str("// Auto-generated by build.rs from glyphnames.json\n");
output.push_str("// Do not edit manually.\n\n");
output.push_str("#[allow(dead_code)]\n");
output.push_str("pub(crate) struct BuiltinIcon {\n");
output.push_str(" pub codepoint: u32,\n");
output.push_str(" pub name: &'static str,\n");
output.push_str(" pub category: &'static str,\n");
output.push_str("}\n\n");
output.push_str("#[allow(dead_code)]\n");
output.push_str(&format!("pub(crate) const BUILTIN_ICON_COUNT: usize = {};\n\n", icons.len()));
output.push_str("#[allow(dead_code)]\n");
output.push_str("pub(crate) static BUILTIN_ICONS: &[BuiltinIcon] = &[\n");
for (cp, name, category) in &icons {
output.push_str(&format!(
" BuiltinIcon {{ codepoint: 0x{:04X}, name: \"{}\", category: \"{}\" }},\n",
cp,
name.escape_default(),
category
));
}
output.push_str("];\n");
output.push_str("\n#[allow(dead_code)]\n");
output.push_str("pub(crate) static BUILTIN_CODEPOINTS: &[u32] = &[\n");
for (cp, _, _) in &icons {
output.push_str(&format!(" 0x{:04X},\n", cp));
}
output.push_str("];\n");
fs::write(&out_path, &output).expect("Failed to write builtin.rs");
let icon_count = icons.len();
println!("cargo::warning=Generated {} built-in NerdFont icon entries", icon_count);
}
fn classify_icon(key: &str) -> (String, String) {
let parts: Vec<&str> = key.splitn(2, '-').collect();
let category = if parts.len() >= 2 { parts[0].to_string() } else { "unknown".to_string() };
(key.to_string(), category)
}