micro/internal/config/plugin.go

158 lines
3.5 KiB
Go
Raw Normal View History

2019-03-19 01:40:53 +03:00
package config
import (
"errors"
2020-01-29 06:06:58 +03:00
"log"
2019-03-19 01:40:53 +03:00
lua "github.com/yuin/gopher-lua"
ulua "github.com/zyedidia/micro/internal/lua"
)
// ErrNoSuchFunction is returned when Call is executed on a function that does not exist
2019-03-19 01:40:53 +03:00
var ErrNoSuchFunction = errors.New("No such function exists")
2019-03-20 01:28:51 +03:00
// LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins)
2019-08-03 09:46:25 +03:00
func LoadAllPlugins() error {
var reterr error
2019-03-19 01:40:53 +03:00
for _, p := range Plugins {
2019-08-03 09:46:25 +03:00
err := p.Load()
if err != nil {
reterr = err
}
2019-03-19 01:40:53 +03:00
}
2019-08-03 09:46:25 +03:00
return reterr
2019-03-19 01:40:53 +03:00
}
2019-03-20 01:28:51 +03:00
// RunPluginFn runs a given function in all plugins
2019-08-03 00:48:59 +03:00
// returns an error if any of the plugins had an error
2019-03-20 01:28:51 +03:00
func RunPluginFn(fn string, args ...lua.LValue) error {
var reterr error
for _, p := range Plugins {
if !p.IsEnabled() {
continue
}
2019-03-20 01:28:51 +03:00
_, err := p.Call(fn, args...)
if err != nil && err != ErrNoSuchFunction {
reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
}
}
return reterr
}
2019-08-03 00:48:59 +03:00
// 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
}
2020-02-06 01:16:31 +03:00
if v, ok := val.(lua.LBool); ok {
2019-08-03 00:48:59 +03:00
retbool = retbool && bool(v)
}
}
return retbool, reterr
}
// Plugin stores information about the source files/info for a plugin
2019-03-19 01:40:53 +03:00
type Plugin struct {
2019-12-28 04:28:25 +03:00
DirName string // name of plugin folder
2019-08-07 08:24:03 +03:00
Name string // name of plugin
Info *PluginInfo // json file containing info
Srcs []RuntimeFile // lua files
Loaded bool
Default bool // pre-installed plugin
}
// IsEnabled returns if a plugin is enabled
func (p *Plugin) IsEnabled() bool {
if v, ok := GlobalSettings[p.Name]; ok {
2019-08-03 09:46:25 +03:00
return v.(bool) && p.Loaded
}
return true
2019-03-19 01:40:53 +03:00
}
// Plugins is a list of all detected plugins (enabled or disabled)
2019-03-19 01:40:53 +03:00
var Plugins []*Plugin
// Load creates an option for the plugin and runs all source files
2019-03-19 01:40:53 +03:00
func (p *Plugin) Load() error {
if v, ok := GlobalSettings[p.Name]; ok && !v.(bool) {
return nil
}
2019-03-19 01:40:53 +03:00
for _, f := range p.Srcs {
dat, err := f.Data()
if err != nil {
return err
}
err = ulua.LoadFile(p.Name, f.Name(), dat)
if err != nil {
return err
}
}
p.Loaded = true
RegisterGlobalOption(p.Name, true)
2019-03-19 01:40:53 +03:00
return nil
}
// Call calls a given function in this plugin
2019-03-19 01:40:53 +03:00
func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
plug := ulua.L.GetGlobal(p.Name)
2020-01-29 06:06:58 +03:00
if plug == lua.LNil {
log.Println("Plugin does not exist:", p.Name, "at", p.DirName, ":", p)
return nil, nil
}
2019-03-19 01:40:53 +03:00
luafn := ulua.L.GetField(plug, fn)
if luafn == lua.LNil {
return nil, ErrNoSuchFunction
}
err := ulua.L.CallByParam(lua.P{
Fn: luafn,
NRet: 1,
Protect: true,
}, args...)
if err != nil {
return nil, err
}
ret := ulua.L.Get(-1)
ulua.L.Pop(1)
return ret, nil
}
2019-08-03 04:29:47 +03:00
// FindPlugin returns the plugin with the given name
2019-08-03 04:29:47 +03:00
func FindPlugin(name string) *Plugin {
var pl *Plugin
for _, p := range Plugins {
if !p.IsEnabled() {
continue
}
if p.Name == name {
pl = p
break
}
}
return pl
}
// FindAnyPlugin does not require the plugin to be enabled
func FindAnyPlugin(name string) *Plugin {
2019-08-03 04:29:47 +03:00
var pl *Plugin
for _, p := range Plugins {
if p.Name == name {
pl = p
break
}
}
return pl
}