3 // SplitType specifies whether a split is horizontal or vertical
9 // HorizontalSplit type
10 HorizontalSplit = true
13 // A Node on the split tree
15 VSplit(buf *Buffer, splitIndex int)
16 HSplit(buf *Buffer, splitIndex int)
20 // A LeafNode is an actual split so it contains a view
21 type LeafNode struct {
27 // NewLeafNode returns a new leaf node containing the given view
28 func NewLeafNode(v *View, parent *SplitTree) *LeafNode {
36 // A SplitTree is a Node itself and it contains other nodes
37 type SplitTree struct {
54 // VSplit creates a vertical split
55 func (l *LeafNode) VSplit(buf *Buffer, splitIndex int) {
60 tab := tabs[l.parent.tabNum]
61 if l.parent.kind == VerticalSplit {
62 if splitIndex > len(l.parent.children) {
63 splitIndex = len(l.parent.children)
66 newView := NewView(buf)
67 newView.TabNum = l.parent.tabNum
69 l.parent.children = append(l.parent.children, nil)
70 copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:])
71 l.parent.children[splitIndex] = NewLeafNode(newView, l.parent)
73 tab.views = append(tab.views, nil)
74 copy(tab.views[splitIndex+1:], tab.views[splitIndex:])
75 tab.views[splitIndex] = newView
77 tab.CurView = splitIndex
84 s.kind = VerticalSplit
86 s.tabNum = l.parent.tabNum
87 newView := NewView(buf)
88 newView.TabNum = l.parent.tabNum
90 s.children = []Node{l, NewLeafNode(newView, s)}
92 s.children = []Node{NewLeafNode(newView, s), l}
94 l.parent.children[search(l.parent.children, l)] = s
97 tab.views = append(tab.views, nil)
98 copy(tab.views[splitIndex+1:], tab.views[splitIndex:])
99 tab.views[splitIndex] = newView
101 tab.CurView = splitIndex
107 // HSplit creates a horizontal split
108 func (l *LeafNode) HSplit(buf *Buffer, splitIndex int) {
113 tab := tabs[l.parent.tabNum]
114 if l.parent.kind == HorizontalSplit {
115 if splitIndex > len(l.parent.children) {
116 splitIndex = len(l.parent.children)
119 newView := NewView(buf)
120 newView.TabNum = l.parent.tabNum
122 l.parent.children = append(l.parent.children, nil)
123 copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:])
124 l.parent.children[splitIndex] = NewLeafNode(newView, l.parent)
126 tab.views = append(tab.views, nil)
127 copy(tab.views[splitIndex+1:], tab.views[splitIndex:])
128 tab.views[splitIndex] = newView
130 tab.CurView = splitIndex
137 s.kind = HorizontalSplit
138 s.tabNum = l.parent.tabNum
140 newView := NewView(buf)
141 newView.TabNum = l.parent.tabNum
142 newView.Num = len(tab.views)
144 s.children = []Node{l, NewLeafNode(newView, s)}
146 s.children = []Node{NewLeafNode(newView, s), l}
148 l.parent.children[search(l.parent.children, l)] = s
151 tab.views = append(tab.views, nil)
152 copy(tab.views[splitIndex+1:], tab.views[splitIndex:])
153 tab.views[splitIndex] = newView
155 tab.CurView = splitIndex
161 // Delete deletes a split
162 func (l *LeafNode) Delete() {
163 i := search(l.parent.children, l)
165 copy(l.parent.children[i:], l.parent.children[i+1:])
166 l.parent.children[len(l.parent.children)-1] = nil
167 l.parent.children = l.parent.children[:len(l.parent.children)-1]
169 tab := tabs[l.parent.tabNum]
170 j := findView(tab.views, l.view)
171 copy(tab.views[j:], tab.views[j+1:])
172 tab.views[len(tab.views)-1] = nil // or the zero value of T
173 tab.views = tab.views[:len(tab.views)-1]
175 for i, v := range tab.views {
183 // Cleanup rearranges all the parents after a split has been deleted
184 func (s *SplitTree) Cleanup() {
185 for i, node := range s.children {
186 if n, ok := node.(*SplitTree); ok {
187 if len(n.children) == 1 {
188 if child, ok := n.children[0].(*LeafNode); ok {
189 s.children[i] = child
199 // ResizeSplits resizes all the splits correctly
200 func (s *SplitTree) ResizeSplits() {
204 for _, node := range s.children {
205 if n, ok := node.(*LeafNode); ok {
206 if s.kind == VerticalSplit {
207 if n.view.LockWidth {
208 lockedWidth += n.view.Width
212 if n.view.LockHeight {
213 lockedHeight += n.view.Height
217 } else if n, ok := node.(*SplitTree); ok {
218 if s.kind == VerticalSplit {
220 lockedWidth += n.width
225 lockedHeight += n.height
232 for _, node := range s.children {
233 if n, ok := node.(*LeafNode); ok {
234 if s.kind == VerticalSplit {
235 if !n.view.LockWidth {
236 n.view.Width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
238 n.view.Height = s.height
244 if !n.view.LockHeight {
245 n.view.Height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
247 n.view.Width = s.width
253 if n.view.Buf.Settings["statusline"].(bool) {
257 n.view.ToggleTabbar()
258 } else if n, ok := node.(*SplitTree); ok {
259 if s.kind == VerticalSplit {
261 n.width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
270 n.height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
283 func (l *LeafNode) String() string {
284 return l.view.Buf.GetName()
287 func search(haystack []Node, needle Node) int {
288 for i, x := range haystack {
296 func findView(haystack []*View, needle *View) int {
297 for i, x := range haystack {
305 // VSplit is here just to make SplitTree fit the Node interface
306 func (s *SplitTree) VSplit(buf *Buffer, splitIndex int) {}
308 // HSplit is here just to make SplitTree fit the Node interface
309 func (s *SplitTree) HSplit(buf *Buffer, splitIndex int) {}
311 func (s *SplitTree) String() string {
313 for _, child := range s.children {
314 str += child.String() + ", "