make repl an engine feature
This commit is contained in:
parent
056f0cf5d5
commit
4a4c8669df
3 changed files with 102 additions and 97 deletions
98
engine/repl.go
Normal file
98
engine/repl.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *Game) REPL(src io.Reader, dst io.Writer, assets fs.FS) error {
|
||||||
|
sc := bufio.NewScanner(src)
|
||||||
|
for sc.Scan() {
|
||||||
|
tok := strings.Split(sc.Text(), " ")
|
||||||
|
if len(tok) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch tok[0] {
|
||||||
|
case "quit":
|
||||||
|
os.Exit(0)
|
||||||
|
case "pause":
|
||||||
|
g.Disable()
|
||||||
|
case "resume", "unpause":
|
||||||
|
g.Enable()
|
||||||
|
case "save":
|
||||||
|
if len(tok) != 2 {
|
||||||
|
fmt.Fprintln(dst, "Usage: save ID")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
id := tok[1]
|
||||||
|
c := g.Component(id)
|
||||||
|
if c == nil {
|
||||||
|
fmt.Fprintf(dst, "Component %q not found\n", id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s, ok := c.(Saver)
|
||||||
|
if !ok {
|
||||||
|
fmt.Fprintf(dst, "Component %q not a Saver (type %T)\n", id, c)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err := s.Save(); err != nil {
|
||||||
|
fmt.Fprintf(dst, "Couldn't save %q: %v\n", id, err)
|
||||||
|
}
|
||||||
|
case "reload":
|
||||||
|
g.Disable()
|
||||||
|
g.Hide()
|
||||||
|
if err := g.Load(assets); err != nil {
|
||||||
|
fmt.Fprintf(dst, "Couldn't load: %v\n", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
g.Prepare()
|
||||||
|
g.Enable()
|
||||||
|
g.Show()
|
||||||
|
case "tree":
|
||||||
|
|
||||||
|
var c interface{} = g
|
||||||
|
if len(tok) == 2 {
|
||||||
|
// subtree
|
||||||
|
id := tok[1]
|
||||||
|
c = g.Component(id)
|
||||||
|
if c == nil {
|
||||||
|
fmt.Fprintf(dst, "Component %q not found\n", id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type item struct {
|
||||||
|
c interface{}
|
||||||
|
depth int
|
||||||
|
}
|
||||||
|
stack := []item{{c, 0}}
|
||||||
|
for len(stack) > 0 {
|
||||||
|
tail := len(stack) - 1
|
||||||
|
x := stack[tail]
|
||||||
|
stack = stack[:tail]
|
||||||
|
c := x.c
|
||||||
|
|
||||||
|
indent := ""
|
||||||
|
if x.depth > 0 {
|
||||||
|
indent = strings.Repeat(" ", x.depth-1) + "↳ "
|
||||||
|
}
|
||||||
|
i, ok := c.(Identifier)
|
||||||
|
if ok {
|
||||||
|
fmt.Fprintf(dst, "%s%T %s\n", indent, c, i.Ident())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(dst, "%s%T\n", indent, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s, ok := c.(Scanner); ok {
|
||||||
|
for _, y := range s.Scan() {
|
||||||
|
stack = append(stack, item{y, x.depth + 1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sc.Err()
|
||||||
|
}
|
Binary file not shown.
99
main.go
99
main.go
|
@ -1,12 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"drjosh.dev/gurgle/engine"
|
"drjosh.dev/gurgle/engine"
|
||||||
"drjosh.dev/gurgle/game"
|
"drjosh.dev/gurgle/game"
|
||||||
|
@ -38,104 +36,13 @@ func main() {
|
||||||
}
|
}
|
||||||
g.Prepare()
|
g.Prepare()
|
||||||
|
|
||||||
|
if runtime.GOOS != "js" {
|
||||||
// Run a repl on the console.
|
// Run a repl on the console.
|
||||||
go repl(g)
|
go g.REPL(os.Stdin, os.Stdout, game.Assets)
|
||||||
|
}
|
||||||
|
|
||||||
// ... while the game also runs
|
// ... while the game also runs
|
||||||
if err := ebiten.RunGame(g); err != nil {
|
if err := ebiten.RunGame(g); err != nil {
|
||||||
log.Fatalf("Game error: %v", err)
|
log.Fatalf("Game error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func repl(g *engine.Game) {
|
|
||||||
if runtime.GOOS == "js" {
|
|
||||||
// can't os.Stdin on js
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sc := bufio.NewScanner(os.Stdin)
|
|
||||||
for sc.Scan() {
|
|
||||||
tok := strings.Split(sc.Text(), " ")
|
|
||||||
if len(tok) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch tok[0] {
|
|
||||||
case "quit":
|
|
||||||
os.Exit(0)
|
|
||||||
case "pause":
|
|
||||||
g.Disable()
|
|
||||||
case "resume", "unpause":
|
|
||||||
g.Enable()
|
|
||||||
case "save":
|
|
||||||
if len(tok) != 2 {
|
|
||||||
log.Print("Usage: save ID")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
id := tok[1]
|
|
||||||
c := g.Component(id)
|
|
||||||
if c == nil {
|
|
||||||
log.Printf("Component %q not found", id)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
s, ok := c.(engine.Saver)
|
|
||||||
if !ok {
|
|
||||||
log.Printf("Component %q not a Saver (type %T)", id, c)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err := s.Save(); err != nil {
|
|
||||||
log.Printf("Couldn't save %q: %v", id, err)
|
|
||||||
}
|
|
||||||
case "reload":
|
|
||||||
g.Disable()
|
|
||||||
g.Hide()
|
|
||||||
if err := g.Load(game.Assets); err != nil {
|
|
||||||
log.Printf("Couldn't load: %v", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
g.Prepare()
|
|
||||||
g.Enable()
|
|
||||||
g.Show()
|
|
||||||
case "tree":
|
|
||||||
var c interface{} = g
|
|
||||||
if len(tok) == 2 {
|
|
||||||
// subtree
|
|
||||||
id := tok[1]
|
|
||||||
c = g.Component(id)
|
|
||||||
if c == nil {
|
|
||||||
log.Printf("Component %q not found", id)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type item struct {
|
|
||||||
c interface{}
|
|
||||||
depth int
|
|
||||||
}
|
|
||||||
stack := []item{{c, 0}}
|
|
||||||
for len(stack) > 0 {
|
|
||||||
tail := len(stack) - 1
|
|
||||||
x := stack[tail]
|
|
||||||
stack = stack[:tail]
|
|
||||||
c := x.c
|
|
||||||
|
|
||||||
indent := ""
|
|
||||||
if x.depth > 0 {
|
|
||||||
indent = strings.Repeat(" ", x.depth-1) + "↳ "
|
|
||||||
}
|
|
||||||
i, ok := c.(engine.Identifier)
|
|
||||||
if ok {
|
|
||||||
log.Printf("%s%T %s", indent, c, i.Ident())
|
|
||||||
} else {
|
|
||||||
log.Printf("%s%T", indent, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s, ok := c.(engine.Scanner); ok {
|
|
||||||
for _, y := range s.Scan() {
|
|
||||||
stack = append(stack, item{y, x.depth + 1})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := sc.Err(); err != nil {
|
|
||||||
log.Fatalf("Couldn't scan stdin: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue