mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-15 21:37:09 +09:00
Begin tab implementation
This commit is contained in:
@@ -988,7 +988,7 @@ func (h *BufHandler) Escape() bool {
|
|||||||
// Quit this will close the current tab or view that is open
|
// Quit this will close the current tab or view that is open
|
||||||
func (h *BufHandler) Quit() bool {
|
func (h *BufHandler) Quit() bool {
|
||||||
quit := func() {
|
quit := func() {
|
||||||
if len(MainTab.Panes) > 1 {
|
if len(MainTab().Panes) > 1 {
|
||||||
h.Unsplit()
|
h.Unsplit()
|
||||||
} else {
|
} else {
|
||||||
screen.Screen.Fini()
|
screen.Screen.Fini()
|
||||||
@@ -1039,12 +1039,12 @@ func (h *BufHandler) HSplitBinding() bool {
|
|||||||
|
|
||||||
// Unsplit closes all splits in the current tab except the active one
|
// Unsplit closes all splits in the current tab except the active one
|
||||||
func (h *BufHandler) Unsplit() bool {
|
func (h *BufHandler) Unsplit() bool {
|
||||||
n := MainTab.GetNode(h.splitID)
|
n := MainTab().GetNode(h.splitID)
|
||||||
n.Unsplit()
|
n.Unsplit()
|
||||||
|
|
||||||
MainTab.RemovePane(MainTab.GetPane(h.splitID))
|
MainTab().RemovePane(MainTab().GetPane(h.splitID))
|
||||||
MainTab.Resize()
|
MainTab().Resize()
|
||||||
MainTab.SetActive(len(MainTab.Panes) - 1)
|
MainTab().SetActive(len(MainTab().Panes) - 1)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -220,17 +220,17 @@ func (h *BufHandler) DoRuneInsert(r rune) {
|
|||||||
|
|
||||||
func (h *BufHandler) vsplit(buf *buffer.Buffer) {
|
func (h *BufHandler) vsplit(buf *buffer.Buffer) {
|
||||||
e := NewBufEditPane(0, 0, 0, 0, buf)
|
e := NewBufEditPane(0, 0, 0, 0, buf)
|
||||||
e.splitID = MainTab.GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool))
|
e.splitID = MainTab().GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool))
|
||||||
MainTab.Panes = append(MainTab.Panes, e)
|
MainTab().Panes = append(MainTab().Panes, e)
|
||||||
MainTab.Resize()
|
MainTab().Resize()
|
||||||
MainTab.SetActive(len(MainTab.Panes) - 1)
|
MainTab().SetActive(len(MainTab().Panes) - 1)
|
||||||
}
|
}
|
||||||
func (h *BufHandler) hsplit(buf *buffer.Buffer) {
|
func (h *BufHandler) hsplit(buf *buffer.Buffer) {
|
||||||
e := NewBufEditPane(0, 0, 0, 0, buf)
|
e := NewBufEditPane(0, 0, 0, 0, buf)
|
||||||
e.splitID = MainTab.GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool))
|
e.splitID = MainTab().GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool))
|
||||||
MainTab.Panes = append(MainTab.Panes, e)
|
MainTab().Panes = append(MainTab().Panes, e)
|
||||||
MainTab.Resize()
|
MainTab().Resize()
|
||||||
MainTab.SetActive(len(MainTab.Panes) - 1)
|
MainTab().SetActive(len(MainTab().Panes) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BufKeyActions contains the list of all possible key actions the bufhandler could execute
|
// BufKeyActions contains the list of all possible key actions the bufhandler could execute
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ func VSplit(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Println("loaded")
|
log.Println("loaded")
|
||||||
MainTab.CurPane().vsplit(buf)
|
MainTab().CurPane().vsplit(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSplit opens a horizontal split with file given in the first argument
|
// HSplit opens a horizontal split with file given in the first argument
|
||||||
@@ -219,7 +219,7 @@ func HSplit(args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
MainTab.CurPane().hsplit(buf)
|
MainTab().CurPane().hsplit(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eval evaluates a lua expression
|
// Eval evaluates a lua expression
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ func NewBufEditPane(x, y, width, height int, b *buffer.Buffer) *EditPane {
|
|||||||
return e
|
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 := new(TabPane)
|
||||||
t.Node = views.NewRoot(0, 0, width, height)
|
t.Node = views.NewRoot(x, y, width, height)
|
||||||
t.Window = display.NewUIWindow(t.Node)
|
t.UIWindow = display.NewUIWindow(t.Node)
|
||||||
|
|
||||||
e := NewBufEditPane(0, 0, width, height, b)
|
e := NewBufEditPane(x, y, width, height, b)
|
||||||
e.splitID = t.ID()
|
e.splitID = t.ID()
|
||||||
|
|
||||||
t.Panes = append(t.Panes, e)
|
t.Panes = append(t.Panes, e)
|
||||||
|
|||||||
@@ -8,30 +8,102 @@ import (
|
|||||||
"github.com/zyedidia/tcell"
|
"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 {
|
type TabPane struct {
|
||||||
*views.Node
|
*views.Node
|
||||||
display.Window
|
*display.UIWindow
|
||||||
Panes []*EditPane
|
Panes []*EditPane
|
||||||
active int
|
active int
|
||||||
|
|
||||||
resizing *views.Node // node currently being resized
|
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) {
|
func (t *TabPane) HandleEvent(event tcell.Event) {
|
||||||
switch e := event.(type) {
|
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:
|
case *tcell.EventMouse:
|
||||||
switch e.Buttons() {
|
switch e.Buttons() {
|
||||||
case tcell.Button1:
|
case tcell.Button1:
|
||||||
mx, my := e.Position()
|
mx, my := e.Position()
|
||||||
|
|
||||||
resizeID := t.GetMouseLoc(buffer.Loc{mx, my}).X
|
resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
|
||||||
if t.resizing != nil {
|
if t.resizing != nil {
|
||||||
var size int
|
var size int
|
||||||
if t.resizing.Kind == views.STVert {
|
if t.resizing.Kind == views.STVert {
|
||||||
@@ -44,7 +116,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resizeID != -1 {
|
if resizeID != 0 {
|
||||||
t.resizing = t.GetNode(uint64(resizeID))
|
t.resizing = t.GetNode(uint64(resizeID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -67,6 +139,7 @@ func (t *TabPane) HandleEvent(event tcell.Event) {
|
|||||||
t.Panes[t.active].HandleEvent(event)
|
t.Panes[t.active].HandleEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetActive changes the currently active pane to the specified index
|
||||||
func (t *TabPane) SetActive(i int) {
|
func (t *TabPane) SetActive(i int) {
|
||||||
t.active = i
|
t.active = i
|
||||||
for j, p := range t.Panes {
|
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 {
|
func (t *TabPane) GetPane(splitid uint64) int {
|
||||||
for i, p := range t.Panes {
|
for i, p := range t.Panes {
|
||||||
if p.splitID == splitid {
|
if p.splitID == splitid {
|
||||||
@@ -87,12 +161,14 @@ func (t *TabPane) GetPane(splitid uint64) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove pane removes the pane with the given index
|
||||||
func (t *TabPane) RemovePane(i int) {
|
func (t *TabPane) RemovePane(i int) {
|
||||||
copy(t.Panes[i:], t.Panes[i+1:])
|
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 // or the zero value of T
|
||||||
t.Panes = t.Panes[:len(t.Panes)-1]
|
t.Panes = t.Panes[:len(t.Panes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize resizes all panes according to their corresponding split nodes
|
||||||
func (t *TabPane) Resize() {
|
func (t *TabPane) Resize() {
|
||||||
for i, p := range t.Panes {
|
for i, p := range t.Panes {
|
||||||
n := t.GetNode(p.splitID)
|
n := t.GetNode(p.splitID)
|
||||||
@@ -107,6 +183,7 @@ func (t *TabPane) Resize() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurPane returns the currently active pane
|
||||||
func (t *TabPane) CurPane() *EditPane {
|
func (t *TabPane) CurPane() *EditPane {
|
||||||
return t.Panes[t.active]
|
return t.Panes[t.active]
|
||||||
}
|
}
|
||||||
|
|||||||
57
cmd/micro/display/tabbar.go
Normal file
57
cmd/micro/display/tabbar.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,36 +36,32 @@ func (w *UIWindow) Display() {
|
|||||||
w.drawNode(w.root)
|
w.drawNode(w.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *UIWindow) Clear() {}
|
func (w *UIWindow) GetMouseSplitID(vloc buffer.Loc) uint64 {
|
||||||
func (w *UIWindow) Relocate() bool { return false }
|
var mouseLoc func(*views.Node) uint64
|
||||||
func (w *UIWindow) GetView() *View { return nil }
|
mouseLoc = func(n *views.Node) uint64 {
|
||||||
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 {
|
|
||||||
cs := n.Children()
|
cs := n.Children()
|
||||||
for i, c := range cs {
|
for i, c := range cs {
|
||||||
if c.Kind == views.STVert {
|
if c.Kind == views.STVert {
|
||||||
if i != len(cs)-1 {
|
if i != len(cs)-1 {
|
||||||
if vloc.X == c.X+c.W && vloc.Y >= c.Y && vloc.Y < c.Y+c.H {
|
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 {
|
} else if c.Kind == views.STHoriz {
|
||||||
if i != len(cs)-1 {
|
if i != len(cs)-1 {
|
||||||
if vloc.Y == c.Y+c.H-1 && vloc.X >= c.X && vloc.X < c.X+c.W {
|
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 {
|
for _, c := range cs {
|
||||||
m := mouseLoc(c)
|
m := mouseLoc(c)
|
||||||
if m.X != -1 {
|
if m != 0 {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffer.Loc{-1, 0}
|
return 0
|
||||||
}
|
}
|
||||||
return mouseLoc(w.root)
|
return mouseLoc(w.root)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,11 +185,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
b := LoadInput()[0]
|
b := LoadInput()
|
||||||
width, height := screen.Screen.Size()
|
action.InitTabs(b)
|
||||||
|
|
||||||
action.MainTab = action.NewTabPane(width, height-1, b)
|
|
||||||
|
|
||||||
action.InitGlobals()
|
action.InitGlobals()
|
||||||
|
|
||||||
// Here is the event loop which runs in a separate thread
|
// Here is the event loop which runs in a separate thread
|
||||||
@@ -206,10 +203,11 @@ func main() {
|
|||||||
// Display everything
|
// Display everything
|
||||||
screen.Screen.Fill(' ', config.DefStyle)
|
screen.Screen.Fill(' ', config.DefStyle)
|
||||||
screen.Screen.HideCursor()
|
screen.Screen.HideCursor()
|
||||||
for _, ep := range action.MainTab.Panes {
|
action.Tabs.Display()
|
||||||
|
for _, ep := range action.MainTab().Panes {
|
||||||
ep.Display()
|
ep.Display()
|
||||||
}
|
}
|
||||||
action.MainTab.Display()
|
action.MainTab().Display()
|
||||||
action.InfoBar.Display()
|
action.InfoBar.Display()
|
||||||
screen.Screen.Show()
|
screen.Screen.Show()
|
||||||
|
|
||||||
@@ -227,7 +225,7 @@ func main() {
|
|||||||
if action.InfoBar.HasPrompt {
|
if action.InfoBar.HasPrompt {
|
||||||
action.InfoBar.HandleEvent(event)
|
action.InfoBar.HandleEvent(event)
|
||||||
} else {
|
} else {
|
||||||
action.MainTab.HandleEvent(event)
|
action.MainTab().HandleEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user