9 "github.com/yuin/gopher-lua"
10 "github.com/zyedidia/tcell"
11 "layeh.com/gopher-luar"
14 var loadedPlugins map[string]string
16 // Call calls the lua function 'function'
17 // If it does not exist nothing happens, if there is an error,
18 // the error is returned
19 func Call(function string, args ...interface{}) (lua.LValue, error) {
20 var luaFunc lua.LValue
21 if strings.Contains(function, ".") {
22 plugin := L.GetGlobal(strings.Split(function, ".")[0])
23 if plugin.String() == "nil" {
24 return nil, errors.New("function does not exist: " + function)
26 luaFunc = L.GetField(plugin, strings.Split(function, ".")[1])
28 luaFunc = L.GetGlobal(function)
31 if luaFunc.String() == "nil" {
32 return nil, errors.New("function does not exist: " + function)
34 var luaArgs []lua.LValue
35 for _, v := range args {
36 luaArgs = append(luaArgs, luar.New(L, v))
38 err := L.CallByParam(lua.P{
43 ret := L.Get(-1) // returned value
44 if ret.String() != "nil" {
45 L.Pop(1) // remove received value
50 // LuaFunctionBinding is a function generator which takes the name of a lua function
51 // and creates a function that will call that lua function
52 // Specifically it creates a function that can be called as a binding because this is used
53 // to bind keys to lua functions
54 func LuaFunctionBinding(function string) func(*View, bool) bool {
55 return func(v *View, _ bool) bool {
56 _, err := Call(function, nil)
64 // LuaFunctionMouseBinding is a function generator which takes the name of a lua function
65 // and creates a function that will call that lua function
66 // Specifically it creates a function that can be called as a mouse binding because this is used
67 // to bind mouse actions to lua functions
68 func LuaFunctionMouseBinding(function string) func(*View, bool, *tcell.EventMouse) bool {
69 return func(v *View, _ bool, e *tcell.EventMouse) bool {
70 _, err := Call(function, e)
78 func unpack(old []string) []interface{} {
79 new := make([]interface{}, len(old))
80 for i, v := range old {
86 // LuaFunctionCommand is the same as LuaFunctionBinding except it returns a normal function
87 // so that a command can be bound to a lua function
88 func LuaFunctionCommand(function string) func([]string) {
89 return func(args []string) {
90 _, err := Call(function, unpack(args)...)
97 // LuaFunctionComplete returns a function which can be used for autocomplete in plugins
98 func LuaFunctionComplete(function string) func(string) []string {
99 return func(input string) (result []string) {
101 res, err := Call(function, input)
105 if tbl, ok := res.(*lua.LTable); !ok {
106 TermMessage(function, "should return a table of strings")
108 for i := 1; i <= tbl.Len(); i++ {
109 val := tbl.RawGetInt(i)
110 if v, ok := val.(lua.LString); !ok {
111 TermMessage(function, "should return a table of strings")
113 result = append(result, string(v))
121 // LuaFunctionJob returns a function that will call the given lua function
122 // structured as a job call i.e. the job output and arguments are provided
123 // to the lua function
124 func LuaFunctionJob(function string) func(string, ...string) {
125 return func(output string, args ...string) {
126 _, err := Call(function, unpack(append([]string{output}, args...))...)
127 if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
133 // luaPluginName convert a human-friendly plugin name into a valid lua variable name.
134 func luaPluginName(name string) string {
135 return strings.Replace(name, "-", "_", -1)
138 // LoadPlugins loads the pre-installed plugins and the plugins located in ~/.config/micro/plugins
140 loadedPlugins = make(map[string]string)
142 for _, plugin := range ListRuntimeFiles(RTPlugin) {
143 pluginName := plugin.Name()
144 if _, ok := loadedPlugins[pluginName]; ok {
148 data, err := plugin.Data()
150 TermMessage("Error loading plugin: " + pluginName)
154 pluginLuaName := luaPluginName(pluginName)
156 if err := LoadFile(pluginLuaName, pluginLuaName, string(data)); err != nil {
161 loadedPlugins[pluginName] = pluginLuaName
165 if _, err := os.Stat(configDir + "/init.lua"); err == nil {
166 data, _ := ioutil.ReadFile(configDir + "/init.lua")
167 if err := LoadFile("init", configDir+"init.lua", string(data)); err != nil {
170 loadedPlugins["init"] = "init"
174 // GlobalCall makes a call to a function in every plugin that is currently
176 func GlobalPluginCall(function string, args ...interface{}) {
177 for pl := range loadedPlugins {
178 _, err := Call(pl+"."+function, args...)
179 if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {