diff --git a/yazi-core/src/tab/selected.rs b/yazi-core/src/tab/selected.rs index f52a5dab..380e5588 100644 --- a/yazi-core/src/tab/selected.rs +++ b/yazi-core/src/tab/selected.rs @@ -11,8 +11,13 @@ pub struct Selected { impl Selected { pub fn new() -> Self { Selected { inner: BTreeSet::new(), parents: HashMap::new() } } - pub fn insert(&mut self, url: Url) -> bool { - let url_buf = url.to_path_buf(); + pub fn insert(&mut self, url: Url) -> bool { self.insert_many(&[&url]) } + + pub fn insert_many(&mut self, urls: &[&Url]) -> bool { + if urls.is_empty() { + return false; + } + let url_buf = urls[0].to_path_buf(); let mut current_path = url_buf.clone(); while let Some(parent) = current_path.parent() { @@ -27,15 +32,17 @@ impl Selected { } let mut current_path = url_buf.clone(); + let len_of_urls = urls.len(); loop { current_path = match current_path.parent() { Some(parent) => parent.to_path_buf(), None => break, }; let counter = self.parents.entry(current_path.clone()).or_insert(0); - *counter += 1; + *counter += len_of_urls; } - self.inner.insert(url.clone()); + + self.inner.extend(urls.iter().cloned().cloned()); true } @@ -118,68 +125,121 @@ mod tests { assert!(selected.parents.is_empty(), "Parents map should be empty after removal"); } - #[test] fn insert_many_success() { let mut selected = Selected::new(); - let parent = Url::from(Path::new("/parent")); - let child1= Url::from(Path::new("/parent/child1")); - let child2= Url::from(Path::new("/parent/child2")); - let urls = vec![ - &child1, - &child2, - ]; - assert!(selected.insert_many(&urls, parent), "Should successfully insert urls with the same parent"); + let child1 = Url::from(Path::new("/parent/child1")); + let child2 = Url::from(Path::new("/parent/child2")); + let child3 = Url::from(Path::new("/parent/child3")); + let urls = vec![&child1, &child2, &child3]; + assert!(selected.insert_many(&urls), "Should successfully insert urls with the same parent"); } #[test] fn insert_many_with_existing_parent_fails() { let mut selected = Selected::new(); - let parent = Url::from(Path::new("/parent")); selected.insert(Url::from(Path::new("/parent"))); - let childs1= Url::from(Path::new("/parent/child1")); - let childs2=Url::from(Path::new("/parent/child2")); - let urls = vec![ - &childs1, - &childs2 - ]; - assert!(!selected.insert_many(&urls, parent), "Should fail to insert since parent already exists"); + + let childs1 = Url::from(Path::new("/parent/child1")); + let childs2 = Url::from(Path::new("/parent/child2")); + let urls = vec![&childs1, &childs2]; + assert!(!selected.insert_many(&urls), "Should fail to insert since parent already exists"); } #[test] fn insert_many_with_existing_child_fails() { let mut selected = Selected::new(); - let parent = Url::from(Path::new("/parent")); let child = Url::from(Path::new("/parent/child1")); selected.insert(child); - let child1= Url::from(Path::new("/parent/child1")); - let child2= Url::from(Path::new("/parent/child2")); - let urls = vec![ - &child1, - &child2 - ]; - assert!(!selected.insert_many(&urls, parent), "Should fail to insert since one of the children already exists"); + + let child1 = Url::from(Path::new("/parent/child1")); + let child2 = Url::from(Path::new("/parent/child2")); + let urls = vec![&child1, &child2]; + assert!( + selected.insert_many(&urls), + "Should success to insert since one of the children already exists" + ); } #[test] fn insert_many_empty_urls_list() { let mut selected = Selected::new(); - let parent = Url::from(Path::new("/parent")); let urls = vec![]; - assert!(selected.insert_many(&urls, parent), "Inserting an empty list of urls should succeed"); + assert!(!selected.insert_many(&urls), "Inserting an empty list of urls should false"); } #[test] fn insert_many_with_parent_as_child_of_another_url() { let mut selected = Selected::new(); - let parent = Url::from(Path::new("/parent/child")); - selected.insert(Url::from(Path::new("/parent"))); - let child1= Url::from(Path::new("/parent/child/child1")); - let child2= Url::from(Path::new("/parent/child/child2")); - let urls = vec![ - &child1, - &child2, - ]; - assert!(selected.insert_many(&urls, parent), "Should successfully insert urls when parent is a child of another url in the set"); + selected.insert(Url::from(Path::new("/parent/child"))); + let child1 = Url::from(Path::new("/parent/child/child1")); + let child2 = Url::from(Path::new("/parent/child/child2")); + let urls = vec![&child1, &child2]; + assert!( + !selected.insert_many(&urls), + "Should successfully insert urls when parent is a child of another url in the set" + ); + } + #[test] + fn insert_many_with_direct_parent_fails() { + let mut selected = Selected::new(); + selected.insert(Url::from(Path::new("/a"))); + let binding = Url::from(Path::new("/a/b")); + let urls = vec![&binding]; + assert!( + !selected.insert_many(&urls), + "Should not allow insert when parent is already selected" + ); + } + + #[test] + fn insert_many_with_nested_child_fails() { + let mut selected = Selected::new(); + selected.insert(Url::from(Path::new("/a/b"))); + let binding = Url::from(Path::new("/a")); + let urls = vec![&binding]; + assert!( + !selected.insert_many(&urls), + "Should not allow insert of a parent when a child is already selected" + ); + } + + #[test] + fn insert_many_sibling_directories_success() { + let mut selected = Selected::new(); + let child1 = Url::from(Path::new("/a/b")); + let child2 = Url::from(Path::new("/a/c")); + let urls = vec![&child1, &child2]; + assert!(selected.insert_many(&urls), "Should allow inserts of sibling directories"); + } + + #[test] + fn insert_many_with_grandchild_fails() { + let mut selected = Selected::new(); + selected.insert(Url::from(Path::new("/a/b"))); + let binding = Url::from(Path::new("/a/b/c")); + let urls = vec![&binding]; + assert!( + !selected.insert_many(&urls), + "Should not allow insert of a grandchild when the child is already selected" + ); + } + #[test] + fn test_insert_many_with_remove() { + let mut selected = Selected::new(); + let child1 = Url::from(Path::new("/parent/child1")); + let child2 = Url::from(Path::new("/parent/child2")); + let child3 = Url::from(Path::new("/parent/child3")); + let urls = vec![&child1, &child2, &child3]; + assert!(selected.insert_many(&urls), "Should successfully insert urls with the same parent"); + assert!(selected.remove(&child1), "Should successfully remove url"); + assert_eq!(selected.inner.len(),2); + assert!(!selected.parents.is_empty(),"parent map should not be empty"); + assert!(selected.remove(&child2), "Should successfully remove url"); + assert!(!selected.parents.is_empty(),"parent map should not be empty"); + assert!(selected.remove(&child3), "Should successfully remove url"); + + assert!(selected.inner.is_empty(), "Inner set should be empty after removal"); + assert!(selected.parents.is_empty(), "Parents map should be empty after removal"); } }