From f72d7d6591f3c586348c6a71834f79d3db680d88 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:54:42 -0700 Subject: [PATCH 01/11] Move corner rendering out of loop --- src/ui/interface.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/interface.rs b/src/ui/interface.rs index f078d3d..99c29fd 100644 --- a/src/ui/interface.rs +++ b/src/ui/interface.rs @@ -12,12 +12,12 @@ fn rect(stdout: &mut Stdout, start: u16, height: u16, width: u16) -> Result<()> } else if x == 0 || x == width - 1 { queue!(stdout, cursor::MoveTo(x, y), style::Print("│"))?; // right side } - queue!(stdout, cursor::MoveTo(width - 1, start), style::Print("┐"))?; // top right - queue!(stdout, cursor::MoveTo(0, start), style::Print("┌"))?; // top left - queue!(stdout, cursor::MoveTo(width - 1, height), style::Print("┘"))?; // bottom right - queue!(stdout, cursor::MoveTo(0, height), style::Print("└"))?; // bottom left } } + queue!(stdout, cursor::MoveTo(width - 1, start), style::Print("┐"))?; // top right + queue!(stdout, cursor::MoveTo(0, start), style::Print("┌"))?; // top left + queue!(stdout, cursor::MoveTo(width - 1, height), style::Print("┘"))?; // bottom right + queue!(stdout, cursor::MoveTo(0, height), style::Print("└"))?; // bottom left Ok(()) } From e8de01be0cc6929ed67169a4bddce250e70f085c Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:55:48 -0700 Subject: [PATCH 02/11] Scroll arithmetically, not via loop --- src/ui/scroll.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ui/scroll.rs b/src/ui/scroll.rs index e462047..9a447fb 100644 --- a/src/ui/scroll.rs +++ b/src/ui/scroll.rs @@ -27,11 +27,21 @@ pub fn down(window: &mut MainWindow) { } pub fn pg_up(window: &mut MainWindow) { - (0..window.config.last_row).for_each(|_| up(window)); + window.config.scroll_state = ScrollState::Free; + window.config.current_end = window + .config + .current_end + .saturating_sub(window.config.last_row as usize) + .max(1); } pub fn pg_down(window: &mut MainWindow) { - (0..window.config.last_row).for_each(|_| down(window)); + window.config.scroll_state = ScrollState::Free; + let num_messages = window.number_of_messages(); + window.config.current_end = min( + num_messages, + window.config.current_end + window.config.last_row as usize, + ); } pub fn bottom(window: &mut MainWindow) { From 13c83be27ef92951c4d82b1357fa7a648d3be356 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:56:33 -0700 Subject: [PATCH 03/11] Cache color regex --- src/constants/cli.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/constants/cli.rs b/src/constants/cli.rs index 60e15dc..9b442dc 100644 --- a/src/constants/cli.rs +++ b/src/constants/cli.rs @@ -9,7 +9,14 @@ pub mod poll_rate { } pub mod patterns { + use std::sync::LazyLock; + + use regex::bytes::Regex; + pub const ANSI_COLOR_PATTERN: &str = r"(?-u)(\x9b|\x1b\[)[0-?]*[ -/]*[@-~]"; + + pub static ANSI_COLOR_REGEX: LazyLock = + LazyLock::new(|| Regex::new(ANSI_COLOR_PATTERN).unwrap()); } pub mod colors { From 9114bdc7bf9e93c852dd45054f3b1e591c98c24f Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:56:50 -0700 Subject: [PATCH 04/11] Cache color regex --- src/communication/handlers/search.rs | 9 ++------- src/util/sanitizers.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/communication/handlers/search.rs b/src/communication/handlers/search.rs index 6587f22..45dcbd9 100644 --- a/src/communication/handlers/search.rs +++ b/src/communication/handlers/search.rs @@ -5,7 +5,7 @@ use regex::bytes::Regex; use super::{handler::Handler, processor::update_progress, user_input::UserInputHandler}; use crate::{ communication::{input::InputType::Normal, reader::MainWindow}, - constants::cli::{cli_chars::NORMAL_STR, patterns::ANSI_COLOR_PATTERN}, + constants::cli::{cli_chars::NORMAL_STR, patterns::ANSI_COLOR_REGEX}, }; /// Shared state and logic for regex filtering and highlight searching. @@ -14,7 +14,6 @@ use crate::{ /// to avoid duplicating pattern matching, match processing, and /// cleanup logic. pub struct SearchState { - color_pattern: Regex, pub current_pattern: Option, pub input_handler: UserInputHandler, } @@ -22,7 +21,6 @@ pub struct SearchState { impl SearchState { pub fn new() -> Self { SearchState { - color_pattern: Regex::new(ANSI_COLOR_PATTERN).unwrap(), current_pattern: None, input_handler: UserInputHandler::new(), } @@ -30,10 +28,7 @@ impl SearchState { /// Test a message to see if it matches the pattern while also escaping the color code pub fn test(&self, message: &str) -> bool { - // TODO: Possibly without the extra allocation here? - let clean_message = self - .color_pattern - .replace_all(message.as_bytes(), "".as_bytes()); + let clean_message = ANSI_COLOR_REGEX.replace_all(message.as_bytes(), "".as_bytes()); match &self.current_pattern { Some(pattern) => pattern.is_match(&clean_message), None => panic!("Match called with no pattern!"), diff --git a/src/util/sanitizers.rs b/src/util/sanitizers.rs index 5bac030..8fc45e9 100644 --- a/src/util/sanitizers.rs +++ b/src/util/sanitizers.rs @@ -1,8 +1,6 @@ use std::{cmp::max, collections::HashSet, str::from_utf8, sync::LazyLock}; -use regex::bytes::Regex; - -use crate::constants::cli::patterns::ANSI_COLOR_PATTERN; +use crate::constants::cli::patterns::ANSI_COLOR_REGEX; /// Characters disallowed in a filename static FILENAME_DISALLOWED_CHARS: LazyLock> = @@ -29,21 +27,17 @@ pub fn sanitize_filename(filename: &str) -> String { .collect() } -pub struct LengthFinder { - color_pattern: Regex, -} +pub struct LengthFinder {} impl LengthFinder { pub fn new() -> LengthFinder { - LengthFinder { - color_pattern: Regex::new(ANSI_COLOR_PATTERN).unwrap(), - } + LengthFinder {} } /// Returns the length of the string without ANSI color codes, i.e. the /// number of visible characters in a string when rendered in a terminal. fn get_real_length(&self, content: &str) -> usize { - self.color_pattern + ANSI_COLOR_REGEX .split(content.as_bytes()) .filter_map(|s| from_utf8(s).ok()) .map(|s| s.chars().count()) From 797fe4e096911af6eb313eef526af0c1ee4a2229 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:57:30 -0700 Subject: [PATCH 05/11] Binary search for highlight, cache color regex --- src/communication/reader.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/communication/reader.rs b/src/communication/reader.rs index 4cce33c..d017aff 100644 --- a/src/communication/reader.rs +++ b/src/communication/reader.rs @@ -32,6 +32,7 @@ use crate::{ constants::cli::{ cli_chars, colors, messages::{NO_MESSAGE_IN_BUFFER_NORMAL, NO_MESSAGE_IN_BUFFER_PARSER, PIPE_INPUT_ERROR}, + patterns::ANSI_COLOR_REGEX, poll_rate::DEFAULT, }, ui::{ @@ -78,8 +79,6 @@ pub struct LogriaConfig { pub last_index_regexed: usize, /// The currently selected row as we scroll between matches; represents an index in the [`LogriaConfig::matched_rows`] vector pub current_matched_row: usize, - /// A regex to remove ANSI color codes - color_replace_regex: Regex, /// Determines whether we highlight the matched text to the user pub highlight_match: bool, @@ -228,10 +227,6 @@ impl MainWindow { matched_rows: vec![], last_index_regexed: 0, current_matched_row: 0, - color_replace_regex: Regex::new( - crate::constants::cli::patterns::ANSI_COLOR_PATTERN, - ) - .unwrap(), parser_index: 0, parser_state: ParserState::Disabled, aggregation_enabled: false, @@ -447,10 +442,7 @@ impl MainWindow { fn highlight_match(&self, message: &str) -> String { // Regex out any existing color codes // We use a bytes regex because we cannot compile the pattern using normal regex - let clean_message = self - .config - .color_replace_regex - .replace_all(message.as_bytes(), "".as_bytes()); + let clean_message = ANSI_COLOR_REGEX.replace_all(message.as_bytes(), "".as_bytes()); // Store some vectors of char bytes so we don't have to cast to a string every loop let mut new_msg: Vec = vec![]; @@ -482,10 +474,7 @@ impl MainWindow { fn highlight_row(&self, message: &str) -> String { // Regex out any existing color codes // We use a bytes regex because we cannot compile the pattern using normal regex - let clean_message = self - .config - .color_replace_regex - .replace_all(message.as_bytes(), "".as_bytes()); + let clean_message = ANSI_COLOR_REGEX.replace_all(message.as_bytes(), "".as_bytes()); // Store some vectors of char bytes so we don't have to cast to a string every loop let mut new_msg: Vec = vec![]; @@ -585,7 +574,9 @@ impl MainWindow { if self.config.highlight_match && self.config.regex_pattern.is_some() { match self.input_type { InputType::Regex => Cow::Owned(self.highlight_match(message)), - InputType::Highlight if self.config.matched_rows.contains(&index) => { + InputType::Highlight + if self.config.matched_rows.binary_search(&index).is_ok() => + { Cow::Owned(self.highlight_row(message)) } _ => Cow::Borrowed(message), From 2d49bd0d2ea22904b3c9cbd4a62904b4b95bb439 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 20:59:43 -0700 Subject: [PATCH 06/11] Refactor CommandInput to eliminate unnecessary Mutex for polling, --- src/communication/input.rs | 42 ++++++++++---------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/communication/input.rs b/src/communication/input.rs index bb96467..b7b9fc7 100644 --- a/src/communication/input.rs +++ b/src/communication/input.rs @@ -21,7 +21,7 @@ use std::{ process::{Child, Command, Stdio}, result::Result, sync::{ - Arc, Mutex, + Arc, atomic::{AtomicBool, Ordering}, mpsc::{Receiver, channel}, }, @@ -139,10 +139,6 @@ impl Input for CommandInput { let should_die = Arc::new(AtomicBool::new(false)); let should_die_clone = Arc::clone(&should_die); - // Handle poll rate for each stream - let poll_rate_stdout = Arc::new(Mutex::new(RollingMean::new(5))); - let poll_rate_stderr = Arc::new(Mutex::new(RollingMean::new(5))); - // Start reading from the queues let handle = thread::Builder::new() .name(format!("CommandInput: {name}")) @@ -153,13 +149,9 @@ impl Input for CommandInput { // Create threads to read stdout and stderr independently let die_clone = Arc::clone(&should_die_clone); - let poll_stdout = poll_rate_stdout.clone(); let stdout_handle = thread::spawn(move || { + let mut poll_rate = RollingMean::new(5); loop { - thread::sleep(time::Duration::from_millis( - poll_stdout.lock().unwrap().mean(), - )); - // Exit if the process is requested to die if die_clone.load(Ordering::Relaxed) { break; @@ -170,10 +162,9 @@ impl Input for CommandInput { stdout_reader.read_line(&mut buf_stdout).unwrap(); if buf_stdout.is_empty() { - poll_stdout - .lock() - .unwrap() - .update(ms_per_message(timestamp.elapsed(), 0)); + poll_rate.update(ms_per_message(timestamp.elapsed(), 0)); + // Back off when no data is available (EOF/empty read) + thread::sleep(time::Duration::from_millis(poll_rate.mean())); continue; } @@ -181,21 +172,14 @@ impl Input for CommandInput { break; } - poll_stdout - .lock() - .unwrap() - .update(ms_per_message(timestamp.elapsed(), 1)); + poll_rate.update(ms_per_message(timestamp.elapsed(), 1)); } }); let die_clone = Arc::clone(&should_die_clone); - let poll_stderr = poll_rate_stderr.clone(); let stderr_handle = thread::spawn(move || { + let mut poll_rate = RollingMean::new(5); loop { - thread::sleep(time::Duration::from_millis( - poll_stderr.lock().unwrap().mean(), - )); - // Exit if the process is requested to die if die_clone.load(Ordering::Relaxed) { break; @@ -206,10 +190,9 @@ impl Input for CommandInput { stderr_reader.read_line(&mut buf_stderr).unwrap(); if buf_stderr.is_empty() { - poll_stderr - .lock() - .unwrap() - .update(ms_per_message(timestamp.elapsed(), 0)); + poll_rate.update(ms_per_message(timestamp.elapsed(), 0)); + // Back off when no data is available (EOF/empty read) + thread::sleep(time::Duration::from_millis(poll_rate.mean())); continue; } @@ -217,10 +200,7 @@ impl Input for CommandInput { break; } - poll_stderr - .lock() - .unwrap() - .update(ms_per_message(timestamp.elapsed(), 1)); + poll_rate.update(ms_per_message(timestamp.elapsed(), 1)); } }); From 03e63953404cac6cbafebfd4bd7c280d9f705d48 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 21:05:29 -0700 Subject: [PATCH 07/11] Fix underflow crash --- src/communication/handlers/user_input.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/communication/handlers/user_input.rs b/src/communication/handlers/user_input.rs index e1dc0e1..b72ad13 100644 --- a/src/communication/handlers/user_input.rs +++ b/src/communication/handlers/user_input.rs @@ -87,7 +87,8 @@ impl UserInputHandler { /// Remove char 1 to the left of the cursor fn backspace(&mut self, window: &mut MainWindow) -> Result<()> { if self.last_write >= 1 && !self.content.is_empty() { - self.content.remove(self.position_as_index() - 1); + self.content + .remove(self.position_as_index().saturating_sub(1)); self.move_left()?; self.write(window)?; } From b33d5c66e814b0dc05ecfb19cbb932448e4dcadd Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 21:06:07 -0700 Subject: [PATCH 08/11] Remove allocations in highlight path --- src/communication/reader.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/communication/reader.rs b/src/communication/reader.rs index d017aff..1353df0 100644 --- a/src/communication/reader.rs +++ b/src/communication/reader.rs @@ -456,17 +456,17 @@ impl MainWindow { .unwrap() .find_iter(&clean_message) { - new_msg.extend(clean_message[last_end..capture.start()].to_vec()); + new_msg.extend_from_slice(&clean_message[last_end..capture.start()]); // Add start color string - new_msg.extend(colors::HIGHLIGHT_COLOR.as_bytes().to_vec()); - new_msg.extend(clean_message[capture.start()..capture.end()].to_vec()); + new_msg.extend_from_slice(colors::HIGHLIGHT_COLOR.as_bytes()); + new_msg.extend_from_slice(&clean_message[capture.start()..capture.end()]); // Add end color string - new_msg.extend(colors::RESET_COLOR.as_bytes().to_vec()); + new_msg.extend_from_slice(colors::RESET_COLOR.as_bytes()); // Store the ending in case we have multiple matches so we can add the end later last_end = capture.end(); } // Add on any extra chars and update the message String - new_msg.extend(clean_message[last_end..].to_vec()); + new_msg.extend_from_slice(&clean_message[last_end..]); String::from_utf8(new_msg).unwrap() } @@ -478,9 +478,9 @@ impl MainWindow { // Store some vectors of char bytes so we don't have to cast to a string every loop let mut new_msg: Vec = vec![]; - new_msg.extend(colors::HIGHLIGHT_COLOR.as_bytes().to_vec()); - new_msg.extend(clean_message.to_vec()); - new_msg.extend(colors::RESET_COLOR.as_bytes().to_vec()); + new_msg.extend_from_slice(colors::HIGHLIGHT_COLOR.as_bytes()); + new_msg.extend_from_slice(&clean_message); + new_msg.extend_from_slice(colors::RESET_COLOR.as_bytes()); String::from_utf8(new_msg).unwrap() } From 14b5dc0933a6f01e98bf67d530a4ae0985133ef9 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Thu, 12 Mar 2026 21:06:28 -0700 Subject: [PATCH 09/11] Defer allocation until ready to render --- src/communication/handlers/parser.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/communication/handlers/parser.rs b/src/communication/handlers/parser.rs index 5dd15ba..a854475 100644 --- a/src/communication/handlers/parser.rs +++ b/src/communication/handlers/parser.rs @@ -146,18 +146,10 @@ impl ParserHandler { match message_parts { Ok(message_parts) => { - // If we got this far, allocate the return value - let mut aggregated_data = vec![]; for (idx, part) in message_parts.iter().enumerate() { if let Some(item) = parser.order.get(idx).cloned() { if let Some(aggregator) = parser.aggregator_map.get_mut(&item) { aggregator.update(part)?; - if render { - // Name of aggregated part - aggregated_data.push(item); - // Messages generated for that aggregator - aggregated_data.extend(aggregator.messages(num_to_get)); - } } else { return Err(LogriaError::InvalidParserState(format!( "aggregator missing for {item}!" @@ -170,7 +162,19 @@ impl ParserHandler { )); } } - Ok(aggregated_data) + // Only generate display messages on the final iteration + if render { + let mut aggregated_data = vec![]; + for item in &parser.order { + if let Some(aggregator) = parser.aggregator_map.get(item) { + aggregated_data.push(item.clone()); + aggregated_data.extend(aggregator.messages(num_to_get)); + } + } + Ok(aggregated_data) + } else { + Ok(vec![]) + } } Err(why) => Err(why), } From 696a9f6be2b291ff85e19dc2c1cc19ad7f64fb32 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Fri, 13 Mar 2026 08:51:14 -0700 Subject: [PATCH 10/11] bump deps --- Cargo.lock | 49 ++++++++++++++++++++++++------------------------- Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3958b9e..e678e18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,18 +75,18 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.58" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] @@ -247,25 +247,24 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ - "bitflags", "libc", ] [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litrs" @@ -378,9 +377,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -430,9 +429,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc_version" @@ -445,9 +444,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -556,9 +555,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.115" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -618,9 +617,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" diff --git a/Cargo.toml b/Cargo.toml index 1be0aff..0352710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/ReagentX/Logria" version = "0.0.0" [dependencies] -clap = { version = "=4.5.58", features = ["cargo"] } +clap = { version = "=4.5.60", features = ["cargo"] } crossterm = "=0.29.0" dirs = "=6.0.0" is_executable = "=1.0.5" From 10a3c93821d946ac2c6ea9b7a51ca5e2d26736a1 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Fri, 13 Mar 2026 09:08:11 -0700 Subject: [PATCH 11/11] Fix fragile tests --- src/communication/handlers/startup.rs | 10 ++++++++-- src/extensions/parser.rs | 4 ++-- src/extensions/session.rs | 11 ++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/communication/handlers/startup.rs b/src/communication/handlers/startup.rs index f28d994..55208ac 100644 --- a/src/communication/handlers/startup.rs +++ b/src/communication/handlers/startup.rs @@ -187,8 +187,15 @@ mod startup_tests { let mut handler = StartupHandler::new(); handler.initialize(); + // Find the correct index for the "ls -la" session + let sessions = Session::list_full(); + let idx = sessions + .iter() + .position(|s| s.ends_with("/ls -la")) + .expect("ls -la session not found"); + // Tests - assert!(handler.process_command(&mut window, "0").is_ok()); + assert!(handler.process_command(&mut window, &idx.to_string()).is_ok()); assert!(matches!(window.input_type, InputType::Normal)); assert!(matches!(window.config.stream_type, StreamType::StdErr)); } @@ -227,6 +234,5 @@ mod startup_tests { ); assert!(matches!(window.input_type, InputType::Startup)); assert!(matches!(window.config.stream_type, StreamType::Auxiliary)); - Session::del(&[Session::list_full().len() - 1]).unwrap(); } } diff --git a/src/extensions/parser.rs b/src/extensions/parser.rs index db51397..1b2e572 100644 --- a/src/extensions/parser.rs +++ b/src/extensions/parser.rs @@ -421,9 +421,9 @@ mod parse_tests { ], map2, ); - parser.save("Hyphen Separated Test 2").unwrap(); + parser.save("Hyphen Separated DateTime Test").unwrap(); - let file_name = format!("{}/{}", patterns(), "Hyphen Separated Test 2"); + let file_name = format!("{}/{}", patterns(), "Hyphen Separated DateTime Test"); let read_parser = Parser::load(&file_name).unwrap(); let expected_parser = Parser::new( String::from(" - "), diff --git a/src/extensions/session.rs b/src/extensions/session.rs index bbc4037..017d1c6 100644 --- a/src/extensions/session.rs +++ b/src/extensions/session.rs @@ -154,6 +154,8 @@ mod tests { #[test] fn test_list_full() { + let session = Session::new(&[String::from("ls -la")], SessionType::Command); + session.save("ls -la").unwrap(); let list = Session::list_full(); assert!( list.iter() @@ -163,6 +165,8 @@ mod tests { #[test] fn test_list_clean() { + let session = Session::new(&[String::from("ls -la")], SessionType::Command); + session.save("ls -la").unwrap(); let list = Session::list_clean(); assert!(list.iter().any(|i| i == "ls -la")); } @@ -195,6 +199,11 @@ mod tests { fn delete_session() { let session = Session::new(&[String::from("ls -la")], SessionType::Command); session.save("zzzfake_file_name").unwrap(); - Session::del(&[Session::list_full().len() - 1]).unwrap(); + let files = Session::list_full(); + let idx = files + .iter() + .position(|s| s.ends_with("/zzzfake_file_name")) + .expect("zzzfake_file_name not found"); + Session::del(&[idx]).unwrap(); } }