aboutsummaryrefslogtreecommitdiffstats
path: root/plugins.go
diff options
context:
space:
mode:
authorterminaldweller <devi@terminaldweller.com>2024-05-31 21:36:10 +0000
committerterminaldweller <devi@terminaldweller.com>2024-05-31 21:36:10 +0000
commit0e1a3e59bed9b8328d9ee98a0bd0b2cb10bbe229 (patch)
tree2c8213d5de479cc96c36f5318feafcfcdc1e5ecb /plugins.go
parentfixes #30 (diff)
downloadmilla-0e1a3e59bed9b8328d9ee98a0bd0b2cb10bbe229.tar.gz
milla-0e1a3e59bed9b8328d9ee98a0bd0b2cb10bbe229.zip
initial support for lua, WIP
Diffstat (limited to 'plugins.go')
-rw-r--r--plugins.go179
1 files changed, 179 insertions, 0 deletions
diff --git a/plugins.go b/plugins.go
new file mode 100644
index 0000000..d64f65b
--- /dev/null
+++ b/plugins.go
@@ -0,0 +1,179 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "reflect"
+
+ lua "github.com/yuin/gopher-lua"
+)
+
+func registerStrucAsLuaMetaTable[T any](
+ luaState *lua.LState,
+ checkStruct func(luaState *lua.LState) *T,
+ structType T,
+ metaTableName string,
+) {
+ metaTable := luaState.NewTypeMetatable(metaTableName)
+
+ luaState.SetGlobal(metaTableName, metaTable)
+
+ luaState.SetField(
+ metaTable,
+ "new",
+ luaState.NewFunction(
+ newStructFunctionFactory(structType, metaTableName),
+ ),
+ )
+
+ var zero [0]T
+
+ luaState.SetField(
+ metaTable,
+ "__index",
+ luaState.SetFuncs(
+ luaState.NewTable(),
+ luaTableGenFactory(reflect.TypeOf(zero),
+ checkStruct,
+ ),
+ ),
+ )
+}
+
+func newStructFunctionFactory[T any](structType T, metaTableName string) func(*lua.LState) int {
+ return func(luaState *lua.LState) int {
+ structInstance := &structType
+ ud := luaState.NewUserData()
+ ud.Value = structInstance
+ luaState.SetMetatable(ud, luaState.GetTypeMetatable(metaTableName))
+ luaState.Push(ud)
+
+ return 1
+ }
+}
+
+func checkStruct[T any](luaState *lua.LState) *T {
+ userData := luaState.CheckUserData(1)
+ if v, ok := userData.Value.(*T); ok {
+ return v
+ }
+
+ luaState.ArgError(1, "got wrong struct")
+
+ return nil
+}
+
+func getterSetterFactory[T any](
+ fieldName string,
+ fieldType reflect.Type,
+ checkStruct func(luaState *lua.LState) *T,
+) func(*lua.LState) int {
+ return func(luaState *lua.LState) int {
+ genericStruct := checkStruct(luaState)
+
+ structValue := reflect.ValueOf(genericStruct).Elem()
+
+ fieldValue := structValue.FieldByName(fieldName)
+
+ if luaState.GetTop() == 2 { //nolint: mnd,gomnd
+ switch fieldType.Kind() {
+ case reflect.String:
+ fieldValue.SetString(luaState.CheckString(2)) //nolint: mnd,gomnd
+ case reflect.Float64:
+ fieldValue.SetFloat(float64(luaState.CheckNumber(2))) //nolint: mnd,gomnd
+ case reflect.Float32:
+ fieldValue.SetFloat(float64(luaState.CheckNumber(2))) //nolint: mnd,gomnd
+ case reflect.Int8:
+ fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd
+ case reflect.Int16:
+ fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd
+ case reflect.Int:
+ fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd
+ case reflect.Int32:
+ fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd
+ case reflect.Int64:
+ fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd
+ case reflect.Bool:
+ fieldValue.SetBool(luaState.CheckBool(2)) //nolint: mnd,gomnd
+ default:
+ log.Print("unsupported type")
+ }
+
+ return 0
+ }
+
+ switch fieldType.Kind() {
+ case reflect.String:
+ luaState.Push(lua.LString(fieldValue.Interface().(string)))
+ case reflect.Float64:
+ luaState.Push(lua.LNumber(fieldValue.Interface().(float64)))
+ case reflect.Float32:
+ luaState.Push(lua.LNumber(fieldValue.Float()))
+ case reflect.Int8:
+ luaState.Push(lua.LNumber(fieldValue.Int()))
+ case reflect.Int16:
+ luaState.Push(lua.LNumber(fieldValue.Int()))
+ case reflect.Int:
+ luaState.Push(lua.LNumber(fieldValue.Int()))
+ case reflect.Int32:
+ luaState.Push(lua.LNumber(fieldValue.Int()))
+ case reflect.Int64:
+ luaState.Push(lua.LNumber(fieldValue.Int()))
+ case reflect.Bool:
+ luaState.Push(lua.LBool(fieldValue.Bool()))
+ default:
+ log.Print("unsupported type")
+ }
+
+ return 1
+ }
+}
+
+func luaTableGenFactory[T any](
+ structType reflect.Type,
+ checkStructType func(luaState *lua.LState) *T) map[string]lua.LGFunction {
+ tableMethods := make(map[string]lua.LGFunction)
+
+ for _, field := range reflect.VisibleFields(structType) {
+ tableMethods[field.Name] = getterSetterFactory(field.Name, field.Type, checkStructType)
+ }
+
+ return tableMethods
+}
+
+func RegisterCustomLuaTypes(luaState *lua.LState) {
+ registerStrucAsLuaMetaTable(luaState, checkStruct, TomlConfig{}, "toml_config")
+ registerStrucAsLuaMetaTable(luaState, checkStruct, CustomCommand{}, "custom_command")
+}
+
+func returnAllPlugins(pluginPath string) ([]string, error) {
+ pluginList := make([]string, 0)
+
+ files, err := os.ReadDir(pluginPath)
+ if err != nil {
+ return pluginList, fmt.Errorf("Error reading plugins directory: %v", err)
+ }
+
+ for _, file := range files {
+ pluginList = append(pluginList, file.Name())
+ }
+
+ return pluginList, nil
+}
+
+func LoadAllPlugins(appConfig *TomlConfig) {
+ luaState := lua.NewState()
+ defer luaState.Close()
+
+ RegisterCustomLuaTypes(luaState)
+
+ allPlugins, err := returnAllPlugins(appConfig.PluginPath)
+ if err != nil {
+ luaState.Close()
+
+ log.Fatal(err) //nolint: gocritic
+ }
+
+ log.Println(allPlugins)
+}