netspd 0.1.7

A beautiful, modern, minimalistic network speed testing terminal application
Documentation
//! Build script: auto-discovers all `*.toml` files under `assets/themes/`
//! and generates `builtin_themes.rs` in OUT_DIR.
// Build scripts report errors by panicking; suppress the project-wide lints
// that forbid expect/unwrap in library and binary code.
#![allow(clippy::expect_used, clippy::unwrap_used)]
//!
//! # Adding a new static theme
//!
//! 1. Create `assets/themes/my-theme.toml` following the structure below.
//! 2. Run `cargo build` — the theme appears in the selector automatically.
//!
//! ```toml
//! name = "My Theme"
//!
//! [colors]
//! background = "#rrggbb"   # app background
//! surface    = "#rrggbb"   # card / panel background
//! overlay    = "#rrggbb"   # popup background
//! text       = "#rrggbb"   # primary text
//! subtext    = "#rrggbb"   # secondary text
//! muted      = "#rrggbb"   # de-emphasized text / separators
//! border     = "#rrggbb"   # borders and outlines
//! accent     = "#rrggbb"   # primary accent
//! accent_alt = "#rrggbb"   # secondary accent (gradients, upload)
//! success    = "#rrggbb"   # positive results
//! warning    = "#rrggbb"   # cautionary values
//! danger     = "#rrggbb"   # errors / failures
//! download   = "#rrggbb"   # download-phase highlight
//! upload     = "#rrggbb"   # upload-phase highlight
//! latency    = "#rrggbb"   # latency highlight
//! ```
//!
//! Themes are loaded in alphabetical filename order. Name the file with a
//! leading digit (`01-my-theme.toml`) to control position in the list.

use std::path::PathBuf;

fn main() {
    let themes_dir = PathBuf::from("assets/themes");

    // Rerun whenever the directory or any file in it changes.
    println!("cargo:rerun-if-changed=assets/themes");

    let mut names: Vec<String> = std::fs::read_dir(&themes_dir)
        .expect("assets/themes directory not found — run from the crate root")
        .filter_map(|entry| entry.ok())
        .filter_map(|entry| {
            let path = entry.path();
            if path.extension().is_some_and(|ext| ext == "toml") {
                path.file_name().and_then(|n| n.to_str()).map(str::to_owned)
            } else {
                None
            }
        })
        .collect();

    names.sort(); // deterministic, alphabetical

    // Emit a per-file rerun trigger so edits to existing themes rebuild too.
    for name in &names {
        println!("cargo:rerun-if-changed=assets/themes/{name}");
    }

    // Generate the constant.  Each entry uses include_str! so the TOML is
    // embedded in the binary at compile time — no runtime file dependency.
    let includes: String = names
        .iter()
        .map(|name| {
            format!(
                "    include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/assets/themes/{name}\")),\n"
            )
        })
        .collect();

    let generated = format!(
        "// AUTO-GENERATED by build.rs — do not edit.\n\
         // Drop a *.toml file into assets/themes/ and rebuild to add a theme.\n\
         pub(super) const BUILTIN_THEME_SOURCES: &[&str] = &[\n\
         {includes}\
         ];\n"
    );

    let out_path =
        PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR not set")).join("builtin_themes.rs");
    std::fs::write(&out_path, generated).expect("failed to write builtin_themes.rs");
}