From 31a06ff45b7b5942bd464314f5a8c0fa82d8e8ad Mon Sep 17 00:00:00 2001 From: Chance Date: Mon, 7 Apr 2025 22:11:38 -0400 Subject: [PATCH] build: remove regex dependency in favor of rust iterators --- Cargo.lock | 39 ------------- engine/Cargo.toml | 1 - engine/src/core/panic.rs | 94 +++++++++++++++++++++++++++----- engine/src/core/repl/commands.rs | 10 +--- engine/src/core/repl/input.rs | 21 +++---- 5 files changed, 90 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45e3f73..e1fd1b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,15 +46,6 @@ dependencies = [ "zerocopy 0.7.35", ] -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "aligned-vec" version = "0.5.0" @@ -2477,35 +2468,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -4196,7 +4158,6 @@ dependencies = [ "native-dialog", "parking_lot", "raw-cpuid", - "regex", "rustyline", "serde", "sysinfo", diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 2ed4bfa..b9d580d 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -12,7 +12,6 @@ chrono = "0.4.39" colored = "3.0.0" parking_lot.workspace = true # TBR (if possible) -regex = "1.11.1" rustyline = { version = "15.0.0", features = ["derive", "rustyline-derive"] } thiserror = "2.0.11" # Tokio is heavy but so far its the best option, we should make better use of it or switch to another runtime. diff --git a/engine/src/core/panic.rs b/engine/src/core/panic.rs index 0a3cc23..53e85f1 100644 --- a/engine/src/core/panic.rs +++ b/engine/src/core/panic.rs @@ -6,7 +6,6 @@ use std::{error::Error, path::PathBuf}; use backtrace::Backtrace; use native_dialog::{MessageDialog, MessageType}; use parking_lot::Once; -use regex::Regex; use tracing::error; static INIT: parking_lot::Once = Once::new(); @@ -71,27 +70,26 @@ For future reference, the error summary is as follows: println!("{}", final_msg.red().bold()); - if let Err(e) = MessageDialog::new() + if let Err(e) = MessageDialog::new() .set_type(MessageType::Error) .set_title("A fatal error in Zenyx has occurred") .set_text(&final_msg) - .show_confirm() { - error!("Failed to show message dialog: {e}") - } - - Ok(()) + .show_confirm() + { + error!("Failed to show message dialog: {e}") + } + + Ok(()) } fn capture_backtrace() -> String { let mut backtrace = String::new(); - let sysinfo = crate::metadata::SystemMetadata::current(); + let sysinfo = crate::metadata::SystemMetadata::current(); backtrace.push_str(&sysinfo.verbose_summary()); let trace = backtrace::Backtrace::new(); let message = format!("\nBacktrace:\n\n"); backtrace.push_str(&message); backtrace.push_str(&format!("{trace:?}")); - - backtrace } @@ -102,8 +100,78 @@ trait Sanitize { impl Sanitize for str { fn sanitize_path(&self) -> String { - let username_pattern = r"(?i)(/home/|/Users/|\\Users\\)([^/\\]+)"; - let re = Regex::new(username_pattern).expect("Failed to compile regex for sanitization"); - re.replace_all(self, "${1}").to_string() + let prefixes = ["/home/", "/Users/", "\\Users\\", "/opt/home/"]; + let mut result = String::from(self); + + for prefix in prefixes { + if let Some(start_index) = result.find(prefix) { + let start_of_user = start_index + prefix.len(); + let mut end_of_user = result[start_of_user..] + .find(|c| c == '/' || c == '\\') + .map(|i| start_of_user + i) + .unwrap_or(result.len()); + if end_of_user == start_of_user && start_of_user < result.len() { + end_of_user = result.len(); + } + result.replace_range(start_of_user..end_of_user, ""); + break; + } + } + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sanitize_home() { + assert_eq!( + "/home//documents", + "/home/john.doe/documents".sanitize_path() + ); + assert_eq!("/home/", "/home/jane".sanitize_path()); + assert_eq!("/opt/home/", "/opt/home/user".sanitize_path()); + } + + #[test] + fn test_sanitize_users_unix() { + assert_eq!( + "/Users//desktop", + "/Users/alice/desktop".sanitize_path() + ); + assert_eq!("/Users//", "/Users/bob/".sanitize_path()); + assert_eq!("/user/Users/", "/user/Users/name".sanitize_path()); + } + + #[test] + fn test_sanitize_users_windows() { + assert_eq!( + "\\Users\\\\documents", + "\\Users\\charlie\\documents".sanitize_path() + ); + assert_eq!("\\Users\\", "\\Users\\david".sanitize_path()); + assert_eq!( + "C:\\Other\\Users\\", + "C:\\Other\\Users\\folder".sanitize_path() + ); + } + + #[test] + fn test_no_match() { + assert_eq!("/opt/data/file.txt", "/opt/data/file.txt".sanitize_path()); + } + + #[test] + fn test_mixed_separators() { + assert_eq!( + "/home/\\documents", + "/home/eve\\documents".sanitize_path() + ); + assert_eq!( + "\\Users\\/desktop", + "\\Users\\frank/desktop".sanitize_path() + ); } } diff --git a/engine/src/core/repl/commands.rs b/engine/src/core/repl/commands.rs index 9e9a3ec..4d64fdb 100644 --- a/engine/src/core/repl/commands.rs +++ b/engine/src/core/repl/commands.rs @@ -1,7 +1,6 @@ use std::{fs, path::PathBuf, str::FromStr}; use parking_lot::RwLock; -use regex::Regex; use super::{handler::Command, input::tokenize}; use crate::core::repl::handler::COMMAND_MANAGER; @@ -286,14 +285,7 @@ fn eval(input: String) -> Result>)>, ZenyxError> .with_message("Input was empty") .build()); } - - let pattern = Regex::new(r"[;|\n]").map_err(|e| { - ZenyxError::builder(ZenyxErrorKind::CommandParsing) - .with_message("Failed to compile regex") - .with_source(e) - .build() - })?; - let commands: Vec<&str> = pattern.split(&input).collect(); + let commands: Vec<&str> = input.split(|c| c == ';' || c == '\n').collect(); let mut evaluted = vec![]; for command in commands { diff --git a/engine/src/core/repl/input.rs b/engine/src/core/repl/input.rs index 770955d..d146ecd 100644 --- a/engine/src/core/repl/input.rs +++ b/engine/src/core/repl/input.rs @@ -6,7 +6,6 @@ use std::{ use chrono::Local; use colored::Colorize; use parking_lot::Mutex; -use regex::Regex; use rustyline::{ Cmd, Completer, ConditionalEventHandler, Editor, Event, EventContext, EventHandler, Helper, Hinter, KeyEvent, RepeatCount, Validator, completion::Completer, error::ReadlineError, @@ -131,12 +130,10 @@ pub fn tokenize(command: &str) -> Vec { } pub fn parse_command(input: &str) -> Result> { - let pattern = Regex::new(r"[;|\n]").map_err(|_| { - ZenyxError::builder(ZenyxErrorKind::CommandParsing) - .with_message("Failed to compile regex pattern") - .build() - })?; - let commands: Vec = pattern.split(input).map(String::from).collect(); + let commands = input + .split(|c| c == ';' || c == '\n') + .map(|slice| slice.to_string()) + .collect::>(); Ok(commands) } @@ -145,12 +142,10 @@ pub fn evaluate_command(input: &str) -> Result<()> { return Ok(()); } - let pattern = Regex::new(r"[;|\n]").map_err(|_| { - ZenyxError::builder(ZenyxErrorKind::CommandParsing) - .with_message("Failed to compile regex pattern") - .build() - })?; - let commands: Vec<&str> = pattern.split(input).collect(); + let commands = input + .split(|c| c == ';' || c == '\n') + .map(|slice| slice.to_string()) + .collect::>(); for command in commands { let command = command.trim();