aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Kovacs2022-05-11 19:12:59 +0000
committerMichael Davis2022-05-21 13:53:16 +0000
commit6bd8924436636c252ec2bfcd02986771665f0c02 (patch)
tree3fcece25373f7de86ef5f095a4aadbea0b2e812e
parent3f10473d30eec79e135ea74fa2bc4cc996426128 (diff)
Move Tree nodes on view swap
Instead of moving the Node contents on view swap if they have the same parent reorder them to keep traversal order otherwise re-parent them.
-rw-r--r--helix-view/src/tree.rs90
1 files changed, 71 insertions, 19 deletions
diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs
index 2aa35dee..e6dba916 100644
--- a/helix-view/src/tree.rs
+++ b/helix-view/src/tree.rs
@@ -538,20 +538,72 @@ impl Tree {
}
}
- pub fn swap_split_in_direction(&mut self, direction: Direction) {
- if let Some(id) = self.find_split_in_direction(self.focus, direction) {
- if let Some([focused, target]) = self.nodes.get_disjoint_mut([self.focus, id]) {
- match (&mut focused.content, &mut target.content) {
- (Content::View(focused), Content::View(target)) => {
- std::mem::swap(&mut focused.doc, &mut target.doc);
- std::mem::swap(&mut focused.id, &mut target.id);
- self.focus = id;
- }
- // self.focus always points to a view which has a content of Content::View
- // and find_split_in_direction() only returns a view which has content of
- // Content::View.
- _ => unreachable!(),
+ pub fn swap_split_in_direction(&mut self, direction: Direction) -> Option<()> {
+ let focus = self.focus;
+ let target = self.find_split_in_direction(focus, direction)?;
+ let focus_parent = self.nodes[focus].parent;
+ let target_parent = self.nodes[target].parent;
+
+ if focus_parent == target_parent {
+ let parent = focus_parent;
+ let [parent, focus, target] = self.nodes.get_disjoint_mut([parent, focus, target])?;
+ match (&mut parent.content, &mut focus.content, &mut target.content) {
+ (
+ Content::Container(parent),
+ Content::View(focus_view),
+ Content::View(target_view),
+ ) => {
+ let focus_pos = parent.children.iter().position(|id| focus_view.id == *id)?;
+ let target_pos = parent
+ .children
+ .iter()
+ .position(|id| target_view.id == *id)?;
+ // swap node positions so that traversal order is kept
+ parent.children[focus_pos] = target_view.id;
+ parent.children[target_pos] = focus_view.id;
+ // swap area so that views rendered at the correct location
+ std::mem::swap(&mut focus_view.area, &mut target_view.area);
+
+ Some(())
}
+ _ => unreachable!(),
+ }
+ } else {
+ let [focus_parent, target_parent, focus, target] =
+ self.nodes
+ .get_disjoint_mut([focus_parent, target_parent, focus, target])?;
+ match (
+ &mut focus_parent.content,
+ &mut target_parent.content,
+ &mut focus.content,
+ &mut target.content,
+ ) {
+ (
+ Content::Container(focus_parent),
+ Content::Container(target_parent),
+ Content::View(focus_view),
+ Content::View(target_view),
+ ) => {
+ let focus_pos = focus_parent
+ .children
+ .iter()
+ .position(|id| focus_view.id == *id)?;
+ let target_pos = target_parent
+ .children
+ .iter()
+ .position(|id| target_view.id == *id)?;
+ // re-parent target and focus nodes
+ std::mem::swap(
+ &mut focus_parent.children[focus_pos],
+ &mut target_parent.children[target_pos],
+ );
+ std::mem::swap(&mut focus.parent, &mut target.parent);
+ // swap area so that views rendered at the correct location
+ std::mem::swap(&mut focus_view.area, &mut target_view.area);
+
+ Some(())
+ }
+ _ => unreachable!(),
}
}
}
@@ -738,7 +790,7 @@ mod test {
tree.swap_split_in_direction(Direction::Down);
// | l1 | l2 | |
// | l0* | r0 |
- assert_eq!(tree.focus, l1);
+ assert_eq!(tree.focus, l0);
assert_eq!(doc_id(&tree, l0), Some(doc_l1));
assert_eq!(doc_id(&tree, l1), Some(doc_l0));
assert_eq!(doc_id(&tree, l2), Some(doc_l2));
@@ -748,7 +800,7 @@ mod test {
// | l1 | l2 | |
// | r0 | l0* |
- assert_eq!(tree.focus, r0);
+ assert_eq!(tree.focus, l0);
assert_eq!(doc_id(&tree, l0), Some(doc_l1));
assert_eq!(doc_id(&tree, l1), Some(doc_r0));
assert_eq!(doc_id(&tree, l2), Some(doc_l2));
@@ -758,7 +810,7 @@ mod test {
tree.swap_split_in_direction(Direction::Up);
// | l1 | l2 | |
// | r0 | l0* |
- assert_eq!(tree.focus, r0);
+ assert_eq!(tree.focus, l0);
assert_eq!(doc_id(&tree, l0), Some(doc_l1));
assert_eq!(doc_id(&tree, l1), Some(doc_r0));
assert_eq!(doc_id(&tree, l2), Some(doc_l2));
@@ -768,7 +820,7 @@ mod test {
tree.swap_split_in_direction(Direction::Down);
// | l1 | l2 | |
// | r0 | l0* |
- assert_eq!(tree.focus, r0);
+ assert_eq!(tree.focus, l0);
assert_eq!(doc_id(&tree, l0), Some(doc_l1));
assert_eq!(doc_id(&tree, l1), Some(doc_r0));
assert_eq!(doc_id(&tree, l2), Some(doc_l2));
@@ -781,7 +833,7 @@ mod test {
tree.swap_split_in_direction(Direction::Down);
// | l1 | r0 | |
// | l2* | l0 |
- assert_eq!(tree.focus, l1);
+ assert_eq!(tree.focus, l2);
assert_eq!(doc_id(&tree, l0), Some(doc_l1));
assert_eq!(doc_id(&tree, l1), Some(doc_l2));
assert_eq!(doc_id(&tree, l2), Some(doc_r0));
@@ -790,7 +842,7 @@ mod test {
tree.swap_split_in_direction(Direction::Up);
// | l2* | r0 | |
// | l1 | l0 |
- assert_eq!(tree.focus, l0);
+ assert_eq!(tree.focus, l2);
assert_eq!(doc_id(&tree, l0), Some(doc_l2));
assert_eq!(doc_id(&tree, l1), Some(doc_l1));
assert_eq!(doc_id(&tree, l2), Some(doc_r0));