config.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package extension
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "moose/internal/editor"
  7. "github.com/creasty/defaults"
  8. lua "github.com/yuin/gopher-lua"
  9. )
  10. func snakeToCamel(s string) string {
  11. parts := strings.Split(strings.ToLower(s), "_")
  12. for i, part := range parts {
  13. if part == "" {
  14. continue
  15. }
  16. parts[i] = strings.ToUpper(part[:1]) + part[1:]
  17. }
  18. return strings.Join(parts, "")
  19. }
  20. func parseStructTable(dst any, table *lua.LTable) error {
  21. if err := defaults.Set(dst); err != nil {
  22. return err
  23. }
  24. val := reflect.ValueOf(dst)
  25. if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
  26. return fmt.Errorf("dst must be a pointer to struct")
  27. }
  28. val = val.Elem()
  29. typ := val.Type()
  30. for i := 0; i < val.NumField(); i++ {
  31. fieldVal := val.Field(i)
  32. fieldType := typ.Field(i)
  33. luaValue := table.RawGetString(fieldType.Name)
  34. if luaValue == lua.LNil {
  35. continue
  36. }
  37. switch fieldVal.Kind() {
  38. case reflect.String:
  39. if v, ok := luaValue.(lua.LString); ok {
  40. fieldVal.SetString(string(v))
  41. }
  42. case reflect.Bool:
  43. if v, ok := luaValue.(lua.LBool); ok {
  44. fieldVal.SetBool(bool(v))
  45. }
  46. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  47. if v, ok := luaValue.(lua.LNumber); ok {
  48. fieldVal.SetInt(int64(v))
  49. }
  50. case reflect.Float32, reflect.Float64:
  51. if v, ok := luaValue.(lua.LNumber); ok {
  52. fieldVal.SetFloat(float64(v))
  53. }
  54. case reflect.Struct:
  55. if tbl, ok := luaValue.(*lua.LTable); ok {
  56. nested := fieldVal.Addr().Interface()
  57. if err := parseStructTable(nested, tbl); err != nil {
  58. return err
  59. }
  60. }
  61. }
  62. }
  63. return nil
  64. }
  65. func parseColors(table *lua.LTable) (editor.Colors, error) {
  66. var colors editor.Colors
  67. err := parseStructTable(&colors, table)
  68. return colors, err
  69. }
  70. func parseProperties(table *lua.LTable) (editor.Properties, error) {
  71. var properties editor.Properties
  72. err := parseStructTable(&properties, table)
  73. return properties, err
  74. }
  75. func HandleSet(em *ExtensionManager, L *lua.LState) int {
  76. key := L.CheckString(1)
  77. switch key {
  78. case "colors":
  79. luaTable := L.CheckTable(2)
  80. colors, err := parseColors(luaTable)
  81. if err != nil {
  82. L.RaiseError(err.Error())
  83. return 0
  84. }
  85. em.M.Config.Colors = colors
  86. em.M.ReloadConfig()
  87. return 0
  88. case "properties":
  89. luaTable := L.CheckTable(2)
  90. properties, err := parseProperties(luaTable)
  91. if err != nil {
  92. L.RaiseError(err.Error())
  93. return 0
  94. }
  95. em.M.Config.Properties = properties
  96. em.M.ReloadConfig()
  97. return 0
  98. default:
  99. fieldName := snakeToCamel(key)
  100. cfgVal := reflect.ValueOf(&em.M.Config).Elem()
  101. propsVal := cfgVal.FieldByName("Properties")
  102. if propsVal.IsValid() {
  103. field := propsVal.FieldByName(fieldName)
  104. if field.IsValid() && field.CanSet() {
  105. value := L.CheckAny(2)
  106. switch field.Kind() {
  107. case reflect.String:
  108. if v, ok := value.(lua.LString); ok {
  109. field.SetString(string(v))
  110. em.M.ReloadConfig()
  111. return 0
  112. }
  113. case reflect.Bool:
  114. if v, ok := value.(lua.LBool); ok {
  115. field.SetBool(bool(v))
  116. em.M.ReloadConfig()
  117. return 0
  118. }
  119. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  120. if v, ok := value.(lua.LNumber); ok {
  121. field.SetInt(int64(v))
  122. em.M.ReloadConfig()
  123. return 0
  124. }
  125. case reflect.Float32, reflect.Float64:
  126. if v, ok := value.(lua.LNumber); ok {
  127. field.SetFloat(float64(v))
  128. em.M.ReloadConfig()
  129. return 0
  130. }
  131. }
  132. }
  133. }
  134. L.RaiseError("unknown config key: %s", key)
  135. return 0
  136. }
  137. }
  138. func GetConfigTable(em *ExtensionManager) *lua.LTable {
  139. config := em.L.NewTable()
  140. em.L.SetFuncs(config, map[string]lua.LGFunction{
  141. "set": func(L *lua.LState) int {
  142. return HandleSet(em, L)
  143. },
  144. "reload": func(L *lua.LState) int {
  145. em.M.ReloadConfig()
  146. return 0
  147. },
  148. })
  149. return config
  150. }