diff --git a/helix-term/src/ui/explore.rs b/helix-term/src/ui/explore.rs index 462a0aa8..f8faa82d 100644 --- a/helix-term/src/ui/explore.rs +++ b/helix-term/src/ui/explore.rs @@ -618,10 +618,9 @@ impl Explorer { .handle_event(Event::Key(event), cx, &mut self.state); } key!(Enter) => { - self.tree.clean_recycle(); - return self - .tree - .handle_event(Event::Key(event), cx, &mut self.state); + if let EventResult::Consumed(_) = prompt.handle_event(Event::Key(event), cx) { + self.tree.filter(prompt.line(), cx, &mut self.state); + } } key!(Esc) | ctrl!('c') => self.tree.restore_recycle(), _ => { diff --git a/helix-term/src/ui/tree.rs b/helix-term/src/ui/tree.rs index 8144c734..1381762d 100644 --- a/helix-term/src/ui/tree.rs +++ b/helix-term/src/ui/tree.rs @@ -165,6 +165,32 @@ impl<'a, T> DoubleEndedIterator for TreeIter<'a, T> { impl<'a, T> ExactSizeIterator for TreeIter<'a, T> {} +impl Tree { + pub fn filter

(tree: &Tree, predicate: &P) -> Option> + where + P: Fn(&T) -> bool, + { + let children = tree + .children + .iter() + .filter_map(|tree| Self::filter(tree, predicate)) + .collect::>(); + if predicate(&tree.item) || !children.is_empty() { + let mut tree = Tree { + item: tree.item.clone(), + parent_index: tree.parent_index, + index: tree.index, + is_opened: tree.is_opened, + children, + }; + tree.regenerate_index(); + Some(tree) + } else { + None + } + } +} + impl Tree { pub fn new(item: T, children: Vec>) -> Self { Self { @@ -234,7 +260,7 @@ impl Tree { pub struct TreeView { tree: Tree, - recycle: Option<(String, Vec>)>, + recycle: Option<(String, Tree)>, /// Selected item idex selected: usize, @@ -878,85 +904,31 @@ impl TreeView { impl TreeView { pub fn filter(&mut self, s: &str, cx: &mut Context, params: &mut T::Params) { - todo!() - // fn filter_recursion( - // elems: &Vec>, - // mut index: usize, - // s: &str, - // cx: &mut Context, - // params: &mut T::Params, - // ) -> (Vec>, usize) - // where - // T: TreeItem + Clone, - // { - // let mut retain = vec![]; - // let elem = &elems[index]; - // loop { - // let child = match elems.get(index + 1) { - // Some(child) if child.item.is_child(&elem.item) => child, - // _ => break, - // }; - // index += 1; - // let next = elems.get(index + 1); - // if next.map_or(false, |n| n.item.is_child(&child.item)) { - // let (sub_retain, current_index) = filter_recursion(elems, index, s, cx, params); - // retain.extend(sub_retain); - // index = current_index; - // } else if child.item.filter(s) { - // retain.push(child.clone()); - // } - // } - // if !retain.is_empty() || elem.item.filter(s) { - // retain.insert(0, elem.clone()); - // } - // (retain, index) - // } - - // if s.is_empty() { - // if let Some((_, recycle)) = self.recycle.take() { - // // self.tree = recycle; - // self.restore_view(); - // return; - // } - // } - - // let mut retain = vec![]; - // let mut index = 0; - // let items = match &self.recycle { - // Some((pre, _)) if pre == s => return, - // Some((pre, recycle)) if pre.contains(s) => recycle, - // _ => &self.tree, - // }; - // while let Some(elem) = items.get(index) { - // let next = items.get(index + 1); - // if next.map_or(false, |n| n.item.is_child(&elem.item)) { - // let (sub_items, current_index) = filter_recursion(items, index, s, cx, params); - // index = current_index; - // retain.extend(sub_items); - // } else if elem.item.filter(s) { - // retain.push(elem.clone()) - // } - // index += 1; - // } - - // if retain.is_empty() { - // if let Some((_, recycle)) = self.recycle.take() { - // self.tree = recycle; - // self.restore_view(); - // } - // return; - // } + if s.is_empty() { + self.restore_recycle(); + return; + } - // let recycle = std::mem::replace(&mut self.tree, retain); - // if let Some(r) = self.recycle.as_mut() { - // r.0 = s.into() - // } else { - // self.recycle = Some((s.into(), recycle)); - // self.save_view(); - // } + let new_tree = Tree::filter(&self.tree, &|item: &T| { + item.text_string() + .to_lowercase() + .contains(&s.to_lowercase()) + }) + .unwrap_or_else(|| Tree { + item: self.tree.item.clone(), + children: vec![], + ..self.tree.clone() + }); + let recycle = std::mem::replace(&mut self.tree, new_tree); + if let Some(r) = self.recycle.as_mut() { + r.0 = s.into() + } else { + self.recycle = Some((s.into(), recycle)); + self.save_view(); + } - // self.selected = self.find(0, false, |elem| elem.item.filter(s)).unwrap_or(0); - // self.winline = self.selected; + self.selected = 0; + self.winline = 0 } pub fn clean_recycle(&mut self) { @@ -964,10 +936,10 @@ impl TreeView { } pub fn restore_recycle(&mut self) { - todo!(); - // if let Some((_, recycle)) = self.recycle.take() { - // self.tree = recycle; - // } + if let Some((_, recycle)) = self.recycle.take() { + self.tree = recycle; + } + self.restore_view(); } } @@ -1196,4 +1168,43 @@ mod test_tree { assert_eq!(result, Some(3)); } + + #[test] + fn test_filter() { + let tree = Tree::new( + ".cargo", + vec![ + Tree::new("spam", vec![Tree::new("Cargo.toml", vec![])]), + Tree::new("Cargo.toml", vec![Tree::new("pam", vec![])]), + Tree::new("hello", vec![]), + ], + ); + + let result = Tree::filter(&tree, &|item| item.to_lowercase().contains("cargo")); + assert_eq!( + result, + Some(Tree::new( + ".cargo", + vec![ + Tree::new("spam", vec![Tree::new("Cargo.toml", vec![])]), + Tree::new("Cargo.toml", vec![]), + ], + )) + ); + + let result = Tree::filter(&tree, &|item| item.to_lowercase().contains("pam")); + assert_eq!( + result, + Some(Tree::new( + ".cargo", + vec![ + Tree::new("spam", vec![]), + Tree::new("Cargo.toml", vec![Tree::new("pam", vec![])]), + ], + )) + ); + + let result = Tree::filter(&tree, &|item| item.to_lowercase().contains("helix")); + assert_eq!(result, None) + } }