package config import ( "bytes" "encoding/json" "fmt" "image/color" "log" "github.com/mazznoer/csscolorparser" mjson "go.starlark.net/lib/json" "go.starlark.net/starlark" "go.starlark.net/syntax" ) type Lark struct { t *starlark.Thread g starlark.StringDict } var colorSchemes = map[string]string{"default": `{ "foreground":"#e5dae5", "background":"#151515", "cursorColor2": "#e5dae5", "color0": "#202020", "color8": "#735264", "color1": "#e84f4f", "color9": "#d43131", "color2": "#b8d68c", "color10": "#578d3b", "color3": "#e2a959", "color11": "#f39713", "color4": "#7dc1cf", "color12": "#4e9fb1", "color5": "#9b64fb", "color13": "#7c1ede", "color6": "#6d878d", "color14": "#42717b", "color7": "#dddddd", "color15": "#dddddd" }`} var defaultConfig = fmt.Sprintf(` config = { "title": "tebit", "initialWidth": 600, "startHeight": 600, "font": { "style": "Fira Mono", "size": 12.0, }, } config.update({"colors": json.decode('%s')}) `, compact(colorSchemes["default"])) func NewLark() (*Lark, error) { t := &starlark.Thread{ Name: "config thread", } preConfig := starlark.StringDict{ "json": mjson.Module, "config": starlark.NewDict(0), } gb, err := starlark.ExecFileOptions(syntax.LegacyFileOptions(), t, "preload.star", defaultConfig, preConfig) if err != nil { if evalErr, ok := err.(*starlark.EvalError); ok { log.Fatal(evalErr.Backtrace()) } return nil, err } // TODO: search for config file return &Lark{ t: t, g: gb, }, nil } func Must[T any](value T, err error) T { if err != nil { panic(err) } return value } func Default[T any](x T) func(value T, err error) T { return func(value T, err error) T { if err != nil { return x } return value } } func (l *Lark) Truthy(path ...string) bool { val, err := l.Val(path...) if err != nil { return false } return bool(val.Truth()) } func (l *Lark) Val(path ...string) (starlark.Value, error) { val := l.g["config"].(*starlark.Dict) for idx, item := range path { tmpVal, ok, err := val.Get(starlark.String(item)) if err != nil { return nil, err } if !ok { return nil, ErrNotFound } if len(path)-1 == idx { return tmpVal, nil } val, ok = tmpVal.(*starlark.Dict) if !ok { return nil, ErrWrongType } } return val, nil } func (l *Lark) Float64(path ...string) (float64, error) { val, err := l.Val(path...) if err != nil { return 0, err } str, ok := val.(starlark.Float) if !ok { return 0, ErrWrongType } return float64(str), nil } func (l *Lark) Str(path ...string) (string, error) { val, err := l.Val(path...) if err != nil { return "", err } str, ok := val.(starlark.String) if !ok { return "", ErrWrongType } return str.GoString(), nil } func (l *Lark) Color(path ...string) (color.Color, error) { str, err := l.Str(path...) if err != nil { return nil, err } clor, err := csscolorparser.Parse(str) if err != nil { return nil, err } return clor, nil } func (l *Lark) Font(path ...string) (*Font, error) { // make sure the parent element exists _, err := l.Val(path...) if err != nil { return nil, err } fill := &Font{} if x, err := l.Str(append(path, "family")...); err == nil { fill.Family = x } if x, err := l.Str(append(path, "style")...); err == nil { fill.Style = x } if x, err := l.Float64(append(path, "size")...); err == nil { fill.Size = x } if x, err := l.Float64(append(path, "dpi")...); err == nil { fill.DPI = x } fill.Ligatures = l.Truthy(append(path, "ligatures")...) return fill, nil } func compact(x string) string { dst := &bytes.Buffer{} if err := json.Compact(dst, []byte(x)); err != nil { panic(err) } log.Println(string(dst.String())) return dst.String() }