diff --git a/.forgejo/workflows/rust.yml b/.forgejo/workflows/rust.yml index 4d559f6..35492aa 100644 --- a/.forgejo/workflows/rust.yml +++ b/.forgejo/workflows/rust.yml @@ -41,8 +41,8 @@ jobs: - name: 🛠️ Install dependencies run: | - sudo apt-get update - sudo apt-get install -y \ + apt-get update + apt-get install -y \ ${{ matrix.deps }} \ pkg-config \ ${{ matrix.pkg_config }} diff --git a/Cargo.lock b/Cargo.lock index 6081867..ffd1ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3586,7 +3586,6 @@ name = "zenyx" version = "0.1.0" dependencies = [ "ahash", - "backtrace", "build-print", "built", "bytemuck", diff --git a/Cargo.toml b/Cargo.toml index bba9f01..e2d1bc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = ["engine","subcrates/zen_core"] [workspace.dependencies] parking_lot = "0.12.3" +zen_core = { path = "./subcrates/zen_core" } [profile.release] lto = true diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 7b54062..6c007e7 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -12,7 +12,6 @@ documentation = "https://zenyx-engine.github.io/docs" repository = "https://codeberg.org/Caznix/Zenyx" [dependencies] -backtrace = { version = "0.3.74", default-features = false } colored = { version = "3.0.0", default-features = false } parking_lot.workspace = true rustyline = { version = "15.0.0", default-features = false, features = ["custom-bindings", "derive","with-file-history"] } @@ -27,7 +26,7 @@ cgmath = { version = "0.18.0", default-features = false } tracing = { version = "0.1.41", default-features = false } tracing-subscriber = { version = "0.3.19", default-features = false, features = ["ansi", "fmt"] } tobj = { version = "4.0.3", default-features = false } -ahash = { version = "0.8.11", default-features = false } +ahash = { version = "0.8.11", default-features = false, features = ["std"] } wgpu_text = { version = "0.9.2", default-features = false } toml = { version = "0.8.20", default-features = false } serde = { version = "1.0.219", default-features = false, features = ["derive"] } diff --git a/engine/src/core/panic.rs b/engine/src/core/panic.rs index 7c494c4..fc7a75b 100644 --- a/engine/src/core/panic.rs +++ b/engine/src/core/panic.rs @@ -5,7 +5,7 @@ use native_dialog::{MessageDialog, MessageType}; use parking_lot::Once; use tracing::error; -static INIT: parking_lot::Once = Once::new(); +static INIT: Once = Once::new(); pub fn set_panic_hook() { INIT.call_once(|| { diff --git a/engine/src/core/render/mod.rs b/engine/src/core/render/mod.rs index ffb4ded..fbaedc3 100644 --- a/engine/src/core/render/mod.rs +++ b/engine/src/core/render/mod.rs @@ -59,11 +59,19 @@ pub struct TerminalState { max_history_lines: usize, input_history: Vec, } -#[derive(Default)] + pub struct App<'window> { windows: ahash::AHashMap>, } +impl Default for App<'_> { + fn default() -> Self { + Self { + windows: ahash::AHashMap::new(), + } + } +} + static CUBE_OBJ: &str = " # Blender 4.2.3 LTS # www.blender.org diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index 8c28a6c..f5eac1b 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,4 +1,4 @@ -use std::{fs, path::PathBuf, str::FromStr}; +use std::{collections::VecDeque, fs, path::PathBuf, str::FromStr}; use parking_lot::RwLock; @@ -151,38 +151,31 @@ impl Command for ExecFile { .build() })?; if file_path.extension().is_some() && file_path.extension().unwrap() != "zensh" { - return Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing) + Err(ZenyxError::builder(ZenyxErrorKind::CommandParsing) .with_message("Selected file was not a zensh file") - .build()); + .build()) } else { - let zscript = fs::read_to_string(file_path).map_err(|e| { - ZenyxError::builder(ZenyxErrorKind::Io) - .with_message("Failed to read file") - .with_source(e) - .build() - })?; let mut script_output = String::new(); - if let Ok(commands_to_execute) = eval(zscript) { - for (cmd_name, cmd_args) in commands_to_execute { - match COMMAND_MANAGER.read().execute(&cmd_name, cmd_args) { - Ok(output) => script_output.push_str(&output), - Err(e) => { - return Err(ZenyxError::builder( - ZenyxErrorKind::CommandExecution, - ) - .with_message(format!( - "Error executing command '{}' in script: {}", - cmd_name, e - )) - .build()); + match self.evaluate_script_heap_based(file_path) { + Ok(commands_to_execute) => { + for (cmd_name, cmd_args) in commands_to_execute { + match COMMAND_MANAGER.read().execute(&cmd_name, cmd_args) { + Ok(output) => script_output.push_str(&output), + Err(e) => { + return Err(ZenyxError::builder( + ZenyxErrorKind::CommandExecution, + ) + .with_message(format!( + "Error executing command '{}' in script: {}", + cmd_name, e + )) + .build()); + } } } + Ok(script_output) } - return Ok(script_output); - } else { - return Err(ZenyxError::builder(ZenyxErrorKind::CommandExecution) - .with_message("Failed to evaluate script") - .build()); + Err(e) => Err(e), } } } @@ -213,6 +206,102 @@ impl Command for ExecFile { } } +impl ExecFile { + const MAX_RECURSION_DEPTH: usize = 100; // Increased for heap-based approach + + fn evaluate_script_heap_based( + &self, + initial_file_path: PathBuf, + ) -> Result>)>, ZenyxError> { + let mut command_queue: VecDeque<(PathBuf, usize)> = VecDeque::new(); + let mut collected_commands = Vec::new(); + command_queue.push_back((initial_file_path, 0)); + + while let Some((current_file_path, current_depth)) = command_queue.pop_front() { + if current_depth > Self::MAX_RECURSION_DEPTH { + return Err(ZenyxError::builder(ZenyxErrorKind::CommandExecution) + .with_message(format!( + "Recursion limit of {} exceeded while executing script.", + Self::MAX_RECURSION_DEPTH + )) + .build()); + } + + let zscript_result = fs::read_to_string(¤t_file_path).map_err(|e| { + ZenyxError::builder(ZenyxErrorKind::Io) + .with_message(format!("Failed to read file: {}", current_file_path.display())) + .with_source(e) + .build() + }); + + match zscript_result { + Ok(zscript) => { + let commands: Vec<&str> = zscript.split(|c| c == ';' || c == '\n').collect(); + for command_str in commands { + let command_str = command_str.trim(); + if command_str.is_empty() { + continue; + } + + let tokens = tokenize(command_str); + if tokens.is_empty() { + continue; + } + + let cmd_name = &tokens[0]; + let args: Option> = if tokens.len() > 1 { + Some(tokens[1..].iter().map(|s| s.to_string()).collect()) + } else { + None + }; + + if cmd_name.to_lowercase() == "exec" { + if let Some(ref file_args) = args { + if let Some(nested_file_path_str) = file_args.first() { + let nested_file_path = + PathBuf::from_str(nested_file_path_str).map_err(|e| { + ZenyxError::builder(ZenyxErrorKind::CommandParsing) + .with_message("Invalid file path in nested exec command") + .with_source(e) + .build() + })?; + if nested_file_path.extension().is_some() + && nested_file_path.extension().unwrap() != "zensh" + { + return Err(ZenyxError::builder( + ZenyxErrorKind::CommandParsing, + ) + .with_message("Nested exec file was not a zensh file") + .build()); + } + command_queue.push_back((nested_file_path, current_depth + 1)); + } else { + return Err(ZenyxError::builder( + ZenyxErrorKind::CommandParsing, + ) + .with_message("Not enough arguments for nested exec command") + .build()); + } + } else { + return Err(ZenyxError::builder( + ZenyxErrorKind::CommandParsing, + ) + .with_message("Not enough arguments for nested exec command") + .build()); + } + } else { + collected_commands.push((cmd_name.to_owned(), args)); + } + } + } + Err(e) => return Err(e), + } + } + + Ok(collected_commands) + } +} + #[derive(Default)] pub struct CounterCommand { counter: RwLock, @@ -318,4 +407,4 @@ fn eval(input: String) -> Result>)>, ZenyxError> evaluted.push((cmd_name.to_owned(), args)); } Ok(evaluted) -} +} \ No newline at end of file diff --git a/engine/src/metadata.rs b/engine/src/metadata.rs index 6dfb1fc..94a7533 100644 --- a/engine/src/metadata.rs +++ b/engine/src/metadata.rs @@ -14,7 +14,7 @@ mod build_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); } -static INIT: parking_lot::Once = Once::new(); +static INIT: Once = Once::new(); pub fn set_panic_hook() { INIT.call_once(|| { @@ -137,14 +137,14 @@ fn rust_version() -> Result> { fn capture_backtrace() -> String { let mut backtrace = String::new(); - let sysinfo = crate::metadata::SystemMetadata::current(); + let sysinfo = SystemMetadata::current(); backtrace.push_str(&format!( "--- System Information ---\n{}\n", sysinfo.verbose_summary() )); let trace = std::backtrace::Backtrace::force_capture(); - let message = format!("\n--- Backtrace ---\n\n"); + let message = "\n--- Backtrace ---\n\n".to_string(); backtrace.push_str(&message); backtrace.push_str(&format!("{trace:#}")); @@ -380,7 +380,7 @@ impl CPU { let current_clock_speed = max_clock_speed; let logical_cores = cpu_opt.map(|_| sys.cpus().len() as u8); - let physical_cores = sysinfo::System::physical_core_count().map(|pc| pc as u8); + let physical_cores = System::physical_core_count().map(|pc| pc as u8); let cpuid = CpuId::new(); let mut l1_cache = None; @@ -420,7 +420,7 @@ impl CPU { Self { brand, - arch: std::env::consts::ARCH + arch: env::consts::ARCH .parse() .unwrap_or(CPUArch::Other("unknown".into())), name, @@ -709,9 +709,9 @@ impl OSInfo { let mut system = System::new(); system.refresh_all(); Self { - name: sysinfo::System::name().unwrap_or_else(|| build_info::TARGET.to_string()), - version: sysinfo::System::os_version(), - kernel_version: sysinfo::System::kernel_version(), + name: System::name().unwrap_or_else(|| build_info::TARGET.to_string()), + version: System::os_version(), + kernel_version: System::kernel_version(), } } diff --git a/engine/test.zensh b/engine/test.zensh index aa8771e..f53ba67 100644 --- a/engine/test.zensh +++ b/engine/test.zensh @@ -1 +1 @@ -cr_exec ./test.zensh +exec ./test.zensh