diff --git a/global.go b/global.go index 6c91170..57269db 100644 --- a/global.go +++ b/global.go @@ -16,6 +16,8 @@ var ( symInterval = gmnlisp.NewSymbol("interval") ) +var ErrCtrlC = errors.New("^C") + type Global struct { w *Watcher term *Term @@ -73,7 +75,7 @@ func (g *Global) spawn(ctx context.Context, w *gmnlisp.World, args []gmnlisp.Nod argStrings = append(argStrings, s.String()) } - sh := g.term.Command(argStrings[0], argStrings[1:]...) + sh := g.term.CommandContext(ctx, argStrings[0], argStrings[1:]...) if err := sh.Start(); err != nil { return nil, err } @@ -113,6 +115,9 @@ func (g *Global) expect(ctx context.Context, w *gmnlisp.World, node gmnlisp.Node } else { result = g.w.ExpectWithTimeout(time.Second*time.Duration(timeOut), patterns...) } + if result == EventCtrlC { + return nil, ErrCtrlC + } return gmnlisp.Integer(result), nil } @@ -164,7 +169,10 @@ func (g *Global) expectX(ctx context.Context, w *gmnlisp.World, node gmnlisp.Nod } else { result = g.w.ExpectWithTimeout(time.Second*time.Duration(timeoutSec), patterns...) } - if result >= 0 { + + if result == EventCtrlC { + return nil, ErrCtrlC + } else if result >= 0 { return gmnlisp.Progn(ctx, w, actions[result]) } else { return gmnlisp.Progn(ctx, w, timeoutAct) diff --git a/main.go b/main.go index c605e59..546f9ed 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,9 @@ func mains(args []string) error { } lisp = lisp.Let(&gmnlisp.Pair{Key: gmnlisp.NewSymbol("args"), Value: gmnlisp.List(posixArgv...)}) - _, err = lisp.Interpret(context.Background(), string(script)) + ctx, cancel := context.WithCancel(context.Background()) + _, err = lisp.Interpret(ctx, string(script)) + cancel() return err } diff --git a/watcher.go b/watcher.go index a40cd6c..bb3fd97 100644 --- a/watcher.go +++ b/watcher.go @@ -1,20 +1,37 @@ package main import ( + "bytes" "io" "os" "strings" "time" ) +const ( + EventCtrlC = -2 + EventTimeOut = -1 +) + type Watcher struct { ch <-chan string lastline string + ctrlc <-chan struct{} } func NewWatcher(pty io.ReadWriter) *Watcher { pipeline := make(chan string, 1024) - go io.Copy(pty, os.Stdin) + ctrlc := make(chan struct{}, 100) + go func() { + for { + var buffer [1024]byte + n, _ := os.Stdin.Read(buffer[:]) + pty.Write(buffer[:n]) + if bytes.IndexByte(buffer[:n], '\x03') >= 0 { + ctrlc <- struct{}{} + } + } + }() go func() { for { var buffer [1024]byte @@ -32,7 +49,7 @@ func NewWatcher(pty io.ReadWriter) *Watcher { } }() - return &Watcher{ch: pipeline} + return &Watcher{ch: pipeline, ctrlc: ctrlc} } func (W *Watcher) checkWords(token string, words []string) int { @@ -52,12 +69,16 @@ func (W *Watcher) checkWords(token string, words []string) int { } func (W *Watcher) Expect(words ...string) int { - for token := range W.ch { - if found := W.checkWords(token, words); found >= 0 { - return found + for { + select { + case token := <-W.ch: + if found := W.checkWords(token, words); found >= 0 { + return found + } + case <-W.ctrlc: + return EventCtrlC } } - return -1 } func (W *Watcher) ExpectWithTimeout(d time.Duration, words ...string) int { @@ -71,7 +92,9 @@ func (W *Watcher) ExpectWithTimeout(d time.Duration, words ...string) int { return found } case <-timer.C: - return -1 + return EventTimeOut + case <-W.ctrlc: + return EventCtrlC } } }