diff --git a/Cargo.lock b/Cargo.lock index e5ee426..76066a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,6 +198,21 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -634,6 +649,16 @@ dependencies = [ "str-buf", ] +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -1087,6 +1112,7 @@ dependencies = [ "directories", "dunce", "env_logger 0.10.0", + "fancy-regex", "futures-util", "glam", "home", diff --git a/Cargo.toml b/Cargo.toml index 092677d..fca4bdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,7 @@ regex = { optional = true, version = "1.7", default-features = false, features = "std", "unicode-perl", ] } +fancy-regex = "0.11.0" rustyline = "12.0.0" ### ROBLOX diff --git a/src/cli/repl.rs b/src/cli/repl.rs index 1fdd90c..544670d 100644 --- a/src/cli/repl.rs +++ b/src/cli/repl.rs @@ -1,5 +1,6 @@ use std::{ env, + fmt::Write, io::ErrorKind, path::PathBuf, process::{exit, ExitCode}, @@ -7,19 +8,17 @@ use std::{ use anyhow::Error; use clap::Command; -use lune::{Lune, LuneError}; +use fancy_regex::Regex; +use lune::lua::stdio::formatting::{pretty_format_luau_error, pretty_format_value}; +use lune::Lune; use mlua::ExternalError; use once_cell::sync::Lazy; use rustyline::{error::ReadlineError, history::FileHistory, DefaultEditor, Editor}; -use lune::lua::stdio::formatting::pretty_format_luau_error; - fn env_var_bool(value: String) -> Option { match value.to_lowercase().as_str() { - "true" => Some(true), - "1" => Some(true), - "0" => Some(false), - "false" => Some(false), + "true" | "1" => Some(true), + "false" | "0" => Some(false), &_ => None, } } @@ -73,18 +72,36 @@ pub async fn show_interface(cmd: Command) -> Result { let no_color = env::var("NO_COLOR").unwrap_or_else(|_| "false".to_string()); if no_color.is_empty() { - false + true } else { !env_var_bool(no_color).unwrap_or_else(|| false) } }); + // Group 2 of this match pattern is the variable contents + + // We're using fancy_regex instead of regex for backreferences + // and lookaround. I'm not too good at regex, so if there's a + // way to do this without backreferences and lookarounds, + // please let me know. + const VARIABLE_DECLARATION_PAT: &str = r#"(?!local.*)(?!\s)(=\s*)(.*)"#; + + // HACK: Prepend this "context" to the source code provided, + // so that the variable is preserved even the following steps + let mut source_code_context: Option = None; + loop { let mut source_code = String::new(); match repl.readline("> ") { Ok(code) => { - source_code = code.clone(); + if let Some(ref ctx) = source_code_context { + // If something breaks, blame this + source_code = format!("{} {}", ctx, code); + } else { + source_code.push_str(code.as_str()); + } + repl.add_history_entry(code.as_str())?; // If source code eval was requested, we reset the counter @@ -117,10 +134,35 @@ pub async fn show_interface(cmd: Command) -> Result { } }; - let eval_result = lune_instance.run("REPL", source_code).await; + let eval_result = lune_instance.run("REPL", source_code.clone()).await; match eval_result { - Ok(_) => (), + Ok(_) => { + if Regex::new(VARIABLE_DECLARATION_PAT)?.is_match(&source_code)? + && !&source_code.contains("\n") + { + let declaration = source_code.split("=").collect::>()[1] + .trim() + .replace("\"", ""); + + let mut formatted_output = String::new(); + pretty_format_value( + &mut formatted_output, + &mlua::IntoLua::into_lua(declaration, &mlua::Lua::new())?, + 1, + )?; + + source_code_context = (|| -> Result, Error> { + let mut ctx = String::new(); + write!(&mut ctx, "{}\n", &source_code)?; + + Ok(Some(ctx)) + })()?; + + println!("{}", formatted_output); + } + } + Err(err) => { eprintln!( "{}",