]> git.lizzy.rs Git - micro.git/blob - internal/config/plugin.go
Merge
[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/v2/internal/lua"
9 )
10
11 // ErrNoSuchFunction is returned when Call is executed on a function that does not exist
12 var ErrNoSuchFunction = errors.New("No such function exists")
13
14 // LoadAllPlugins loads all detected plugins (in runtime/plugins and ConfigDir/plugins)
15 func LoadAllPlugins() error {
16         var reterr error
17         for _, p := range Plugins {
18                 err := p.Load()
19                 if err != nil {
20                         reterr = err
21                 }
22         }
23         return reterr
24 }
25
26 // RunPluginFn runs a given function in all plugins
27 // returns an error if any of the plugins had an error
28 func RunPluginFn(fn string, args ...lua.LValue) error {
29         var reterr error
30         for _, p := range Plugins {
31                 if !p.IsEnabled() {
32                         continue
33                 }
34                 _, err := p.Call(fn, args...)
35                 if err != nil && err != ErrNoSuchFunction {
36                         reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
37                 }
38         }
39         return reterr
40 }
41
42 // RunPluginFnBool runs a function in all plugins and returns
43 // false if any one of them returned false
44 // also returns an error if any of the plugins had an error
45 func RunPluginFnBool(fn string, args ...lua.LValue) (bool, error) {
46         var reterr error
47         retbool := true
48         for _, p := range Plugins {
49                 if !p.IsEnabled() {
50                         continue
51                 }
52                 val, err := p.Call(fn, args...)
53                 if err == ErrNoSuchFunction {
54                         continue
55                 }
56                 if err != nil {
57                         reterr = errors.New("Plugin " + p.Name + ": " + err.Error())
58                         continue
59                 }
60                 if v, ok := val.(lua.LBool); ok {
61                         retbool = retbool && bool(v)
62                 }
63         }
64         return retbool, reterr
65 }
66
67 // Plugin stores information about the source files/info for a plugin
68 type Plugin struct {
69         DirName string        // name of plugin folder
70         Name    string        // name of plugin
71         Info    *PluginInfo   // json file containing info
72         Srcs    []RuntimeFile // lua files
73         Loaded  bool
74         Default bool // pre-installed plugin
75 }
76
77 // IsEnabled returns if a plugin is enabled
78 func (p *Plugin) IsEnabled() bool {
79         if v, ok := GlobalSettings[p.Name]; ok {
80                 return v.(bool) && p.Loaded
81         }
82         return true
83 }
84
85 // Plugins is a list of all detected plugins (enabled or disabled)
86 var Plugins []*Plugin
87
88 // Load creates an option for the plugin and runs all source files
89 func (p *Plugin) Load() error {
90         if v, ok := GlobalSettings[p.Name]; ok && !v.(bool) {
91                 return nil
92         }
93         for _, f := range p.Srcs {
94                 dat, err := f.Data()
95                 if err != nil {
96                         return err
97                 }
98                 err = ulua.LoadFile(p.Name, f.Name(), dat)
99                 if err != nil {
100                         return err
101                 }
102         }
103         p.Loaded = true
104         RegisterGlobalOption(p.Name, true)
105         return nil
106 }
107
108 // Call calls a given function in this plugin
109 func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, error) {
110         plug := ulua.L.GetGlobal(p.Name)
111         if plug == lua.LNil {
112                 log.Println("Plugin does not exist:", p.Name, "at", p.DirName, ":", p)
113                 return nil, nil
114         }
115         luafn := ulua.L.GetField(plug, fn)
116         if luafn == lua.LNil {
117                 return nil, ErrNoSuchFunction
118         }
119         err := ulua.L.CallByParam(lua.P{
120                 Fn:      luafn,
121                 NRet:    1,
122                 Protect: true,
123         }, args...)
124         if err != nil {
125                 return nil, err
126         }
127         ret := ulua.L.Get(-1)
128         ulua.L.Pop(1)
129         return ret, nil
130 }
131
132 // FindPlugin returns the plugin with the given name
133 func FindPlugin(name string) *Plugin {
134         var pl *Plugin
135         for _, p := range Plugins {
136                 if !p.IsEnabled() {
137                         continue
138                 }
139                 if p.Name == name {
140                         pl = p
141                         break
142                 }
143         }
144         return pl
145 }
146
147 // FindAnyPlugin does not require the plugin to be enabled
148 func FindAnyPlugin(name string) *Plugin {
149         var pl *Plugin
150         for _, p := range Plugins {
151                 if p.Name == name {
152                         pl = p
153                         break
154                 }
155         }
156         return pl
157 }