runmat-lsp 0.4.8

Language Server Protocol implementation for RunMat editors and tooling
use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
    let builtins_dir = manifest_dir.join("../runmat-runtime/src/builtins/builtins-json");

    // Re-run when builtins-json changes (best-effort: per-file + directory).
    println!("cargo:rerun-if-changed={}", builtins_dir.display());

    let mut entries: Vec<(String, String)> = Vec::new(); // (lookup key, file name)
    let read_dir = fs::read_dir(&builtins_dir).unwrap_or_else(|e| {
        panic!(
            "failed to read builtins-json at {}: {e}",
            builtins_dir.display()
        )
    });

    for entry in read_dir {
        let entry = entry.expect("failed to read dir entry");
        let path = entry.path();
        if path.extension().and_then(|s| s.to_str()) != Some("json") {
            continue;
        }
        let file_name = path
            .file_name()
            .and_then(|s| s.to_str())
            .expect("invalid utf-8 file name")
            .to_string();
        let stem = path
            .file_stem()
            .and_then(|s| s.to_str())
            .expect("invalid utf-8 file stem")
            .to_string();
        let key = stem.to_ascii_lowercase();
        println!("cargo:rerun-if-changed={}", path.display());
        entries.push((key, file_name));
    }

    entries.sort_by(|a, b| a.0.cmp(&b.0));

    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
    let dest = out_dir.join("builtins_json_generated.rs");

    let mut out = String::new();
    out.push_str("// @generated by runmat-lsp/build.rs\n");
    out.push_str("// Do not edit by hand.\n\n");

    out.push_str("pub fn builtin_json_by_name(name: &str) -> Option<&'static str> {\n");
    out.push_str("    let key = name.to_ascii_lowercase();\n");
    out.push_str("    match key.as_str() {\n");
    for (key, file_name) in &entries {
        // include_str! must be a compile-time constant; use concat! with CARGO_MANIFEST_DIR.
        out.push_str(&format!(
            "        {:?} => Some(include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../runmat-runtime/src/builtins/builtins-json/{}\"))),\n",
            key, file_name
        ));
    }
    out.push_str("        _ => None,\n");
    out.push_str("    }\n");
    out.push_str("}\n\n");

    fs::write(&dest, out).unwrap_or_else(|e| {
        panic!(
            "failed to write generated builtins json map at {}: {e}",
            dest.display()
        )
    });
}