X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=cmd%2Fmicro%2Fsplit_tree.go;h=e34c37f1335865b1d146557afd922c1a61da94b2;hb=3c87d1cfb41e318e9349650e931b5e99cf0fc949;hp=c0c5acd5d3d5cdaceeb19835a23a9122bb72e346;hpb=8ad217942349e8baead7811b12e9ef25467ed4dc;p=micro.git diff --git a/cmd/micro/split_tree.go b/cmd/micro/split_tree.go index c0c5acd5..e34c37f1 100644 --- a/cmd/micro/split_tree.go +++ b/cmd/micro/split_tree.go @@ -1,24 +1,30 @@ package main +// SplitType specifies whether a split is horizontal or vertical type SplitType bool const ( - VerticalSplit = false + // VerticalSplit type + VerticalSplit = false + // HorizontalSplit type HorizontalSplit = true ) +// A Node on the split tree type Node interface { - VSplit(buf *Buffer) - HSplit(buf *Buffer) + VSplit(buf *Buffer, splitIndex int) + HSplit(buf *Buffer, splitIndex int) String() string } +// A LeafNode is an actual split so it contains a view type LeafNode struct { view *View parent *SplitTree } +// NewLeafNode returns a new leaf node containing the given view func NewLeafNode(v *View, parent *SplitTree) *LeafNode { n := new(LeafNode) n.view = v @@ -27,6 +33,7 @@ func NewLeafNode(v *View, parent *SplitTree) *LeafNode { return n } +// A SplitTree is a Node itself and it contains other nodes type SplitTree struct { kind SplitType @@ -36,66 +43,122 @@ type SplitTree struct { x int y int - width int - height int + width int + height int + lockWidth bool + lockHeight bool tabNum int } -func (l *LeafNode) VSplit(buf *Buffer) { +// VSplit creates a vertical split +func (l *LeafNode) VSplit(buf *Buffer, splitIndex int) { + if splitIndex < 0 { + splitIndex = 0 + } + tab := tabs[l.parent.tabNum] if l.parent.kind == VerticalSplit { + if splitIndex > len(l.parent.children) { + splitIndex = len(l.parent.children) + } + newView := NewView(buf) newView.TabNum = l.parent.tabNum - newView.Num = len(tab.views) - l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent)) - tab.curView++ - tab.views = append(tab.views, newView) + l.parent.children = append(l.parent.children, nil) + copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:]) + l.parent.children[splitIndex] = NewLeafNode(newView, l.parent) + + tab.Views = append(tab.Views, nil) + copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:]) + tab.Views[splitIndex] = newView + + tab.CurView = splitIndex } else { + if splitIndex > 1 { + splitIndex = 1 + } + s := new(SplitTree) s.kind = VerticalSplit s.parent = l.parent s.tabNum = l.parent.tabNum newView := NewView(buf) newView.TabNum = l.parent.tabNum - newView.Num = len(tab.views) - s.children = []Node{l, NewLeafNode(newView, s)} + if splitIndex == 1 { + s.children = []Node{l, NewLeafNode(newView, s)} + } else { + s.children = []Node{NewLeafNode(newView, s), l} + } l.parent.children[search(l.parent.children, l)] = s l.parent = s - tab.curView++ - tab.views = append(tab.views, newView) + tab.Views = append(tab.Views, nil) + copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:]) + tab.Views[splitIndex] = newView + + tab.CurView = splitIndex } + + tab.Resize() } -func (l *LeafNode) HSplit(buf *Buffer) { +// HSplit creates a horizontal split +func (l *LeafNode) HSplit(buf *Buffer, splitIndex int) { + if splitIndex < 0 { + splitIndex = 0 + } + tab := tabs[l.parent.tabNum] if l.parent.kind == HorizontalSplit { + if splitIndex > len(l.parent.children) { + splitIndex = len(l.parent.children) + } + newView := NewView(buf) newView.TabNum = l.parent.tabNum - newView.Num = len(tab.views) - l.parent.children = append(l.parent.children, NewLeafNode(newView, l.parent)) - tab.curView++ - tab.views = append(tab.views, newView) + l.parent.children = append(l.parent.children, nil) + copy(l.parent.children[splitIndex+1:], l.parent.children[splitIndex:]) + l.parent.children[splitIndex] = NewLeafNode(newView, l.parent) + + tab.Views = append(tab.Views, nil) + copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:]) + tab.Views[splitIndex] = newView + + tab.CurView = splitIndex } else { + if splitIndex > 1 { + splitIndex = 1 + } + s := new(SplitTree) s.kind = HorizontalSplit s.tabNum = l.parent.tabNum s.parent = l.parent newView := NewView(buf) newView.TabNum = l.parent.tabNum - newView.Num = len(tab.views) - s.children = []Node{l, NewLeafNode(newView, s)} + newView.Num = len(tab.Views) + if splitIndex == 1 { + s.children = []Node{l, NewLeafNode(newView, s)} + } else { + s.children = []Node{NewLeafNode(newView, s), l} + } l.parent.children[search(l.parent.children, l)] = s l.parent = s - tab.curView++ - tab.views = append(tab.views, newView) + tab.Views = append(tab.Views, nil) + copy(tab.Views[splitIndex+1:], tab.Views[splitIndex:]) + tab.Views[splitIndex] = newView + + tab.CurView = splitIndex } + + tab.Resize() } +// Delete deletes a split func (l *LeafNode) Delete() { i := search(l.parent.children, l) @@ -104,19 +167,20 @@ func (l *LeafNode) Delete() { l.parent.children = l.parent.children[:len(l.parent.children)-1] tab := tabs[l.parent.tabNum] - j := findView(tab.views, l.view) - copy(tab.views[j:], tab.views[j+1:]) - tab.views[len(tab.views)-1] = nil // or the zero value of T - tab.views = tab.views[:len(tab.views)-1] + j := findView(tab.Views, l.view) + copy(tab.Views[j:], tab.Views[j+1:]) + tab.Views[len(tab.Views)-1] = nil // or the zero value of T + tab.Views = tab.Views[:len(tab.Views)-1] - for i, v := range tab.views { + for i, v := range tab.Views { v.Num = i } - if tab.curView > 0 { - tab.curView-- + if tab.CurView > 0 { + tab.CurView-- } } +// Cleanup rearranges all the parents after a split has been deleted func (s *SplitTree) Cleanup() { for i, node := range s.children { if n, ok := node.(*SplitTree); ok { @@ -132,41 +196,84 @@ func (s *SplitTree) Cleanup() { } } +// ResizeSplits resizes all the splits correctly func (s *SplitTree) ResizeSplits() { - for i, node := range s.children { + lockedWidth := 0 + lockedHeight := 0 + lockedChildren := 0 + for _, node := range s.children { if n, ok := node.(*LeafNode); ok { if s.kind == VerticalSplit { - n.view.width = s.width / len(s.children) - n.view.height = s.height + if n.view.LockWidth { + lockedWidth += n.view.Width + lockedChildren++ + } + } else { + if n.view.LockHeight { + lockedHeight += n.view.Height + lockedChildren++ + } + } + } else if n, ok := node.(*SplitTree); ok { + if s.kind == VerticalSplit { + if n.lockWidth { + lockedWidth += n.width + lockedChildren++ + } + } else { + if n.lockHeight { + lockedHeight += n.height + lockedChildren++ + } + } + } + } + x, y := 0, 0 + for _, node := range s.children { + if n, ok := node.(*LeafNode); ok { + if s.kind == VerticalSplit { + if !n.view.LockWidth { + n.view.Width = (s.width - lockedWidth) / (len(s.children) - lockedChildren) + } + n.view.Height = s.height - n.view.x = s.x + n.view.width*i + n.view.x = s.x + x n.view.y = s.y + x += n.view.Width } else { - n.view.height = s.height / len(s.children) - n.view.width = s.width + if !n.view.LockHeight { + n.view.Height = (s.height - lockedHeight) / (len(s.children) - lockedChildren) + } + n.view.Width = s.width - n.view.y = s.y + n.view.height*i + n.view.y = s.y + y n.view.x = s.x + y += n.view.Height } if n.view.Buf.Settings["statusline"].(bool) { - n.view.height-- + n.view.Height-- } n.view.ToggleTabbar() - n.view.matches = Match(n.view) } else if n, ok := node.(*SplitTree); ok { if s.kind == VerticalSplit { - n.width = s.width / len(s.children) + if !n.lockWidth { + n.width = (s.width - lockedWidth) / (len(s.children) - lockedChildren) + } n.height = s.height - n.x = s.x + n.width*i + n.x = s.x + x n.y = s.y + x += n.width } else { - n.height = s.height / len(s.children) + if !n.lockHeight { + n.height = (s.height - lockedHeight) / (len(s.children) - lockedChildren) + } n.width = s.width - n.y = s.y + n.height*i + n.y = s.y + y n.x = s.x + y += n.height } n.ResizeSplits() } @@ -174,7 +281,7 @@ func (s *SplitTree) ResizeSplits() { } func (l *LeafNode) String() string { - return l.view.Buf.Name + return l.view.Buf.GetName() } func search(haystack []Node, needle Node) int { @@ -195,8 +302,11 @@ func findView(haystack []*View, needle *View) int { return 0 } -func (s *SplitTree) VSplit(buf *Buffer) {} -func (s *SplitTree) HSplit(buf *Buffer) {} +// VSplit is here just to make SplitTree fit the Node interface +func (s *SplitTree) VSplit(buf *Buffer, splitIndex int) {} + +// HSplit is here just to make SplitTree fit the Node interface +func (s *SplitTree) HSplit(buf *Buffer, splitIndex int) {} func (s *SplitTree) String() string { str := "["