From 8dd059871afa5a8dd9fbde121a3fed9b9b30cb22 Mon Sep 17 00:00:00 2001 From: Caznix Date: Thu, 5 Dec 2024 10:46:36 -0500 Subject: [PATCH 01/10] print logging state upon change --- engine/src/core/repl/repl.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 0b983a3..354cb89 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -48,6 +48,7 @@ impl ConditionalEventHandler for BacktickEventHandler { if let Some(k) = evt.get(0) { if *k == KeyEvent::from('`') { let mut state = self.toggle_state.lock().unwrap(); + println!("Stdout Logging: {}", if *state { "ON".green() } else { "OFF".red() }); if *state { LOGGER.write_to_stdout(); } else { From ecad886ed95c0a9794592b13616143fde6312981 Mon Sep 17 00:00:00 2001 From: Caznix Date: Thu, 5 Dec 2024 11:00:08 -0500 Subject: [PATCH 02/10] add rust formatting rules --- engine/src/core/renderer/mod.rs | 4 ++-- engine/src/core/repl/commands.rs | 3 ++- engine/src/core/repl/mod.rs | 3 ++- engine/src/core/repl/repl.rs | 19 ++++++++++++------- engine/src/utils/logger.rs | 7 ++++--- rust-toolchain.toml | 2 ++ rustfmt.toml | 7 +++++++ 7 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 rust-toolchain.toml create mode 100644 rustfmt.toml diff --git a/engine/src/core/renderer/mod.rs b/engine/src/core/renderer/mod.rs index 65486a3..7a9147b 100644 --- a/engine/src/core/renderer/mod.rs +++ b/engine/src/core/renderer/mod.rs @@ -1,8 +1,8 @@ pub mod ctx; -use ctx::WgpuCtx; +use std::sync::Arc; +use ctx::WgpuCtx; use log::{debug, trace}; -use std::sync::Arc; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index 97b95c8..518b79c 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,6 +1,7 @@ -use super::COMMAND_LIST; use std::process::Command; +use super::COMMAND_LIST; + pub(crate) fn say_hello() { println!("Hello, World!"); } diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 19a0cdf..87776ec 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -1,10 +1,11 @@ pub mod commands; pub mod repl; +use std::{borrow::Borrow, collections::HashMap, sync::Arc}; + use lazy_static::lazy_static; use log::{debug, info}; use parking_lot::RwLock; -use std::{borrow::Borrow, collections::HashMap, sync::Arc}; lazy_static! { pub static ref COMMAND_LIST: Arc = Arc::new(CommandList::new()); diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 354cb89..bb675ee 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -1,7 +1,8 @@ -use crate::{ - core::repl::{commands, Callable, COMMAND_LIST}, - utils::logger::LOGGER, +use std::{ + borrow::Cow::{self, Borrowed, Owned}, + sync::{Arc, Mutex}, }; + use anyhow::Result; use chrono::Local; use colored::Colorize; @@ -12,9 +13,10 @@ use rustyline::{ Cmd, Completer, ConditionalEventHandler, Editor, Event, EventContext, EventHandler, Helper, Hinter, KeyEvent, RepeatCount, Validator, }; -use std::{ - borrow::Cow::{self, Borrowed, Owned}, - sync::{Arc, Mutex}, + +use crate::{ + core::repl::{commands, Callable, COMMAND_LIST}, + utils::logger::LOGGER, }; #[derive(Completer, Helper, Hinter, Validator)] @@ -48,7 +50,10 @@ impl ConditionalEventHandler for BacktickEventHandler { if let Some(k) = evt.get(0) { if *k == KeyEvent::from('`') { let mut state = self.toggle_state.lock().unwrap(); - println!("Stdout Logging: {}", if *state { "ON".green() } else { "OFF".red() }); + println!( + "Stdout Logging: {}", + if *state { "ON".green() } else { "OFF".red() } + ); if *state { LOGGER.write_to_stdout(); } else { diff --git a/engine/src/utils/logger.rs b/engine/src/utils/logger.rs index 1830a45..63b3dad 100644 --- a/engine/src/utils/logger.rs +++ b/engine/src/utils/logger.rs @@ -1,10 +1,11 @@ -use colored::Colorize; -use log::{Level, Log, Metadata, Record}; -use once_cell::sync::Lazy; use std::fs::OpenOptions; use std::io::{self, Write}; use std::sync::{Arc, Mutex}; +use colored::Colorize; +use log::{Level, Log, Metadata, Record}; +use once_cell::sync::Lazy; + pub static LOGGER: Lazy = Lazy::new(DynamicLogger::new); // A logger that dynamically switches between file and stdout diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..2678f0b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +indent_style = "Block" +wrap_comments = true +format_code_in_doc_comments = true +trailing_comma = "Vertical" +group_imports = "StdExternalCrate" +reorder_impl_items = true +unstable_features = true \ No newline at end of file From 4926e03fdcc2b11b07de7b31ac6ece67477cc9ec Mon Sep 17 00:00:00 2001 From: Caznix Date: Thu, 5 Dec 2024 11:16:40 -0500 Subject: [PATCH 03/10] fix unwrap errors --- engine/src/core/mod.rs | 2 +- engine/src/core/renderer/ctx.rs | 8 ++++---- engine/src/core/repl/repl.rs | 5 +++-- engine/src/main.rs | 4 +++- engine/src/utils/logger.rs | 11 ++++++----- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/engine/src/core/mod.rs b/engine/src/core/mod.rs index 5615f54..2e15980 100644 --- a/engine/src/core/mod.rs +++ b/engine/src/core/mod.rs @@ -6,7 +6,7 @@ use renderer::App; use winit::event_loop::{ControlFlow, EventLoop}; pub fn init_renderer() -> Result<()> { - let event_loop = EventLoop::new().unwrap(); + let event_loop = EventLoop::new()?; event_loop.set_control_flow(ControlFlow::Poll); let mut app = App::default(); Ok(event_loop.run_app(&mut app)?) diff --git a/engine/src/core/renderer/ctx.rs b/engine/src/core/renderer/ctx.rs index fca1090..88ff9ae 100644 --- a/engine/src/core/renderer/ctx.rs +++ b/engine/src/core/renderer/ctx.rs @@ -41,7 +41,9 @@ impl<'window> WgpuCtx<'window> { let width = size.width.max(1); let height = size.height.max(1); - let surface_config = surface.get_default_config(&adapter, width, height).unwrap(); + let surface_config = surface + .get_default_config(&adapter, width, height) + .expect("Failed to get default surface configuration"); surface.configure(&device, &surface_config); Ok(WgpuCtx { @@ -55,9 +57,7 @@ impl<'window> WgpuCtx<'window> { pub fn new_blocking(window: Arc) -> Result> { tokio::task::block_in_place(|| { - tokio::runtime::Runtime::new() - .unwrap() - .block_on(async { WgpuCtx::new(window).await }) + tokio::runtime::Runtime::new()?.block_on(async { WgpuCtx::new(window).await }) }) } diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index bb675ee..21c19a3 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -1,12 +1,13 @@ use std::{ borrow::Cow::{self, Borrowed, Owned}, - sync::{Arc, Mutex}, + sync::Arc, }; use anyhow::Result; use chrono::Local; use colored::Colorize; use log::debug; +use parking_lot::Mutex; use regex::Regex; use rustyline::{ error::ReadlineError, highlight::Highlighter, hint::HistoryHinter, history::DefaultHistory, @@ -49,7 +50,7 @@ impl ConditionalEventHandler for BacktickEventHandler { fn handle(&self, evt: &Event, _: RepeatCount, _: bool, _: &EventContext) -> Option { if let Some(k) = evt.get(0) { if *k == KeyEvent::from('`') { - let mut state = self.toggle_state.lock().unwrap(); + let mut state = self.toggle_state.lock(); println!( "Stdout Logging: {}", if *state { "ON".green() } else { "OFF".red() } diff --git a/engine/src/main.rs b/engine/src/main.rs index fb575b6..1501b3f 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -1,3 +1,5 @@ +#![deny(clippy::unwrap_in_result)] + use anyhow::Result; use log::LevelFilter; @@ -11,7 +13,7 @@ async fn main() -> Result<()> { let t = zephyr::add(0, 2); println!("{}", t); - log::set_logger(&*LOGGER).unwrap(); + log::set_logger(&*LOGGER).ok(); log::set_max_level(LevelFilter::Debug); print_splash(); diff --git a/engine/src/utils/logger.rs b/engine/src/utils/logger.rs index 63b3dad..bfe442d 100644 --- a/engine/src/utils/logger.rs +++ b/engine/src/utils/logger.rs @@ -1,10 +1,11 @@ use std::fs::OpenOptions; use std::io::{self, Write}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use colored::Colorize; use log::{Level, Log, Metadata, Record}; use once_cell::sync::Lazy; +use parking_lot::Mutex; pub static LOGGER: Lazy = Lazy::new(DynamicLogger::new); @@ -28,11 +29,11 @@ impl DynamicLogger { .open(file_path) .expect("Failed to open log file"); - *self.writer.lock().unwrap() = Box::new(file); + *self.writer.lock() = Box::new(file); } pub fn write_to_stdout(&self) { - *self.writer.lock().unwrap() = Box::new(io::stdout()); + *self.writer.lock() = Box::new(io::stdout()); } fn colorize_level(level: Level) -> colored::ColoredString { @@ -58,7 +59,7 @@ impl Log for DynamicLogger { fn log(&self, record: &Record) { if self.enabled(record.metadata()) { - let mut writer = self.writer.lock().unwrap(); + let mut writer = self.writer.lock(); let level = Self::colorize_level(record.level()); // Apply coloring writeln!( writer, @@ -72,7 +73,7 @@ impl Log for DynamicLogger { } fn flush(&self) { - let mut writer = self.writer.lock().unwrap(); + let mut writer = self.writer.lock(); writer.flush().unwrap(); } } From e1aad59ab5da184bbcc590eeb4516a46bddc9887 Mon Sep 17 00:00:00 2001 From: Caznix Date: Thu, 5 Dec 2024 17:05:20 -0500 Subject: [PATCH 04/10] make repl support strings via both double and single quotes --- engine/src/core/repl/repl.rs | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 21c19a3..0798286 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -111,6 +111,32 @@ fn register_commands() { COMMAND_LIST.add_alias("clear".to_string(), "cls".to_string()); } +fn tokenize(command: &str) -> Vec { + let mut tokens = Vec::new(); + let mut current_token = String::new(); + let mut inside_string = false; + + for char in command.chars() { + if char == '"' || char == '\'' { + inside_string = !inside_string; + } else if char.is_whitespace() && !inside_string { + if !current_token.is_empty() { + tokens.push(current_token); + current_token = String::new(); + } + } else { + current_token.push(char); + } + } + + // ignore the last token if it's empty. Who are we. Mojang? - Caz + if !current_token.is_empty() { + tokens.push(current_token); + } + + tokens +} + fn evaluate_command(input: &str) { if input.trim().is_empty() { return; @@ -126,13 +152,13 @@ fn evaluate_command(input: &str) { continue; } - let tokens: Vec<&str> = command.split_whitespace().collect(); + let tokens = tokenize(command); if tokens.is_empty() { - return; + println!("Empty command, skipping."); + continue; } - - let cmd_name = tokens[0]; - let args: Vec = tokens[1..].iter().map(|&s| s.to_string()).collect(); + let cmd_name = &tokens[0]; + let args: Vec = tokens[1..].iter().map(|s| s.to_string()).collect(); COMMAND_LIST.execute_command( cmd_name.to_string(), From 8dc0765f783f6544e0bc679b58a892e242e671e8 Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 10:56:18 -0500 Subject: [PATCH 05/10] change the look of autocompletion --- engine/src/core/repl/mod.rs | 3 +++ engine/src/core/repl/repl.rs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 87776ec..85dce9a 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -3,6 +3,7 @@ pub mod repl; use std::{borrow::Borrow, collections::HashMap, sync::Arc}; +use colored::Colorize; use lazy_static::lazy_static; use log::{debug, info}; use parking_lot::RwLock; @@ -128,6 +129,8 @@ impl CommandList { } (_, _) => command.execute(args), } + } else { + eprintln!("Command: '{}' was not found", name.red().italic()); } } } diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 0798286..ca5c598 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -37,7 +37,7 @@ impl Highlighter for MyHelper { } fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { - Owned(hint.bold().to_string()) + Owned(hint.italic().bright_black().to_string()) } } @@ -139,6 +139,7 @@ fn tokenize(command: &str) -> Vec { fn evaluate_command(input: &str) { if input.trim().is_empty() { + println!("Empty command, skipping. type 'help' for a list of commands."); return; } From b289e3d26ba1c13e85917b24572b0556c99aa422 Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 11:19:12 -0500 Subject: [PATCH 06/10] check command similarity --- engine/src/core/repl/mod.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 85dce9a..1545816 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -62,6 +62,24 @@ pub struct CommandList { pub aliases: RwLock>, } +fn check_similarity(target: &str, strings: &[String]) -> Option { + strings + .iter().filter(|s| { + target.chars().zip(s.chars()).any(|(c1, c2)| c1 == c2) + }) + .min_by_key(|s| { + let mut diff_count = 0; + for (c1, c2) in target.chars().zip(s.chars()) { + if c1 != c2 { + diff_count += 1; + } + } + diff_count += target.len().abs_diff(s.len()); + diff_count + }) + .cloned() +} + impl CommandList { fn new() -> Self { CommandList { @@ -131,6 +149,25 @@ impl CommandList { } } else { eprintln!("Command: '{}' was not found", name.red().italic()); + + let most_similar = check_similarity( + &name, + &self + .commands + .read() + .iter() + .map(|cmd| cmd.name.to_string()) + .collect::>(), + ); + match most_similar { + Some(similar) => { + eprintln!( + "Did you mean: '{}'?", + similar.green().italic().bold() + ); + } + None => {} + } } } } From 48bdd140e215ed4f551220bc1d1ca5acad988c89 Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 15:54:31 -0500 Subject: [PATCH 07/10] exec .zenshell files + shell extensions Co-authored-by: Tristan Poland (Trident_For_U) --- Cargo.toml | 2 +- engine/Cargo.toml | 3 + engine/src/core/repl/commands.rs | 48 ++++++- engine/src/core/repl/mod.rs | 44 +++--- engine/src/core/repl/repl.rs | 22 ++- engine/src/main.rs | 16 ++- engine/src/utils/mathi.rs | 1 + engine/src/utils/mod.rs | 1 + engine/src/utils/splash.rs | 3 +- plugin_api/Cargo.toml | 25 ++++ plugin_api/build.rs | 224 +++++++++++++++++++++++++++++++ plugin_api/src/lib.rs | 77 +++++++++++ plugin_api/src/plugin_imports.rs | 18 +++ plugins/player_lib/Cargo.toml | 11 ++ plugins/player_lib/src/lib.rs | 36 +++++ test.zensh | 0 16 files changed, 494 insertions(+), 37 deletions(-) create mode 100644 engine/src/utils/mathi.rs create mode 100644 plugin_api/Cargo.toml create mode 100644 plugin_api/build.rs create mode 100644 plugin_api/src/lib.rs create mode 100644 plugin_api/src/plugin_imports.rs create mode 100644 plugins/player_lib/Cargo.toml create mode 100644 plugins/player_lib/src/lib.rs create mode 100644 test.zensh diff --git a/Cargo.toml b/Cargo.toml index 3d77c9d..6e96b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["engine", "subcrates/zephyr"] +members = ["engine", "subcrates/zephyr", "plugin_api"] [profile.dev] rpath = false diff --git a/engine/Cargo.toml b/engine/Cargo.toml index ac4eabe..3dc51af 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -11,6 +11,7 @@ lazy_static = "1.5.0" log = "0.4.22" once_cell = "1.20.2" parking_lot = "0.12.3" +rand = "0.8.5" regex = "1.11.1" rustyline = { version = "15.0.0", features = ["derive", "rustyline-derive"] } thiserror = "2.0.3" @@ -18,3 +19,5 @@ tokio = { version = "1.41.1", features = ["macros", "rt", "rt-multi-thread"] } wgpu = "23.0.1" winit = "0.30.5" zephyr.workspace = true +plugin_api = { path = "../plugin_api" } +horizon-plugin-api = "0.1.13" diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index 518b79c..dad0fa2 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,32 +1,66 @@ -use std::process::Command; +use std::{ffi::OsStr, process::Command}; + + + + + +use crate::core::repl::repl::evaluate_command; use super::COMMAND_LIST; -pub(crate) fn say_hello() { +pub(crate) fn say_hello() -> anyhow::Result<()> { println!("Hello, World!"); + Ok(()) } -pub(crate) fn echo(args: Vec) { - println!("{}", args.join(" ")) +pub(crate) fn echo(args: Vec) -> anyhow::Result<()> { + println!("{}", args.join(" ")); + Ok(()) } -pub(crate) fn exit() { +pub(crate) fn exit() -> anyhow::Result<()> { println!("Exiting..."); std::process::exit(0) } -pub(crate) fn clear() { +pub(crate) fn clear() -> anyhow::Result<()> { println!("Clearing screen..., running command"); let _result = if cfg!(target_os = "windows") { Command::new("cmd").args(["/c", "cls"]).spawn() } else { Command::new("clear").spawn() }; + Ok(()) } -pub(crate) fn help() { +pub(crate) fn help() -> anyhow::Result<()> { println!("Commands:"); for cmd in COMMAND_LIST.commands.read().iter() { println!("{:#}", cmd); } + Ok(()) +} +pub(crate) fn exec(args: Vec) -> anyhow::Result<()> { + let file_path_str = &args[0]; + let file_path = std::path::Path::new(file_path_str); + println!("File path: {:#?}", file_path); + + if !file_path.is_file() { + eprintln!("Error: File does not exist or is not a valid file: {}", file_path.display()); + return Ok(()); + } + if file_path.extension() != Some(OsStr::new("zensh")) { + eprintln!("Error: File is not a zenshell script: {:#?}", file_path.extension()); + //TODO: dont panic on this error + return Ok(()); + } + println!("Executing file: {:#?}", file_path); + let file_content = std::fs::read_to_string(file_path)?; + if file_content.is_empty() { + eprintln!("Error: file has no content. Is this a valid zenshell script?"); + return Ok(()); + } + println!("File contents:\n{file_content}"); + evaluate_command(file_content.trim())?; + Ok(()) } diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 1545816..0f84cfd 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -3,6 +3,7 @@ pub mod repl; use std::{borrow::Borrow, collections::HashMap, sync::Arc}; +use anyhow::Ok; use colored::Colorize; use lazy_static::lazy_static; use log::{debug, info}; @@ -14,8 +15,8 @@ lazy_static! { #[derive(Clone, Debug)] enum Callable { - Simple(fn()), - WithArgs(fn(Vec)), + Simple(fn() -> anyhow::Result<()>), + WithArgs(fn(Vec) -> anyhow::Result<()>), } #[derive(Debug)] @@ -27,7 +28,7 @@ pub struct Command { } impl Command { - pub fn execute(&self, args: Option>) { + pub fn execute(&self, args: Option>) -> anyhow::Result<()> { match &self.function { Callable::Simple(f) => { if let Some(args) = args { @@ -36,11 +37,16 @@ impl Command { args.len() ); } - f() + f()?; + Ok(()) } Callable::WithArgs(f) => match args { Some(args) => f(args), - None => eprintln!("Command expected arguments but received 0"), + None => { + Ok(()) + + + }, }, } } @@ -50,9 +56,14 @@ impl std::fmt::Display for Command { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - " {:<10} {}", + " {:<10} {}, {}", self.name, - self.description.unwrap_or("No description available") + self.description.unwrap_or("No description available"), + if self.arg_count > 0 { + format!("{} args", self.arg_count) + } else { + "No args".to_string() + } ) } } @@ -64,9 +75,8 @@ pub struct CommandList { fn check_similarity(target: &str, strings: &[String]) -> Option { strings - .iter().filter(|s| { - target.chars().zip(s.chars()).any(|(c1, c2)| c1 == c2) - }) + .iter() + .filter(|s| target.chars().zip(s.chars()).any(|(c1, c2)| c1 == c2)) .min_by_key(|s| { let mut diff_count = 0; for (c1, c2) in target.chars().zip(s.chars()) { @@ -111,6 +121,7 @@ impl CommandList { eprintln!("Alias: '{}' already exists", alias); return; } + let mut commands = self.commands.write(); if let Some(command) = commands.iter_mut().find(|cmd| cmd.name == name) { debug!("Adding alias: {} for cmd: {}", alias, command.name); @@ -122,7 +133,7 @@ impl CommandList { } } - fn execute_command(&self, mut name: String, args: Option>) { + fn execute_command(&self, mut name: String, args: Option>) -> anyhow::Result<()> { let commands = self.commands.borrow(); if self.aliases.read().contains_key(&name) { name = self @@ -144,6 +155,7 @@ impl CommandList { expected, args_vec.len() ); + Ok(()) } (_, _) => command.execute(args), } @@ -161,12 +173,12 @@ impl CommandList { ); match most_similar { Some(similar) => { - eprintln!( - "Did you mean: '{}'?", - similar.green().italic().bold() - ); + eprintln!("Did you mean: '{}'?", similar.green().italic().bold()); + Ok(()) + } + None => { + Ok(()) } - None => {} } } } diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index ca5c598..5ef467d 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -3,7 +3,8 @@ use std::{ sync::Arc, }; -use anyhow::Result; + + use chrono::Local; use colored::Colorize; use log::debug; @@ -106,6 +107,12 @@ fn register_commands() { Callable::Simple(commands::help), None, ); + COMMAND_LIST.add_command( + "exec", + Some("Executes a .nyx file."), + Callable::WithArgs(commands::exec), + Some(1), + ); // Example of adding aliases for commands COMMAND_LIST.add_alias("clear".to_string(), "cls".to_string()); @@ -137,10 +144,10 @@ fn tokenize(command: &str) -> Vec { tokens } -fn evaluate_command(input: &str) { +pub fn evaluate_command(input: &str) -> anyhow::Result<()> { if input.trim().is_empty() { println!("Empty command, skipping. type 'help' for a list of commands."); - return; + return Ok(()); } let pattern = Regex::new(r"[;|\n]").unwrap(); @@ -164,11 +171,12 @@ fn evaluate_command(input: &str) { COMMAND_LIST.execute_command( cmd_name.to_string(), if args.is_empty() { None } else { Some(args) }, - ); - } + )?; + }; + Ok(()) } -pub async fn handle_repl() -> Result<()> { +pub async fn handle_repl() -> anyhow::Result<()> { let mut rl = Editor::::new()?; rl.set_helper(Some(MyHelper(HistoryHinter::new()))); @@ -193,7 +201,7 @@ pub async fn handle_repl() -> Result<()> { match sig { Ok(line) => { rl.add_history_entry(line.as_str())?; - evaluate_command(line.as_str()); + evaluate_command(line.as_str())?; } Err(ReadlineError::Interrupted) => { println!("CTRL+C received, exiting..."); diff --git a/engine/src/main.rs b/engine/src/main.rs index 1501b3f..1dc0458 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -2,6 +2,8 @@ use anyhow::Result; use log::LevelFilter; +use plugin_api::plugin_imports::*; +use plugin_api::{get_plugin, PluginManager}; pub mod core; pub mod utils; @@ -10,20 +12,26 @@ use utils::{logger::LOGGER, splash::print_splash}; #[tokio::main] async fn main() -> Result<()> { - let t = zephyr::add(0, 2); - println!("{}", t); + // Load all plugins log::set_logger(&*LOGGER).ok(); - log::set_max_level(LevelFilter::Debug); + log::set_max_level(LevelFilter::Off); print_splash(); + let mut plugin_manager = PluginManager::new(); + let plugins = plugin_manager.load_all(); + println!("Plugins loaded: {:?}", plugins); + + // Get the player plugin + let player_lib = get_plugin!(player_lib, plugins); + player_lib.test(); LOGGER.write_to_stdout(); let shell_thread = tokio::task::spawn(async { core::repl::repl::handle_repl().await }); core::init_renderer()?; - let _ = shell_thread.await?; + let _ = shell_thread.await??; Ok(()) } diff --git a/engine/src/utils/mathi.rs b/engine/src/utils/mathi.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/engine/src/utils/mathi.rs @@ -0,0 +1 @@ + diff --git a/engine/src/utils/mod.rs b/engine/src/utils/mod.rs index a0f8995..df309c5 100644 --- a/engine/src/utils/mod.rs +++ b/engine/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod logger; +pub mod mathi; pub mod splash; diff --git a/engine/src/utils/splash.rs b/engine/src/utils/splash.rs index 5f55560..051d11e 100644 --- a/engine/src/utils/splash.rs +++ b/engine/src/utils/splash.rs @@ -1,8 +1,7 @@ use colored::Colorize; -use log::info; pub fn print_splash() { - info!( + println!( "{}", format!( r#" diff --git a/plugin_api/Cargo.toml b/plugin_api/Cargo.toml new file mode 100644 index 0000000..f702587 --- /dev/null +++ b/plugin_api/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "plugin_api" +version = "0.3.0" +authors = ["Tristan Poland "] +description = "Horizon Plugins API" +license = "MIT" +edition = "2021" + +[build-dependencies] +toml_edit = "0.22.22" +pathdiff = "0.2.3" + +[dependencies] +async-trait = "0.1.83" +tokio = { version = "1.42.0", features = ["rt", "net", "rt-multi-thread"] } +uuid = "1.11.0" +socketioxide = "0.15.0" +horizon-plugin-api = "0.1.11" +# +# +# +# +###### BEGIN AUTO-GENERATED PLUGIN DEPENDENCIES - DO NOT EDIT THIS SECTION ###### +player_lib = { path = "../plugins/player_lib", version = "0.1.0" } +###### END AUTO-GENERATED PLUGIN DEPENDENCIES ###### diff --git a/plugin_api/build.rs b/plugin_api/build.rs new file mode 100644 index 0000000..801cf3a --- /dev/null +++ b/plugin_api/build.rs @@ -0,0 +1,224 @@ +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::path::Path; + +fn main() { + // Get the path to the plugins directory + let plugins_dir = Path::new("..").join("plugins"); + + println!("cargo:warning=Looking for plugins in: {:?}", plugins_dir); + + // Ensure the plugins directory exists + if !plugins_dir.exists() { + println!( + "cargo:warning=Plugins directory not found at {:?}", + plugins_dir + ); + return; + } + + // Find all valid plugin directories + let plugin_paths = discover_plugins(&plugins_dir); + println!("cargo:warning=Found {} plugins", plugin_paths.len()); + + // Update Cargo.toml with plugin dependencies + if let Err(e) = update_cargo_toml(&plugin_paths) { + println!("cargo:warning=Failed to update Cargo.toml: {}", e); + std::process::exit(1); + } + + // Generate the plugin macro and imports files + if let Err(e) = generate_plugin_files(&plugin_paths) { + println!("cargo:warning=Failed to generate plugin files: {}", e); + std::process::exit(1); + } + + // Tell Cargo to rerun this script if the plugins directory or Cargo.toml + // changes + println!("cargo:rerun-if-changed=../plugins"); + println!("cargo:rerun-if-changed=Cargo.toml"); +} + +fn discover_plugins(plugins_dir: &Path) -> Vec<(String, String, String)> { + let mut valid_plugins = Vec::new(); + + if let Ok(entries) = fs::read_dir(plugins_dir) { + for entry in entries.flatten() { + let path = entry.path(); + + // Check if this is a directory + if !path.is_dir() { + continue; + } + + let plugin_name = path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_string(); + + // Skip if empty plugin name + if plugin_name.is_empty() { + continue; + } + + // Check for required files/directories + let cargo_toml = path.join("Cargo.toml"); + let src_dir = path.join("src"); + let lib_rs = path.join("src").join("lib.rs"); + + if cargo_toml.exists() && src_dir.exists() && lib_rs.exists() { + // Read the Cargo.toml to get the package name and version + if let Ok(mut file) = File::open(&cargo_toml) { + let mut contents = String::new(); + if file.read_to_string(&mut contents).is_ok() { + // Simple parsing for package name and version + let mut name = None; + let mut version = None; + + for line in contents.lines() { + let line = line.trim(); + if line.starts_with("name") { + name = line + .split('=') + .nth(1) + .map(|s| s.trim().trim_matches('"').to_string()); + } else if line.starts_with("version") { + version = line + .split('=') + .nth(1) + .map(|s| s.trim().trim_matches('"').to_string()); + } + } + + if let (Some(name), Some(version)) = (name, version) { + println!( + "cargo:warning=Found plugin: {} v{} in {}", + name, version, plugin_name + ); + valid_plugins.push((name, version, plugin_name)); + } + } + } + } + } + } + + valid_plugins +} + +const AUTO_GENERATED_START: &str = + "###### BEGIN AUTO-GENERATED PLUGIN DEPENDENCIES - DO NOT EDIT THIS SECTION ######"; +const AUTO_GENERATED_END: &str = "###### END AUTO-GENERATED PLUGIN DEPENDENCIES ######"; + +fn update_cargo_toml(plugin_paths: &[(String, String, String)]) -> std::io::Result<()> { + let cargo_path = "Cargo.toml"; + let mut contents = String::new(); + File::open(cargo_path)?.read_to_string(&mut contents)?; + + // Normalize line endings to \n for consistent processing + contents = contents.replace("\r\n", "\n"); + + // Find the boundaries of the auto-generated section + let start_idx = contents.find(AUTO_GENERATED_START); + let end_idx = contents.find(AUTO_GENERATED_END); + + let base_contents = match (start_idx, end_idx) { + (Some(start), Some(end)) => { + // If an existing section is found, take everything before it + contents[..start].trim_end().to_string() + } + _ => { + // If no section exists, use all current contents + contents.trim_end().to_string() + } + }; + + // Generate the new dependencies section + let mut new_section = String::new(); + new_section.push('\n'); // Add a newline before the section + new_section.push_str(AUTO_GENERATED_START); + new_section.push('\n'); // Add newline after start marker + + // Sort plugins by name for consistent output + let mut sorted_plugins = plugin_paths.to_vec(); + sorted_plugins.sort_by(|a, b| a.0.cmp(&b.0)); + + for (name, version, plugin_dir) in sorted_plugins { + new_section.push_str(&format!( + "{} = {{ path = \"../plugins/{}\", version = \"{}\" }}\n", + name, plugin_dir, version + )); + } + + new_section.push_str(AUTO_GENERATED_END); + + // Combine the base contents with the new section + let mut final_contents = base_contents; + final_contents.push_str(&new_section); + + // Ensure file ends with a single newline + if !final_contents.ends_with('\n') { + final_contents.push('\n'); + } + + // Write the updated Cargo.toml + fs::write(cargo_path, final_contents)?; + + Ok(()) +} + +fn generate_plugin_files(plugin_paths: &[(String, String, String)]) -> std::io::Result<()> { + // Create the output directory if it doesn't exist + let out_dir = Path::new("src"); + fs::create_dir_all(out_dir)?; + + // Then generate the imports file that uses the macro + generate_imports_file(plugin_paths, out_dir)?; + + Ok(()) +} + +fn generate_imports_file( + plugin_paths: &[(String, String, String)], + out_dir: &Path, +) -> std::io::Result<()> { + let mut file = fs::File::create(out_dir.join("plugin_imports.rs"))?; + + // Write the header + writeln!(file, "// This file is automatically generated by build.rs")?; + writeln!(file, "// Do not edit this file manually!\n")?; + writeln!( + file, + "use horizon_plugin_api::{{Pluginstate, LoadedPlugin, Plugin}};" + )?; + writeln!(file, "use std::collections::HashMap;\n")?; + for (i, (name, _, _)) in plugin_paths.iter().enumerate() { + write!(file, "pub use {};\n", name)?; + write!(file, "pub use {}::*;\n", name)?; + write!(file, "pub use {}::Plugin as {}_plugin;\n", name, name)?; + } + writeln!(file, "\n"); + + // Use the macro with discovered plugins + writeln!(file, "// Invoke the macro with all discovered plugins")?; + writeln!( + file, + "pub fn load_plugins() -> HashMap {{" + )?; + write!(file, " let plugins = crate::load_plugins!(")?; + + // Add each plugin to the macro invocation + for (i, (name, _, _)) in plugin_paths.iter().enumerate() { + if i > 0 { + write!(file, ",")?; + } + write!(file, "\n {}", name)?; + } + + writeln!(file, "\n );")?; + writeln!(file, " plugins")?; + writeln!(file, "}}")?; + + Ok(()) +} diff --git a/plugin_api/src/lib.rs b/plugin_api/src/lib.rs new file mode 100644 index 0000000..426ed2e --- /dev/null +++ b/plugin_api/src/lib.rs @@ -0,0 +1,77 @@ +use std::collections::HashMap; + +pub use horizon_plugin_api::{get_plugin, LoadedPlugin, Plugin, Pluginstate, Version}; + +pub mod plugin_imports; + +// Define the current plugin version +const PLUGIN_API_VERSION: Version = Version { + major: 0, + minor: 1, + hotfix: 0, +}; + +#[derive(Clone)] +pub struct PluginManager { + plugins: HashMap, +} + +#[macro_export] +macro_rules! load_plugins { + ($($plugin:ident),* $(,)?) => { + { + let mut plugins = HashMap::new(); + $( + plugins.insert( + stringify!($plugin).to_string(), + (Pluginstate::ACTIVE, <$plugin::Plugin as $plugin::PluginConstruct>::new(plugins.clone())), + ); + )* + + plugins + } + }; +} + +impl PluginManager { + /// Allow instantiation of the ``PluginManager`` struct + pub fn new() -> PluginManager { + let new_manager = PluginManager { + plugins: HashMap::new(), + }; + + new_manager + } + + pub fn load_plugin(mut self, name: String, plugin: Plugin) { + self.plugins.insert(name, (Pluginstate::ACTIVE, plugin)); + } + + pub fn unload_plugin(mut self, name: String) { + self.plugins.remove(&name); + } + + pub fn get_plugins(self) -> HashMap { + self.plugins + } + + pub fn load_all(&mut self) -> HashMap { + self.plugins = plugin_imports::load_plugins(); + + //let my_test_plugin = get_plugin!(test_plugin, plugins); + //let result = my_test_plugin.thing(); + + let mut loaded_plugins = HashMap::new(); + for (name, (state, plugin)) in &self.plugins { + if *state == Pluginstate::ACTIVE { + loaded_plugins.insert( + name.clone(), + LoadedPlugin { + instance: plugin.clone(), + }, + ); + } + } + loaded_plugins + } +} diff --git a/plugin_api/src/plugin_imports.rs b/plugin_api/src/plugin_imports.rs new file mode 100644 index 0000000..7875142 --- /dev/null +++ b/plugin_api/src/plugin_imports.rs @@ -0,0 +1,18 @@ +// This file is automatically generated by build.rs +// Do not edit this file manually! + +use horizon_plugin_api::{Pluginstate, LoadedPlugin, Plugin}; +use std::collections::HashMap; + +pub use player_lib; +pub use player_lib::*; +pub use player_lib::Plugin as player_lib_plugin; + + +// Invoke the macro with all discovered plugins +pub fn load_plugins() -> HashMap { + let plugins = crate::load_plugins!( + player_lib + ); + plugins +} diff --git a/plugins/player_lib/Cargo.toml b/plugins/player_lib/Cargo.toml new file mode 100644 index 0000000..567b135 --- /dev/null +++ b/plugins/player_lib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "player_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] +PebbleVault = "0.6.1" +horizon-plugin-api = "0.1.13" +horizon_data_types = "0.4.0" +socketioxide = "0.15.1" +parking_lot = "0.12.3" diff --git a/plugins/player_lib/src/lib.rs b/plugins/player_lib/src/lib.rs new file mode 100644 index 0000000..9fbadb7 --- /dev/null +++ b/plugins/player_lib/src/lib.rs @@ -0,0 +1,36 @@ +use std::collections::HashMap; + +pub use horizon_plugin_api::{LoadedPlugin, Plugin, Pluginstate}; + +// Define the trait properly +pub trait PluginAPI { + fn test(&self); +} + +pub trait PluginConstruct { + fn get_structs(&self) -> Vec<&str>; + // If you want default implementations, mark them with 'default' + fn new(plugins: HashMap) -> Plugin; +} + +// Implement constructor separately +impl PluginConstruct for Plugin { + fn new(plugins: HashMap) -> Plugin { + Plugin {} + } + + fn get_structs(&self) -> Vec<&str> { + vec!["MyPlayer"] + } +} + +// Implement the trait for Plugin +impl PluginAPI for Plugin { + fn test(&self) { + println!("test"); + } +} + +//----------------------------------------------------------------------------- +// Plugin Implementation +//----------------------------------------------------------------------------- diff --git a/test.zensh b/test.zensh new file mode 100644 index 0000000..e69de29 From 4d2383d54ca190c50fa938bdb791953849465bd7 Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 16:20:16 -0500 Subject: [PATCH 08/10] fix tokio runtime stack overflow due to recursion --- engine/src/core/repl/commands.rs | 15 ++++++++++++++- test.zensh | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index dad0fa2..e9b756d 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,12 +1,18 @@ use std::{ffi::OsStr, process::Command}; - +use parking_lot::Mutex; +use lazy_static::lazy_static; use crate::core::repl::repl::evaluate_command; use super::COMMAND_LIST; +const MAX_RECURSION_DEPTH: usize = 500; // increasing this value WILL cause a stack overflow. attempt at your own risk - Caz + +lazy_static! { + static ref RECURSION_DEPTH: Mutex = parking_lot::Mutex::new(0); +} pub(crate) fn say_hello() -> anyhow::Result<()> { println!("Hello, World!"); @@ -41,6 +47,13 @@ pub(crate) fn help() -> anyhow::Result<()> { Ok(()) } pub(crate) fn exec(args: Vec) -> anyhow::Result<()> { + *RECURSION_DEPTH.lock() += 1; + if *RECURSION_DEPTH.lock() > MAX_RECURSION_DEPTH { + eprintln!("Maximum recursion depth reached. Aborting."); + *RECURSION_DEPTH.lock() = 0; + return Ok(()); + } + println!("Recursion depth: {}", *RECURSION_DEPTH.lock()); let file_path_str = &args[0]; let file_path = std::path::Path::new(file_path_str); println!("File path: {:#?}", file_path); diff --git a/test.zensh b/test.zensh index e69de29..0fbb7d4 100644 --- a/test.zensh +++ b/test.zensh @@ -0,0 +1,4 @@ +echo ping +echo pong +exec test.zensh +break \ No newline at end of file From 8d1f838a6836924c2bb8ab83f7ca4466b9982a17 Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 16:55:49 -0500 Subject: [PATCH 09/10] fix formatting --- engine/src/core/repl/commands.rs | 22 +++++++++++++--------- engine/src/core/repl/mod.rs | 14 ++++---------- engine/src/core/repl/repl.rs | 6 ++---- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index e9b756d..cf59b48 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,14 +1,12 @@ use std::{ffi::OsStr, process::Command}; - -use parking_lot::Mutex; use lazy_static::lazy_static; - - -use crate::core::repl::repl::evaluate_command; +use parking_lot::Mutex; use super::COMMAND_LIST; -const MAX_RECURSION_DEPTH: usize = 500; // increasing this value WILL cause a stack overflow. attempt at your own risk - Caz +use crate::core::repl::repl::evaluate_command; +const MAX_RECURSION_DEPTH: usize = 500; // increasing this value WILL cause a stack overflow. attempt at your own risk - + // Caz lazy_static! { static ref RECURSION_DEPTH: Mutex = parking_lot::Mutex::new(0); @@ -59,11 +57,17 @@ pub(crate) fn exec(args: Vec) -> anyhow::Result<()> { println!("File path: {:#?}", file_path); if !file_path.is_file() { - eprintln!("Error: File does not exist or is not a valid file: {}", file_path.display()); - return Ok(()); + eprintln!( + "Error: File does not exist or is not a valid file: {}", + file_path.display() + ); + return Ok(()); } if file_path.extension() != Some(OsStr::new("zensh")) { - eprintln!("Error: File is not a zenshell script: {:#?}", file_path.extension()); + eprintln!( + "Error: File is not a zenshell script: {:#?}", + file_path.extension() + ); //TODO: dont panic on this error return Ok(()); } diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index 0f84cfd..ebafd40 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -3,7 +3,7 @@ pub mod repl; use std::{borrow::Borrow, collections::HashMap, sync::Arc}; -use anyhow::Ok; +use anyhow::Context; use colored::Colorize; use lazy_static::lazy_static; use log::{debug, info}; @@ -42,11 +42,7 @@ impl Command { } Callable::WithArgs(f) => match args { Some(args) => f(args), - None => { - Ok(()) - - - }, + None => Ok(()), }, } } @@ -140,7 +136,7 @@ impl CommandList { .aliases .read() .get_key_value(&name) - .unwrap() + .context("Failed to get alias")? .1 .to_string(); @@ -176,9 +172,7 @@ impl CommandList { eprintln!("Did you mean: '{}'?", similar.green().italic().bold()); Ok(()) } - None => { - Ok(()) - } + None => Ok(()), } } } diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/repl.rs index 5ef467d..eae0dc9 100644 --- a/engine/src/core/repl/repl.rs +++ b/engine/src/core/repl/repl.rs @@ -3,8 +3,6 @@ use std::{ sync::Arc, }; - - use chrono::Local; use colored::Colorize; use log::debug; @@ -111,7 +109,7 @@ fn register_commands() { "exec", Some("Executes a .nyx file."), Callable::WithArgs(commands::exec), - Some(1), + Some(1), ); // Example of adding aliases for commands @@ -172,7 +170,7 @@ pub fn evaluate_command(input: &str) -> anyhow::Result<()> { cmd_name.to_string(), if args.is_empty() { None } else { Some(args) }, )?; - }; + } Ok(()) } From e4a45eee82ccff9a9960583fb12268fbbfe1b6da Mon Sep 17 00:00:00 2001 From: Caznix Date: Fri, 6 Dec 2024 16:57:52 -0500 Subject: [PATCH 10/10] apply clippy changes --- engine/src/core/renderer/ctx.rs | 2 +- engine/src/core/repl/commands.rs | 2 +- engine/src/core/repl/{repl.rs => exec.rs} | 0 engine/src/core/repl/mod.rs | 2 +- engine/src/main.rs | 4 ++-- engine/src/utils/logger.rs | 8 +++++++- 6 files changed, 12 insertions(+), 6 deletions(-) rename engine/src/core/repl/{repl.rs => exec.rs} (100%) diff --git a/engine/src/core/renderer/ctx.rs b/engine/src/core/renderer/ctx.rs index 88ff9ae..d2045d8 100644 --- a/engine/src/core/renderer/ctx.rs +++ b/engine/src/core/renderer/ctx.rs @@ -80,7 +80,7 @@ impl<'window> WgpuCtx<'window> { .device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); { - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + let rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &view, diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index cf59b48..d41fe5f 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -4,7 +4,7 @@ use lazy_static::lazy_static; use parking_lot::Mutex; use super::COMMAND_LIST; -use crate::core::repl::repl::evaluate_command; +use crate::core::repl::exec::evaluate_command; const MAX_RECURSION_DEPTH: usize = 500; // increasing this value WILL cause a stack overflow. attempt at your own risk - // Caz diff --git a/engine/src/core/repl/repl.rs b/engine/src/core/repl/exec.rs similarity index 100% rename from engine/src/core/repl/repl.rs rename to engine/src/core/repl/exec.rs diff --git a/engine/src/core/repl/mod.rs b/engine/src/core/repl/mod.rs index ebafd40..6a935bc 100644 --- a/engine/src/core/repl/mod.rs +++ b/engine/src/core/repl/mod.rs @@ -1,5 +1,5 @@ pub mod commands; -pub mod repl; +pub mod exec; use std::{borrow::Borrow, collections::HashMap, sync::Arc}; diff --git a/engine/src/main.rs b/engine/src/main.rs index 1dc0458..4b2dc0e 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -28,10 +28,10 @@ async fn main() -> Result<()> { LOGGER.write_to_stdout(); - let shell_thread = tokio::task::spawn(async { core::repl::repl::handle_repl().await }); + let shell_thread = tokio::task::spawn(async { core::repl::exec::handle_repl().await }); core::init_renderer()?; - let _ = shell_thread.await??; + shell_thread.await??; Ok(()) } diff --git a/engine/src/utils/logger.rs b/engine/src/utils/logger.rs index bfe442d..b927556 100644 --- a/engine/src/utils/logger.rs +++ b/engine/src/utils/logger.rs @@ -14,6 +14,12 @@ pub struct DynamicLogger { pub writer: Arc>>, } +impl Default for DynamicLogger { + fn default() -> Self { + Self::new() + } +} + impl DynamicLogger { pub fn new() -> Self { Self { @@ -24,7 +30,7 @@ impl DynamicLogger { pub fn write_to_file(&self, file_path: &str) { let file = OpenOptions::new() .create(true) - .write(true) + .append(true) .open(file_path) .expect("Failed to open log file");