Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-view/src/tree.rs')
| -rw-r--r-- | helix-view/src/tree.rs | 201 |
1 files changed, 67 insertions, 134 deletions
diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index d596b35a..469e913d 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -214,56 +214,33 @@ impl Tree { node } - /// Get a mutable reference to a [Container] by index. - /// # Panics - /// Panics if `index` is not in self.nodes, or if the node's content is not a [Content::Container]. - fn container_mut(&mut self, index: ViewId) -> &mut Container { - match &mut self.nodes[index] { - Node { - content: Content::Container(container), - .. - } => container, - _ => unreachable!(), - } - } - - fn remove_or_replace(&mut self, child: ViewId, replacement: Option<ViewId>) { - let parent = self.nodes[child].parent; - - self.nodes.remove(child); - - let container = self.container_mut(parent); - let pos = container - .children - .iter() - .position(|&item| item == child) - .unwrap(); - - if let Some(new) = replacement { - container.children[pos] = new; - self.nodes[new].parent = parent; - } else { - container.children.remove(pos); - } - } - pub fn remove(&mut self, index: ViewId) { + let mut stack = Vec::new(); + if self.focus == index { // focus on something else self.focus = self.prev(); } - let parent = self.nodes[index].parent; - let parent_is_root = parent == self.root; + stack.push(index); - self.remove_or_replace(index, None); - - let parent_container = self.container_mut(parent); - if parent_container.children.len() == 1 && !parent_is_root { - // Lets merge the only child back to its grandparent so that Views - // are equally spaced. - let sibling = parent_container.children.pop().unwrap(); - self.remove_or_replace(parent, Some(sibling)); + while let Some(index) = stack.pop() { + let parent_id = self.nodes[index].parent; + if let Node { + content: Content::Container(container), + .. + } = &mut self.nodes[parent_id] + { + if let Some(pos) = container.children.iter().position(|&child| child == index) { + container.children.remove(pos); + // TODO: if container now only has one child, remove it and place child in parent + if container.children.is_empty() && parent_id != self.root { + // if container now empty, remove it + stack.push(parent_id); + } + } + } + self.nodes.remove(index); } self.recalculate() @@ -301,15 +278,16 @@ impl Tree { self.try_get(index).unwrap() } - /// Try to get reference to a [View] by index. Returns `None` if node content is not a [`Content::View`]. + /// Try to get reference to a [View] by index. Returns `None` if node content is not a [Content::View] + /// # Panics /// - /// Does not panic if the view does not exists anymore. + /// Panics if `index` is not in self.nodes. This can be checked with [Self::contains] pub fn try_get(&self, index: ViewId) -> Option<&View> { - match self.nodes.get(index) { - Some(Node { + match &self.nodes[index] { + Node { content: Content::View(view), .. - }) => Some(view), + } => Some(view), _ => None, } } @@ -407,13 +385,11 @@ impl Tree { } Layout::Vertical => { let len = container.children.len(); - let len_u16 = len as u16; - let inner_gap = 1u16; - let total_gap = inner_gap * len_u16.saturating_sub(2); + let width = area.width / len as u16; - let used_area = area.width.saturating_sub(total_gap); - let width = used_area / len_u16; + let inner_gap = 1u16; + // let total_gap = inner_gap * (len as u16 - 1); let mut child_x = area.x; @@ -441,7 +417,7 @@ impl Tree { } } - pub fn traverse(&self) -> Traverse<'_> { + pub fn traverse(&self) -> Traverse { Traverse::new(self) } @@ -560,7 +536,7 @@ impl Tree { id } else { // extremely crude, take the last item - let (key, _) = self.traverse().next_back().unwrap(); + let (key, _) = self.traverse().rev().next().unwrap(); key } } @@ -705,7 +681,7 @@ impl<'a> Iterator for Traverse<'a> { } } -impl DoubleEndedIterator for Traverse<'_> { +impl<'a> DoubleEndedIterator for Traverse<'a> { fn next_back(&mut self) -> Option<Self::Item> { loop { let key = self.stack.pop()?; @@ -725,7 +701,7 @@ impl DoubleEndedIterator for Traverse<'_> { #[cfg(test)] mod test { use super::*; - use crate::editor::GutterConfig; + use crate::editor::GutterType; use crate::DocumentId; #[test] @@ -736,28 +712,41 @@ mod test { width: 180, height: 80, }); - let mut view = View::new(DocumentId::default(), GutterConfig::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; - let view = View::new(DocumentId::default(), GutterConfig::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default(), GutterConfig::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default(), GutterConfig::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); + let l2 = tree.focus; // Tree in test // | L0 | L2 | | // | L1 | R0 | - let l2 = tree.focus; + tree.focus = l2; assert_eq!(Some(l0), tree.find_split_in_direction(l2, Direction::Left)); assert_eq!(Some(l1), tree.find_split_in_direction(l2, Direction::Down)); assert_eq!(Some(r0), tree.find_split_in_direction(l2, Direction::Right)); @@ -792,28 +781,40 @@ mod test { }); let doc_l0 = DocumentId::default(); - let mut view = View::new(doc_l0, GutterConfig::default()); + let mut view = View::new( + doc_l0, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; let doc_r0 = DocumentId::default(); - let view = View::new(doc_r0, GutterConfig::default()); + let view = View::new( + doc_r0, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; let doc_l1 = DocumentId::default(); - let view = View::new(doc_l1, GutterConfig::default()); + let view = View::new( + doc_l1, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; let doc_l2 = DocumentId::default(); - let view = View::new(doc_l2, GutterConfig::default()); + let view = View::new( + doc_l2, + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let l2 = tree.focus; @@ -898,72 +899,4 @@ mod test { assert_eq!(doc_id(&tree, l2), Some(doc_r0)); assert_eq!(doc_id(&tree, r0), Some(doc_l0)); } - - #[test] - fn all_vertical_views_have_same_width() { - let tree_area_width = 180; - let mut tree = Tree::new(Rect { - x: 0, - y: 0, - width: tree_area_width, - height: 80, - }); - let mut view = View::new(DocumentId::default(), GutterConfig::default()); - view.area = Rect::new(0, 0, 180, 80); - tree.insert(view); - - let view = View::new(DocumentId::default(), GutterConfig::default()); - tree.split(view, Layout::Vertical); - - let view = View::new(DocumentId::default(), GutterConfig::default()); - tree.split(view, Layout::Horizontal); - - tree.remove(tree.focus); - - let view = View::new(DocumentId::default(), GutterConfig::default()); - tree.split(view, Layout::Vertical); - - // Make sure that we only have one level in the tree. - assert_eq!(3, tree.views().count()); - assert_eq!( - vec![ - tree_area_width / 3 - 1, // gap here - tree_area_width / 3 - 1, // gap here - tree_area_width / 3 - ], - tree.views() - .map(|(view, _)| view.area.width) - .collect::<Vec<_>>() - ); - } - - #[test] - fn vsplit_gap_rounding() { - let (tree_area_width, tree_area_height) = (80, 24); - let mut tree = Tree::new(Rect { - x: 0, - y: 0, - width: tree_area_width, - height: tree_area_height, - }); - let mut view = View::new(DocumentId::default(), GutterConfig::default()); - view.area = Rect::new(0, 0, tree_area_width, tree_area_height); - tree.insert(view); - - for _ in 0..9 { - let view = View::new(DocumentId::default(), GutterConfig::default()); - tree.split(view, Layout::Vertical); - } - - assert_eq!(10, tree.views().count()); - assert_eq!( - std::iter::repeat(7) - .take(9) - .chain(Some(8)) // Rounding in `recalculate`. - .collect::<Vec<_>>(), - tree.views() - .map(|(view, _)| view.area.width) - .collect::<Vec<_>>() - ); - } } |