Autoclose plugin support
This commit is contained in:
parent
a47e1f0ca5
commit
e3ae38e54a
8 changed files with 179 additions and 1096 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
ulua "github.com/zyedidia/micro/internal/lua"
|
||||
"github.com/zyedidia/micro/internal/screen"
|
||||
"github.com/zyedidia/micro/internal/shell"
|
||||
"github.com/zyedidia/micro/internal/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -24,6 +25,8 @@ func LuaImport(pkg string) *lua.LTable {
|
|||
return luaImportMicro()
|
||||
case "micro/shell":
|
||||
return luaImportMicroShell()
|
||||
case "micro/util":
|
||||
return luaImportMicroUtil()
|
||||
default:
|
||||
return ulua.Import(pkg)
|
||||
}
|
||||
|
@ -52,3 +55,13 @@ func luaImportMicroShell() *lua.LTable {
|
|||
|
||||
return pkg
|
||||
}
|
||||
|
||||
func luaImportMicroUtil() *lua.LTable {
|
||||
pkg := ulua.L.NewTable()
|
||||
|
||||
ulua.L.SetField(pkg, "RuneAt", luar.New(ulua.L, util.LuaRuneAt))
|
||||
ulua.L.SetField(pkg, "GetLeadingWhitespace", luar.New(ulua.L, util.LuaGetLeadingWhitespace))
|
||||
ulua.L.SetField(pkg, "IsWordChar", luar.New(ulua.L, util.LuaIsWordChar))
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
|
|
@ -124,6 +124,27 @@ 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
|
||||
|
@ -236,14 +257,21 @@ func (h *BufPane) DoKeyEvent(e Event) bool {
|
|||
for _, c := range cursors {
|
||||
h.Buf.SetCurCursor(c.Num)
|
||||
h.Cursor = c
|
||||
if action(h) {
|
||||
if !h.PluginCB("pre" + estr) {
|
||||
// canceled by plugin
|
||||
continue
|
||||
}
|
||||
if action(h) && h.PluginCB("on"+estr) {
|
||||
h.Relocate()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
if action(h) {
|
||||
if !h.PluginCB("pre" + estr) {
|
||||
return false
|
||||
}
|
||||
if action(h) && h.PluginCB("on"+estr) {
|
||||
h.Relocate()
|
||||
}
|
||||
return true
|
||||
|
@ -277,6 +305,9 @@ func (h *BufPane) DoRuneInsert(r rune) {
|
|||
for _, c := range cursors {
|
||||
// Insert a character
|
||||
h.Buf.SetCurCursor(c.Num)
|
||||
if !h.PluginCBRune("preRune", r) {
|
||||
continue
|
||||
}
|
||||
if c.HasSelection() {
|
||||
c.DeleteSelection()
|
||||
c.ResetSelection()
|
||||
|
@ -289,6 +320,7 @@ func (h *BufPane) DoRuneInsert(r rune) {
|
|||
} else {
|
||||
h.Buf.Insert(c.Loc, string(r))
|
||||
}
|
||||
h.PluginCBRune("onRune", r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -293,6 +294,7 @@ func (b *Buffer) SetName(s string) {
|
|||
|
||||
func (b *Buffer) Insert(start Loc, text string) {
|
||||
if !b.Type.Readonly {
|
||||
log.Println("INSERT", start, text)
|
||||
b.EventHandler.cursors = b.cursors
|
||||
b.EventHandler.active = b.curCursor
|
||||
b.EventHandler.Insert(start, text)
|
||||
|
@ -747,3 +749,7 @@ func ParseCursorLocation(cursorPositions []string) (Loc, error) {
|
|||
|
||||
return startpos, err
|
||||
}
|
||||
|
||||
func (b *Buffer) Line(i int) string {
|
||||
return string(b.LineBytes(i))
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ func LoadAllPlugins() {
|
|||
}
|
||||
|
||||
// RunPluginFn runs a given function in all plugins
|
||||
// returns an error if any of the plugins had an error
|
||||
func RunPluginFn(fn string, args ...lua.LValue) error {
|
||||
var reterr error
|
||||
for _, p := range Plugins {
|
||||
|
@ -31,6 +32,33 @@ func RunPluginFn(fn string, args ...lua.LValue) error {
|
|||
return reterr
|
||||
}
|
||||
|
||||
// RunPluginFnBool runs a function in all plugins and returns
|
||||
// false if any one of them returned false
|
||||
// also returns an error if any of the plugins had an error
|
||||
func RunPluginFnBool(fn string, args ...lua.LValue) (bool, error) {
|
||||
var reterr error
|
||||
retbool := true
|
||||
for _, p := range Plugins {
|
||||
if !p.IsEnabled() {
|
||||
continue
|
||||
}
|
||||
val, err := p.Call(fn, args...)
|
||||
if err == ErrNoSuchFunction {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
|
||||
continue
|
||||
}
|
||||
if v, ok := val.(lua.LBool); !ok {
|
||||
reterr = errors.New(p.Name + "." + fn + " should return a boolean")
|
||||
} else {
|
||||
retbool = retbool && bool(v)
|
||||
}
|
||||
}
|
||||
return retbool, reterr
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
Name string // name of plugin
|
||||
Info RuntimeFile // json file containing info
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -16,6 +16,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
luar "layeh.com/gopher-luar"
|
||||
|
@ -66,6 +67,8 @@ func Import(pkg string) *lua.LTable {
|
|||
return importErrors()
|
||||
case "time":
|
||||
return importTime()
|
||||
case "utf8":
|
||||
return importUtf8()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -532,3 +535,24 @@ func importTime() *lua.LTable {
|
|||
|
||||
return pkg
|
||||
}
|
||||
|
||||
func importUtf8() *lua.LTable {
|
||||
pkg := L.NewTable()
|
||||
|
||||
L.SetField(pkg, "DecodeLastRune", luar.New(L, utf8.DecodeLastRune))
|
||||
L.SetField(pkg, "DecodeLastRuneInString", luar.New(L, utf8.DecodeLastRuneInString))
|
||||
L.SetField(pkg, "DecodeRune", luar.New(L, utf8.DecodeRune))
|
||||
L.SetField(pkg, "DecodeRuneInString", luar.New(L, utf8.DecodeRuneInString))
|
||||
L.SetField(pkg, "EncodeRune", luar.New(L, utf8.EncodeRune))
|
||||
L.SetField(pkg, "FullRune", luar.New(L, utf8.FullRune))
|
||||
L.SetField(pkg, "FullRuneInString", luar.New(L, utf8.FullRuneInString))
|
||||
L.SetField(pkg, "RuneCount", luar.New(L, utf8.RuneCount))
|
||||
L.SetField(pkg, "RuneCountInString", luar.New(L, utf8.RuneCountInString))
|
||||
L.SetField(pkg, "RuneLen", luar.New(L, utf8.RuneLen))
|
||||
L.SetField(pkg, "RuneStart", luar.New(L, utf8.RuneStart))
|
||||
L.SetField(pkg, "Valid", luar.New(L, utf8.Valid))
|
||||
L.SetField(pkg, "ValidRune", luar.New(L, utf8.ValidRune))
|
||||
L.SetField(pkg, "ValidString", luar.New(L, utf8.ValidString))
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
|
41
internal/util/lua.go
Normal file
41
internal/util/lua.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func LuaRuneAt(str string, runeidx int) string {
|
||||
i := 0
|
||||
for len(str) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(str)
|
||||
|
||||
str = str[size:]
|
||||
|
||||
if i == runeidx {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func LuaGetLeadingWhitespace(s string) string {
|
||||
ws := []byte{}
|
||||
for len(s) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
if r == ' ' || r == '\t' {
|
||||
ws = append(ws, byte(r))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
s = s[size:]
|
||||
}
|
||||
return string(ws)
|
||||
}
|
||||
|
||||
func LuaIsWordChar(s string) bool {
|
||||
r, _ := utf8.DecodeRuneInString(s)
|
||||
return IsWordChar(r)
|
||||
}
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue