erm/app/darktile/config/lark.go

192 lines
3.7 KiB
Go

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()
}