Autoclose plugin support

This commit is contained in:
Zachary Yedidia 2019-08-02 14:48:59 -07:00
parent a47e1f0ca5
commit e3ae38e54a
8 changed files with 179 additions and 1096 deletions

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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))
}

View file

@ -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

View file

@ -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
View 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