diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..339a774 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 88f3db6..c83d27d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,19 +23,21 @@ builtin-parser = ["dep:logos"] [dependencies] # This crate by itself doesn't use any bevy features, but `bevy_egui` (dep) uses "bevy_asset". -bevy = { version = "0.14.0", default-features = false, features = [] } -bevy_egui = "0.28.0" +bevy = { version = "0.16.0", default-features = false, features = ["bevy_log", "bevy_color"] } +bevy_reflect = "0.16.0" +bevy_egui = "0.34.1" chrono = "0.4.31" tracing-log = "0.2.0" tracing-subscriber = "0.3.18" web-time = "1.0.0" +winit = "0.30.5" # builtin-parser features logos = { version = "0.14.0", optional = true } fuzzy-matcher = { version = "0.3.7", optional = true } [dev-dependencies] -bevy = "0.14.0" +bevy = "0.16.0" [lints] clippy.useless_format = "allow" diff --git a/src/builtin_parser/runner.rs b/src/builtin_parser/runner.rs index 1146605..f53fcfc 100644 --- a/src/builtin_parser/runner.rs +++ b/src/builtin_parser/runner.rs @@ -8,8 +8,6 @@ use bevy::reflect::{ DynamicEnum, DynamicTuple, ReflectMut, TypeInfo, TypeRegistration, VariantInfo, }; -use crate::ui::COMMAND_RESULT_NAME; - use self::error::EvalError; use self::member::{eval_member_expression, eval_path, Path}; use self::reflection::{object_to_dynamic_struct, CreateRegistration, IntoResource}; @@ -142,7 +140,7 @@ pub fn run(ast: Ast, world: &mut World) -> Result<(), ExecutionError> { value => { let value = value.try_format(span, world, ®istrations)?; - info!(name: COMMAND_RESULT_NAME, "{}{value}", crate::ui::COMMAND_RESULT_PREFIX); + info!(name: crate::ui::COMMAND_RESULT_NAME, "{}{value}", crate::ui::COMMAND_RESULT_PREFIX); } } } @@ -332,7 +330,11 @@ fn eval_expression( }?; dynamic_tuple.insert_boxed( - element.value.into_inner().reflect(element.span, ty)?, + element + .value + .into_inner() + .reflect(element.span, ty)? + .into_partial_reflect(), ); } @@ -369,13 +371,9 @@ fn eval_expression( .reflect_path_mut(resource.path.as_str()) .unwrap(); - reflect.set(value_reflect).map_err(|value_reflect| { - EvalError::IncompatibleReflectTypes { - span, - expected: reflect.reflect_type_path().to_string(), - actual: value_reflect.reflect_type_path().to_string(), - } - })?; + reflect + .try_apply(value_reflect.as_partial_reflect()) + .map_err(|apply_error| EvalError::ApplyError { apply_error, span })?; } } @@ -441,7 +439,6 @@ fn eval_expression( )?; Ok(Value::StructTuple { name, tuple }) } - Expression::BinaryOp { left, operator, diff --git a/src/builtin_parser/runner/environment.rs b/src/builtin_parser/runner/environment.rs index b30d345..32bf463 100644 --- a/src/builtin_parser/runner/environment.rs +++ b/src/builtin_parser/runner/environment.rs @@ -5,7 +5,7 @@ use std::fmt::Debug; use crate::builtin_parser::SpanExtension; use bevy::ecs::world::World; -use bevy::log::warn; +use bevy::prelude::*; use bevy::reflect::TypeRegistration; use logos::Span; diff --git a/src/builtin_parser/runner/error.rs b/src/builtin_parser/runner/error.rs index 6892de4..b3cafc3 100644 --- a/src/builtin_parser/runner/error.rs +++ b/src/builtin_parser/runner/error.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use bevy::reflect::ApplyError; use logos::Span; use crate::builtin_parser::number::Number; @@ -75,6 +76,10 @@ pub enum EvalError { field_index: usize, tuple_size: usize, }, + ApplyError { + apply_error: ApplyError, + span: Span, + }, } impl EvalError { @@ -106,6 +111,7 @@ impl EvalError { E::InvalidOperation { span, .. } => vec![span.clone()], E::IncorrectAccessOperation { span, .. } => vec![span.clone()], E::FieldNotFoundInTuple { span, .. } => vec![span.clone()], + E::ApplyError { span, .. } => vec![span.clone()], } } /// Returns all the hints for this error. @@ -232,6 +238,15 @@ impl std::fmt::Display for EvalError { f, "Field {field_index} is out of bounds for tuple of size {tuple_size}" ), + E::ApplyError { + apply_error, + span: _, + } => { + write!( + f, + "Error while applying value (todo make this error better): {apply_error}" + ) + } } } } diff --git a/src/builtin_parser/runner/reflection.rs b/src/builtin_parser/runner/reflection.rs index 2114f5d..f8bd2e1 100644 --- a/src/builtin_parser/runner/reflection.rs +++ b/src/builtin_parser/runner/reflection.rs @@ -46,15 +46,16 @@ impl IntoResource { } pub fn object_to_dynamic_struct( - hashmap: HashMap, + _hashmap: HashMap, ) -> Result { - let mut dynamic_struct = DynamicStruct::default(); + todo!() + // let mut dynamic_struct = DynamicStruct::default(); - for (key, (value, span, reflect)) in hashmap { - dynamic_struct.insert_boxed(&key, value.reflect(span, reflect)?); - } + // for (key, (value, span, reflect)) in hashmap { + // dynamic_struct.insert_boxed(&key, value.reflect(span, reflect)?); + // } - Ok(dynamic_struct) + // Ok(dynamic_struct) } pub fn mut_dyn_reflect<'a>( diff --git a/src/builtin_parser/runner/stdlib.rs b/src/builtin_parser/runner/stdlib.rs index 938df3b..0561f25 100644 --- a/src/builtin_parser/runner/stdlib.rs +++ b/src/builtin_parser/runner/stdlib.rs @@ -1,7 +1,7 @@ use crate::builtin_parser::runner::environment::Variable; use crate::register; use bevy::ecs::world::World; -use bevy::log::info; +use bevy::prelude::*; use bevy::reflect::TypeRegistration; use std::cell::Ref; use std::ops::Range; diff --git a/src/builtin_parser/runner/unique_rc.rs b/src/builtin_parser/runner/unique_rc.rs index f4e5c29..1b5f016 100644 --- a/src/builtin_parser/runner/unique_rc.rs +++ b/src/builtin_parser/runner/unique_rc.rs @@ -46,7 +46,7 @@ impl UniqueRc { .into_inner() } } -impl Clone for UniqueRc { +impl Clone for UniqueRc { fn clone(&self) -> Self { let t = self.borrow_inner().clone().into_inner(); diff --git a/src/builtin_parser/runner/value.rs b/src/builtin_parser/runner/value.rs index 711ed3a..ac1487c 100644 --- a/src/builtin_parser/runner/value.rs +++ b/src/builtin_parser/runner/value.rs @@ -12,7 +12,7 @@ use super::unique_rc::WeakRef; use bevy::ecs::world::World; use bevy::reflect::{ - DynamicStruct, DynamicTuple, GetPath, Reflect, ReflectRef, TypeInfo, TypeRegistration, + DynamicStruct, DynamicTuple, GetPath, PartialReflect, ReflectRef, TypeInfo, TypeRegistration, VariantInfo, VariantType, }; @@ -61,13 +61,15 @@ pub enum Value { } impl Value { - /// Converts this value into a [`Box`]. + /// Converts this value into a [`Box`]. /// /// `ty` is used for type inference. - pub fn reflect(self, span: Span, ty: &str) -> Result, EvalError> { + pub fn reflect(self, span: Span, ty: &str) -> Result, EvalError> { match self { Value::None => Ok(Box::new(())), - Value::Number(number) => number.reflect(span, ty), + Value::Number(number) => number + .reflect(span, ty) + .map(PartialReflect::into_partial_reflect), Value::Boolean(boolean) => Ok(Box::new(boolean)), Value::String(string) => Ok(Box::new(string)), Value::Reference(_reference) => Err(EvalError::CannotReflectReference(span)), @@ -245,7 +247,7 @@ fn fancy_debug_print( let reflect = dyn_reflect.reflect_path(resource.path.as_str()).unwrap(); - fn debug_subprint(reflect: &dyn Reflect, indentation: usize) -> String { + fn debug_subprint(reflect: &dyn PartialReflect, indentation: usize) -> String { let mut f = String::new(); let reflect_ref = reflect.reflect_ref(); let indentation_string = TAB.repeat(indentation); @@ -311,9 +313,10 @@ fn fancy_debug_print( VariantType::Unit => {} } } - ReflectRef::Value(_) => { + ReflectRef::Opaque(_) => { f += &format!("{reflect:?}"); } + ReflectRef::Set(_) => todo!(), } f @@ -343,6 +346,7 @@ fn fancy_debug_print( ReflectRef::List(_) => todo!(), ReflectRef::Array(_) => todo!(), ReflectRef::Map(_) => todo!(), + ReflectRef::Set(_) => todo!(), ReflectRef::Enum(set_variant_info) => { // Print out the enum types f += &format!("enum {} {{\n", set_variant_info.reflect_short_type_path()); @@ -401,7 +405,7 @@ fn fancy_debug_print( VariantType::Unit => {} } } - ReflectRef::Value(value) => { + ReflectRef::Opaque(value) => { f += &format!("{value:?}"); } } diff --git a/src/command.rs b/src/command.rs index 8ab6fa4..a3f0bd5 100644 --- a/src/command.rs +++ b/src/command.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use std::ops::Range; -use bevy::ecs::world::Command; use bevy::prelude::*; /// The command parser currently being used by the dev console. @@ -168,6 +167,7 @@ impl Command for ExecuteCommand { } } +#[allow(missing_docs)] #[derive(Resource, Default, Deref, DerefMut)] #[cfg(feature = "completions")] pub struct AutoCompletions(pub(crate) Vec); diff --git a/src/lib.rs b/src/lib.rs index 46fb4cb..78f1c23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,9 @@ pub struct DevConsolePlugin; impl Plugin for DevConsolePlugin { fn build(&self, app: &mut App) { if !app.is_plugin_added::() { - app.add_plugins(EguiPlugin); + app.add_plugins(EguiPlugin { + enable_multipass_for_primary_context: false, + }); } #[cfg(feature = "builtin-parser")] diff --git a/src/logging.rs b/src/logging.rs index 1c375ad..af638ad 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,8 +1,7 @@ //! Custom [LogPlugin](bevy::log::LogPlugin) functionality. -use bevy::log::{BoxedLayer, Level}; +use bevy::log::tracing::Subscriber; use bevy::prelude::*; -use bevy::utils::tracing::Subscriber; use std::sync::mpsc; use tracing_subscriber::field::Visit; use tracing_subscriber::Layer; @@ -10,7 +9,7 @@ use web_time::SystemTime; /// A function that implements the log reading functionality for the /// developer console via [`LogPlugin::custom_layer`](bevy::log::LogPlugin::custom_layer). -pub fn custom_log_layer(app: &mut App) -> Option { +pub fn custom_log_layer(app: &mut App) -> Option { Some(Box::new(create_custom_log_layer(app))) } @@ -39,7 +38,7 @@ pub(crate) struct LogMessage { pub target: &'static str, /// The level of verbosity of the described span. - pub level: Level, + pub level: bevy::log::Level, /// The name of the Rust module where the span occurred, /// or `None` if this could not be determined. @@ -62,7 +61,7 @@ fn transfer_log_events( receiver: NonSend, mut log_events: EventWriter, ) { - log_events.send_batch(receiver.0.try_iter()); + log_events.write_batch(receiver.0.try_iter()); } /// This struct temporarily stores [`LogMessage`]s before they are @@ -76,7 +75,7 @@ struct LogCaptureLayer { impl Layer for LogCaptureLayer { fn on_event( &self, - event: &bevy::utils::tracing::Event<'_>, + event: &bevy::log::tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>, ) { let mut message = None; @@ -104,7 +103,7 @@ struct LogEventVisitor<'a>(&'a mut Option); impl Visit for LogEventVisitor<'_> { fn record_debug( &mut self, - field: &bevy::utils::tracing::field::Field, + field: &bevy::log::tracing::field::Field, value: &dyn std::fmt::Debug, ) { // Only log out messages diff --git a/src/ui.rs b/src/ui.rs index aa859d5..a42bf8d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -31,6 +31,7 @@ pub const COMMAND_MESSAGE_NAME: &str = "console_command"; /// Identifier for log messages that show the result of a command. pub const COMMAND_RESULT_NAME: &str = "console_result"; +#[allow(missing_docs)] #[derive(Default, Resource)] pub struct ConsoleUiState { /// Whether the console is open or not. @@ -117,7 +118,7 @@ pub fn render_ui( info!(name: COMMAND_MESSAGE_NAME, "{COMMAND_MESSAGE_PREFIX}{}", command.trim()); // Get the owned command string by replacing it with an empty string let command = std::mem::take(command); - commands.add(ExecuteCommand(command)); + commands.queue(ExecuteCommand(command)); } } @@ -125,18 +126,18 @@ pub fn render_ui( submit_command(&mut state.command, commands); } - completions::change_selected_completion(ui, state, &completions); + completions::change_selected_completion(ui, state, completions); // A General rule when creating layouts in egui is to place elements which fill remaining space last. // Since immediate mode ui can't predict the final sizes of widgets until they've already been drawn // Thus we create a bottom panel first, where our text edit and submit button resides. egui::TopBottomPanel::bottom("bottom panel") - .frame(egui::Frame::none().outer_margin(egui::Margin { - left: 5.0, - right: 5.0, - top: 5. + 6., - bottom: 5.0, + .frame(egui::Frame::NONE.outer_margin(egui::Margin { + left: 5, + right: 5, + top: 5 + 6, + bottom: 5, })) .show_inside(ui, |ui| { let text_edit_id = egui::Id::new("text_edit"); @@ -169,8 +170,8 @@ pub fn render_ui( state, ui, commands, - &completions, - &config, + completions, + config, ); // Each time we open the console, we want to set focus to the text edit control. @@ -188,7 +189,7 @@ pub fn render_ui( let mut command_index = 0; for (id, (message, is_new)) in state.log.iter_mut().enumerate() { - add_log(ui, id, message, is_new, hints, &config, &mut command_index); + add_log(ui, id, message, is_new, hints, config, &mut command_index); } }); }); diff --git a/src/ui/completions.rs b/src/ui/completions.rs index 208cc13..026a512 100644 --- a/src/ui/completions.rs +++ b/src/ui/completions.rs @@ -60,7 +60,7 @@ pub fn completions( // If not found, the whole substring is a word None => before_cursor, }; - commands.add(UpdateAutoComplete(keyword_before.to_owned())); + commands.queue(UpdateAutoComplete(keyword_before.to_owned())); } else { ui.memory_mut(|mem| { if mem.is_popup_open(text_edit_complete_id) {