]> git.lizzy.rs Git - micro.git/blob - cmd/micro/split_tree.go
78a6928b1dfd9904e63e5034a5e6e71ca9652d9f
[micro.git] / cmd / micro / split_tree.go
1 package main
2
3 // SpltType specifies whether a split is horizontal or vertical
4 type SplitType bool
5
6 const (
7         // VerticalSplit type
8         VerticalSplit = false
9         // HorizontalSplit type
10         HorizontalSplit = true
11 )
12
13 // A Node on the split tree
14 type Node interface {
15         VSplit(buf *Buffer)
16         HSplit(buf *Buffer)
17         String() string
18 }
19
20 // A LeafNode is an actual split so it contains a view
21 type LeafNode struct {
22         view *View
23
24         parent *SplitTree
25 }
26
27 // NewLeafNode returns a new leaf node containing the given view
28 func NewLeafNode(v *View, parent *SplitTree) *LeafNode {
29         n := new(LeafNode)
30         n.view = v
31         n.view.splitNode = n
32         n.parent = parent
33         return n
34 }
35
36 // A SplitTree is a Node itself and it contains other nodes
37 type SplitTree struct {
38         kind SplitType
39
40         parent   *SplitTree
41         children []Node
42
43         x int
44         y int
45
46         width  int
47         height int
48
49         tabNum int
50 }
51
52 // VSplit creates a vertical split
53 func (l *LeafNode) VSplit(buf *Buffer) {
54         tab := tabs[l.parent.tabNum]
55         if l.parent.kind == VerticalSplit {
56                 newView := NewView(buf)
57                 newView.TabNum = l.parent.tabNum
58                 newView.Num = len(tab.views)
59                 l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent))
60
61                 tab.curView++
62                 tab.views = append(tab.views, newView)
63         } else {
64                 s := new(SplitTree)
65                 s.kind = VerticalSplit
66                 s.parent = l.parent
67                 s.tabNum = l.parent.tabNum
68                 newView := NewView(buf)
69                 newView.TabNum = l.parent.tabNum
70                 newView.Num = len(tab.views)
71                 s.children = []Node{l, NewLeafNode(newView, s)}
72                 l.parent.children[search(l.parent.children, l)] = s
73                 l.parent = s
74
75                 tab.curView++
76                 tab.views = append(tab.views, newView)
77         }
78 }
79
80 // HSplit creates a horizontal split
81 func (l *LeafNode) HSplit(buf *Buffer) {
82         tab := tabs[l.parent.tabNum]
83         if l.parent.kind == HorizontalSplit {
84                 newView := NewView(buf)
85                 newView.TabNum = l.parent.tabNum
86                 newView.Num = len(tab.views)
87                 l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent))
88
89                 tab.curView++
90                 tab.views = append(tab.views, newView)
91         } else {
92                 s := new(SplitTree)
93                 s.kind = HorizontalSplit
94                 s.tabNum = l.parent.tabNum
95                 s.parent = l.parent
96                 newView := NewView(buf)
97                 newView.TabNum = l.parent.tabNum
98                 newView.Num = len(tab.views)
99                 s.children = []Node{l, NewLeafNode(newView, s)}
100                 l.parent.children[search(l.parent.children, l)] = s
101                 l.parent = s
102
103                 tab.curView++
104                 tab.views = append(tab.views, newView)
105         }
106 }
107
108 // Delete deletes a split
109 func (l *LeafNode) Delete() {
110         i := search(l.parent.children, l)
111
112         copy(l.parent.children[i:], l.parent.children[i+1:])
113         l.parent.children[len(l.parent.children)-1] = nil
114         l.parent.children = l.parent.children[:len(l.parent.children)-1]
115
116         tab := tabs[l.parent.tabNum]
117         j := findView(tab.views, l.view)
118         copy(tab.views[j:], tab.views[j+1:])
119         tab.views[len(tab.views)-1] = nil // or the zero value of T
120         tab.views = tab.views[:len(tab.views)-1]
121
122         for i, v := range tab.views {
123                 v.Num = i
124         }
125         if tab.curView > 0 {
126                 tab.curView--
127         }
128 }
129
130 // Cleanup rearranges all the parents after a split has been deleted
131 func (s *SplitTree) Cleanup() {
132         for i, node := range s.children {
133                 if n, ok := node.(*SplitTree); ok {
134                         if len(n.children) == 1 {
135                                 if child, ok := n.children[0].(*LeafNode); ok {
136                                         s.children[i] = child
137                                         child.parent = s
138                                         continue
139                                 }
140                         }
141                         n.Cleanup()
142                 }
143         }
144 }
145
146 // ResizeSplits resizes all the splits correctly
147 func (s *SplitTree) ResizeSplits() {
148         for i, node := range s.children {
149                 if n, ok := node.(*LeafNode); ok {
150                         if s.kind == VerticalSplit {
151                                 n.view.width = s.width / len(s.children)
152                                 n.view.height = s.height
153
154                                 n.view.x = s.x + n.view.width*i
155                                 n.view.y = s.y
156                         } else {
157                                 n.view.height = s.height / len(s.children)
158                                 n.view.width = s.width
159
160                                 n.view.y = s.y + n.view.height*i
161                                 n.view.x = s.x
162                         }
163                         if n.view.Buf.Settings["statusline"].(bool) {
164                                 n.view.height--
165                         }
166
167                         n.view.ToggleTabbar()
168                         n.view.matches = Match(n.view)
169                 } else if n, ok := node.(*SplitTree); ok {
170                         if s.kind == VerticalSplit {
171                                 n.width = s.width / len(s.children)
172                                 n.height = s.height
173
174                                 n.x = s.x + n.width*i
175                                 n.y = s.y
176                         } else {
177                                 n.height = s.height / len(s.children)
178                                 n.width = s.width
179
180                                 n.y = s.y + n.height*i
181                                 n.x = s.x
182                         }
183                         n.ResizeSplits()
184                 }
185         }
186 }
187
188 func (l *LeafNode) String() string {
189         return l.view.Buf.Name
190 }
191
192 func search(haystack []Node, needle Node) int {
193         for i, x := range haystack {
194                 if x == needle {
195                         return i
196                 }
197         }
198         return 0
199 }
200
201 func findView(haystack []*View, needle *View) int {
202         for i, x := range haystack {
203                 if x == needle {
204                         return i
205                 }
206         }
207         return 0
208 }
209
210 // VSplit is here just to make SplitTree fit the Node interface
211 func (s *SplitTree) VSplit(buf *Buffer) {}
212
213 // HSplit is here just to make SplitTree fit the Node interface
214 func (s *SplitTree) HSplit(buf *Buffer) {}
215
216 func (s *SplitTree) String() string {
217         str := "["
218         for _, child := range s.children {
219                 str += child.String() + ", "
220         }
221         return str + "]"
222 }