refactor: replace build.rs module codegen with a static registry
The core ribbon registry no longer needs build-time generation. Replace the generated all_modules() (included from OUT_DIR) with a hand-written static list in src/modules/registry.rs, listing the seven built-in tabs in display order. Trim build.rs down to its only remaining job: embedding the Windows executable icon via winresource (issue #107). The external plugin system is unaffected — plugin::registry still appends dynamically-loaded add-on tabs on top of the core list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
415dbe08d4
commit
7cb666801f
3 changed files with 31 additions and 96 deletions
93
build.rs
93
build.rs
|
|
@ -1,30 +1,11 @@
|
||||||
// build.rs — auto-generates src/modules/registry.rs
|
// build.rs — Windows executable icon embedding.
|
||||||
//
|
//
|
||||||
// Scans src/modules/ for subdirectories containing a mod.rs file.
|
// The core ribbon module registry used to be generated here; it is now a
|
||||||
// Each subdirectory name like "home" maps to a struct "HomeModule"
|
// hand-written static list in src/modules/registry.rs.
|
||||||
// defined in src/modules/home/mod.rs.
|
|
||||||
//
|
|
||||||
// Rules for a directory to be picked up:
|
|
||||||
// • Located directly in src/modules/
|
|
||||||
// • Contains a mod.rs file
|
|
||||||
// • Does NOT contain plugin.toml (add-ons register via BuiltinPlugin::ribbon)
|
|
||||||
// • Defines a pub struct {PascalCase}Module implementing CadModule
|
|
||||||
// (unit struct — no ::new() needed)
|
|
||||||
//
|
|
||||||
// Tab display order: the PRIORITY list below controls order.
|
|
||||||
// Unlisted modules appear after priority modules, sorted alphabetically.
|
|
||||||
//
|
|
||||||
// Adding a new module:
|
|
||||||
// 1. Create src/modules/my_name/mod.rs (implement CadModule as MyNameModule)
|
|
||||||
// 2. Add `pub mod my_name;` to src/modules/mod.rs
|
|
||||||
// 3. cargo build → module appears in the ribbon
|
|
||||||
|
|
||||||
use std::fs;
|
#[cfg(windows)]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
// Display order for known modules; unknown modules follow alphabetically.
|
|
||||||
const PRIORITY: &[&str] = &["draw", "model", "insert", "annotate", "view", "manage"];
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Windows: embed AppIcon.ico into the .exe so the executable carries its
|
// Windows: embed AppIcon.ico into the .exe so the executable carries its
|
||||||
// own icon (Explorer, taskbar, Start-menu tile, file associations). The
|
// own icon (Explorer, taskbar, Start-menu tile, file associations). The
|
||||||
|
|
@ -41,70 +22,4 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mods_dir = Path::new("src/modules");
|
|
||||||
println!("cargo:rerun-if-changed=src/modules");
|
|
||||||
|
|
||||||
// Collect subdirectories that contain mod.rs.
|
|
||||||
let mut modules: Vec<String> = fs::read_dir(mods_dir)
|
|
||||||
.expect("src/modules/ not found")
|
|
||||||
.filter_map(|e| {
|
|
||||||
let entry = e.ok()?;
|
|
||||||
if !entry.file_type().ok()?.is_dir() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let name = entry.file_name().into_string().ok()?;
|
|
||||||
let mod_file = mods_dir.join(&name).join("mod.rs");
|
|
||||||
let plugin_toml = mods_dir.join(&name).join("plugin.toml");
|
|
||||||
if mod_file.exists() && !plugin_toml.exists() {
|
|
||||||
Some(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Sort: priority order first, then alphabetical for the rest.
|
|
||||||
modules.sort_by_key(|name| {
|
|
||||||
let pri = PRIORITY.iter().position(|p| *p == name.as_str());
|
|
||||||
(pri.map(|i| i as u32).unwrap_or(u32::MAX), name.clone())
|
|
||||||
});
|
|
||||||
|
|
||||||
// snake_case → PascalCase + "Module"
|
|
||||||
let to_struct = |s: &str| -> String {
|
|
||||||
s.split('_')
|
|
||||||
.map(|w| {
|
|
||||||
let mut c = w.chars();
|
|
||||||
match c.next() {
|
|
||||||
None => String::new(),
|
|
||||||
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<String>()
|
|
||||||
+ "Module"
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut out = String::from(
|
|
||||||
"// AUTO-GENERATED by build.rs — do not edit by hand.\n\
|
|
||||||
// To add a module: create src/modules/my_name/mod.rs + add `pub mod my_name;` to modules/mod.rs.\n\n\
|
|
||||||
use crate::modules::CadModule;\n\n\
|
|
||||||
/// Returns one boxed instance of every registered CAD module.\n\
|
|
||||||
/// Called once at startup by `Ribbon::new()`.\n\
|
|
||||||
pub fn all_modules() -> Vec<Box<dyn CadModule>> {\n\
|
|
||||||
\tvec![\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
for module in &modules {
|
|
||||||
let s = to_struct(module);
|
|
||||||
out.push_str(&format!("\t\tBox::new(super::{module}::{s}),\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
out.push_str("\t]\n}\n");
|
|
||||||
|
|
||||||
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
|
|
||||||
let out_path = Path::new(&out_dir).join("modules_registry.rs");
|
|
||||||
let current = fs::read_to_string(&out_path).unwrap_or_default();
|
|
||||||
if current != out {
|
|
||||||
fs::write(&out_path, &out).expect("failed to write modules_registry.rs");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
// 1. Create `src/modules/my_name/` directory (no `plugin.toml`)
|
// 1. Create `src/modules/my_name/` directory (no `plugin.toml`)
|
||||||
// 2. Add `src/modules/my_name/mod.rs` implementing `CadModule` as `MyNameModule`
|
// 2. Add `src/modules/my_name/mod.rs` implementing `CadModule` as `MyNameModule`
|
||||||
// 3. Add `pub mod my_name;` below
|
// 3. Add `pub mod my_name;` below
|
||||||
// 4. `cargo build` — tab appears via build.rs registry
|
// 4. Add a `Box::new(my_name::MyNameModule)` line in `registry::all_modules()`
|
||||||
//
|
//
|
||||||
// To add an **add-on plugin** (Storm Sewer, …):
|
// To add an **add-on plugin** (Storm Sewer, …):
|
||||||
// See `docs/plugin-architecture.md` and copy `docs/plugin-template/`.
|
// See `docs/plugin-architecture.md` and copy `docs/plugin-template/`.
|
||||||
|
|
@ -32,6 +32,6 @@ pub mod layout;
|
||||||
pub mod manage;
|
pub mod manage;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
|
|
||||||
// ── Auto-generated module registry ───────────────────────────────────────
|
// ── Core module registry ─────────────────────────────────────────────────
|
||||||
// build.rs writes this file; it contains only `all_modules()`.
|
// Hand-written `all_modules()` listing the built-in ribbon tabs.
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
// AUTO-GENERATED include — see build.rs for the actual generator.
|
// Core ribbon module registry — one boxed instance of every built-in CAD
|
||||||
// The generated registry is written to Cargo's OUT_DIR and included here so
|
// module, in ribbon-tab display order. External add-ons are appended on top
|
||||||
// the source tree is not modified during build.
|
// of this list at runtime by `plugin::registry`.
|
||||||
include!(concat!(env!("OUT_DIR"), "/modules_registry.rs"));
|
//
|
||||||
|
// To add a core module:
|
||||||
|
// 1. Create src/modules/my_name/mod.rs (implement CadModule as MyNameModule)
|
||||||
|
// 2. Add `pub mod my_name;` to src/modules/mod.rs
|
||||||
|
// 3. Add one `Box::new(super::my_name::MyNameModule)` line below, in the
|
||||||
|
// position you want its tab to appear.
|
||||||
|
use crate::modules::CadModule;
|
||||||
|
|
||||||
|
/// Returns one boxed instance of every registered core CAD module.
|
||||||
|
/// Called once at startup by `Ribbon::new()`.
|
||||||
|
pub fn all_modules() -> Vec<Box<dyn CadModule>> {
|
||||||
|
vec![
|
||||||
|
Box::new(super::draw::DrawModule),
|
||||||
|
Box::new(super::model::ModelModule),
|
||||||
|
Box::new(super::insert::InsertModule),
|
||||||
|
Box::new(super::annotate::AnnotateModule),
|
||||||
|
Box::new(super::view::ViewModule),
|
||||||
|
Box::new(super::manage::ManageModule),
|
||||||
|
Box::new(super::layout::LayoutModule),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue