From 5b427a73cb89491236add0dd4e5117f187ad4f2d Mon Sep 17 00:00:00 2001 From: Maksymilian Mozolewski Date: Sat, 22 Feb 2025 16:50:38 +0000 Subject: [PATCH] feat: create `ScriptingDocgenPlugin` to allow exporting `LAD` files + export BMS bindings (#303) --- .gitignore | 5 +- Cargo.toml | 6 + assets/scripts/bevy_api.lua | 159 ------------------ assets/scripts/complex_game_loop.lua | 17 -- assets/scripts/console_integration.lua | 12 -- assets/scripts/console_integration.rhai | 13 -- assets/scripts/coroutines.lua | 23 --- assets/scripts/dynamic_queries.lua | 23 --- assets/scripts/dynamic_queries.rhai | 11 -- assets/scripts/event_recipients.lua | 6 - assets/scripts/event_recipients.rune | 3 - assets/scripts/minimal.rune | 3 - assets/scripts/multiple_events_rhai.rhai | 16 -- assets/scripts/runtime_error.lua | 3 - crates/bevy_mod_scripting_core/Cargo.toml | 1 - .../bevy_mod_scripting_core/src/docgen/mod.rs | 1 + crates/ladfile_builder/Cargo.toml | 1 + crates/ladfile_builder/src/lib.rs | 1 + crates/ladfile_builder/src/plugin.rs | 120 +++++++++++++ crates/xtask/src/main.rs | 111 +++++++++++- docs/book.toml | 2 + docs/src/SUMMARY.md | 6 +- examples/docgen.rs | 20 +++ 23 files changed, 269 insertions(+), 294 deletions(-) delete mode 100644 assets/scripts/bevy_api.lua delete mode 100644 assets/scripts/complex_game_loop.lua delete mode 100644 assets/scripts/console_integration.lua delete mode 100644 assets/scripts/console_integration.rhai delete mode 100644 assets/scripts/coroutines.lua delete mode 100644 assets/scripts/dynamic_queries.lua delete mode 100644 assets/scripts/dynamic_queries.rhai delete mode 100644 assets/scripts/event_recipients.lua delete mode 100644 assets/scripts/event_recipients.rune delete mode 100644 assets/scripts/minimal.rune delete mode 100644 assets/scripts/multiple_events_rhai.rhai delete mode 100644 assets/scripts/runtime_error.lua create mode 100644 crates/ladfile_builder/src/plugin.rs create mode 100644 examples/docgen.rs diff --git a/.gitignore b/.gitignore index 524c94e6..f8a15065 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ Cargo.lock assets/scripts/tlconfig.lua **.log **build/ -.html \ No newline at end of file +.html + +/assets/**/*.lad.json +/docs/src/ladfiles/*.lad.json \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index ee94dddf..8b1bc182 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ rand = "0.8.5" bevy_console = "0.13" # rhai-rand = "0.1" ansi-parser = "0.9" +ladfile_builder = { path = "crates/ladfile_builder", version = "0.2.0" } [workspace] members = [ @@ -134,6 +135,11 @@ required-features = [ "bevy/multi_threaded", ] +[[example]] +name = "docgen" +path = "examples/docgen.rs" +required-features = [] + [workspace.lints.clippy] panic = "deny" unwrap_used = "deny" diff --git a/assets/scripts/bevy_api.lua b/assets/scripts/bevy_api.lua deleted file mode 100644 index 7cb343b3..00000000 --- a/assets/scripts/bevy_api.lua +++ /dev/null @@ -1,159 +0,0 @@ -function table_to_string(t) - local result = "[" - for k,v in pairs(t) do - result = result .. string.format("%s:%s,",k,v) - end - return result .. "]" -end - - -function on_event() - -- send exit event, to finish after one call - world.exit() - - print(entity) - print(script) - print(world) - - -- print(world.hello(entity, entity)) - -- print(world.test_vec({entity, entity})[1]) - - - local my_component_type = world.get_type_by_name("MyComponent") - print("MyComponent type: ", my_component_type:short_name()) - - local comp = world.get_component(entity, my_component_type) - print("Before script: ", comp:print_value()) - - print("\noption") - -- print(comp:get("option_usize")) - print(comp.option_usize) - comp.option_usize = 69 - print(comp.option_usize) - comp.option_usize = nil - print(comp.option_usize) - print("\nvec") - -- print(table_to_string(comp.vec_of_usize)) - comp.vec_of_usize = {42,69,72} - print(comp.vec_of_usize:print_value()) - comp.vec_of_usize[1] = 612312312 - print(comp.vec_of_usize:print_value()) - -- print(table_to_string(comp.vec_of_usize)) - -- comp.vec_of_usize[1] = 0 - -- print(comp.vec_of_usize[2]) - -- print(table_to_string(comp.vec_of_usize)) - -- comp.vec_of_usize = {} - -- print(table_to_string(comp.vec_of_usize)) - -- comp.vec_of_usize = comp.vec_of_usize2 - -- print(table_to_string(comp.vec_of_usize)) - -- comp.vec_of_usize = comp.vec_of_usize - -- print(table_to_string(comp.vec_of_usize)) - -- comp.vec_of_usize:insert(1, 42) - -- print(table_to_string(comp.vec_of_usize)) - - -- print("\nmap") - -- -- print(comp.map_of_strings["key"]) - -- comp.map_of_strings:insert("key2", "value") - -- -- print(comp.map_of_strings["key2"]) - - - - -- print("============") - - -- -- vec's and matrices have custom __index and __newindex overrides - -- print("comp.vec2 before: ", comp.vec2) - -- comp.vec2[1] = 69 - -- print("comp.vec2 after: ", comp.vec2) - - -- -- Option's get converted to nil or the value inside - -- print("comp.option_vec3 before: ", comp.option_vec3) - -- comp.option_vec3 = Vec3.new(2,1,3) - -- print("comp.option_vec3 after: ", comp.option_vec3) - - -- -- reflection via index is indexed starting at 1, unlike in Rust to match Lua's indexing - -- print("comp.option_vec3[1] before: ", comp.option_vec3[1]) - -- comp.option_vec3[1] = 5 - -- print("comp.option_vec3[1] after: ", comp.option_vec3[1]) - - -- print("============") - - -- -- Vec references get converted to a custom proxy `LuaVec` which is - -- -- also assignable via lua tables - - -- print("comp.vec_of_option_bools before: ", table_to_string(comp.vec_of_option_bools)) - -- comp.vec_of_option_bools = {true,false,true} - -- print("comp.vec_of_option_bools after assignment: ", table_to_string(comp.vec_of_option_bools)) - - -- print("comp.vec_of_option_bools[1] before: ", comp.vec_of_option_bools[1]) - -- comp.vec_of_option_bools[1] = false - -- print("comp.vec_of_option_bools[1] after: ", comp.vec_of_option_bools[1]) - - -- -- there are some additional methods available on LuaVec proxies imitating the Vec api - -- print("comp.vec_of_option_bools before insert: ", table_to_string(comp.vec_of_option_bools)) - -- comp.vec_of_option_bools:insert(1,nil) - -- print("comp.vec_of_option_bools after insert: ", table_to_string(comp.vec_of_option_bools)) - - - - -- print("comp.vec_of_option_bools before push: ", table_to_string(comp.vec_of_option_bools)) - -- comp.vec_of_option_bools:push(false) - -- print("comp.vec_of_option_bools after push: ", table_to_string(comp.vec_of_option_bools)) - - -- print("comp.vec_of_option_bools len after push: ", #comp.vec_of_option_bools) - - -- print("comp.vec_of_option_bools before pop: ", table_to_string(comp.vec_of_option_bools)) - -- print(comp.vec_of_option_bools:pop():print_value()) - -- print("comp.vec_of_option_bools after pop: ", table_to_string(comp.vec_of_option_bools)) - - -- print("the pairs inside comp.vec_of_option_bools: ") - -- for k,v in pairs(comp.vec_of_option_bools) do - -- print(string.format(" - %s:%s",k,v)) - -- end - - - -- comp.vec_of_option_bools:clear() - -- print("comp.vec_of_option_bools after clear: ", table_to_string(comp.vec_of_option_bools)) - -- print("comp.vec_of_option_bools len after clear: ", #comp.vec_of_option_bools) - - -- print("============") - - -- print(Vec3.new(0,1,0) + Vec3.new(1,0,0)) - -- print(Vec3.new(0,1,0):any_orthonormal_vector()) - -- print(comp.mat3[1]) - -- print(Vec3.new(0,1,0):any_orthonormal_vector() + comp.mat3[1]) - -- local complex_vec_op = Vec3.new(0,1,0):any_orthonormal_vector() + comp.mat3[1] - -- print("(0,1,0).any_orthonormal_vector() + mat3.x_axis is: ", complex_vec_op) - - -- local new_mat3 = Mat3.from_cols(Vec3.new(1,0,0),Vec3.new(0,1,0),Vec3.new(0,0,-1)) - -- print("new_mat3 is:", new_mat3) - - -- comp.vec2 = comp.vec2 + comp.vec2 - -- print("A") - -- comp.usize = comp.vec2:min_element() - - -- print("B") - -- comp.f32 = comp.f32 + comp.f32 + comp.vec2:min_element() - -- print("C") - -- comp.vec2 = Vec2.new(2,1) - -- print("D") - -- comp.quat = Quat.from_xyzw(3,2,1,4) - -- print("E") - -- comp.mat3[1] = Vec3.new(69,69,69) - -- print("F") - - - -- world.exit() - -- do return end - -- print("============") - - -- -- this is an example of something impossible to achieve with plain bevy reflection under the hood - -- comp.mat3[1][1] = 42 - - -- -- now let's retrieve these again to see if we actually changed their values permanently - -- comp = world.get_component(entity,my_component_type) - - -- print("After script:") - -- print(comp) - - -- world.exit() -end \ No newline at end of file diff --git a/assets/scripts/complex_game_loop.lua b/assets/scripts/complex_game_loop.lua deleted file mode 100644 index b5e1b880..00000000 --- a/assets/scripts/complex_game_loop.lua +++ /dev/null @@ -1,17 +0,0 @@ - - -function on_pre_physics(id) - print("on_pre_physics, Handling:") - print(string.format("\t-> id: %d",id)) -end - -function on_post_physics(id) - print("on_post_physics, Handling:") - print(string.format("\t-> id: %d",id)) -end - - -function on_post_update(id) - print("on_post_update, Handling:") - print(string.format("\t-> id: %d",id)) -end diff --git a/assets/scripts/console_integration.lua b/assets/scripts/console_integration.lua deleted file mode 100644 index 2c6527c5..00000000 --- a/assets/scripts/console_integration.lua +++ /dev/null @@ -1,12 +0,0 @@ -local a = 0 - -function on_update() - - if a % 100 == 0 then - -- print_to_console() is defined in console_integration.rs - -- by the api provider - print_to_console(string.format("%d, entity index:%d", a, entity:index())) - end - - a = a + 1 -end \ No newline at end of file diff --git a/assets/scripts/console_integration.rhai b/assets/scripts/console_integration.rhai deleted file mode 100644 index 04fcf60c..00000000 --- a/assets/scripts/console_integration.rhai +++ /dev/null @@ -1,13 +0,0 @@ - -fn on_update(){ - - if !("a" in state){ - state.a = 0; - } - - if (state.a % 100) == 0 { - print_to_console(world,`${state.a}, entity:${ entity_id(entity)}`); - } - - state.a = state.a + 1; -} \ No newline at end of file diff --git a/assets/scripts/coroutines.lua b/assets/scripts/coroutines.lua deleted file mode 100644 index 728dd03d..00000000 --- a/assets/scripts/coroutines.lua +++ /dev/null @@ -1,23 +0,0 @@ -local my_routine; - -function on_update() - if my_routine == nil then - my_routine = coroutine.create(function() - local starttime = os.time() - local endtime = starttime + 5 - while os.time() < endtime do - print(os.date("waiting %H:%M:%S", os.time())) - coroutine.yield() - end - - print(os.date("finished! %H:%M:%S", os.time())) - end) - else - if coroutine.status(my_routine) ~= "dead" then - coroutine.resume(my_routine) - else - print("Couroutine has finished, no longer running") - world.exit() - end - end -end diff --git a/assets/scripts/dynamic_queries.lua b/assets/scripts/dynamic_queries.lua deleted file mode 100644 index a12c8e4a..00000000 --- a/assets/scripts/dynamic_queries.lua +++ /dev/null @@ -1,23 +0,0 @@ -local component_a = world.get_type_by_name("ComponentA") -local component_b = world.get_type_by_name("ComponentB") -local component_c = world.get_type_by_name("ComponentC") - -print("Querying for entities with component_a and without component_c") -for entity, c in world.query(component_a):without(component_c):iter() do - print("Entity with index: " .. entity:index() .. " component: " .. tostring(c)) -end - -print("Querying for entities with component_b and without component_a") -for entity, c in world.query(component_b):without(component_a):iter() do - print("Entity with index: " .. entity:index() .. " component: " .. tostring(c)) -end - -print("Querying for all components at once") -for entity, c1,c2,c3 in world.query(component_a, component_b, component_c):iter() do - print("Entity with index: " .. entity:index()) - print("\tComponentA: " .. tostring(c1)) - print("\tComponentB: " .. tostring(c2)) - print("\tComponentC: " .. tostring(c3)) -end - -world.exit() \ No newline at end of file diff --git a/assets/scripts/dynamic_queries.rhai b/assets/scripts/dynamic_queries.rhai deleted file mode 100644 index 73701d7b..00000000 --- a/assets/scripts/dynamic_queries.rhai +++ /dev/null @@ -1,11 +0,0 @@ -fn on_event() { - let component_a = world.get_type_by_name("ComponentA"); - let component_b = world.get_type_by_name("ComponentB"); - let component_c = world.get_type_by_name("ComponentC"); - - // Use with_components/without_components, as the word `with` is - // reserved in rhai - for results in world.query([component_a]).with_components([component_b]).without_components([component_c]) { - print(results.Entity); - } -} diff --git a/assets/scripts/event_recipients.lua b/assets/scripts/event_recipients.lua deleted file mode 100644 index b846a742..00000000 --- a/assets/scripts/event_recipients.lua +++ /dev/null @@ -1,6 +0,0 @@ -function on_event(id) - print(string.format("on_event, script_id: %s, Handling:", script_id)) - print(string.format("\t-> id : %d", id)) - print(string.format("\t-> entity : %s", entity)) - -end diff --git a/assets/scripts/event_recipients.rune b/assets/scripts/event_recipients.rune deleted file mode 100644 index e3b58056..00000000 --- a/assets/scripts/event_recipients.rune +++ /dev/null @@ -1,3 +0,0 @@ -pub fn on_event(id) { - info(`id: ${id}`); -} diff --git a/assets/scripts/minimal.rune b/assets/scripts/minimal.rune deleted file mode 100644 index 4b905ac4..00000000 --- a/assets/scripts/minimal.rune +++ /dev/null @@ -1,3 +0,0 @@ -pub fn on_event() { - print_fancy("Hello, World!"); -} diff --git a/assets/scripts/multiple_events_rhai.rhai b/assets/scripts/multiple_events_rhai.rhai deleted file mode 100644 index bc7c6680..00000000 --- a/assets/scripts/multiple_events_rhai.rhai +++ /dev/null @@ -1,16 +0,0 @@ -fn on_init(name) { - print(`Hello World! From "${name}" in Init`); - - let parent = world.get_parent(entity); - if parent == () { - print(`Parent doesn't exist`); - } else { - print(`Parent exists`); - } -} - -fn on_update(name, delta) { - print(`Hello World! From "${name}" in Update: ${delta}`); - - world.despawn_recursive(entity); -} \ No newline at end of file diff --git a/assets/scripts/runtime_error.lua b/assets/scripts/runtime_error.lua deleted file mode 100644 index 2fc59571..00000000 --- a/assets/scripts/runtime_error.lua +++ /dev/null @@ -1,3 +0,0 @@ -function on_update() - print(string.format("%d","a")) -end \ No newline at end of file diff --git a/crates/bevy_mod_scripting_core/Cargo.toml b/crates/bevy_mod_scripting_core/Cargo.toml index 75887c2d..dec63456 100644 --- a/crates/bevy_mod_scripting_core/Cargo.toml +++ b/crates/bevy_mod_scripting_core/Cargo.toml @@ -44,7 +44,6 @@ derivative = "2.2" profiling = { workspace = true } bevy_mod_scripting_derive = { workspace = true } - [dev-dependencies] test_utils = { workspace = true } tokio = { version = "1", features = ["rt", "macros"] } diff --git a/crates/bevy_mod_scripting_core/src/docgen/mod.rs b/crates/bevy_mod_scripting_core/src/docgen/mod.rs index e74e9696..1918070c 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/mod.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/mod.rs @@ -1,3 +1,4 @@ //! Documentation generation for scripting languages. + pub mod info; pub mod typed_through; diff --git a/crates/ladfile_builder/Cargo.toml b/crates/ladfile_builder/Cargo.toml index 5d77b2ad..f72d45a8 100644 --- a/crates/ladfile_builder/Cargo.toml +++ b/crates/ladfile_builder/Cargo.toml @@ -15,6 +15,7 @@ readme = "readme.md" [dependencies] bevy_mod_scripting_core = { workspace = true } # I don't think bevy has a top level feature for this :C +bevy = { workspace = true } bevy_reflect = { version = "0.15.2", features = ["documentation"] } ladfile = { version = "0.2.0", path = "../ladfile" } regex = "1.11" diff --git a/crates/ladfile_builder/src/lib.rs b/crates/ladfile_builder/src/lib.rs index 329b6247..0de0665b 100644 --- a/crates/ladfile_builder/src/lib.rs +++ b/crates/ladfile_builder/src/lib.rs @@ -1,4 +1,5 @@ //! Parsing definitions for the LAD (Language Agnostic Decleration) file format. +pub mod plugin; use bevy_mod_scripting_core::{ bindings::{ diff --git a/crates/ladfile_builder/src/plugin.rs b/crates/ladfile_builder/src/plugin.rs new file mode 100644 index 00000000..fa93a64b --- /dev/null +++ b/crates/ladfile_builder/src/plugin.rs @@ -0,0 +1,120 @@ +//! Plugins for bevy which allow generating ladfiles at startup + +use std::path::PathBuf; + +use bevy::{ + app::{App, Plugin, Startup}, + ecs::{ + reflect::AppTypeRegistry, + system::{Res, Resource}, + }, +}; +use bevy_mod_scripting_core::bindings::function::{ + namespace::Namespace, script_function::AppScriptFunctionRegistry, +}; + +use crate::LadFileBuilder; + +/// Plugin which enables the generation of LAD files at runtime for the purposes of creating documentation and other goodies. +/// +/// When added, will automatically generate a LAD file on the Startup schedule +pub struct ScriptingDocgenPlugin(LadFileSettings); + +#[derive(Resource, Clone)] +/// Stores the settings for the generated Ladfile +pub struct LadFileSettings { + /// The path at which to generate the LAD file. If relative, will be relative from the assets directory + /// The extension should be `json.lad` + /// + /// By default this will be `assets/bindings.lad.json` + pub path: PathBuf, + /// The description to use for the LAD file, by default it's empty + pub description: &'static str, + + /// Whether to pretty print the output JSON. By default this is true (slay) + pub pretty: bool, +} + +impl Default for ScriptingDocgenPlugin { + fn default() -> Self { + Self(LadFileSettings { + path: PathBuf::from("bindings.lad.json"), + description: "", + pretty: true, + }) + } +} + +impl ScriptingDocgenPlugin { + /// Create a new instance of the plugin with the given path + pub fn new(path: PathBuf, description: &'static str, pretty: bool) -> Self { + Self(LadFileSettings { + path, + description, + pretty, + }) + } +} + +fn generate_lad_file( + type_registry: Res, + function_registry: Res, + settings: Res, +) { + let type_registry = type_registry.read(); + let function_registry = function_registry.read(); + let mut builder = LadFileBuilder::new(&type_registry); + builder + .set_description(settings.description) + .set_sorted(true); + + // first of all, iterate over all the types and register them + for registration in type_registry.iter() { + let type_info = registration.type_info(); + + // ignore things without an identifier + if type_info.type_path_table().ident().is_none() { + continue; + } + + builder.add_type_info(type_info); + + // find functions on the namespace + for (_, function) in + function_registry.iter_namespace(Namespace::OnType(type_info.type_id())) + { + builder.add_function_info(function.info.clone()); + } + } + + let file = builder.build(); + + let mut path = PathBuf::from("assets"); + path.push(settings.path.clone()); + + // generate + let file = match ladfile::serialize_lad_file(&file, settings.pretty) { + Ok(file) => file, + Err(e) => { + bevy::log::error!("Error serializing LAD file: {}", e); + return; + } + }; + + // save + match std::fs::write(&path, file) { + Ok(_) => { + bevy::log::info!("Successfully generated LAD file at {:?}", path); + } + Err(e) => { + bevy::log::error!("Error saving LAD file to {:?}: {}", path, e); + } + } +} + +impl Plugin for ScriptingDocgenPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(self.0.clone()); + app.add_systems(Startup, generate_lad_file); + } +} diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 33fa4853..c4752ad1 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -202,6 +202,35 @@ impl From for Features { } } +/// Enumerates the binaries available in the project and their paths +#[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + strum::EnumString, + strum::AsRefStr, + strum::VariantNames, +)] +#[strum(serialize_all = "snake_case")] +enum Binary { + MdbookPreprocessor, +} + +impl Binary { + pub fn path(self) -> PathBuf { + PathBuf::from(match self { + Binary::MdbookPreprocessor => "./crates/lad_backends/mdbook_lad_preprocessor/", + }) + } + + pub fn to_placeholder() -> clap::builder::Str { + format!("[{}]", Binary::VARIANTS.join("|")).into() + } +} + #[derive( Debug, Clone, @@ -310,6 +339,12 @@ impl App { .arg("--bevy-features") .arg(bevy_features.join(",")); } + Xtasks::Example { example } => { + cmd.arg("example").arg(example); + } + Xtasks::Install { binary } => { + cmd.arg("install").arg(binary.as_ref()); + } } cmd @@ -515,6 +550,20 @@ enum Xtasks { )] kind: CheckKind, }, + /// Run the example with the given name + Example { + /// The example to run + example: String, + }, + /// Installs a binary produced by the workspace + Install { + /// The binary to install + #[clap( + value_parser=clap::value_parser!(Binary), + value_name=Binary::to_placeholder(), + )] + binary: Binary, + }, /// Build the rust crates.io docs as well as any other docs Docs { /// Open in browser @@ -592,6 +641,7 @@ impl Xtasks { Xtasks::Test { name, package } => Self::test(app_settings, package, name), Xtasks::CiCheck => Self::cicd(app_settings), Xtasks::Init { dont_update_ide } => Self::init(app_settings, dont_update_ide), + Xtasks::Example { example } => Self::example(app_settings, example), Xtasks::Macros { macro_name } => match macro_name { Macro::ScriptTests => { let mut settings = app_settings.clone(); @@ -636,6 +686,7 @@ impl Xtasks { output_dir, bevy_features, } => Self::codegen(app_settings, output_dir, bevy_features), + Xtasks::Install { binary } => Self::install(app_settings, binary), }?; Ok("".into()) @@ -739,7 +790,8 @@ impl Xtasks { args.push(command.to_owned()); - if command != "fmt" && command != "bevy-api-gen" { + if command != "fmt" && command != "bevy-api-gen" && command != "run" && command != "install" + { // fmt doesn't care about features, workspaces or profiles args.push("--workspace".to_owned()); @@ -1046,6 +1098,23 @@ impl Xtasks { fn docs(mut app_settings: GlobalArgs, open: bool, no_rust_docs: bool) -> Result<()> { // find [package.metadata."docs.rs"] key in Cargo.toml if !no_rust_docs { + info!("installing mdbook ladfile preprocessor binary"); + Self::install(app_settings.clone(), Binary::MdbookPreprocessor)?; + + info!("Running docgen example to generate ladfiles"); + Self::example(app_settings.clone(), "docgen".to_owned())?; + + // copy the `/assets/bindings.lad.json` file to it's path in the book + let ladfile_path = + Self::relative_workspace_dir(&app_settings, "assets/bindings.lad.json")?; + let destination_path = + Self::relative_workspace_dir(&app_settings, "docs/src/ladfiles/bindings.lad.json")?; + + info!("Copying generated ladfile from: {ladfile_path:?} to: {destination_path:?}"); + std::fs::create_dir_all(destination_path.parent().unwrap())?; + std::fs::copy(ladfile_path, destination_path) + .with_context(|| "copying generated ladfile")?; + info!("Building rust docs"); let metadata = Self::main_workspace_cargo_metadata()?; @@ -1430,6 +1499,44 @@ impl Xtasks { warn!("Could not merge json, overrides and target are not objects"); } } + + fn example(app_settings: GlobalArgs, example: String) -> std::result::Result<(), Error> { + // find the required features for the example named this in the cargo.toml of the main workspace + // the keys look like + // [[example]] + // name = "docgen" + // path = "examples/docgen.rs" + // required-features = [] + + // let metadata = Self::main_workspace_cargo_metadata()?; + // let metadata = &metadata.root_package().unwrap().targets; + // println!("{metadata:#?}"); + + // run the example + Self::run_workspace_command( + &app_settings, + "run", + "Failed to run example", + vec!["--example", example.as_str()], + None, + )?; + + Ok(()) + } + + fn install(app_settings: GlobalArgs, binary: Binary) -> std::result::Result<(), Error> { + // run cargo install --path + let binary_path = Self::relative_workspace_dir(&app_settings, binary.path())?; + Self::run_system_command( + &app_settings, + "cargo", + "Failed to install binary", + vec!["install", "--path", binary_path.to_str().unwrap()], + None, + )?; + + Ok(()) + } } /// Because we are likely already runnnig in the context of a cargo invocation, @@ -1438,7 +1545,7 @@ impl Xtasks { fn pop_cargo_env() -> Result<()> { let env = std::env::vars().collect::>(); // RUSTUP TOOLCHAIN exclude is a temporary fix, it might make deving the api codegen crate not work - let exclude_list = ["CARGO_HOME", "RUSTUP_TOOLCHAIN"]; + let exclude_list = []; for (key, value) in env.iter() { if key.starts_with("CARGO_") && !exclude_list.contains(&(key.as_str())) { diff --git a/docs/book.toml b/docs/book.toml index dd964e12..bace7142 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -10,3 +10,5 @@ description = "Documentation for the Bevy Scripting library" additional-js = ["multi-code-block.js"] git-repository-url = "https://github.com/makspll/bevy_mod_scripting" edit-url-template = "https://github.com/makspll/bevy_mod_scripting/edit/main/docs/{path}" + +[preprocessor.lad-preprocessor] diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 23f2f544..438602bb 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -30,4 +30,8 @@ - [Setup](./Development/setup.md) - [New Languages](./Development/AddingLanguages/introduction.md) - [Evaluating Feasibility](./Development/AddingLanguages/evaluating-feasibility.md) - - [Necessary Features](./Development/AddingLanguages/necessary-features.md) \ No newline at end of file + - [Necessary Features](./Development/AddingLanguages/necessary-features.md) + +# WIP + +- [Generated Docs](./ladfiles/bindings.lad.json) diff --git a/examples/docgen.rs b/examples/docgen.rs new file mode 100644 index 00000000..e77efa86 --- /dev/null +++ b/examples/docgen.rs @@ -0,0 +1,20 @@ +use bevy::{app::App, asset::AssetPlugin, hierarchy::HierarchyPlugin, MinimalPlugins}; +use bevy_mod_scripting::ScriptFunctionsPlugin; +use ladfile_builder::plugin::ScriptingDocgenPlugin; + +fn main() -> std::io::Result<()> { + let mut app = App::new(); + // headless bevy + app.add_plugins((MinimalPlugins, AssetPlugin::default(), HierarchyPlugin)); + + // docgen + scripting + app.add_plugins((ScriptFunctionsPlugin, ScriptingDocgenPlugin::default())); + + // run once + app.cleanup(); + app.finish(); + app.update(); + + // bah bye + Ok(()) +}