]> git.lizzy.rs Git - micro.git/blobdiff - internal/action/bufpane.go
Terminal plugin callback support
[micro.git] / internal / action / bufpane.go
index ae6d56ce08c995bdb61a98cca039ed2b75585f85..4f03e6407ea9a56ad5791ba18e11e384ea4f8428 100644 (file)
@@ -6,6 +6,7 @@ import (
 
        luar "layeh.com/gopher-luar"
 
+       lua "github.com/yuin/gopher-lua"
        "github.com/zyedidia/micro/internal/buffer"
        "github.com/zyedidia/micro/internal/config"
        "github.com/zyedidia/micro/internal/display"
@@ -27,21 +28,59 @@ func init() {
        BufMouseBindings = make(map[MouseEvent]BufMouseAction)
 }
 
+func LuaAction(fn string) func(*BufPane) bool {
+       luaFn := strings.Split(fn, ".")
+       if len(luaFn) <= 1 {
+               return nil
+       }
+       plName, plFn := luaFn[0], luaFn[1]
+       pl := config.FindPlugin(plName)
+       if pl == nil {
+               return nil
+       }
+       return func(h *BufPane) bool {
+               val, err := pl.Call(plFn, luar.New(ulua.L, h))
+               if err != nil {
+                       screen.TermMessage(err)
+               }
+               if v, ok := val.(lua.LBool); !ok {
+                       return false
+               } else {
+                       return bool(v)
+               }
+       }
+}
+
 // BufMapKey maps a key event to an action
 func BufMapKey(k Event, action string) {
-       if strings.HasPrefix(action, "command:") {
-               action = strings.SplitN(action, ":", 2)[1]
-               BufKeyStrings[k] = action
-               BufKeyBindings[k] = CommandAction(action)
-       } else if strings.HasPrefix(action, "command-edit:") {
-               action = strings.SplitN(action, ":", 2)[1]
-               BufKeyStrings[k] = action
-               BufKeyBindings[k] = CommandEditAction(action)
-       } else if f, ok := BufKeyActions[action]; ok {
-               BufKeyStrings[k] = action
-               BufKeyBindings[k] = f
-       } else {
-               screen.TermMessage("Error:", action, "does not exist")
+       actions := strings.SplitN(action, ",", -1)
+       BufKeyStrings[k] = action
+       actionfns := make([]func(*BufPane) bool, len(actions))
+       for i, a := range actions {
+               a = strings.TrimSpace(a)
+               var afn func(*BufPane) bool
+               if strings.HasPrefix(action, "command:") {
+                       a = strings.SplitN(a, ":", 2)[1]
+                       afn = CommandAction(a)
+               } else if strings.HasPrefix(a, "command-edit:") {
+                       a = strings.SplitN(a, ":", 2)[1]
+                       afn = CommandEditAction(a)
+               } else if strings.HasPrefix(a, "lua:") {
+                       a = strings.SplitN(a, ":", 2)[1]
+                       afn = LuaAction(a)
+               } else if f, ok := BufKeyActions[a]; ok {
+                       afn = f
+               } else {
+                       screen.TermMessage("Error:", action, "does not exist")
+               }
+               actionfns[i] = afn
+       }
+       BufKeyBindings[k] = func(h *BufPane) bool {
+               b := false
+               for _, a := range actionfns {
+                       b = a(h) || b
+               }
+               return b
        }
 }
 
@@ -67,9 +106,6 @@ type BufPane struct {
 
        Cursor *buffer.Cursor // the active cursor
 
-       StartLine int // Vertical scrolling
-       StartCol  int // Horizontal scrolling
-
        // Since tcell doesn't differentiate between a mouse release event
        // and a mouse move event with no keys pressed, we need to keep
        // track of whether or not the mouse was pressed (or not released) last event to determine
@@ -127,11 +163,33 @@ func NewBufPaneFromBuf(buf *buffer.Buffer) *BufPane {
        return NewBufPane(buf, w)
 }
 
+// PluginCB calls all plugin callbacks with a certain name and
+// displays an error if there is one and returns the aggregrate
+// boolean response
+func (h *BufPane) PluginCB(cb string) bool {
+       b, err := config.RunPluginFnBool(cb, luar.New(ulua.L, h))
+       if err != nil {
+               screen.TermMessage(err)
+       }
+       return b
+}
+
+// PluginCBRune is the same as PluginCB but also passes a rune to
+// the plugins
+func (h *BufPane) PluginCBRune(cb string, r rune) bool {
+       b, err := config.RunPluginFnBool(cb, luar.New(ulua.L, h), luar.New(ulua.L, string(r)))
+       if err != nil {
+               screen.TermMessage(err)
+       }
+       return b
+}
+
 func (h *BufPane) OpenBuffer(b *buffer.Buffer) {
        h.Buf.Close()
        h.Buf = b
        h.BWindow.SetBuffer(b)
        h.Cursor = b.GetActiveCursor()
+       h.Resize(h.GetView().Width, h.GetView().Height)
        v := new(display.View)
        h.SetView(v)
        h.Relocate()
@@ -209,18 +267,20 @@ func (h *BufPane) HandleEvent(event tcell.Event) {
        }
        h.Buf.MergeCursors()
 
-       // Display any gutter messages for this line
-       c := h.Buf.GetActiveCursor()
-       none := true
-       for _, m := range h.Buf.Messages {
-               if c.Y == m.Start.Y || c.Y == m.End.Y {
-                       InfoBar.GutterMessage(m.Msg)
-                       none = false
-                       break
+       if h.IsActive() {
+               // Display any gutter messages for this line
+               c := h.Buf.GetActiveCursor()
+               none := true
+               for _, m := range h.Buf.Messages {
+                       if c.Y == m.Start.Y || c.Y == m.End.Y {
+                               InfoBar.GutterMessage(m.Msg)
+                               none = false
+                               break
+                       }
+               }
+               if none && InfoBar.HasGutter {
+                       InfoBar.ClearGutter()
                }
-       }
-       if none && InfoBar.HasGutter {
-               InfoBar.ClearGutter()
        }
 }
 
@@ -229,20 +289,38 @@ func (h *BufPane) HandleEvent(event tcell.Event) {
 func (h *BufPane) DoKeyEvent(e Event) bool {
        if action, ok := BufKeyBindings[e]; ok {
                estr := BufKeyStrings[e]
+               if estr != "InsertTab" {
+                       h.Buf.HasSuggestions = false
+               }
                for _, s := range MultiActions {
                        if s == estr {
                                cursors := h.Buf.GetCursors()
                                for _, c := range cursors {
                                        h.Buf.SetCurCursor(c.Num)
                                        h.Cursor = c
-                                       if action(h) {
+                                       if !h.PluginCB("pre" + estr) {
+                                               // canceled by plugin
+                                               continue
+                                       }
+                                       rel := action(h)
+                                       if h.PluginCB("on"+estr) && rel {
                                                h.Relocate()
                                        }
+
+                                       if recording_macro {
+                                               if estr != "ToggleMacro" && estr != "PlayMacro" {
+                                                       curmacro = append(curmacro, e)
+                                               }
+                                       }
                                }
                                return true
                        }
                }
-               if action(h) {
+               if !h.PluginCB("pre" + estr) {
+                       return false
+               }
+               rel := action(h)
+               if h.PluginCB("on"+estr) && rel {
                        h.Relocate()
                }
                return true
@@ -276,6 +354,10 @@ func (h *BufPane) DoRuneInsert(r rune) {
        for _, c := range cursors {
                // Insert a character
                h.Buf.SetCurCursor(c.Num)
+               h.Cursor = c
+               if !h.PluginCBRune("preRune", r) {
+                       continue
+               }
                if c.HasSelection() {
                        c.DeleteSelection()
                        c.ResetSelection()
@@ -288,27 +370,53 @@ func (h *BufPane) DoRuneInsert(r rune) {
                } else {
                        h.Buf.Insert(c.Loc, string(r))
                }
+               if recording_macro {
+                       curmacro = append(curmacro, r)
+               }
+               h.PluginCBRune("onRune", r)
        }
 }
 
-func (h *BufPane) VSplitBuf(buf *buffer.Buffer) {
+func (h *BufPane) VSplitBuf(buf *buffer.Buffer) *BufPane {
        e := NewBufPaneFromBuf(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)
+       return e
 }
-func (h *BufPane) HSplitBuf(buf *buffer.Buffer) {
+func (h *BufPane) HSplitBuf(buf *buffer.Buffer) *BufPane {
        e := NewBufPaneFromBuf(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)
+       return e
 }
 func (h *BufPane) Close() {
        h.Buf.Close()
 }
 
+func (h *BufPane) SetActive(b bool) {
+       h.BWindow.SetActive(b)
+       if b {
+               // Display any gutter messages for this line
+               c := h.Buf.GetActiveCursor()
+               none := true
+               for _, m := range h.Buf.Messages {
+                       if c.Y == m.Start.Y || c.Y == m.End.Y {
+                               InfoBar.GutterMessage(m.Msg)
+                               none = false
+                               break
+                       }
+               }
+               if none && InfoBar.HasGutter {
+                       InfoBar.ClearGutter()
+               }
+       }
+
+}
+
 // BufKeyActions contains the list of all possible key actions the bufhandler could execute
 var BufKeyActions = map[string]BufKeyAction{
        "CursorUp":               (*BufPane).CursorUp,
@@ -376,7 +484,6 @@ var BufKeyActions = map[string]BufKeyAction{
        "ToggleHelp":             (*BufPane).ToggleHelp,
        "ToggleKeyMenu":          (*BufPane).ToggleKeyMenu,
        "ToggleRuler":            (*BufPane).ToggleRuler,
-       "JumpLine":               (*BufPane).JumpLine,
        "ClearStatus":            (*BufPane).ClearStatus,
        "ShellMode":              (*BufPane).ShellMode,
        "CommandMode":            (*BufPane).CommandMode,