ichigo/engine/repl.go

146 lines
2.8 KiB
Go
Raw Normal View History

2021-08-26 10:03:11 +10:00
package engine
import (
"bufio"
"fmt"
"io"
"io/fs"
"os"
2021-08-27 15:39:10 +10:00
"reflect"
2021-08-26 10:03:11 +10:00
"strings"
)
2021-08-26 10:06:51 +10:00
// REPL runs a read-evaluate-print-loop. Commands are taken from src and output
// is written to dst. assets is needed for commands like reload.
2021-08-26 10:03:11 +10:00
func (g *Game) REPL(src io.Reader, dst io.Writer, assets fs.FS) error {
2021-08-27 14:30:39 +10:00
const prompt = "game> "
fmt.Fprint(dst, prompt)
2021-08-26 10:03:11 +10:00
sc := bufio.NewScanner(src)
for sc.Scan() {
2021-08-27 13:08:04 +10:00
argv := strings.Split(sc.Text(), " ")
if len(argv) == 0 {
2021-08-26 10:03:11 +10:00
continue
}
2021-08-27 13:08:04 +10:00
switch argv[0] {
2021-08-26 10:03:11 +10:00
case "quit":
os.Exit(0)
case "pause":
g.Disable()
case "resume", "unpause":
g.Enable()
case "save":
2021-08-27 13:08:04 +10:00
g.cmdSave(dst, argv)
2021-08-26 10:03:11 +10:00
case "reload":
2021-08-27 13:08:04 +10:00
g.cmdReload(dst, assets)
2021-08-26 10:03:11 +10:00
case "tree":
2021-08-27 13:08:04 +10:00
g.cmdTree(dst, argv)
2021-08-27 15:39:10 +10:00
case "query":
g.cmdQuery(dst, argv)
2021-08-27 13:08:04 +10:00
}
2021-08-27 14:30:39 +10:00
fmt.Fprint(dst, prompt)
2021-08-27 13:08:04 +10:00
}
return sc.Err()
}
2021-08-26 10:03:11 +10:00
2021-08-27 13:08:04 +10:00
func (g *Game) cmdSave(dst io.Writer, argv []string) {
if len(argv) != 2 {
fmt.Fprintln(dst, "Usage: save ID")
return
}
id := argv[1]
c := g.Component(id)
if c == nil {
fmt.Fprintf(dst, "Component %q not found\n", id)
return
}
s, ok := c.(Saver)
if !ok {
fmt.Fprintf(dst, "Component %q not a Saver (type %T)\n", id, c)
return
}
if err := s.Save(); err != nil {
fmt.Fprintf(dst, "Couldn't save %q: %v\n", id, err)
}
}
func (g *Game) cmdReload(dst io.Writer, assets fs.FS) {
g.Disable()
g.Hide()
2021-08-27 13:56:50 +10:00
if err := g.LoadAndPrepare(assets); err != nil {
2021-08-27 13:08:04 +10:00
fmt.Fprintf(dst, "Couldn't load: %v\n", err)
return
}
g.Enable()
g.Show()
}
2021-08-26 10:03:11 +10:00
2021-08-27 13:08:04 +10:00
func (g *Game) cmdTree(dst io.Writer, argv []string) {
if len(argv) < 1 || len(argv) > 2 {
fmt.Println(dst, "Usage: tree [ID]")
2021-08-28 18:16:36 +10:00
return
2021-08-27 13:08:04 +10:00
}
2021-08-27 15:39:10 +10:00
c := interface{}(g)
2021-08-27 13:08:04 +10:00
if len(argv) == 2 { // subtree
id := argv[1]
c = g.Component(id)
if c == nil {
fmt.Fprintf(dst, "Component %q not found\n", id)
return
}
}
2021-08-27 13:56:50 +10:00
Walk(c, func(c interface{}, p []interface{}) error {
2021-08-27 13:08:04 +10:00
indent := ""
2021-08-27 13:56:50 +10:00
if len(p) > 0 {
indent = strings.Repeat(" ", len(p)-1) + "↳ "
2021-08-27 13:08:04 +10:00
}
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)
}
2021-08-27 13:56:50 +10:00
return nil
})
2021-08-26 10:03:11 +10:00
}
2021-08-27 15:39:10 +10:00
func (g *Game) cmdQuery(dst io.Writer, argv []string) {
if len(argv) < 2 || len(argv) > 3 {
fmt.Fprintln(dst, "Usage: query BEHAVIOUR [ANCESTOR_ID]")
2021-08-28 18:24:26 +10:00
fmt.Fprint(dst, "Behaviours:")
for _, b := range Behaviours {
fmt.Fprintf(dst, " %s", b.Name())
}
2021-08-28 18:16:36 +10:00
return
2021-08-27 15:39:10 +10:00
}
var behav reflect.Type
for _, b := range Behaviours {
if b.Name() == argv[1] {
behav = b
}
}
if behav == nil {
fmt.Fprintf(dst, "Unknown behaviour %q\n", argv[1])
}
2021-08-28 18:14:37 +10:00
ances := g.Ident()
2021-08-27 15:39:10 +10:00
if len(argv) == 3 {
2021-08-28 18:14:37 +10:00
ances = argv[2]
2021-08-27 15:39:10 +10:00
}
x := g.Query(ances, behav)
if len(x) == 0 {
fmt.Fprintln(dst, "No results")
return
}
for _, c := range x {
i, ok := c.(Identifier)
if ok {
fmt.Fprintf(dst, "%T %s\n", c, i.Ident())
} else {
fmt.Fprintf(dst, "%T\n", c)
}
}
}