diff --git a/cmd/micro/action/actions.go b/cmd/micro/action/actions.go index b9813723..e913ef0a 100644 --- a/cmd/micro/action/actions.go +++ b/cmd/micro/action/actions.go @@ -988,7 +988,7 @@ func (h *BufHandler) Escape() bool { // Quit this will close the current tab or view that is open func (h *BufHandler) Quit() bool { quit := func() { - if len(MainTab.Panes) > 1 { + if len(MainTab().Panes) > 1 { h.Unsplit() } else { screen.Screen.Fini() @@ -1039,12 +1039,12 @@ func (h *BufHandler) HSplitBinding() bool { // Unsplit closes all splits in the current tab except the active one func (h *BufHandler) Unsplit() bool { - n := MainTab.GetNode(h.splitID) + n := MainTab().GetNode(h.splitID) n.Unsplit() - MainTab.RemovePane(MainTab.GetPane(h.splitID)) - MainTab.Resize() - MainTab.SetActive(len(MainTab.Panes) - 1) + MainTab().RemovePane(MainTab().GetPane(h.splitID)) + MainTab().Resize() + MainTab().SetActive(len(MainTab().Panes) - 1) return false } diff --git a/cmd/micro/action/bufhandler.go b/cmd/micro/action/bufhandler.go index 1eecf143..3beab69c 100644 --- a/cmd/micro/action/bufhandler.go +++ b/cmd/micro/action/bufhandler.go @@ -220,17 +220,17 @@ func (h *BufHandler) DoRuneInsert(r rune) { func (h *BufHandler) vsplit(buf *buffer.Buffer) { e := NewBufEditPane(0, 0, 0, 0, buf) - e.splitID = MainTab.GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool)) - MainTab.Panes = append(MainTab.Panes, e) - MainTab.Resize() - MainTab.SetActive(len(MainTab.Panes) - 1) + e.splitID = MainTab().GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool)) + MainTab().Panes = append(MainTab().Panes, e) + MainTab().Resize() + MainTab().SetActive(len(MainTab().Panes) - 1) } func (h *BufHandler) hsplit(buf *buffer.Buffer) { e := NewBufEditPane(0, 0, 0, 0, buf) - e.splitID = MainTab.GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool)) - MainTab.Panes = append(MainTab.Panes, e) - MainTab.Resize() - MainTab.SetActive(len(MainTab.Panes) - 1) + e.splitID = MainTab().GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool)) + MainTab().Panes = append(MainTab().Panes, e) + MainTab().Resize() + MainTab().SetActive(len(MainTab().Panes) - 1) } // BufKeyActions contains the list of all possible key actions the bufhandler could execute diff --git a/cmd/micro/action/command.go b/cmd/micro/action/command.go index aee63e71..6a89a98d 100644 --- a/cmd/micro/action/command.go +++ b/cmd/micro/action/command.go @@ -207,7 +207,7 @@ func VSplit(args []string) { } log.Println("loaded") - MainTab.CurPane().vsplit(buf) + MainTab().CurPane().vsplit(buf) } // HSplit opens a horizontal split with file given in the first argument @@ -219,7 +219,7 @@ func HSplit(args []string) { return } - MainTab.CurPane().hsplit(buf) + MainTab().CurPane().hsplit(buf) } // Eval evaluates a lua expression diff --git a/cmd/micro/action/editpane.go b/cmd/micro/action/editpane.go index cf9ad392..54218893 100644 --- a/cmd/micro/action/editpane.go +++ b/cmd/micro/action/editpane.go @@ -28,12 +28,12 @@ func NewBufEditPane(x, y, width, height int, b *buffer.Buffer) *EditPane { return e } -func NewTabPane(width, height int, b *buffer.Buffer) *TabPane { +func NewTabPane(x, y, width, height int, b *buffer.Buffer) *TabPane { t := new(TabPane) - t.Node = views.NewRoot(0, 0, width, height) - t.Window = display.NewUIWindow(t.Node) + t.Node = views.NewRoot(x, y, width, height) + t.UIWindow = display.NewUIWindow(t.Node) - e := NewBufEditPane(0, 0, width, height, b) + e := NewBufEditPane(x, y, width, height, b) e.splitID = t.ID() t.Panes = append(t.Panes, e) diff --git a/cmd/micro/action/tab.go b/cmd/micro/action/tab.go index b4c23d22..91794be9 100644 --- a/cmd/micro/action/tab.go +++ b/cmd/micro/action/tab.go @@ -8,30 +8,102 @@ import ( "github.com/zyedidia/tcell" ) -var MainTab *TabPane +type TabList struct { + *display.TabWindow + List []*TabPane + Active int +} +func NewTabList(bufs []*buffer.Buffer) *TabList { + w, h := screen.Screen.Size() + tl := new(TabList) + tl.List = make([]*TabPane, len(bufs)) + if len(bufs) > 1 { + for i, b := range bufs { + tl.List[i] = NewTabPane(0, 1, w, h-2, b) + } + } else { + tl.List[0] = NewTabPane(0, 0, w, h-1, bufs[0]) + } + tl.TabWindow = display.NewTabWindow(w, 0) + tl.Names = make([]string, len(bufs)) + tl.UpdateNames() + + return tl +} + +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()) + } +} + +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() + } + case *tcell.EventMouse: + switch e.Buttons() { + case tcell.Button1: + } + + } + t.List[t.Active].HandleEvent(event) +} + +func (t *TabList) Display() { + if len(t.List) > 1 { + t.TabWindow.Display() + } +} + +var Tabs *TabList + +func InitTabs(bufs []*buffer.Buffer) { + Tabs = NewTabList(bufs) +} + +func MainTab() *TabPane { + return Tabs.List[Tabs.Active] +} + +// A TabPane 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 { *views.Node - display.Window + *display.UIWindow Panes []*EditPane active int resizing *views.Node // node currently being resized } +// 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) { switch e := event.(type) { - case *tcell.EventResize: - w, h := screen.Screen.Size() - InfoBar.Resize(w, h-1) - t.Node.Resize(w, h-1) - t.Resize() case *tcell.EventMouse: switch e.Buttons() { case tcell.Button1: mx, my := e.Position() - resizeID := t.GetMouseLoc(buffer.Loc{mx, my}).X + resizeID := t.GetMouseSplitID(buffer.Loc{mx, my}) if t.resizing != nil { var size int if t.resizing.Kind == views.STVert { @@ -44,7 +116,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) { return } - if resizeID != -1 { + if resizeID != 0 { t.resizing = t.GetNode(uint64(resizeID)) return } @@ -67,6 +139,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) { t.Panes[t.active].HandleEvent(event) } +// SetActive changes the currently active pane to the specified index func (t *TabPane) SetActive(i int) { t.active = i for j, p := range t.Panes { @@ -78,6 +151,7 @@ func (t *TabPane) SetActive(i int) { } } +// GetPane returns the pane with the given split index func (t *TabPane) GetPane(splitid uint64) int { for i, p := range t.Panes { if p.splitID == splitid { @@ -87,12 +161,14 @@ func (t *TabPane) GetPane(splitid uint64) int { return 0 } +// Remove pane removes the pane with the given index func (t *TabPane) 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 = 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) @@ -107,6 +183,7 @@ func (t *TabPane) Resize() { } } +// CurPane returns the currently active pane func (t *TabPane) CurPane() *EditPane { return t.Panes[t.active] } diff --git a/cmd/micro/display/tabbar.go b/cmd/micro/display/tabbar.go new file mode 100644 index 00000000..4527aa0f --- /dev/null +++ b/cmd/micro/display/tabbar.go @@ -0,0 +1,57 @@ +package display + +import ( + "log" + + "github.com/zyedidia/micro/cmd/micro/config" + "github.com/zyedidia/micro/cmd/micro/screen" +) + +type TabWindow struct { + Names []string + Active int + width int + hscroll int + y int +} + +func NewTabWindow(w int, y int) *TabWindow { + tw := new(TabWindow) + tw.width = w + tw.y = y + return tw +} + +func (w *TabWindow) Display() { + x := -w.hscroll + + draw := func(r rune, n int) { + for i := 0; i < n; i++ { + screen.Screen.SetContent(x, w.y, r, nil, config.DefStyle.Reverse(true)) + x++ + log.Println(x) + } + } + + for i, n := range w.Names { + if i == w.Active { + draw('[', 1) + } + for _, c := range n { + draw(c, 1) + } + if i == w.Active { + draw(']', 1) + draw(' ', 3) + } else { + draw(' ', 4) + } + if x >= w.width { + break + } + } + + if x < w.width { + draw(' ', w.width-x) + } +} diff --git a/cmd/micro/display/uiwindow.go b/cmd/micro/display/uiwindow.go index 1c9210eb..50f94a3c 100644 --- a/cmd/micro/display/uiwindow.go +++ b/cmd/micro/display/uiwindow.go @@ -36,36 +36,32 @@ func (w *UIWindow) Display() { w.drawNode(w.root) } -func (w *UIWindow) Clear() {} -func (w *UIWindow) Relocate() bool { return false } -func (w *UIWindow) GetView() *View { return nil } -func (w *UIWindow) SetView(*View) {} -func (w *UIWindow) GetMouseLoc(vloc buffer.Loc) buffer.Loc { - var mouseLoc func(*views.Node) buffer.Loc - mouseLoc = func(n *views.Node) buffer.Loc { +func (w *UIWindow) GetMouseSplitID(vloc buffer.Loc) uint64 { + var mouseLoc func(*views.Node) uint64 + mouseLoc = func(n *views.Node) uint64 { cs := n.Children() for i, c := range cs { if c.Kind == views.STVert { if i != len(cs)-1 { if vloc.X == c.X+c.W && vloc.Y >= c.Y && vloc.Y < c.Y+c.H { - return buffer.Loc{int(c.ID()), 0} + return c.ID() } } } else if c.Kind == views.STHoriz { if i != len(cs)-1 { if vloc.Y == c.Y+c.H-1 && vloc.X >= c.X && vloc.X < c.X+c.W { - return buffer.Loc{int(c.ID()), 0} + return c.ID() } } } } for _, c := range cs { m := mouseLoc(c) - if m.X != -1 { + if m != 0 { return m } } - return buffer.Loc{-1, 0} + return 0 } return mouseLoc(w.root) } diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index e711bec7..50e36d86 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -185,11 +185,8 @@ func main() { } }() - b := LoadInput()[0] - width, height := screen.Screen.Size() - - action.MainTab = action.NewTabPane(width, height-1, b) - + b := LoadInput() + action.InitTabs(b) action.InitGlobals() // Here is the event loop which runs in a separate thread @@ -206,10 +203,11 @@ func main() { // Display everything screen.Screen.Fill(' ', config.DefStyle) screen.Screen.HideCursor() - for _, ep := range action.MainTab.Panes { + action.Tabs.Display() + for _, ep := range action.MainTab().Panes { ep.Display() } - action.MainTab.Display() + action.MainTab().Display() action.InfoBar.Display() screen.Screen.Show() @@ -227,7 +225,7 @@ func main() { if action.InfoBar.HasPrompt { action.InfoBar.HandleEvent(event) } else { - action.MainTab.HandleEvent(event) + action.MainTab().HandleEvent(event) } } }