Skip to content

Instantly share code, notes, and snippets.

@tiborvass
Last active January 17, 2020 16:04
Show Gist options
  • Save tiborvass/78a400028bab4fa5b423f100b1e0eee1 to your computer and use it in GitHub Desktop.
Save tiborvass/78a400028bab4fa5b423f100b1e0eee1 to your computer and use it in GitHub Desktop.
Script to show fake demos with monkey typing: go run demo.go path/to/textfile [number_of_steps_to_skip]
package main
import (
"bufio"
"fmt"
"io"
"log"
"math/rand"
"os"
"os/exec"
"strconv"
"strings"
"time"
term "github.com/nsf/termbox-go"
)
func main() {
if len(os.Args) > 2 {
i, err := strconv.Atoi(os.Args[2])
if err != nil {
log.Fatal(err)
}
stepsToSkip = i
}
var f *os.File
var err error
if len(os.Args) > 1 {
f, err = os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
if err := term.Init(); err != nil {
panic(err)
}
defer term.Close()
defer func() {
if x := recover(); x != nil {
if _, ok := x.(exit); ok {
return
}
panic(x)
}
}()
if err := read(f); err != nil {
log.Fatal(err)
}
}
type mode int
const (
modeNormal mode = iota
modeType
modeExec
modeANSI
)
type printer struct {
mode mode
}
func read(f io.Reader) error {
// show cursor
os.Stdout.Write(append([]byte{27}, []byte("[?25h")...))
s := bufio.NewScanner(f)
p := &printer{}
for s.Scan() {
t := s.Text()
p.print(t)
}
return s.Err()
}
func ansi(s string) mode {
os.Stdout.Write([]byte{27})
os.Stdout.WriteString(s)
return modeANSI
}
func (p *printer) print(t string) {
if len(t) > 0 {
switch p.mode {
case modeNormal:
if i := strings.Index(t, "#{{"); i >= 0 {
fmt.Print(t[:i])
//pause()
t = t[i+3:]
j := strings.Index(t, ":")
if j < 0 {
panic("could not find ':' in #{{...}}")
}
switch t[:j] {
case "ansi":
k := strings.Index(t[j+1:], "}}")
if j < 0 {
panic("wtf")
}
p.mode = ansi(t[j+1 : j+1+k])
t = t[j+1+k:]
p.print(t)
return
case "underline":
p.mode = ansi("[4m")
case "reverse":
p.mode = ansi("[7m")
case "bold":
p.mode = ansi("[1m")
case "darkgrey":
p.mode = ansi("[38;5;236m")
case "exec":
p.mode = modeExec
case "type":
p.mode = modeType
}
t = t[j+1:]
p.print(t)
return
} else {
fmt.Print(t)
}
case modeType, modeExec:
if i := strings.Index(t, "}}"); i >= 0 {
if p.mode == modeExec {
if counter >= stepsToSkip {
cmd := exec.Command("sh", "-c", t[:i])
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
} else {
slowprint(t[:i])
}
t = t[i+2:]
//pause()
p.mode = modeNormal
p.print(t)
return
} else {
slowprint(t)
}
case modeANSI:
if i := strings.Index(t, "}}"); i >= 0 {
fmt.Print(t[:i])
os.Stdout.Write([]byte{27, 91, '0', 'm'})
p.mode = modeNormal
t = t[i+2:]
p.print(t)
return
}
}
}
fmt.Println()
return
}
func typingSleep() {
time.Sleep(time.Millisecond * time.Duration(rand.Int63n(100)))
}
func slowprint(s string) {
for _, r := range s {
pause(false)
//typingSleep()
fmt.Print(string(r))
}
pause(true)
}
type exit struct{}
var counter, stepsToSkip int
func pause(expectEnter bool) {
if stepsToSkip > 0 {
counter++
if counter < stepsToSkip {
return
}
}
for {
switch ev := term.PollEvent(); ev.Type {
case term.EventKey:
switch ev.Key {
case term.KeyCtrlC:
panic(exit{})
case term.KeyEnter:
return
default:
if !expectEnter {
return
}
}
case term.EventError:
panic(ev.Err)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment