config.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package extension
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "moose/internal/editor"
  7. "github.com/creasty/defaults"
  8. "github.com/gdamore/tcell/v3"
  9. lua "github.com/yuin/gopher-lua"
  10. )
  11. type Config struct {
  12. StyleDefault tcell.Style
  13. Colors Colors
  14. Properties Properties
  15. }
  16. type Properties struct {
  17. GutterWidth int `default:"4"`
  18. TabSpaces bool `default:"false"`
  19. TabWidthSpaces int `default:"4"`
  20. }
  21. type Colors struct {
  22. MainBackground string `default:"#0E142E"`
  23. MainForeground string `default:"#dddddd"`
  24. LineNumberBackground string `default:"#090603"`
  25. LineNumberForeground string `default:"#dddddd"`
  26. CursorColor string `default:"#777777"`
  27. CursorColorWrite string `default:"#dddddd"`
  28. PaletteBarBackground string `default:"#3b3b3b"`
  29. PaletteBarForeground string `default:"#dddddd"`
  30. PaletteInputBackground string `default:"#090603"`
  31. PaletteInputForeground string `default:"#dddddd"`
  32. InfoMsgBackground string `default:"#090603"`
  33. InfoMsgForeground string `default:"#dddddd"`
  34. WarnMsgBackground string `default:"#090603"`
  35. WarnMsgForeground string `default:"#efc541"`
  36. ErrorMsgBackground string `default:"#090603"`
  37. ErrorMsgForeground string `default:"#ff5e56"`
  38. WorkspaceBackground string `default:"#3b3b3b"`
  39. WorkspaceForeground string `default:"#b9b9b9"`
  40. WorkspaceBackgroundActive string `default:"#dddddd"`
  41. WorkspaceForegroundActive string `default:"#3b3b3b"`
  42. TabBackground string `default:"#3b3b3b"`
  43. TabForeground string `default:"#b9b9b9"`
  44. TabBackgroundActive string `default:"#3b3b3b"`
  45. TabForegroundActive string `default:"#dddddd"`
  46. }
  47. func DefaultConfig() Config {
  48. config := Config{}
  49. if err := defaults.Set(&config); err != nil {
  50. panic(err)
  51. }
  52. config.StyleDefault = tcell.StyleDefault.Background(tcell.GetColor(config.Colors.MainBackground)).Foreground(tcell.GetColor(config.Colors.MainForeground))
  53. return config
  54. }
  55. func snakeToCamel(s string) string {
  56. parts := strings.Split(strings.ToLower(s), "_")
  57. for i, part := range parts {
  58. if part == "" {
  59. continue
  60. }
  61. parts[i] = strings.ToUpper(part[:1]) + part[1:]
  62. }
  63. return strings.Join(parts, "")
  64. }
  65. func parseStructTable(dst any, table *lua.LTable) error {
  66. if err := defaults.Set(dst); err != nil {
  67. return err
  68. }
  69. val := reflect.ValueOf(dst)
  70. if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
  71. return fmt.Errorf("dst must be a pointer to struct")
  72. }
  73. val = val.Elem()
  74. typ := val.Type()
  75. for i := 0; i < val.NumField(); i++ {
  76. fieldVal := val.Field(i)
  77. fieldType := typ.Field(i)
  78. luaValue := table.RawGetString(fieldType.Name)
  79. if luaValue == lua.LNil {
  80. continue
  81. }
  82. switch fieldVal.Kind() {
  83. case reflect.String:
  84. if v, ok := luaValue.(lua.LString); ok {
  85. fieldVal.SetString(string(v))
  86. }
  87. case reflect.Bool:
  88. if v, ok := luaValue.(lua.LBool); ok {
  89. fieldVal.SetBool(bool(v))
  90. }
  91. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  92. if v, ok := luaValue.(lua.LNumber); ok {
  93. fieldVal.SetInt(int64(v))
  94. }
  95. case reflect.Float32, reflect.Float64:
  96. if v, ok := luaValue.(lua.LNumber); ok {
  97. fieldVal.SetFloat(float64(v))
  98. }
  99. case reflect.Struct:
  100. if tbl, ok := luaValue.(*lua.LTable); ok {
  101. nested := fieldVal.Addr().Interface()
  102. if err := parseStructTable(nested, tbl); err != nil {
  103. return err
  104. }
  105. }
  106. }
  107. }
  108. return nil
  109. }
  110. func parseColors(table *lua.LTable) (editor.Colors, error) {
  111. var colors editor.Colors
  112. err := parseStructTable(&colors, table)
  113. return colors, err
  114. }
  115. func parseProperties(table *lua.LTable) (editor.Properties, error) {
  116. var properties editor.Properties
  117. err := parseStructTable(&properties, table)
  118. return properties, err
  119. }
  120. func HandleSet(em *ExtensionManager, L *lua.LState) int {
  121. key := L.CheckString(1)
  122. switch key {
  123. case "colors":
  124. luaTable := L.CheckTable(2)
  125. colors, err := parseColors(luaTable)
  126. if err != nil {
  127. L.RaiseError(err.Error())
  128. return 0
  129. }
  130. em.M.Config.Colors = colors
  131. em.M.ReloadConfig()
  132. return 0
  133. case "properties":
  134. luaTable := L.CheckTable(2)
  135. properties, err := parseProperties(luaTable)
  136. if err != nil {
  137. L.RaiseError(err.Error())
  138. return 0
  139. }
  140. em.M.Config.Properties = properties
  141. em.M.ReloadConfig()
  142. return 0
  143. default:
  144. fieldName := snakeToCamel(key)
  145. cfgVal := reflect.ValueOf(&em.M.Config).Elem()
  146. propsVal := cfgVal.FieldByName("Properties")
  147. if propsVal.IsValid() {
  148. field := propsVal.FieldByName(fieldName)
  149. if field.IsValid() && field.CanSet() {
  150. value := L.CheckAny(2)
  151. switch field.Kind() {
  152. case reflect.String:
  153. if v, ok := value.(lua.LString); ok {
  154. field.SetString(string(v))
  155. em.M.ReloadConfig()
  156. return 0
  157. }
  158. case reflect.Bool:
  159. if v, ok := value.(lua.LBool); ok {
  160. field.SetBool(bool(v))
  161. em.M.ReloadConfig()
  162. return 0
  163. }
  164. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  165. if v, ok := value.(lua.LNumber); ok {
  166. field.SetInt(int64(v))
  167. em.M.ReloadConfig()
  168. return 0
  169. }
  170. case reflect.Float32, reflect.Float64:
  171. if v, ok := value.(lua.LNumber); ok {
  172. field.SetFloat(float64(v))
  173. em.M.ReloadConfig()
  174. return 0
  175. }
  176. }
  177. }
  178. }
  179. L.RaiseError("unknown config key: %s", key)
  180. return 0
  181. }
  182. }
  183. func GetConfigTable(em *ExtensionManager) *lua.LTable {
  184. config := em.L.NewTable()
  185. em.L.SetFuncs(config, map[string]lua.LGFunction{
  186. "set": func(L *lua.LState) int {
  187. return HandleSet(em, L)
  188. },
  189. "reload": func(L *lua.LState) int {
  190. em.M.ReloadConfig()
  191. return 0
  192. },
  193. })
  194. return config
  195. }