From 080d216ffd901bac776c77dba23bf8fd7adf8c9a Mon Sep 17 00:00:00 2001 From: Neko Box Coder Date: Sun, 30 Mar 2025 14:17:24 +0100 Subject: [PATCH 1/2] Fixing chained parents by flattening the tree on unsplit --- internal/views/splits.go | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/internal/views/splits.go b/internal/views/splits.go index b28a6c09..1e4e96b4 100644 --- a/internal/views/splits.go +++ b/internal/views/splits.go @@ -479,9 +479,58 @@ func (n *Node) Unsplit() bool { if n.parent.IsLeaf() { return n.parent.Unsplit() } + + n.parent.flatten() return true } +// flattens the tree by removing unnecessary intermediate parents that have only one child +// and handles the side effect of it +func (n *Node) flatten() { + if n.parent == nil || len(n.children) != 1 { + return + } + + ind := 0 + for i, c := range n.parent.children { + if c.id == n.id { + ind = i + } + } + + // Replace current node with its child node to remove chained parent + successor := n.children[0] + n.parent.children[ind] = successor + successor.parent = n.parent + + // Maintain the tree in a consistent state: any child node's kind (horiz vs vert) + // should be the opposite of its parent's kind. + if successor.IsLeaf() { + successor.Kind = n.Kind + } else { + // If the successor node has children, that means it is a chained parent as well. + // Therefore it can be replaced by its own children. + origsize := len(n.parent.children) + + // Let's say we have 5 children and want to replace [2] with its children [a] [b] [c] + // [0] [1] [2] [3] [4] --> [0] [1] [a] [b] [c] [3] [4] + // insertcount will be `3 - 1 = 2` in this case + insertcount := len(successor.children) - 1 + + n.parent.children = append(n.parent.children, make([]*Node, insertcount)...) + copy(n.parent.children[ind+insertcount+1:], n.parent.children[ind+1:origsize]) + copy(n.parent.children[ind:], successor.children) + + for i := 0; i < len(successor.children); i++ { + n.parent.children[ind+i].parent = n.parent + } + } + + // Update propW and propH since the parent of the children has been updated, + // so the children have new siblings + n.parent.markSizes() +} + // String returns the string form of the node and all children (used for debugging) func (n *Node) String() string { var strf func(n *Node, ident int) string From 8e7089993dfdd01c70fd7c6b8d9ef7792370076a Mon Sep 17 00:00:00 2001 From: Neko Box Coder Date: Sat, 5 Apr 2025 23:34:59 +0100 Subject: [PATCH 2/2] Simplifying unsplit logic --- internal/views/splits.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/internal/views/splits.go b/internal/views/splits.go index 1e4e96b4..b2a20873 100644 --- a/internal/views/splits.go +++ b/internal/views/splits.go @@ -439,11 +439,12 @@ func (n *Node) VSplit(right bool) uint64 { } // unsplits the child of a split -func (n *Node) unsplit(i int, h bool) { +func (n *Node) unsplit(i int) { copy(n.children[i:], n.children[i+1:]) n.children[len(n.children)-1] = nil n.children = n.children[:len(n.children)-1] + h := n.Kind == STVert nonrs, numr := n.getResizeInfo(h) if numr == 0 { // This means that this was the last child @@ -470,12 +471,7 @@ func (n *Node) Unsplit() bool { ind = i } } - if n.parent.Kind == STVert { - n.parent.unsplit(ind, true) - } else { - n.parent.unsplit(ind, false) - } - + n.parent.unsplit(ind) if n.parent.IsLeaf() { return n.parent.Unsplit() }