config.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package editor
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "moose/internal/highlight"
  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. var DefaultTheme = highlight.StyleMap{
  48. "keyword": tcell.StyleDefault.Foreground(tcell.GetColor("#c678dd")).Bold(true),
  49. "keyword.function": tcell.StyleDefault.Foreground(tcell.GetColor("#c678dd")).Bold(true),
  50. "keyword.modifier": tcell.StyleDefault.Foreground(tcell.GetColor("#c678dd")),
  51. "string": tcell.StyleDefault.Foreground(tcell.GetColor("#98c379")),
  52. "string.escape": tcell.StyleDefault.Foreground(tcell.GetColor("#56b6c2")),
  53. "comment": tcell.StyleDefault.Foreground(tcell.GetColor("#5c6370")).Italic(true),
  54. "function": tcell.StyleDefault.Foreground(tcell.GetColor("#61afef")),
  55. "function.method": tcell.StyleDefault.Foreground(tcell.GetColor("#61afef")),
  56. "variable": tcell.StyleDefault.Foreground(tcell.GetColor("#abb2bf")),
  57. "variable.builtin": tcell.StyleDefault.Foreground(tcell.GetColor("#e5c07b")),
  58. "variable.parameter": tcell.StyleDefault.Foreground(tcell.GetColor("#e06c75")),
  59. "property": tcell.StyleDefault.Foreground(tcell.GetColor("#e06c75")),
  60. "number": tcell.StyleDefault.Foreground(tcell.GetColor("#d19a66")),
  61. "constant.builtin": tcell.StyleDefault.Foreground(tcell.GetColor("#d19a66")),
  62. "module": tcell.StyleDefault.Foreground(tcell.GetColor("#e5c07b")),
  63. "operator": tcell.StyleDefault.Foreground(tcell.GetColor("#56b6c2")),
  64. }
  65. func DefaultConfig() Config {
  66. config := Config{}
  67. if err := defaults.Set(&config); err != nil {
  68. panic(err)
  69. }
  70. config.StyleDefault = tcell.StyleDefault.Background(tcell.GetColor(config.Colors.MainBackground)).Foreground(tcell.GetColor(config.Colors.MainForeground))
  71. return config
  72. }
  73. func snakeToCamel(s string) string {
  74. parts := strings.Split(strings.ToLower(s), "_")
  75. for i, part := range parts {
  76. if part == "" {
  77. continue
  78. }
  79. parts[i] = strings.ToUpper(part[:1]) + part[1:]
  80. }
  81. return strings.Join(parts, "")
  82. }
  83. func parseStructTable(dst any, table *lua.LTable) error {
  84. if err := defaults.Set(dst); err != nil {
  85. return err
  86. }
  87. val := reflect.ValueOf(dst)
  88. if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
  89. return fmt.Errorf("dst must be a pointer to struct")
  90. }
  91. val = val.Elem()
  92. typ := val.Type()
  93. for i := 0; i < val.NumField(); i++ {
  94. fieldVal := val.Field(i)
  95. fieldType := typ.Field(i)
  96. luaValue := table.RawGetString(fieldType.Name)
  97. if luaValue == lua.LNil {
  98. continue
  99. }
  100. switch fieldVal.Kind() {
  101. case reflect.String:
  102. if v, ok := luaValue.(lua.LString); ok {
  103. fieldVal.SetString(string(v))
  104. }
  105. case reflect.Bool:
  106. if v, ok := luaValue.(lua.LBool); ok {
  107. fieldVal.SetBool(bool(v))
  108. }
  109. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  110. if v, ok := luaValue.(lua.LNumber); ok {
  111. fieldVal.SetInt(int64(v))
  112. }
  113. case reflect.Float32, reflect.Float64:
  114. if v, ok := luaValue.(lua.LNumber); ok {
  115. fieldVal.SetFloat(float64(v))
  116. }
  117. case reflect.Struct:
  118. if tbl, ok := luaValue.(*lua.LTable); ok {
  119. nested := fieldVal.Addr().Interface()
  120. if err := parseStructTable(nested, tbl); err != nil {
  121. return err
  122. }
  123. }
  124. }
  125. }
  126. return nil
  127. }
  128. func parseColors(table *lua.LTable) (Colors, error) {
  129. var colors Colors
  130. err := parseStructTable(&colors, table)
  131. return colors, err
  132. }
  133. func parseProperties(table *lua.LTable) (Properties, error) {
  134. var properties Properties
  135. err := parseStructTable(&properties, table)
  136. return properties, err
  137. }
  138. func HandleSet(em *ExtensionManager, L *lua.LState) int {
  139. key := L.CheckString(1)
  140. switch key {
  141. case "colors":
  142. luaTable := L.CheckTable(2)
  143. colors, err := parseColors(luaTable)
  144. if err != nil {
  145. L.RaiseError("%s", err.Error())
  146. return 0
  147. }
  148. em.M.Config.Colors = colors
  149. em.M.ReloadConfig()
  150. return 0
  151. case "properties":
  152. luaTable := L.CheckTable(2)
  153. properties, err := parseProperties(luaTable)
  154. if err != nil {
  155. L.RaiseError("%s", err.Error())
  156. return 0
  157. }
  158. em.M.Config.Properties = properties
  159. em.M.ReloadConfig()
  160. return 0
  161. default:
  162. fieldName := snakeToCamel(key)
  163. cfgVal := reflect.ValueOf(&em.M.Config).Elem()
  164. propsVal := cfgVal.FieldByName("Properties")
  165. if propsVal.IsValid() {
  166. field := propsVal.FieldByName(fieldName)
  167. if field.IsValid() && field.CanSet() {
  168. value := L.CheckAny(2)
  169. switch field.Kind() {
  170. case reflect.String:
  171. if v, ok := value.(lua.LString); ok {
  172. field.SetString(string(v))
  173. em.M.ReloadConfig()
  174. return 0
  175. }
  176. case reflect.Bool:
  177. if v, ok := value.(lua.LBool); ok {
  178. field.SetBool(bool(v))
  179. em.M.ReloadConfig()
  180. return 0
  181. }
  182. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  183. if v, ok := value.(lua.LNumber); ok {
  184. field.SetInt(int64(v))
  185. em.M.ReloadConfig()
  186. return 0
  187. }
  188. case reflect.Float32, reflect.Float64:
  189. if v, ok := value.(lua.LNumber); ok {
  190. field.SetFloat(float64(v))
  191. em.M.ReloadConfig()
  192. return 0
  193. }
  194. }
  195. }
  196. }
  197. L.RaiseError("unknown config key: %s", key)
  198. return 0
  199. }
  200. }
  201. func GetConfigTable(em *ExtensionManager) *lua.LTable {
  202. config := em.L.NewTable()
  203. em.L.SetFuncs(config, map[string]lua.LGFunction{
  204. "set": func(L *lua.LState) int {
  205. return HandleSet(em, L)
  206. },
  207. "reload": func(L *lua.LState) int {
  208. em.M.ReloadConfig()
  209. return 0
  210. },
  211. })
  212. return config
  213. }