]> git.lizzy.rs Git - micro.git/blob - cmd/micro/split_tree.go
Add cd and pwd commands to change the working dir
[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         lockWidth  bool
49         lockHeight bool
50
51         tabNum int
52 }
53
54 // VSplit creates a vertical split
55 func (l *LeafNode) VSplit(buf *Buffer) {
56         tab := tabs[l.parent.tabNum]
57         if l.parent.kind == VerticalSplit {
58                 newView := NewView(buf)
59                 newView.TabNum = l.parent.tabNum
60                 newView.Num = len(tab.views)
61                 l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent))
62
63                 tab.curView++
64                 tab.views = append(tab.views, newView)
65         } else {
66                 s := new(SplitTree)
67                 s.kind = VerticalSplit
68                 s.parent = l.parent
69                 s.tabNum = l.parent.tabNum
70                 newView := NewView(buf)
71                 newView.TabNum = l.parent.tabNum
72                 newView.Num = len(tab.views)
73                 s.children = []Node{l, NewLeafNode(newView, s)}
74                 l.parent.children[search(l.parent.children, l)] = s
75                 l.parent = s
76
77                 tab.curView++
78                 tab.views = append(tab.views, newView)
79         }
80 }
81
82 // HSplit creates a horizontal split
83 func (l *LeafNode) HSplit(buf *Buffer) {
84         tab := tabs[l.parent.tabNum]
85         if l.parent.kind == HorizontalSplit {
86                 newView := NewView(buf)
87                 newView.TabNum = l.parent.tabNum
88                 newView.Num = len(tab.views)
89                 l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent))
90
91                 tab.curView++
92                 tab.views = append(tab.views, newView)
93         } else {
94                 s := new(SplitTree)
95                 s.kind = HorizontalSplit
96                 s.tabNum = l.parent.tabNum
97                 s.parent = l.parent
98                 newView := NewView(buf)
99                 newView.TabNum = l.parent.tabNum
100                 newView.Num = len(tab.views)
101                 s.children = []Node{l, NewLeafNode(newView, s)}
102                 l.parent.children[search(l.parent.children, l)] = s
103                 l.parent = s
104
105                 tab.curView++
106                 tab.views = append(tab.views, newView)
107         }
108 }
109
110 // Delete deletes a split
111 func (l *LeafNode) Delete() {
112         i := search(l.parent.children, l)
113
114         copy(l.parent.children[i:], l.parent.children[i+1:])
115         l.parent.children[len(l.parent.children)-1] = nil
116         l.parent.children = l.parent.children[:len(l.parent.children)-1]
117
118         tab := tabs[l.parent.tabNum]
119         j := findView(tab.views, l.view)
120         copy(tab.views[j:], tab.views[j+1:])
121         tab.views[len(tab.views)-1] = nil // or the zero value of T
122         tab.views = tab.views[:len(tab.views)-1]
123
124         for i, v := range tab.views {
125                 v.Num = i
126         }
127         if tab.curView > 0 {
128                 tab.curView--
129         }
130 }
131
132 // Cleanup rearranges all the parents after a split has been deleted
133 func (s *SplitTree) Cleanup() {
134         for i, node := range s.children {
135                 if n, ok := node.(*SplitTree); ok {
136                         if len(n.children) == 1 {
137                                 if child, ok := n.children[0].(*LeafNode); ok {
138                                         s.children[i] = child
139                                         child.parent = s
140                                         continue
141                                 }
142                         }
143                         n.Cleanup()
144                 }
145         }
146 }
147
148 // ResizeSplits resizes all the splits correctly
149 func (s *SplitTree) ResizeSplits() {
150         lockedWidth := 0
151         lockedHeight := 0
152         lockedChildren := 0
153         for _, node := range s.children {
154                 if n, ok := node.(*LeafNode); ok {
155                         if s.kind == VerticalSplit {
156                                 if n.view.lockWidth {
157                                         lockedWidth += n.view.width
158                                         lockedChildren++
159                                 }
160                         } else {
161                                 if n.view.lockHeight {
162                                         lockedHeight += n.view.height
163                                         lockedChildren++
164                                 }
165                         }
166                 } else if n, ok := node.(*SplitTree); ok {
167                         if s.kind == VerticalSplit {
168                                 if n.lockWidth {
169                                         lockedWidth += n.width
170                                         lockedChildren++
171                                 }
172                         } else {
173                                 if n.lockHeight {
174                                         lockedHeight += n.height
175                                         lockedChildren++
176                                 }
177                         }
178                 }
179         }
180         x, y := 0, 0
181         for _, node := range s.children {
182                 if n, ok := node.(*LeafNode); ok {
183                         if s.kind == VerticalSplit {
184                                 if !n.view.lockWidth {
185                                         n.view.width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
186                                 }
187                                 n.view.height = s.height
188
189                                 n.view.x = s.x + x
190                                 n.view.y = s.y
191                                 x += n.view.width
192                         } else {
193                                 if !n.view.lockHeight {
194                                         n.view.height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
195                                 }
196                                 n.view.width = s.width
197
198                                 n.view.y = s.y + y
199                                 n.view.x = s.x
200                                 y += n.view.height
201                         }
202                         if n.view.Buf.Settings["statusline"].(bool) {
203                                 n.view.height--
204                         }
205
206                         n.view.ToggleTabbar()
207                         n.view.matches = Match(n.view)
208                 } else if n, ok := node.(*SplitTree); ok {
209                         if s.kind == VerticalSplit {
210                                 if !n.lockWidth {
211                                         n.width = (s.width - lockedWidth) / (len(s.children) - lockedChildren)
212                                 }
213                                 n.height = s.height
214
215                                 n.x = s.x + x
216                                 n.y = s.y
217                                 x += n.width
218                         } else {
219                                 if !n.lockHeight {
220                                         n.height = (s.height - lockedHeight) / (len(s.children) - lockedChildren)
221                                 }
222                                 n.width = s.width
223
224                                 n.y = s.y + y
225                                 n.x = s.x
226                                 y += n.height
227                         }
228                         n.ResizeSplits()
229                 }
230         }
231 }
232
233 func (l *LeafNode) String() string {
234         return l.view.Buf.Name
235 }
236
237 func search(haystack []Node, needle Node) int {
238         for i, x := range haystack {
239                 if x == needle {
240                         return i
241                 }
242         }
243         return 0
244 }
245
246 func findView(haystack []*View, needle *View) int {
247         for i, x := range haystack {
248                 if x == needle {
249                         return i
250                 }
251         }
252         return 0
253 }
254
255 // VSplit is here just to make SplitTree fit the Node interface
256 func (s *SplitTree) VSplit(buf *Buffer) {}
257
258 // HSplit is here just to make SplitTree fit the Node interface
259 func (s *SplitTree) HSplit(buf *Buffer) {}
260
261 func (s *SplitTree) String() string {
262         str := "["
263         for _, child := range s.children {
264                 str += child.String() + ", "
265         }
266         return str + "]"
267 }