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.rs201
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<_>>()
- );
- }
}