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