This commit is contained in:
a 2024-10-21 03:15:19 -05:00
parent f66ea270f9
commit cbdee44734
Signed by: a
GPG Key ID: 374BC539FE795AF0
7 changed files with 178 additions and 117 deletions

View File

@ -7,6 +7,7 @@ import (
"log/slog" "log/slog"
"os" "os"
"anime.bike/slogutil/slogenv"
"gfx.cafe/util/go/fxplus" "gfx.cafe/util/go/fxplus"
"github.com/lmittmann/tint" "github.com/lmittmann/tint"
"go.uber.org/fx" "go.uber.org/fx"
@ -41,7 +42,7 @@ func (r *Term) Run(ctx *Context) error {
func() *slog.Logger { func() *slog.Logger {
return slog.New(tint.NewHandler(os.Stdout, &tint.Options{ return slog.New(tint.NewHandler(os.Stdout, &tint.Options{
AddSource: true, AddSource: true,
Level: slog.LevelInfo.Level(), Level: slogenv.EnvLevel(),
})) }))
}, },
fxplus.Context, fxplus.Context,

View File

@ -5,7 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"image/color" "image/color"
"log" "log/slog"
"github.com/mazznoer/csscolorparser" "github.com/mazznoer/csscolorparser"
mjson "go.starlark.net/lib/json" mjson "go.starlark.net/lib/json"
@ -14,8 +14,10 @@ import (
) )
type Lark struct { type Lark struct {
t *starlark.Thread t *starlark.Thread
g starlark.StringDict config *starlark.Dict
log *slog.Logger
} }
var colorSchemes = map[string]string{"default": `{ var colorSchemes = map[string]string{"default": `{
@ -41,39 +43,65 @@ var colorSchemes = map[string]string{"default": `{
}`} }`}
var defaultConfig = fmt.Sprintf(` var defaultConfig = fmt.Sprintf(`
config = { config.update({
"title": "tebit", "title": "erm",
"initialWidth": 600, "initial_cols": 120,
"startHeight": 600, "initial_rows": 24,
"font": { "font": {
"style": "Fira Mono", "style": "Fira Mono",
"size": 12.0, "size": 12.0,
}, },
} })
config.update({"colors": json.decode('%s')}) config.update({"colors": json.decode('%s')})
`, compact(colorSchemes["default"])) `, compact(colorSchemes["default"]))
func NewLark() (*Lark, error) { func NewLark(log *slog.Logger) (*Lark, error) {
t := &starlark.Thread{ t := &starlark.Thread{
Name: "config thread", Name: "config thread",
} }
config := starlark.NewDict(0)
preConfig := starlark.StringDict{ preConfig := starlark.StringDict{
"json": mjson.Module, "json": mjson.Module,
"config": starlark.NewDict(0), "config": config,
} }
gb, err := starlark.ExecFileOptions(syntax.LegacyFileOptions(), t, "preload.star", defaultConfig, preConfig) _, err := starlark.ExecFileOptions(syntax.LegacyFileOptions(), t, "preload.star", defaultConfig, preConfig)
if err != nil { if err != nil {
if evalErr, ok := err.(*starlark.EvalError); ok { if evalErr, ok := err.(*starlark.EvalError); ok {
log.Fatal(evalErr.Backtrace()) log.Error("failed to evaluate starlark preload", "trace", evalErr.Backtrace())
} }
return nil, err return nil, err
} }
// TODO: search for config file l := &Lark{
return &Lark{ t: t,
t: t, config: config,
g: gb, log: log,
}, nil }
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 { func Must[T any](value T, err error) T {
@ -103,7 +131,7 @@ func (l *Lark) Truthy(path ...string) bool {
} }
func (l *Lark) Val(path ...string) (starlark.Value, error) { func (l *Lark) Val(path ...string) (starlark.Value, error) {
val := l.g["config"].(*starlark.Dict) val := l.config
for idx, item := range path { for idx, item := range path {
tmpVal, ok, err := val.Get(starlark.String(item)) tmpVal, ok, err := val.Get(starlark.String(item))
if err != nil { if err != nil {
@ -135,6 +163,18 @@ func (l *Lark) Float64(path ...string) (float64, error) {
return float64(str), nil 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) { func (l *Lark) Str(path ...string) (string, error) {
val, err := l.Val(path...) val, err := l.Val(path...)
if err != nil { if err != nil {
@ -186,6 +226,5 @@ func compact(x string) string {
if err := json.Compact(dst, []byte(x)); err != nil { if err := json.Compact(dst, []byte(x)); err != nil {
panic(err) panic(err)
} }
log.Println(string(dst.String()))
return dst.String() return dst.String()
} }

View File

@ -54,9 +54,9 @@ const (
) )
func New(terminal *termutil2.Terminal, c *config.Lark, log *slog.Logger) (*GUI, error) { func New(terminal *termutil2.Terminal, c *config.Lark, log *slog.Logger) (*GUI, error) {
g := &GUI{ g := &GUI{
terminal: terminal, terminal: terminal,
size: image.Point{80, 30},
updateChan: make(chan struct{}), updateChan: make(chan struct{}),
fontManager: font.NewManager(), fontManager: font.NewManager(),
activeHinter: -1, activeHinter: -1,
@ -67,21 +67,9 @@ func New(terminal *termutil2.Terminal, c *config.Lark, log *slog.Logger) (*GUI,
theme: termutil.ThemeFromLark(c), theme: termutil.ThemeFromLark(c),
} }
terminal.SetWindowManipulator(NewManipulator(g)) terminal.SetWindowManipulator(NewManipulator(g))
return g, nil
}
func (g *GUI) Run(s fx.Shutdowner) error {
go func() {
if err := g.terminal.Run(g.updateChan, uint16(g.size.X), uint16(g.size.Y)); err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err)
s.Shutdown(fx.ExitCode(1))
}
s.Shutdown(fx.ExitCode(0))
}()
font, err := g.c.Font("font") font, err := g.c.Font("font")
if err != nil { if err != nil {
return err return nil, err
} }
g.log.Info("running gui", "font", font) g.log.Info("running gui", "font", font)
g.fontManager.SetFontByFamilyName(font.Family) g.fontManager.SetFontByFamilyName(font.Family)
@ -93,8 +81,8 @@ func (g *GUI) Run(s fx.Shutdowner) error {
} }
g.fontManager.SetDPI(96) g.fontManager.SetDPI(96)
g.enableLigatures = font.Ligatures g.enableLigatures = font.Ligatures
title := config.Default("erm")(g.c.Str("title"))
ebiten.SetWindowTitle("erm") ebiten.SetWindowTitle(title)
ebiten.SetScreenClearedEveryFrame(true) ebiten.SetScreenClearedEveryFrame(true)
ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled) ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled)
ebiten.SetRunnableOnUnfocused(true) ebiten.SetRunnableOnUnfocused(true)
@ -106,11 +94,39 @@ func (g *GUI) Run(s fx.Shutdowner) error {
ebiten.SetVsyncEnabled(false) ebiten.SetVsyncEnabled(false)
} }
rows := config.Default(128)(g.c.Int("initial_rows"))
cols := config.Default(128)(g.c.Int("initial_cols"))
scale := ebiten.Monitor().DeviceScaleFactor()
w := int(cols * g.fontManager.CharSize().X)
h := int(rows * g.fontManager.CharSize().Y)
initialSize := image.Point{
int(float64(w) * scale), int(float64(h) * scale),
}
g.size = initialSize
ebiten.SetWindowSize(w, h)
return g, nil
}
func (g *GUI) Run(s fx.Shutdowner) error {
rows := config.Default(128)(g.c.Int("initial_rows"))
cols := config.Default(128)(g.c.Int("initial_cols"))
go func() {
if err := g.terminal.Run(g.updateChan, uint16(rows), uint16(cols)); err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err)
s.Shutdown(fx.ExitCode(1))
}
s.Shutdown(fx.ExitCode(0))
}()
title := config.Default("erm")(g.c.Str("title"))
for _, f := range g.startupFuncs { for _, f := range g.startupFuncs {
go f(g) go f(g)
} }
g.log.Info("initial size", "size", g.size)
return ebiten.RunGame(g) return ebiten.RunGameWithOptions(g, &ebiten.RunGameOptions{
X11ClassName: title,
})
} }
func (g *GUI) CellSize() image.Point { func (g *GUI) CellSize() image.Point {

View File

@ -14,8 +14,7 @@ func (g *GUI) Layout(outsideWidth, outsideHeight int) (int, int) {
// Layout provides the terminal gui size in pixels. Required to implement the ebiten interface. // Layout provides the terminal gui size in pixels. Required to implement the ebiten interface.
func (g *GUI) LayoutF(outsideWidth, outsideHeight float64) (float64, float64) { func (g *GUI) LayoutF(outsideWidth, outsideHeight float64) (float64, float64) {
scale := ebiten.Monitor().DeviceScaleFactor()
scale := ebiten.DeviceScaleFactor()
sw, sh := math.Ceil(scale*outsideWidth), math.Ceil(scale*outsideHeight) sw, sh := math.Ceil(scale*outsideWidth), math.Ceil(scale*outsideHeight)
w, h := int(sw), int(sh) w, h := int(sw), int(sh)
@ -43,6 +42,7 @@ func (g *GUI) resize(w, h int) {
defer g.terminal.Unlock() defer g.terminal.Unlock()
if g.terminal.IsRunning() { if g.terminal.IsRunning() {
g.log.Info("terminal resizing", "w", w, "h", h, "rows", rows, "cols", cols)
_ = g.terminal.SetSize(rows, cols) _ = g.terminal.SetSize(rows, cols)
} }
} }

View File

@ -37,7 +37,8 @@ type Terminal struct {
shell string shell string
initialCommand string initialCommand string
log *slog.Logger config *config.Lark
log *slog.Logger
} }
// NewTerminal creates a new terminal instance // NewTerminal creates a new terminal instance
@ -47,6 +48,7 @@ func New(c *config.Lark, log *slog.Logger) *Terminal {
closeChan: make(chan struct{}), closeChan: make(chan struct{}),
theme: ThemeFromLark(c), theme: ThemeFromLark(c),
log: log, log: log,
config: c,
} }
fg := term.theme.DefaultForeground() fg := term.theme.DefaultForeground()
@ -152,6 +154,7 @@ func (t *Terminal) Run(updateChan chan struct{}, rows uint16, cols uint16) error
// Make sure to close the pty at the end. // Make sure to close the pty at the end.
defer func() { _ = t.pty.Close() }() // Best effort. defer func() { _ = t.pty.Close() }() // Best effort.
t.log.Info("terminal started", "rows", rows, "cols", cols)
if err := t.SetSize(rows, cols); err != nil { if err := t.SetSize(rows, cols); err != nil {
return err return err
} }
@ -170,7 +173,8 @@ func (t *Terminal) Run(updateChan chan struct{}, rows uint16, cols uint16) error
t.running = true t.running = true
t.windowManipulator.SetTitle("erm") title := config.Default("erm")(t.config.Str("title"))
t.windowManipulator.SetTitle(title)
if t.initialCommand != "" { if t.initialCommand != "" {
if err := t.WriteToPty([]byte(t.initialCommand)); err != nil { if err := t.WriteToPty([]byte(t.initialCommand)); err != nil {

43
go.mod
View File

@ -1,23 +1,24 @@
module tuxpa.in/t/erm module tuxpa.in/t/erm
go 1.21.3 go 1.22.0
toolchain go1.22.0 toolchain go1.22.5
require ( require (
gfx.cafe/util/go v1.1.0 anime.bike/slogutil v0.0.0-20240603065252-938fd61854c6
github.com/alecthomas/kong v0.7.1 gfx.cafe/util/go v1.14.0
github.com/creack/pty v1.1.12 github.com/alecthomas/kong v1.2.1
github.com/creack/pty v1.1.23
github.com/d-tsuji/clipboard v0.0.3 github.com/d-tsuji/clipboard v0.0.3
github.com/hajimehoshi/ebiten/v2 v2.7.0-alpha.7 github.com/hajimehoshi/ebiten/v2 v2.8.1
github.com/lmittmann/tint v1.0.4 github.com/lmittmann/tint v1.0.5
github.com/mazznoer/csscolorparser v0.1.3 github.com/mazznoer/csscolorparser v0.1.5
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.9.0
go.starlark.net v0.0.0-20240123142251-f86470692795 go.starlark.net v0.0.0-20240925182052-1207426daebd
go.uber.org/fx v1.20.1 go.uber.org/fx v1.23.0
golang.org/x/image v0.15.0 golang.org/x/image v0.21.0
golang.org/x/text v0.14.0 golang.org/x/text v0.19.0
mvdan.cc/xurls v1.1.0 mvdan.cc/xurls v1.1.0
) )
@ -26,21 +27,21 @@ require (
github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843 // indirect github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843 // indirect
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 // indirect github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ebitengine/hideconsole v0.1.1-0.20240128160611-57e7b6b00abd // indirect github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
github.com/ebitengine/purego v0.6.0-alpha.4.0.20240127153756-e7ad88ddfffe // indirect github.com/ebitengine/hideconsole v1.0.0 // indirect
github.com/ebitengine/purego v0.8.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/jezek/xgb v1.1.1 // indirect github.com/jezek/xgb v1.1.1 // indirect
github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 // indirect github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 // indirect
github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 // indirect github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mvdan/xurls v1.1.0 // indirect github.com/mvdan/xurls v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/dig v1.17.1 // indirect go.uber.org/dig v1.18.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

104
go.sum
View File

@ -1,88 +1,88 @@
gfx.cafe/util/go v1.1.0 h1:0zn2DDjC6ervotcRgeqrvZpvFJkJlqYISU+WDjpvFiY= anime.bike/slogutil v0.0.0-20240603065252-938fd61854c6 h1:IwPf+xd2sxj2r4DJGsv0OYmG2Xm5dgUhm6OVrxE4asI=
gfx.cafe/util/go v1.1.0/go.mod h1:1jKv4bpEdBfr5jHw5yqwciUQW6Uztiq9XhVOpwDLUhI= anime.bike/slogutil v0.0.0-20240603065252-938fd61854c6/go.mod h1:iod7Bhpk1ewwZEu/kpUfQs0iR2TuPjiwj0ZtkyHY5ck=
gfx.cafe/util/go v1.14.0 h1:W15T4ZQSraASbl1eNZmF8pEsM435uAEIxTBzx691vRg=
gfx.cafe/util/go v1.14.0/go.mod h1:s6KPm1PUsYFL00XoMOI+Y2iorVPZ+9yBc1WWUjI0n9Y=
git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5 h1:OKeTjZST+/TKvtdA258NXJH+/gIx/xwyZxKrAezNFvk= git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5 h1:OKeTjZST+/TKvtdA258NXJH+/gIx/xwyZxKrAezNFvk=
git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5/go.mod h1:NLdpaBoMQNFqncwP8OVRNWUDw1Kt9XWm3snfT7cXu24= git.wow.st/gmp/clip v0.0.0-20191001134149-1458ba6a7cf5/go.mod h1:NLdpaBoMQNFqncwP8OVRNWUDw1Kt9XWm3snfT7cXu24=
github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843 h1:3iF31c7rp7nGZVDv7YQ+VxOgpipVfPKotLXykjZmwM8= github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843 h1:3iF31c7rp7nGZVDv7YQ+VxOgpipVfPKotLXykjZmwM8=
github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20200324125942-20f126ea2843/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4= github.com/alecthomas/kong v1.2.1 h1:E8jH4Tsgv6wCRX2nGrdPyHDUCSG83WH2qE4XLACD33Q=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= github.com/alecthomas/kong v1.2.1/go.mod h1:rKTSFhbdp3Ryefn8x5MOEprnRFQ7nlmMC01GKhehhBM=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4= github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/creack/pty v1.1.12 h1:2QLiUCEbsI13vUyWH6026g0o4u7vxgg2hLUc+D7FPFU= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0=
github.com/creack/pty v1.1.12/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/d-tsuji/clipboard v0.0.3 h1:ceGmYEF+uiuSZXnAfMu56DDZaSN+SgM2+3OHrNy0ABY= github.com/d-tsuji/clipboard v0.0.3 h1:ceGmYEF+uiuSZXnAfMu56DDZaSN+SgM2+3OHrNy0ABY=
github.com/d-tsuji/clipboard v0.0.3/go.mod h1:hF88aLYx9LHNUFRrT6KPRkXEUm34nqP97IFgORGBRFs= github.com/d-tsuji/clipboard v0.0.3/go.mod h1:hF88aLYx9LHNUFRrT6KPRkXEUm34nqP97IFgORGBRFs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ebitengine/hideconsole v0.1.1-0.20240128160611-57e7b6b00abd h1:ZOUjLrx0thTZUs43SlHbC/SnLX1ApeCV3S+wElVZfjE= github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
github.com/ebitengine/hideconsole v0.1.1-0.20240128160611-57e7b6b00abd/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
github.com/ebitengine/purego v0.6.0-alpha.4.0.20240127153756-e7ad88ddfffe h1:bac7sG+vDG+mBmjElwI0p1a2L09rxkY8xcmv5QEFyGA= github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
github.com/ebitengine/purego v0.6.0-alpha.4.0.20240127153756-e7ad88ddfffe/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hajimehoshi/bitmapfont/v3 v3.0.0 h1:r2+6gYK38nfztS/et50gHAswb9hXgxXECYgE8Nczmi4= github.com/hajimehoshi/bitmapfont/v3 v3.2.0 h1:0DISQM/rseKIJhdF29AkhvdzIULqNIIlXAGWit4ez1Q=
github.com/hajimehoshi/bitmapfont/v3 v3.0.0/go.mod h1:+CxxG+uMmgU4mI2poq944i3uZ6UYFfAkj9V6WqmuvZA= github.com/hajimehoshi/bitmapfont/v3 v3.2.0/go.mod h1:8gLqGatKVu0pwcNCJguW3Igg9WQqVXF0zg/RvrGQWyg=
github.com/hajimehoshi/ebiten/v2 v2.7.0-alpha.7 h1:RnopmjZT7Nh0FWpwS1pH9oBLYGT+DOoRNp9Sr2gjhVU= github.com/hajimehoshi/ebiten/v2 v2.8.1 h1:6n6ZXnbeSCZccdqrH7s9Ut+dll9TEostUqbc72Tis/g=
github.com/hajimehoshi/ebiten/v2 v2.7.0-alpha.7/go.mod h1:1Lvt+5rJa8DW8zzEP+1XrnpXQpSWPn/Hk7KjNXmHfq0= github.com/hajimehoshi/ebiten/v2 v2.8.1/go.mod h1:SXx/whkvpfsavGo6lvZykprerakl+8Uo1X8d2U5aAnA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= github.com/lmittmann/tint v1.0.5 h1:NQclAutOfYsqs2F1Lenue6OoWCajs5wJcP3DfWVpePw=
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/lmittmann/tint v1.0.5/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 h1:/QwQcwWVOQXcoNuV9tHx30gQ3q7jCE/rKcGjwzsa5tg= github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1 h1:/QwQcwWVOQXcoNuV9tHx30gQ3q7jCE/rKcGjwzsa5tg=
github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/walk v0.0.0-20191128110447-55ccb3a9f5c1/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 h1:5BmtGkQbch91lglMHQ9JIDGiYCL3kBRBA0ItZTvOcEI= github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4 h1:5BmtGkQbch91lglMHQ9JIDGiYCL3kBRBA0ItZTvOcEI=
github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= github.com/lxn/win v0.0.0-20191128105842-2da648fda5b4/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA=
github.com/mazznoer/csscolorparser v0.1.3 h1:vug4zh6loQxAUxfU1DZEu70gTPufDPspamZlHAkKcxE= github.com/mazznoer/csscolorparser v0.1.5 h1:Wr4uNIE+pHWN3TqZn2SGpA2nLRG064gB7WdSfSS5cz4=
github.com/mazznoer/csscolorparser v0.1.3/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic= github.com/mazznoer/csscolorparser v0.1.5/go.mod h1:OQRVvgCyHDCAquR1YWfSwwaDcM0LhnSffGnlbOew/3I=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww= github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww=
github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.starlark.net v0.0.0-20240123142251-f86470692795 h1:LmbG8Pq7KDGkglKVn8VpZOZj6vb9b8nKEGcg9l03epM= go.starlark.net v0.0.0-20240925182052-1207426daebd h1:S+EMisJOHklQxnS3kqsY8jl2y5aF0FDEdcLnOw3q22E=
go.starlark.net v0.0.0-20240123142251-f86470692795/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= go.starlark.net v0.0.0-20240925182052-1207426daebd/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg=
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU=
go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3 h1:tImqKNm/Iclm3Rqb6GffLiURSp3m1iRx/C4mturH8Ys= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/exp/shiny v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b h1:kfWLZgb8iUBHdE9WydD5V5dHIS/F6HjlBZNyJfn2bs4=
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b/go.mod h1:4efzQnuA1nICq6h4kmZRMGzbPiP06lZvgADUu1VpJCE=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc=
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=