1
0

config.go 5.5 KB

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