231 lines
4.6 KiB
Go
231 lines
4.6 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"image/color"
|
|
"log/slog"
|
|
|
|
"github.com/mazznoer/csscolorparser"
|
|
mjson "go.starlark.net/lib/json"
|
|
"go.starlark.net/starlark"
|
|
"go.starlark.net/syntax"
|
|
)
|
|
|
|
type Lark struct {
|
|
t *starlark.Thread
|
|
config *starlark.Dict
|
|
|
|
log *slog.Logger
|
|
}
|
|
|
|
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.update({
|
|
"title": "erm",
|
|
"initial_cols": 120,
|
|
"initial_rows": 24,
|
|
"font": {
|
|
"style": "Fira Mono",
|
|
"size": 12.0,
|
|
},
|
|
})
|
|
config.update({"colors": json.decode('%s')})
|
|
`, compact(colorSchemes["default"]))
|
|
|
|
func NewLark(log *slog.Logger) (*Lark, error) {
|
|
t := &starlark.Thread{
|
|
Name: "config thread",
|
|
}
|
|
config := starlark.NewDict(0)
|
|
|
|
preConfig := starlark.StringDict{
|
|
"json": mjson.Module,
|
|
"config": config,
|
|
}
|
|
_, err := starlark.ExecFileOptions(syntax.LegacyFileOptions(), t, "preload.star", defaultConfig, preConfig)
|
|
if err != nil {
|
|
if evalErr, ok := err.(*starlark.EvalError); ok {
|
|
log.Error("failed to evaluate starlark preload", "trace", evalErr.Backtrace())
|
|
}
|
|
return nil, err
|
|
}
|
|
l := &Lark{
|
|
t: t,
|
|
config: config,
|
|
log: log,
|
|
}
|
|
if err := l.loadConfig(); err != nil {
|
|
log.Error("failed to load config", "err", err)
|
|
}
|
|
log.Info("config", "conf", config)
|
|
return l, nil
|
|
}
|
|
|
|
func (o *Lark) loadConfig() error {
|
|
path, err := getConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
o.log.Info("loading config", "path", path)
|
|
preConfig := starlark.StringDict{
|
|
"json": mjson.Module,
|
|
"config": o.config,
|
|
}
|
|
_, err = starlark.ExecFileOptions(syntax.LegacyFileOptions(), o.t, path, nil, preConfig)
|
|
if err != nil {
|
|
if evalErr, ok := err.(*starlark.EvalError); ok {
|
|
o.log.Error("failed to evaluate starlark config", "path", path, "trace", evalErr.Backtrace())
|
|
}
|
|
return err
|
|
}
|
|
return 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.config
|
|
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) Int(path ...string) (int, error) {
|
|
val, err := l.Val(path...)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
str, ok := val.(starlark.Int)
|
|
if !ok {
|
|
return 0, ErrWrongType
|
|
}
|
|
return int(str.BigInt().Int64()), 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)
|
|
}
|
|
return dst.String()
|
|
}
|