Add split_tree and ability to create splits

This commit is contained in:
Zachary Yedidia 2016-08-11 10:45:35 -04:00
parent 2cbd9428aa
commit cbbe312762
7 changed files with 202 additions and 51 deletions

View file

@ -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
}

View file

@ -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())
// }
// }
// }
}
}

View file

@ -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

View file

@ -126,7 +126,7 @@ func SetOption(view *View, args []string) {
}
if option == "statusline" {
view.Resize(screen.Size())
// view.Resize(screen.Size())
}
err := WriteSettings(filename)

152
cmd/micro/split_tree.go Normal file
View file

@ -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 + "]"
}

View file

@ -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]

View file

@ -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