From cbbe312762ff2e30d8edd7033c76704689dfbac3 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Thu, 11 Aug 2016 10:45:35 -0400 Subject: [PATCH] Add split_tree and ability to create splits --- cmd/micro/actions.go | 18 ++--- cmd/micro/command.go | 14 ++-- cmd/micro/micro.go | 10 +-- cmd/micro/settings.go | 2 +- cmd/micro/split_tree.go | 152 ++++++++++++++++++++++++++++++++++++++++ cmd/micro/tab.go | 14 ++++ cmd/micro/view.go | 43 ++++-------- 7 files changed, 202 insertions(+), 51 deletions(-) create mode 100644 cmd/micro/split_tree.go diff --git a/cmd/micro/actions.go b/cmd/micro/actions.go index a269d531..ce849eff 100644 --- a/cmd/micro/actions.go +++ b/cmd/micro/actions.go @@ -768,6 +768,8 @@ func (v *View) Quit() bool { if v.CanClose("Quit anyway? (yes, no, save) ") { v.CloseBuffer() if len(tabs[curTab].views) > 1 { + screen.Fini() + os.Exit(0) } else if len(tabs) > 1 { if len(tabs[v.TabNum].views) == 1 { tabs = tabs[:v.TabNum+copy(tabs[v.TabNum:], tabs[v.TabNum+1:])] @@ -778,7 +780,7 @@ func (v *View) Quit() bool { curTab-- } if curTab == 0 { - CurView().Resize(screen.Size()) + // CurView().Resize(screen.Size()) CurView().matches = Match(CurView()) } } @@ -796,13 +798,13 @@ func (v *View) AddTab() bool { tab.SetNum(len(tabs)) tabs = append(tabs, tab) curTab++ - if len(tabs) == 2 { - for _, t := range tabs { - for _, v := range t.views { - v.Resize(screen.Size()) - } - } - } + // if len(tabs) == 2 { + // for _, t := range tabs { + // for _, v := range t.views { + // v.Resize(screen.Size()) + // } + // } + // } return true } diff --git a/cmd/micro/command.go b/cmd/micro/command.go index 9fcec415..f88d6172 100644 --- a/cmd/micro/command.go +++ b/cmd/micro/command.go @@ -126,13 +126,13 @@ func NewTab(args []string) { tab.SetNum(len(tabs)) tabs = append(tabs, tab) curTab++ - if len(tabs) == 2 { - for _, t := range tabs { - for _, v := range t.views { - v.Resize(screen.Size()) - } - } - } + // if len(tabs) == 2 { + // for _, t := range tabs { + // for _, v := range t.views { + // v.Resize(screen.Size()) + // } + // } + // } } } diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 395a7461..3316e67f 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -247,11 +247,11 @@ func main() { tab := NewTabFromView(NewView(buf)) tab.SetNum(len(tabs)) tabs = append(tabs, tab) - for _, t := range tabs { - for _, v := range t.views { - v.Resize(screen.Size()) - } - } + // for _, t := range tabs { + // for _, v := range t.views { + // v.Resize(screen.Size()) + // } + // } } // Load all the plugin stuff diff --git a/cmd/micro/settings.go b/cmd/micro/settings.go index 784824cd..8ffef420 100644 --- a/cmd/micro/settings.go +++ b/cmd/micro/settings.go @@ -126,7 +126,7 @@ func SetOption(view *View, args []string) { } if option == "statusline" { - view.Resize(screen.Size()) + // view.Resize(screen.Size()) } err := WriteSettings(filename) diff --git a/cmd/micro/split_tree.go b/cmd/micro/split_tree.go new file mode 100644 index 00000000..5afbf001 --- /dev/null +++ b/cmd/micro/split_tree.go @@ -0,0 +1,152 @@ +package main + +type SplitType bool + +const ( + VerticalSplit = false + HorizontalSplit = true +) + +type Node interface { + VSplit(buf *Buffer) + HSplit(buf *Buffer) + String() string +} + +type LeafNode struct { + view *View + + parent *SplitTree +} + +func NewLeafNode(v *View, parent *SplitTree) *LeafNode { + n := new(LeafNode) + n.view = v + n.view.splitNode = n + n.parent = parent + return n +} + +type SplitTree struct { + kind SplitType + + parent *SplitTree + children []Node + + x int + y int + + width int + height int + + tabNum int +} + +func (l *LeafNode) VSplit(buf *Buffer) { + tab := tabs[l.parent.tabNum] + if l.parent.kind == VerticalSplit { + 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) + } else { + s := new(SplitTree) + s.kind = VerticalSplit + s.parent = l.parent + newView := NewView(buf) + newView.TabNum = l.parent.tabNum + newView.Num = len(tab.views) + s.children = []Node{l, NewLeafNode(newView, s)} + l.parent.children[search(l.parent.children, l)] = s + + tab.curView++ + tab.views = append(tab.views, newView) + } +} + +func (l *LeafNode) HSplit(buf *Buffer) { + tab := tabs[l.parent.tabNum] + if l.parent.kind == HorizontalSplit { + 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) + } else { + s := new(SplitTree) + s.kind = HorizontalSplit + s.parent = l.parent + newView := NewView(buf) + newView.TabNum = l.parent.tabNum + newView.Num = len(tab.views) + s.children = []Node{l, NewLeafNode(newView, s)} + l.parent.children[search(l.parent.children, l)] = s + + tab.curView++ + tab.views = append(tab.views, newView) + } +} + +func (s *SplitTree) ResizeSplits() { + for i, 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 + + n.view.x = s.x + n.view.width*i + n.view.y = s.y + } else { + n.view.height = s.height / len(s.children) + n.view.width = s.width + + n.view.y = s.y + n.view.height*i + n.view.x = s.x + } + } else if n, ok := node.(*SplitTree); ok { + if s.kind == VerticalSplit { + n.width = s.width / len(s.children) + n.height = s.height + + n.x = s.x + n.width*i + n.y = s.y + } else { + n.height = s.height / len(s.children) + n.width = s.width + + n.y = s.y + n.height*i + n.x = s.x + } + n.ResizeSplits() + } + } +} + +func (l *LeafNode) String() string { + return l.view.Buf.Name +} + +func search(haystack []Node, needle Node) int { + for i, x := range haystack { + if x == needle { + return i + } + } + return 0 +} + +func (s *SplitTree) VSplit(buf *Buffer) {} +func (s *SplitTree) HSplit(buf *Buffer) {} + +func (s *SplitTree) String() string { + str := "[" + for _, child := range s.children { + str += child.String() + ", " + } + return str + "]" +} diff --git a/cmd/micro/tab.go b/cmd/micro/tab.go index c32bd4b4..6f289468 100644 --- a/cmd/micro/tab.go +++ b/cmd/micro/tab.go @@ -15,6 +15,8 @@ type Tab struct { curView int // Generally this is the name of the current view's buffer name string + + tree *SplitTree } // NewTabFromView creates a new tab and puts the given view in the tab @@ -22,6 +24,14 @@ func NewTabFromView(v *View) *Tab { t := new(Tab) t.views = append(t.views, v) t.views[0].Num = 0 + + t.tree = new(SplitTree) + t.tree.kind = VerticalSplit + t.tree.children = []Node{NewLeafNode(t.views[0], t.tree)} + + w, h := screen.Size() + t.tree.width = w + t.tree.height = h return t } @@ -32,6 +42,10 @@ func (t *Tab) SetNum(num int) { } } +func (t *Tab) Resize() { + t.tree.ResizeSplits() +} + // CurView returns the current view func CurView() *View { curTab := tabs[curTab] diff --git a/cmd/micro/view.go b/cmd/micro/view.go index c69e3622..88b108c5 100644 --- a/cmd/micro/view.go +++ b/cmd/micro/view.go @@ -82,11 +82,14 @@ type View struct { matches SyntaxMatches // The matches from the last frame lastMatches SyntaxMatches + + splitNode *LeafNode } // NewView returns a new fullscreen view func NewView(buf *Buffer) *View { - return NewViewWidthHeight(buf, 100, 100) + screenW, screenH := screen.Size() + return NewViewWidthHeight(buf, screenW, screenH-1) } // NewViewWidthHeight returns a new view with the specified width and height percentages @@ -96,9 +99,8 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View { v.x, v.y = 0, 0 - v.widthPercent = w - v.heightPercent = h - v.Resize(screen.Size()) + v.width = w + v.height = h v.OpenBuffer(buf) @@ -108,34 +110,11 @@ func NewViewWidthHeight(buf *Buffer, w, h int) *View { view: v, } - return v -} - -// Resize recalculates the actual width and height of the view from the width and height -// percentages -// This is usually called when the window is resized, or when a split has been added and -// the percentages have changed -func (v *View) Resize(w, h int) { - // Always include 1 line for the command line at the bottom - h-- - if len(tabs) > 1 { - if v.y == 0 { - // Include one line for the tab bar at the top - h-- - v.y = 1 - } - } else { - if v.y == 1 { - v.y = 0 - } - } - v.width = int(float32(w) * float32(v.widthPercent) / 100) - // We subtract 1 for the statusline - v.height = int(float32(h) * float32(v.heightPercent) / 100) if settings["statusline"].(bool) { - // Make room for the status line if it is enabled v.height-- } + + return v } // ScrollUp scrolls the view up n lines (if possible) @@ -219,11 +198,15 @@ func (v *View) ReOpen() { // HSplit opens a horizontal split with the given buffer func (v *View) HSplit(buf *Buffer) bool { + v.splitNode.HSplit(buf) + tabs[v.TabNum].Resize() return false } // VSplit opens a vertical split with the given buffer func (v *View) VSplit(buf *Buffer) bool { + v.splitNode.VSplit(buf) + tabs[v.TabNum].Resize() return false } @@ -297,7 +280,7 @@ func (v *View) HandleEvent(event tcell.Event) { switch e := event.(type) { case *tcell.EventResize: // Window resized - v.Resize(e.Size()) + // v.Resize(e.Size()) case *tcell.EventKey: if e.Key() == tcell.KeyRune && (e.Modifiers() == 0 || e.Modifiers() == tcell.ModShift) { // Insert a character