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"
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
}
}
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
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()
}
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()
}
}
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
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()
} 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,
"ToggleHelp": (*BufPane).ToggleHelp,
"ToggleKeyMenu": (*BufPane).ToggleKeyMenu,
"ToggleRuler": (*BufPane).ToggleRuler,
- "JumpLine": (*BufPane).JumpLine,
"ClearStatus": (*BufPane).ClearStatus,
"ShellMode": (*BufPane).ShellMode,
"CommandMode": (*BufPane).CommandMode,