test(ui/tree): find

pull/9/head
wongjiahau 2 years ago
parent bdab93e856
commit 82fe4a309d

@ -7,7 +7,7 @@ use crate::{
compositor::{Context, EventResult}, compositor::{Context, EventResult},
ctrl, key, shift, ctrl, key, shift,
}; };
use helix_core::unicode::width::UnicodeWidthStr; use helix_core::{movement::Direction, unicode::width::UnicodeWidthStr};
use helix_view::{ use helix_view::{
graphics::Rect, graphics::Rect,
input::{Event, KeyEvent}, input::{Event, KeyEvent},
@ -142,7 +142,7 @@ impl<'a, T> Iterator for TreeIter<'a, T> {
None None
} else { } else {
self.current_index_forward = self.current_index_forward.saturating_add(1); self.current_index_forward = self.current_index_forward.saturating_add(1);
self.tree.find_by_index(index) self.tree.get(index)
} }
} }
@ -158,7 +158,7 @@ impl<'a, T> DoubleEndedIterator for TreeIter<'a, T> {
None None
} else { } else {
self.current_index_reverse = self.current_index_reverse.saturating_sub(1); self.current_index_reverse = self.current_index_reverse.saturating_sub(1);
self.tree.find_by_index(index as usize) self.tree.get(index as usize)
} }
} }
} }
@ -166,13 +166,6 @@ impl<'a, T> DoubleEndedIterator for TreeIter<'a, T> {
impl<'a, T> ExactSizeIterator for TreeIter<'a, T> {} impl<'a, T> ExactSizeIterator for TreeIter<'a, T> {}
impl<T> Tree<T> { impl<T> Tree<T> {
fn iter(&self) -> TreeIter<T> {
TreeIter {
tree: self,
current_index_forward: 0,
current_index_reverse: (self.len() - 1) as isize,
}
}
pub fn new(item: T, children: Vec<Tree<T>>) -> Self { pub fn new(item: T, children: Vec<Tree<T>>) -> Self {
Self { Self {
item, item,
@ -182,28 +175,50 @@ impl<T> Tree<T> {
is_opened: false, is_opened: false,
} }
} }
fn iter(&self) -> TreeIter<T> {
TreeIter {
tree: self,
current_index_forward: 0,
current_index_reverse: (self.len() - 1) as isize,
}
}
/// Find an element in the tree with given `predicate`.
/// `start_index` is inclusive if direction is `Forward`.
/// `start_index` is exclusive if direction is `Backward`.
pub fn find<F>(&self, start_index: usize, direction: Direction, predicate: F) -> Option<usize>
where
F: FnMut(&Tree<T>) -> bool,
{
let iter = self.iter();
match direction {
Direction::Forward => iter
.skip(start_index)
.position(predicate)
.map(|index| index + start_index),
Direction::Backward => iter.take(start_index).rposition(predicate),
}
}
pub fn item(&self) -> &T { pub fn item(&self) -> &T {
&self.item &self.item
} }
fn find_by_index(&self, index: usize) -> Option<&Tree<T>> { fn get(&self, index: usize) -> Option<&Tree<T>> {
if self.index == index { if self.index == index {
Some(self) Some(self)
} else { } else {
self.children self.children.iter().find_map(|elem| elem.get(index))
.iter()
.find_map(|elem| elem.find_by_index(index))
} }
} }
fn find_by_index_mut(&mut self, index: usize) -> Option<&mut Tree<T>> { fn get_mut(&mut self, index: usize) -> Option<&mut Tree<T>> {
if self.index == index { if self.index == index {
Some(self) Some(self)
} else { } else {
self.children self.children
.iter_mut() .iter_mut()
.find_map(|elem| elem.find_by_index_mut(index)) .find_map(|elem| elem.get_mut(index))
} }
} }
@ -298,18 +313,6 @@ impl<T: TreeItem> TreeView<T> {
self self
} }
fn find<F>(&self, start: usize, reverse: bool, f: F) -> Option<usize>
where
F: FnMut(&Tree<T>) -> bool,
{
let iter = self.tree.iter();
if reverse {
iter.take(start).rposition(f)
} else {
iter.skip(start).position(f).map(|index| index + start)
}
}
/// Reveal item in the tree based on the given `segments`. /// Reveal item in the tree based on the given `segments`.
/// ///
/// The name of the root should be excluded. /// The name of the root should be excluded.
@ -424,7 +427,7 @@ impl<T: TreeItem> TreeView<T> {
// } // }
// } // }
// //
let mut selected_item = self.find_by_index_mut(selected_index); let mut selected_item = self.get_mut(selected_index);
if selected_item.is_opened { if selected_item.is_opened {
selected_item.is_opened = false; selected_item.is_opened = false;
selected_item.children = vec![]; selected_item.children = vec![];
@ -434,7 +437,7 @@ impl<T: TreeItem> TreeView<T> {
if let Some(mut on_open_fn) = self.on_opened_fn.take() { if let Some(mut on_open_fn) = self.on_opened_fn.take() {
let mut f = || { let mut f = || {
let current = &mut self.find_by_index_mut(selected_index); let current = &mut self.get_mut(selected_index);
match on_open_fn(&mut current.item, cx, params) { match on_open_fn(&mut current.item, cx, params) {
TreeOp::Restore => { TreeOp::Restore => {
panic!(); panic!();
@ -474,7 +477,7 @@ impl<T: TreeItem> TreeView<T> {
self.on_opened_fn = Some(on_open_fn) self.on_opened_fn = Some(on_open_fn)
} else { } else {
panic!(); panic!();
self.find_by_index_mut(selected_index).children = vec![]; self.get_mut(selected_index).children = vec![];
// let current = &mut self.items[selected_index]; // let current = &mut self.items[selected_index];
// let inserts = std::mem::take(&mut current.folded); // let inserts = std::mem::take(&mut current.folded);
// let _: Vec<_> = self // let _: Vec<_> = self
@ -496,7 +499,8 @@ impl<T: TreeItem> TreeView<T> {
pub fn search_next(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) { pub fn search_next(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) {
let skip = std::cmp::max(2, self.save_view.0 + 1); let skip = std::cmp::max(2, self.save_view.0 + 1);
self.selected = self self.selected = self
.find(skip, false, |e| e.item.filter(s)) .tree
.find(skip, Direction::Forward, |e| e.item.filter(s))
.unwrap_or(self.save_view.0); .unwrap_or(self.save_view.0);
self.winline = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0); self.winline = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0);
@ -505,7 +509,8 @@ impl<T: TreeItem> TreeView<T> {
pub fn search_previous(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) { pub fn search_previous(&mut self, cx: &mut Context, s: &str, params: &mut T::Params) {
let take = self.save_view.0; let take = self.save_view.0;
self.selected = self self.selected = self
.find(take, true, |e| e.item.filter(s)) .tree
.find(take, Direction::Backward, |e| e.item.filter(s))
.unwrap_or(self.save_view.0); .unwrap_or(self.save_view.0);
self.winline = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0); self.winline = (self.save_view.1 + self.selected).saturating_sub(self.save_view.0);
@ -570,28 +575,25 @@ impl<T: TreeItem> TreeView<T> {
(self.selected, self.winline) = self.save_view; (self.selected, self.winline) = self.save_view;
} }
fn find_by_index(&self, index: usize) -> &Tree<T> { fn get(&self, index: usize) -> &Tree<T> {
self.tree self.tree.get(index).unwrap()
.iter()
.find_map(|item| item.find_by_index(index))
.unwrap()
} }
fn find_by_index_mut(&mut self, index: usize) -> &mut Tree<T> { fn get_mut(&mut self, index: usize) -> &mut Tree<T> {
self.tree.find_by_index_mut(index).unwrap() self.tree.get_mut(index).unwrap()
} }
pub fn current(&self) -> &Tree<T> { pub fn current(&self) -> &Tree<T> {
self.find_by_index(self.selected) self.get(self.selected)
} }
pub fn current_mut(&mut self) -> &mut Tree<T> { pub fn current_mut(&mut self) -> &mut Tree<T> {
self.find_by_index_mut(self.selected) self.get_mut(self.selected)
} }
fn current_parent(&self) -> Option<&Tree<T>> { fn current_parent(&self) -> Option<&Tree<T>> {
if let Some(parent_index) = self.current().parent_index { if let Some(parent_index) = self.current().parent_index {
Some(self.find_by_index(parent_index)) Some(self.get(parent_index))
} else { } else {
None None
} }
@ -599,7 +601,7 @@ impl<T: TreeItem> TreeView<T> {
fn current_parent_mut(&mut self) -> Option<&mut Tree<T>> { fn current_parent_mut(&mut self) -> Option<&mut Tree<T>> {
if let Some(parent_index) = self.current().parent_index { if let Some(parent_index) = self.current().parent_index {
Some(self.find_by_index_mut(parent_index)) Some(self.get_mut(parent_index))
} else { } else {
None None
} }
@ -1011,10 +1013,12 @@ fn index_elems<T>(start_index: usize, elems: Vec<Tree<T>>) -> Vec<Tree<T>> {
#[cfg(test)] #[cfg(test)]
mod test_tree { mod test_tree {
use helix_core::movement::Direction;
use super::{index_elems, Tree}; use super::{index_elems, Tree};
#[test] #[test]
fn test_indexs_elems_1() { fn test_indexs_elems() {
let result = index_elems( let result = index_elems(
0, 0,
vec![ vec![
@ -1065,7 +1069,7 @@ mod test_tree {
} }
#[test] #[test]
fn test_iter_1() { fn test_iter() {
let tree = Tree::new( let tree = Tree::new(
"spam", "spam",
vec![ vec![
@ -1083,7 +1087,25 @@ mod test_tree {
} }
#[test] #[test]
fn test_len_1() { fn test_iter_double_ended() {
let tree = Tree::new(
"spam",
vec![
Tree::new("jar", vec![Tree::new("yo", vec![])]),
Tree::new("foo", vec![Tree::new("bar", vec![])]),
],
);
let mut iter = tree.iter();
assert_eq!(iter.next_back().map(|tree| tree.item), Some("bar"));
assert_eq!(iter.next_back().map(|tree| tree.item), Some("foo"));
assert_eq!(iter.next_back().map(|tree| tree.item), Some("yo"));
assert_eq!(iter.next_back().map(|tree| tree.item), Some("jar"));
assert_eq!(iter.next_back().map(|tree| tree.item), Some("spam"));
}
#[test]
fn test_len() {
let tree = Tree::new( let tree = Tree::new(
"spam", "spam",
vec![ vec![
@ -1094,4 +1116,84 @@ mod test_tree {
assert_eq!(tree.len(), 5) assert_eq!(tree.len(), 5)
} }
#[test]
fn test_find_forward() {
let tree = Tree::new(
".cargo",
vec![
Tree::new("jar", vec![Tree::new("Cargo.toml", vec![])]),
Tree::new("Cargo.toml", vec![Tree::new("bar", vec![])]),
],
);
let result = tree.find(0, Direction::Forward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(0));
let result = tree.find(1, Direction::Forward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(2));
let result = tree.find(2, Direction::Forward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(2));
let result = tree.find(3, Direction::Forward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(3));
let result = tree.find(4, Direction::Forward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, None);
}
#[test]
fn test_find_backward() {
let tree = Tree::new(
".cargo",
vec![
Tree::new("jar", vec![Tree::new("Cargo.toml", vec![])]),
Tree::new("Cargo.toml", vec![Tree::new("bar", vec![])]),
],
);
let result = tree.find(0, Direction::Backward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, None);
let result = tree.find(1, Direction::Backward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(0));
let result = tree.find(2, Direction::Backward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(0));
let result = tree.find(3, Direction::Backward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(2));
let result = tree.find(4, Direction::Backward, |tree| {
tree.item.to_lowercase().contains(&"cargo".to_lowercase())
});
assert_eq!(result, Some(3));
}
} }

Loading…
Cancel
Save