Repository: zyedidia/micro
File: internal/views/splits.go (Go)

Code before:
		}
	}

	if len(n.children) == 1 {
		// Replace current node with its child node to remove chained parent
		n.parent.children[ind] = n.children[0]
		n.parent.children[ind].parent = n.parent
		if n.children[0].IsLeaf() {
			n.parent.children[ind].Kind = n.Kind
		} else {
			// Flatten the child node that replaced the current node
			n.parent.children[ind].flatten()
		}
	} else if !n.IsLeaf() && n.Kind == n.parent.Kind {
		// If we have the same kind as the parent (caused by previous flattening),
		// replace this node with its 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(n.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:], n.parent.children)

		for i := 0; i < len(n.children); i++ {
			n.parent.children[ind+i].parent = n.parent
		}
	}

	// Update propW and propH since the parent of the children might have been updated,
	// so the children may 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
	strf = func(n *Node, ident int) string {
		marker := "|"
		if n.Kind == STHoriz {
			marker = "-"
		}
		str := fmt.Sprint(strings.Repeat("\t", ident), marker, n.View, n.id)
		if n.IsLeaf() {
			str += "🍁"
		}
		str += "\n"
		for _, c := range n.children {

Review comment (bug):
`n.children`, not `n.parent.children`.

I've observed at least 2 problems because of this:
1. Open a vsplit, then a hsplit in the right split, then a vsplit in the right bottom split, then close the right top split (so that only vertical splits remain), then open another vsplit -> proportional resize isn't really working (the leftmost split is not resized), and also after closing this last created vsplit, micro crashes:

```
Micro encountered an error: runtime.errorString runtime error: invalid memory address or nil pointer dereference
runtime/panic.go:260 (0x44d836)
runtime/panic.go:259 (0x44d806)
github.com/zyedidia/micro/v2/internal/action/tab.go:385 (0x8cad20)
github.com/zyedidia/micro/v2/internal/action/actions.go:2041 (0x8b0a45)
github.com/zyedidia/micro/v2/internal/action/actions.go:1898 (0x8afe78)
github.com/zyedidia/micro/v2/internal/action/actions.go:1936 (0x8aff0e)
github.com/zyedidia/micro/v2/internal/action/bufpane.go:569 (0x8b8354)
github.com/zyedidia/micro/v2/internal/action/tab.go:224 (0x8b64be)
github.com/zyedidia/micro/v2/internal/action/bufpane.go:183 (0x8b62df)
github.com/zyedidia/micro/v2/internal/action/bufpane.go:33 (0x8b6276)
github.com/zyedidia/micro/v2/internal/action/bufpane.go:548 (0x8b8059)
github.com/zyedidia/micro/v2/internal/action/bufpane.go:466 (0x8b7955)
github.com/zyedidia/micro/v2/internal/action/tab.go:337 (0x8ca4e6)
github.com/zyedidia/micro/v2/internal/action/tab.go:141 (0x8c93fe)
github.com/zyedidia/micro/v2/cmd/micro/micro.go:518 (0x8fcabd)
github.com/zyedidia/micro/v2/cmd/micro/micro.go:455 (0x8fc50e)
runtime/proc.go:250 (0x439472)
runtime/asm_amd64.s:1594 (0x469141)
```

2. Open a vsplit, then a hsplit in the right split, then a vsplit in the right bottom split, then close the right top split (so that only 3 vertical splits remain), then close the rightmost split, then close the rightmost split again (so that only 1 split remains) -> weird thing happens.

Code after:
	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
	strf = func(n *Node, ident int) string {
		marker := "|"
		if n.Kind == STHoriz {
			marker = "-"
		}
		str := fmt.Sprint(strings.Repeat("\t", ident), marker, n.View, n.id)
		if n.IsLeaf() {
			str += "🍁"
		}
		str += "\n"
		for _, c := range n.children {
			str += strf(c, ident+1)
		}
		return str
	}
	return strf(n, 0)