mirror of https://github.com/chzyer/readline.git
let stdin cancelable (#72)
This commit is contained in:
parent
27fdf0b285
commit
6cbc078c57
52
std.go
52
std.go
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Stdin io.ReadCloser = os.Stdin
|
Stdin io.ReadCloser = NewCancelableStdin()
|
||||||
Stdout io.WriteCloser = os.Stdout
|
Stdout io.WriteCloser = os.Stdout
|
||||||
Stderr io.WriteCloser = os.Stderr
|
Stderr io.WriteCloser = os.Stderr
|
||||||
)
|
)
|
||||||
|
@ -64,3 +64,53 @@ func Line(prompt string) (string, error) {
|
||||||
ins.SetPrompt(prompt)
|
ins.SetPrompt(prompt)
|
||||||
return ins.Readline()
|
return ins.Readline()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CancelableStdin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
|
stop chan struct{}
|
||||||
|
notify chan struct{}
|
||||||
|
data []byte
|
||||||
|
read int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCancelableStdin() *CancelableStdin {
|
||||||
|
c := &CancelableStdin{
|
||||||
|
notify: make(chan struct{}),
|
||||||
|
stop: make(chan struct{}),
|
||||||
|
}
|
||||||
|
go c.ioloop()
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CancelableStdin) ioloop() {
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c.notify:
|
||||||
|
c.read, c.err = os.Stdin.Read(c.data)
|
||||||
|
<-c.notify
|
||||||
|
case <-c.stop:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CancelableStdin) Read(b []byte) (n int, err error) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
|
c.data = b
|
||||||
|
c.notify <- struct{}{}
|
||||||
|
select {
|
||||||
|
case <-c.notify:
|
||||||
|
return c.read, c.err
|
||||||
|
case <-c.stop:
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CancelableStdin) Close() error {
|
||||||
|
close(c.stop)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
14
terminal.go
14
terminal.go
|
@ -3,6 +3,7 @@ package readline
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -109,7 +110,11 @@ func (t *Terminal) KickRead() {
|
||||||
|
|
||||||
func (t *Terminal) ioloop() {
|
func (t *Terminal) ioloop() {
|
||||||
t.wg.Add(1)
|
t.wg.Add(1)
|
||||||
defer t.wg.Done()
|
defer func() {
|
||||||
|
t.wg.Done()
|
||||||
|
close(t.outchan)
|
||||||
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
isEscape bool
|
isEscape bool
|
||||||
isEscapeEx bool
|
isEscapeEx bool
|
||||||
|
@ -182,7 +187,7 @@ func (t *Terminal) ioloop() {
|
||||||
t.outchan <- r
|
t.outchan <- r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(t.outchan)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) Bell() {
|
func (t *Terminal) Bell() {
|
||||||
|
@ -193,7 +198,10 @@ func (t *Terminal) Close() error {
|
||||||
if atomic.SwapInt32(&t.closed, 1) != 0 {
|
if atomic.SwapInt32(&t.closed, 1) != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
t.stopChan <- struct{}{}
|
if closer, ok := t.cfg.Stdin.(io.Closer); ok {
|
||||||
|
closer.Close()
|
||||||
|
}
|
||||||
|
close(t.stopChan)
|
||||||
t.wg.Wait()
|
t.wg.Wait()
|
||||||
return t.ExitRawMode()
|
return t.ExitRawMode()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue