]> git.lizzy.rs Git - micro.git/blob - internal/config/plugin.go
Autoclose plugin support
[micro.git] / internal / config / plugin.go
1 package config
2
3 import (
4         "errors"
5
6         lua "github.com/yuin/gopher-lua"
7         ulua "github.com/zyedidia/micro/internal/lua"
8 )
9
10 var ErrNoSuchFunction = errors.New("No such function exists")
11
12 // LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins)
13 func LoadAllPlugins() {
14         for _, p := range Plugins {
15                 p.Load()
16         }
17 }
18
19 // RunPluginFn runs a given function in all plugins
20 // returns an error if any of the plugins had an error
21 func RunPluginFn(fn string, args ...lua.LValue) error {
22         var reterr error
23         for _, p := range Plugins {
24                 if !p.IsEnabled() {
25                         continue
26                 }
27                 _, err := p.Call(fn, args...)
28                 if err != nil && err != ErrNoSuchFunction {
29                         reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
30                 }
31         }
32         return reterr
33 }
34
35 // RunPluginFnBool runs a function in all plugins and returns
36 // false if any one of them returned false
37 // also returns an error if any of the plugins had an error
38 func RunPluginFnBool(fn string, args ...lua.LValue) (bool, error) {
39         var reterr error
40         retbool := true
41         for _, p := range Plugins {
42                 if !p.IsEnabled() {
43                         continue
44                 }
45                 val, err := p.Call(fn, args...)
46                 if err == ErrNoSuchFunction {
47                         continue
48                 }
49                 if err != nil {
50                         reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
51                         continue
52                 }
53                 if v, ok := val.(lua.LBool); !ok {
54                         reterr = errors.New(p.Name + "." + fn + " should return a boolean")
55                 } else {
56                         retbool = retbool && bool(v)
57                 }
58         }
59         return retbool, reterr
60 }
61
62 type Plugin struct {
63         Name   string        // name of plugin
64         Info   RuntimeFile   // json file containing info
65         Srcs   []RuntimeFile // lua files
66         Loaded bool
67 }
68
69 func (p *Plugin) IsEnabled() bool {
70         if v, ok := GlobalSettings[p.Name]; ok {
71                 return v.(bool)
72         }
73         return true
74 }
75
76 var Plugins []*Plugin
77
78 func (p *Plugin) Load() error {
79         for _, f := range p.Srcs {
80                 if !p.IsEnabled() {
81                         return nil
82                 }
83                 dat, err := f.Data()
84                 if err != nil {
85                         return err
86                 }
87                 err = ulua.LoadFile(p.Name, f.Name(), dat)
88                 if err != nil {
89                         return err
90                 }
91                 p.Loaded = true
92                 if _, ok := GlobalSettings[p.Name]; !ok {
93                         AddOption(p.Name, true)
94                 }
95         }
96         return nil
97 }
98
99 func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
100         plug := ulua.L.GetGlobal(p.Name)
101         luafn := ulua.L.GetField(plug, fn)
102         if luafn == lua.LNil {
103                 return nil, ErrNoSuchFunction
104         }
105         err := ulua.L.CallByParam(lua.P{
106                 Fn:      luafn,
107                 NRet:    1,
108                 Protect: true,
109         }, args...)
110         if err != nil {
111                 return nil, err
112         }
113         ret := ulua.L.Get(-1)
114         ulua.L.Pop(1)
115         return ret, nil
116 }