@@ -538,6 +538,24 @@ impl Tree {
538538 }
539539 }
540540
541+ pub fn swap_split_in_direction(&mut self, direction: Direction) {
542+ if let Some(id) = self.find_split_in_direction(self.focus, direction) {
543+ if let Some([focused, target]) = self.nodes.get_disjoint_mut([self.focus, id]) {
544+ match (&mut focused.content, &mut target.content) {
545+ (Content::View(focused), Content::View(target)) => {
546+ std::mem::swap(&mut focused.doc, &mut target.doc);
547+ std::mem::swap(&mut focused.id, &mut target.id);
548+ self.focus = id;
549+ }
550+ // self.focus always points to a view which has a content of Content::View
551+ // and find_split_in_direction() only returns a view which has content of
552+ // Content::View.
553+ _ => unreachable!(),
554+ }
555+ }
556+ }
557+ }
558+
541559 pub fn area(&self) -> Rect {
542560 self.area
543561 }
@@ -649,4 +667,133 @@ mod test {
649667 assert_eq!(None, tree.find_split_in_direction(r0, Direction::Right));
650668 assert_eq!(None, tree.find_split_in_direction(r0, Direction::Up));
651669 }
670+
671+ #[test]
672+ fn swap_split_in_direction() {
673+ let mut tree = Tree::new(Rect {
674+ x: 0,
675+ y: 0,
676+ width: 180,
677+ height: 80,
678+ });
679+
680+ let doc_l0 = DocumentId::default();
681+ let mut view = View::new(
682+ doc_l0,
683+ vec![GutterType::Diagnostics, GutterType::LineNumbers],
684+ );
685+ view.area = Rect::new(0, 0, 180, 80);
686+ tree.insert(view);
687+
688+ let l0 = tree.focus;
689+
690+ let doc_r0 = DocumentId::default();
691+ let view = View::new(
692+ doc_r0,
693+ vec![GutterType::Diagnostics, GutterType::LineNumbers],
694+ );
695+ tree.split(view, Layout::Vertical);
696+ let r0 = tree.focus;
697+
698+ tree.focus = l0;
699+
700+ let doc_l1 = DocumentId::default();
701+ let view = View::new(
702+ doc_l1,
703+ vec![GutterType::Diagnostics, GutterType::LineNumbers],
704+ );
705+ tree.split(view, Layout::Horizontal);
706+ let l1 = tree.focus;
707+
708+ tree.focus = l0;
709+
710+ let doc_l2 = DocumentId::default();
711+ let view = View::new(
712+ doc_l2,
713+ vec![GutterType::Diagnostics, GutterType::LineNumbers],
714+ );
715+ tree.split(view, Layout::Vertical);
716+ let l2 = tree.focus;
717+
718+ // Views in test
719+ // | L0 | L2 | |
720+ // | L1 | R0 |
721+
722+ // Document IDs in test
723+ // | l0 | l2 | |
724+ // | l1 | r0 |
725+
726+ fn doc_id(tree: &Tree, view_id: ViewId) -> Option<DocumentId> {
727+ if let Content::View(view) = &tree.nodes[view_id].content {
728+ Some(view.doc)
729+ } else {
730+ None
731+ }
732+ }
733+
734+ tree.focus = l0;
735+ // `*` marks the view in focus from view table (here L0)
736+ // | l0* | l2 | |
737+ // | l1 | r0 |
738+ tree.swap_split_in_direction(Direction::Down);
739+ // | l1 | l2 | |
740+ // | l0* | r0 |
741+ assert_eq!(tree.focus, l1);
742+ assert_eq!(doc_id(&tree, l0), Some(doc_l1));
743+ assert_eq!(doc_id(&tree, l1), Some(doc_l0));
744+ assert_eq!(doc_id(&tree, l2), Some(doc_l2));
745+ assert_eq!(doc_id(&tree, r0), Some(doc_r0));
746+
747+ tree.swap_split_in_direction(Direction::Right);
748+
749+ // | l1 | l2 | |
750+ // | r0 | l0* |
751+ assert_eq!(tree.focus, r0);
752+ assert_eq!(doc_id(&tree, l0), Some(doc_l1));
753+ assert_eq!(doc_id(&tree, l1), Some(doc_r0));
754+ assert_eq!(doc_id(&tree, l2), Some(doc_l2));
755+ assert_eq!(doc_id(&tree, r0), Some(doc_l0));
756+
757+ // cannot swap, nothing changes
758+ tree.swap_split_in_direction(Direction::Up);
759+ // | l1 | l2 | |
760+ // | r0 | l0* |
761+ assert_eq!(tree.focus, r0);
762+ assert_eq!(doc_id(&tree, l0), Some(doc_l1));
763+ assert_eq!(doc_id(&tree, l1), Some(doc_r0));
764+ assert_eq!(doc_id(&tree, l2), Some(doc_l2));
765+ assert_eq!(doc_id(&tree, r0), Some(doc_l0));
766+
767+ // cannot swap, nothing changes
768+ tree.swap_split_in_direction(Direction::Down);
769+ // | l1 | l2 | |
770+ // | r0 | l0* |
771+ assert_eq!(tree.focus, r0);
772+ assert_eq!(doc_id(&tree, l0), Some(doc_l1));
773+ assert_eq!(doc_id(&tree, l1), Some(doc_r0));
774+ assert_eq!(doc_id(&tree, l2), Some(doc_l2));
775+ assert_eq!(doc_id(&tree, r0), Some(doc_l0));
776+
777+ tree.focus = l2;
778+ // | l1 | l2* | |
779+ // | r0 | l0 |
780+
781+ tree.swap_split_in_direction(Direction::Down);
782+ // | l1 | r0 | |
783+ // | l2* | l0 |
784+ assert_eq!(tree.focus, l1);
785+ assert_eq!(doc_id(&tree, l0), Some(doc_l1));
786+ assert_eq!(doc_id(&tree, l1), Some(doc_l2));
787+ assert_eq!(doc_id(&tree, l2), Some(doc_r0));
788+ assert_eq!(doc_id(&tree, r0), Some(doc_l0));
789+
790+ tree.swap_split_in_direction(Direction::Up);
791+ // | l2* | r0 | |
792+ // | l1 | l0 |
793+ assert_eq!(tree.focus, l0);
794+ assert_eq!(doc_id(&tree, l0), Some(doc_l2));
795+ assert_eq!(doc_id(&tree, l1), Some(doc_l1));
796+ assert_eq!(doc_id(&tree, l2), Some(doc_r0));
797+ assert_eq!(doc_id(&tree, r0), Some(doc_l0));
798+ }
652799}