X Tutup
Skip to content

Commit 6cbc886

Browse files
committed
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.
1 parent 355d281 commit 6cbc886

File tree

1 file changed

+39
-59
lines changed

1 file changed

+39
-59
lines changed

pkg/cmd/repo/garden/garden.go

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ import (
88
"net/http"
99
"os"
1010
"os/exec"
11-
"os/signal"
1211
"runtime"
1312
"strconv"
1413
"strings"
15-
"syscall"
1614

1715
"github.com/cli/cli/api"
1816
"github.com/cli/cli/internal/ghinstance"
@@ -21,6 +19,7 @@ import (
2119
"github.com/cli/cli/pkg/iostreams"
2220
"github.com/cli/cli/utils"
2321
"github.com/spf13/cobra"
22+
"golang.org/x/term"
2423
)
2524

2625
type Geometry struct {
@@ -51,10 +50,11 @@ type Cell struct {
5150
}
5251

5352
const (
54-
DirUp = iota
53+
DirUp Direction = iota
5554
DirDown
5655
DirLeft
5756
DirRight
57+
Quit
5858
)
5959

6060
type Direction = int
@@ -182,18 +182,6 @@ func gardenRun(opts *GardenOptions) error {
182182

183183
maxCommits := (geo.Width * geo.Height) / 2
184184

185-
sttyFileArg := "-F"
186-
if runtime.GOOS == "darwin" {
187-
sttyFileArg = "-f"
188-
}
189-
190-
oldTTYCommand := exec.Command("stty", sttyFileArg, "/dev/tty", "-g")
191-
oldTTYSettings, err := oldTTYCommand.CombinedOutput()
192-
if err != nil {
193-
fmt.Fprintln(out, "getting TTY settings failed:", string(oldTTYSettings))
194-
return err
195-
}
196-
197185
opts.IO.StartProgressIndicator()
198186
fmt.Fprintln(out, "gathering commits; this could take a minute...")
199187
commits, err := getCommits(httpClient, toView, maxCommits)
@@ -215,57 +203,42 @@ func gardenRun(opts *GardenOptions) error {
215203
clear(opts.IO)
216204
drawGarden(opts.IO, garden, player)
217205

218-
// thanks stackoverflow https://stackoverflow.com/a/17278776
219-
_ = exec.Command("stty", sttyFileArg, "/dev/tty", "cbreak", "min", "1").Run()
220-
_ = exec.Command("stty", sttyFileArg, "/dev/tty", "-echo").Run()
221-
222-
walkAway := func() {
223-
clear(opts.IO)
224-
fmt.Fprint(out, "\033[?25h")
225-
_ = exec.Command("stty", sttyFileArg, "/dev/tty", strings.TrimSpace(string(oldTTYSettings))).Run()
226-
fmt.Fprintln(out)
227-
fmt.Fprintln(out, cs.Bold("You turn and walk away from the wildflower garden..."))
206+
// TODO: use opts.IO instead of os.Stdout
207+
oldTermState, err := term.MakeRaw(int(os.Stdout.Fd()))
208+
if err != nil {
209+
return fmt.Errorf("term.MakeRaw: %w", err)
228210
}
229211

230-
c := make(chan os.Signal)
231-
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
212+
dirc := make(chan Direction)
232213
go func() {
233-
<-c
234-
walkAway()
235-
os.Exit(0)
214+
b := make([]byte, 3)
215+
for {
216+
_, _ = opts.IO.In.Read(b)
217+
switch {
218+
case isLeft(b):
219+
dirc <- DirLeft
220+
case isRight(b):
221+
dirc <- DirRight
222+
case isUp(b):
223+
dirc <- DirUp
224+
case isDown(b):
225+
dirc <- DirDown
226+
case isQuit(b):
227+
dirc <- Quit
228+
}
229+
}
236230
}()
237231

238-
var b []byte = make([]byte, 3)
232+
mainLoop:
239233
for {
240-
_, _ = opts.IO.In.Read(b)
241-
242234
oldX := player.X
243235
oldY := player.Y
244-
moved := false
245-
quitting := false
246-
continuing := false
247-
248-
switch {
249-
case isLeft(b):
250-
moved = player.move(DirLeft)
251-
case isRight(b):
252-
moved = player.move(DirRight)
253-
case isUp(b):
254-
moved = player.move(DirUp)
255-
case isDown(b):
256-
moved = player.move(DirDown)
257-
case isQuit(b):
258-
quitting = true
259-
default:
260-
continuing = true
261-
}
262236

263-
if quitting {
264-
break
265-
}
266-
267-
if !moved || continuing {
268-
continue
237+
d := <-dirc
238+
if d == Quit {
239+
break mainLoop
240+
} else if !player.move(d) {
241+
continue mainLoop
269242
}
270243

271244
underPlayer := garden[player.Y][player.X]
@@ -315,7 +288,12 @@ func gardenRun(opts *GardenOptions) error {
315288
fmt.Fprint(out, cs.Bold(sl))
316289
}
317290

318-
walkAway()
291+
clear(opts.IO)
292+
fmt.Fprint(out, "\033[?25h")
293+
// TODO: use opts.IO instead of os.Stdout
294+
_ = term.Restore(int(os.Stdout.Fd()), oldTermState)
295+
fmt.Fprintln(out, cs.Bold("You turn and walk away from the wildflower garden..."))
296+
319297
return nil
320298
}
321299

@@ -343,8 +321,10 @@ func isUp(b []byte) bool {
343321
return bytes.EqualFold(b, up) || r == 'w' || r == 'k'
344322
}
345323

324+
var ctrlC = []byte{0x3, 0x5b, 0x43}
325+
346326
func isQuit(b []byte) bool {
347-
return rune(b[0]) == 'q'
327+
return rune(b[0]) == 'q' || bytes.Equal(b, ctrlC)
348328
}
349329

350330
func plantGarden(commits []*Commit, geo *Geometry) [][]*Cell {

0 commit comments

Comments
 (0)
X Tutup