From 5fb02c768f82d81af2426661b67183dbc333b21d Mon Sep 17 00:00:00 2001 From: Bertrand Chardon <51328958+bertrand-chardon@users.noreply.github.com> Date: Sun, 8 Dec 2024 23:21:34 +0100 Subject: [PATCH] perf: merge contiguous name match ranges (#108) in the entries that are used in the `build_results_list` function in `television-screen::results`, it seems like there the ranges returned are sometimes contiguous since they're used to create `ratatui` spans, we want to reduce them to their minimal equivalent form --- crates/television-channels/src/entry.rs | 107 ++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/crates/television-channels/src/entry.rs b/crates/television-channels/src/entry.rs index 59fce29..c5c765f 100644 --- a/crates/television-channels/src/entry.rs +++ b/crates/television-channels/src/entry.rs @@ -65,6 +65,31 @@ impl Entry { self.value = Some(value); self } + #[allow(clippy::needless_return)] + pub fn minimal_name_match_ranges(self) -> Option> { + // This method takes the existing `name_match_ranges` + // and merges contiguous ranges into the minimal equivalent + // set of ranges. If no ranges exist, it returns `None`. + if let Some(name_match_ranges) = self.name_match_ranges { + let minimal_name_match_ranges: Vec<(u32, u32)> = name_match_ranges + .into_iter() + .fold(Vec::new(), |mut acc, x| { + if let Some(last) = acc.last_mut() { + if last.1 == x.0 { + last.1 = x.1 + } else { + acc.push(x); + } + } else { + acc.push(x); + } + return acc; + }); + Some(minimal_name_match_ranges) + } else { + None + } + } pub fn with_name_match_ranges( mut self, @@ -146,3 +171,85 @@ pub enum PreviewType { Files, Command(PreviewCommand), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_minimal_name_match_ranges_none() { + let entry = Entry { + name: "test".to_string(), + value: None, + name_match_ranges: None, + value_match_ranges: None, + icon: None, + line_number: None, + preview_type: PreviewType::Files, + }; + assert_eq!(entry.minimal_name_match_ranges(), None); + } + #[test] + fn test_minimal_name_match_ranges_empty() { + let entry = Entry { + name: "test".to_string(), + value: None, + name_match_ranges: Some(vec![]), + value_match_ranges: None, + icon: None, + line_number: None, + preview_type: PreviewType::Files, + }; + + assert_eq!(entry.minimal_name_match_ranges(), Some(vec![])); + } + #[test] + fn test_minimal_name_match_ranges_non_contiguous() { + let entry = Entry { + name: "test".to_string(), + value: None, + name_match_ranges: Some(vec![(0, 1), (2, 4), (6, 9)]), + value_match_ranges: None, + icon: None, + line_number: None, + preview_type: PreviewType::Files, + }; + assert_eq!( + entry.minimal_name_match_ranges(), + Some(vec![(0, 1), (2, 4), (6, 9)]) + ); + } + + #[test] + fn test_minimal_name_match_ranges_contiguous() { + let entry = Entry { + name: "test".to_string(), + value: None, + name_match_ranges: Some(vec![(0, 1), (1, 2), (2, 3), (3, 4)]), + value_match_ranges: None, + icon: None, + line_number: None, + preview_type: PreviewType::Files, + }; + + assert_eq!(entry.minimal_name_match_ranges(), Some(vec![(0, 4)])); + } + + #[test] + fn test_minimal_name_match_ranges_both_contiguous_and_non_contiguous() { + let entry = Entry { + name: "test".to_string(), + value: None, + name_match_ranges: Some(vec![(0, 1), (2, 3), (3, 4)]), + value_match_ranges: None, + icon: None, + line_number: None, + preview_type: PreviewType::Files, + }; + + assert_eq!( + entry.minimal_name_match_ranges(), + Some(vec![(0, 1), (2, 4)]) + ); + } +}