]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/action/tab.go
Gutter message support
[micro.git] / cmd / micro / action / tab.go
index 91794be90f59269a98ac880c0a4aae654748fa4a..0dab39f664cac7a173a336ca48fb8df7cdf68965 100644 (file)
@@ -8,101 +8,173 @@ import (
        "github.com/zyedidia/tcell"
 )
 
+// The TabList is a list of tabs and a window to display the tab bar
+// at the top of the screen
 type TabList struct {
        *display.TabWindow
-       List   []*TabPane
-       Active int
+       List []*Tab
 }
 
+// NewTabList creates a TabList from a list of buffers by creating a Tab
+// for each buffer
 func NewTabList(bufs []*buffer.Buffer) *TabList {
        w, h := screen.Screen.Size()
        tl := new(TabList)
-       tl.List = make([]*TabPane, len(bufs))
+       tl.List = make([]*Tab, len(bufs))
        if len(bufs) > 1 {
                for i, b := range bufs {
-                       tl.List[i] = NewTabPane(0, 1, w, h-2, b)
+                       tl.List[i] = NewTabFromBuffer(0, 1, w, h-2, b)
                }
        } else {
-               tl.List[0] = NewTabPane(0, 0, w, h-1, bufs[0])
+               tl.List[0] = NewTabFromBuffer(0, 0, w, h-1, bufs[0])
        }
        tl.TabWindow = display.NewTabWindow(w, 0)
        tl.Names = make([]string, len(bufs))
-       tl.UpdateNames()
 
        return tl
 }
 
+// UpdateNames makes sure that the list of names the tab window has access to is
+// correct
 func (t *TabList) UpdateNames() {
        t.Names = t.Names[:0]
        for _, p := range t.List {
-               t.Names = append(t.Names, p.Panes[p.active].Buf.GetName())
+               t.Names = append(t.Names, p.Panes[p.active].Name())
        }
 }
 
+// AddTab adds a new tab to this TabList
+func (t *TabList) AddTab(p *Tab) {
+       t.List = append(t.List, p)
+       t.Resize()
+       t.UpdateNames()
+}
+
+// RemoveTab removes a tab with the given id from the TabList
+func (t *TabList) RemoveTab(id uint64) {
+       for i, p := range t.List {
+               if len(p.Panes) == 0 {
+                       continue
+               }
+               if p.Panes[0].ID() == id {
+                       copy(t.List[i:], t.List[i+1:])
+                       t.List[len(t.List)-1] = nil
+                       t.List = t.List[:len(t.List)-1]
+                       if t.Active() >= len(t.List) {
+                               t.SetActive(len(t.List) - 1)
+                       }
+                       t.Resize()
+                       t.UpdateNames()
+                       return
+               }
+       }
+}
+
+// Resize resizes all elements within the tab list
+// One thing to note is that when there is only 1 tab
+// the tab bar should not be drawn so resizing must take
+// that into account
+func (t *TabList) Resize() {
+       w, h := screen.Screen.Size()
+       InfoBar.Resize(w, h-1)
+       if len(t.List) > 1 {
+               for _, p := range t.List {
+                       p.Y = 1
+                       p.Node.Resize(w, h-2)
+                       p.Resize()
+               }
+       } else if len(t.List) == 1 {
+               t.List[0].Y = 0
+               t.List[0].Node.Resize(w, h-1)
+               t.List[0].Resize()
+       }
+}
+
+// HandleEvent checks for a resize event or a mouse event on the tab bar
+// otherwise it will forward the event to the currently active tab
 func (t *TabList) HandleEvent(event tcell.Event) {
        switch e := event.(type) {
        case *tcell.EventResize:
-               w, h := screen.Screen.Size()
-               InfoBar.Resize(w, h-1)
-               if len(t.List) > 1 {
-                       for _, p := range t.List {
-                               p.Node.Resize(w, h-2)
-                               p.Resize()
-                       }
-               } else {
-                       t.List[0].Node.Resize(w, h-2)
-                       t.List[0].Resize()
-               }
+               t.Resize()
        case *tcell.EventMouse:
+               mx, my := e.Position()
                switch e.Buttons() {
                case tcell.Button1:
+                       ind := t.GetMouseLoc(buffer.Loc{mx, my})
+                       if ind != -1 {
+                               t.SetActive(ind)
+                       }
+               case tcell.WheelUp:
+                       if my == t.Y {
+                               t.Scroll(4)
+                               return
+                       }
+               case tcell.WheelDown:
+                       if my == t.Y {
+                               t.Scroll(-4)
+                               return
+                       }
                }
-
        }
-       t.List[t.Active].HandleEvent(event)
+       t.List[t.Active()].HandleEvent(event)
 }
 
+// Display updates the names and then displays the tab bar
 func (t *TabList) Display() {
+       t.UpdateNames()
        if len(t.List) > 1 {
                t.TabWindow.Display()
        }
 }
 
+// Tabs is the global tab list
 var Tabs *TabList
 
 func InitTabs(bufs []*buffer.Buffer) {
        Tabs = NewTabList(bufs)
 }
 
-func MainTab() *TabPane {
-       return Tabs.List[Tabs.Active]
+func MainTab() *Tab {
+       return Tabs.List[Tabs.Active()]
 }
 
-// A TabPane represents a single tab
+// A Tab represents a single tab
 // It consists of a list of edit panes (the open buffers),
 // a split tree (stored as just the root node), and a uiwindow
 // to display the UI elements like the borders between splits
-type TabPane struct {
+type Tab struct {
        *views.Node
        *display.UIWindow
-       Panes  []*EditPane
+       Panes  []Pane
        active int
 
        resizing *views.Node // node currently being resized
 }
 
+// NewTabFromBuffer creates a new tab from the given buffer
+func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
+       t := new(Tab)
+       t.Node = views.NewRoot(x, y, width, height)
+       t.UIWindow = display.NewUIWindow(t.Node)
+
+       e := NewBufEditPane(x, y, width, height, b)
+       e.splitID = t.ID()
+
+       t.Panes = append(t.Panes, e)
+       return t
+}
+
 // HandleEvent takes a tcell event and usually dispatches it to the current
 // active pane. However if the event is a resize or a mouse event where the user
 // is interacting with the UI (resizing splits) then the event is consumed here
 // If the event is a mouse event in a pane, that pane will become active and get
 // the event
-func (t *TabPane) HandleEvent(event tcell.Event) {
+func (t *Tab) HandleEvent(event tcell.Event) {
        switch e := event.(type) {
        case *tcell.EventMouse:
+               mx, my := e.Position()
                switch e.Buttons() {
                case tcell.Button1:
-                       mx, my := e.Position()
-
                        resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
                        if t.resizing != nil {
                                var size int
@@ -125,14 +197,21 @@ func (t *TabPane) HandleEvent(event tcell.Event) {
                                v := p.GetView()
                                inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
                                if inpane {
-                                       t.active = i
-                                       p.SetActive(true)
-                               } else {
-                                       p.SetActive(false)
+                                       t.SetActive(i)
+                                       break
                                }
                        }
                case tcell.ButtonNone:
                        t.resizing = nil
+               default:
+                       for _, p := range t.Panes {
+                               v := p.GetView()
+                               inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
+                               if inpane {
+                                       p.HandleEvent(event)
+                                       return
+                               }
+                       }
                }
 
        }
@@ -140,7 +219,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) {
 }
 
 // SetActive changes the currently active pane to the specified index
-func (t *TabPane) SetActive(i int) {
+func (t *Tab) SetActive(i int) {
        t.active = i
        for j, p := range t.Panes {
                if j == i {
@@ -152,9 +231,9 @@ func (t *TabPane) SetActive(i int) {
 }
 
 // GetPane returns the pane with the given split index
-func (t *TabPane) GetPane(splitid uint64) int {
+func (t *Tab) GetPane(splitid uint64) int {
        for i, p := range t.Panes {
-               if p.splitID == splitid {
+               if p.ID() == splitid {
                        return i
                }
        }
@@ -162,19 +241,19 @@ func (t *TabPane) GetPane(splitid uint64) int {
 }
 
 // Remove pane removes the pane with the given index
-func (t *TabPane) RemovePane(i int) {
+func (t *Tab) RemovePane(i int) {
        copy(t.Panes[i:], t.Panes[i+1:])
-       t.Panes[len(t.Panes)-1] = nil // or the zero value of T
+       t.Panes[len(t.Panes)-1] = nil
        t.Panes = t.Panes[:len(t.Panes)-1]
 }
 
 // Resize resizes all panes according to their corresponding split nodes
-func (t *TabPane) Resize() {
-       for i, p := range t.Panes {
-               n := t.GetNode(p.splitID)
+func (t *Tab) Resize() {
+       for _, p := range t.Panes {
+               n := t.GetNode(p.ID())
                pv := p.GetView()
                offset := 0
-               if i != 0 {
+               if n.X != 0 {
                        offset = 1
                }
                pv.X, pv.Y = n.X+offset, n.Y
@@ -184,6 +263,6 @@ func (t *TabPane) Resize() {
 }
 
 // CurPane returns the currently active pane
-func (t *TabPane) CurPane() *EditPane {
+func (t *Tab) CurPane() Pane {
        return t.Panes[t.active]
 }