Use x/term package for repo garden instead of shelling out to stty

Shelling out to stty seems hard to get right between Linux and macOS.
This commit is contained in:
Mislav Marohnić 2021-08-26 16:45:55 +02:00
parent 355d28195e
commit 6cbc886c53

View file

@ -8,11 +8,9 @@ import (
"net/http"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
"strings"
"syscall"
"github.com/cli/cli/api"
"github.com/cli/cli/internal/ghinstance"
@ -21,6 +19,7 @@ import (
"github.com/cli/cli/pkg/iostreams"
"github.com/cli/cli/utils"
"github.com/spf13/cobra"
"golang.org/x/term"
)
type Geometry struct {
@ -51,10 +50,11 @@ type Cell struct {
}
const (
DirUp = iota
DirUp Direction = iota
DirDown
DirLeft
DirRight
Quit
)
type Direction = int
@ -182,18 +182,6 @@ func gardenRun(opts *GardenOptions) error {
maxCommits := (geo.Width * geo.Height) / 2
sttyFileArg := "-F"
if runtime.GOOS == "darwin" {
sttyFileArg = "-f"
}
oldTTYCommand := exec.Command("stty", sttyFileArg, "/dev/tty", "-g")
oldTTYSettings, err := oldTTYCommand.CombinedOutput()
if err != nil {
fmt.Fprintln(out, "getting TTY settings failed:", string(oldTTYSettings))
return err
}
opts.IO.StartProgressIndicator()
fmt.Fprintln(out, "gathering commits; this could take a minute...")
commits, err := getCommits(httpClient, toView, maxCommits)
@ -215,57 +203,42 @@ func gardenRun(opts *GardenOptions) error {
clear(opts.IO)
drawGarden(opts.IO, garden, player)
// thanks stackoverflow https://stackoverflow.com/a/17278776
_ = exec.Command("stty", sttyFileArg, "/dev/tty", "cbreak", "min", "1").Run()
_ = exec.Command("stty", sttyFileArg, "/dev/tty", "-echo").Run()
walkAway := func() {
clear(opts.IO)
fmt.Fprint(out, "\033[?25h")
_ = exec.Command("stty", sttyFileArg, "/dev/tty", strings.TrimSpace(string(oldTTYSettings))).Run()
fmt.Fprintln(out)
fmt.Fprintln(out, cs.Bold("You turn and walk away from the wildflower garden..."))
// TODO: use opts.IO instead of os.Stdout
oldTermState, err := term.MakeRaw(int(os.Stdout.Fd()))
if err != nil {
return fmt.Errorf("term.MakeRaw: %w", err)
}
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
dirc := make(chan Direction)
go func() {
<-c
walkAway()
os.Exit(0)
b := make([]byte, 3)
for {
_, _ = opts.IO.In.Read(b)
switch {
case isLeft(b):
dirc <- DirLeft
case isRight(b):
dirc <- DirRight
case isUp(b):
dirc <- DirUp
case isDown(b):
dirc <- DirDown
case isQuit(b):
dirc <- Quit
}
}
}()
var b []byte = make([]byte, 3)
mainLoop:
for {
_, _ = opts.IO.In.Read(b)
oldX := player.X
oldY := player.Y
moved := false
quitting := false
continuing := false
switch {
case isLeft(b):
moved = player.move(DirLeft)
case isRight(b):
moved = player.move(DirRight)
case isUp(b):
moved = player.move(DirUp)
case isDown(b):
moved = player.move(DirDown)
case isQuit(b):
quitting = true
default:
continuing = true
}
if quitting {
break
}
if !moved || continuing {
continue
d := <-dirc
if d == Quit {
break mainLoop
} else if !player.move(d) {
continue mainLoop
}
underPlayer := garden[player.Y][player.X]
@ -315,7 +288,12 @@ func gardenRun(opts *GardenOptions) error {
fmt.Fprint(out, cs.Bold(sl))
}
walkAway()
clear(opts.IO)
fmt.Fprint(out, "\033[?25h")
// TODO: use opts.IO instead of os.Stdout
_ = term.Restore(int(os.Stdout.Fd()), oldTermState)
fmt.Fprintln(out, cs.Bold("You turn and walk away from the wildflower garden..."))
return nil
}
@ -343,8 +321,10 @@ func isUp(b []byte) bool {
return bytes.EqualFold(b, up) || r == 'w' || r == 'k'
}
var ctrlC = []byte{0x3, 0x5b, 0x43}
func isQuit(b []byte) bool {
return rune(b[0]) == 'q'
return rune(b[0]) == 'q' || bytes.Equal(b, ctrlC)
}
func plantGarden(commits []*Commit, geo *Geometry) [][]*Cell {