diff --git a/internal/views/splits.go b/internal/views/splits.go index b28a6c09..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,18 +471,62 @@ 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() } + + 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