forked from mirror/readline
kickoff ioloop only needs, solved #1
This commit is contained in:
parent
8fcf9da96c
commit
a904b314b8
13
operation.go
13
operation.go
|
@ -10,12 +10,14 @@ type Operation struct {
|
|||
t *Terminal
|
||||
buf *RuneBuffer
|
||||
outchan chan []rune
|
||||
|
||||
*opHistory
|
||||
*opSearch
|
||||
}
|
||||
|
||||
type wrapWriter struct {
|
||||
r *Operation
|
||||
t *Terminal
|
||||
target io.Writer
|
||||
}
|
||||
|
||||
|
@ -23,7 +25,9 @@ func (w *wrapWriter) Write(b []byte) (int, error) {
|
|||
buf := w.r.buf
|
||||
buf.Clean()
|
||||
n, err := w.target.Write(b)
|
||||
w.r.buf.Refresh()
|
||||
if w.t.IsReading() {
|
||||
w.r.buf.Refresh()
|
||||
}
|
||||
if w.r.IsSearchMode() {
|
||||
w.r.SearchRefresh(-1)
|
||||
}
|
||||
|
@ -135,7 +139,11 @@ func (o *Operation) ioloop() {
|
|||
}
|
||||
|
||||
func (o *Operation) Stderr() io.Writer {
|
||||
return &wrapWriter{target: os.Stderr, r: o}
|
||||
return &wrapWriter{target: os.Stderr, r: o, t: o.t}
|
||||
}
|
||||
|
||||
func (o *Operation) Stdout() io.Writer {
|
||||
return &wrapWriter{target: os.Stdout, r: o, t: o.t}
|
||||
}
|
||||
|
||||
func (o *Operation) String() (string, error) {
|
||||
|
@ -148,6 +156,7 @@ func (o *Operation) String() (string, error) {
|
|||
|
||||
func (o *Operation) Runes() ([]rune, error) {
|
||||
o.buf.Refresh() // print prompt
|
||||
o.t.KickRead()
|
||||
r := <-o.outchan
|
||||
if r == nil {
|
||||
return nil, io.EOF
|
||||
|
|
|
@ -28,6 +28,10 @@ func New(prompt string) (*Instance, error) {
|
|||
return NewEx(&Config{Prompt: prompt})
|
||||
}
|
||||
|
||||
func (i *Instance) Stdout() io.Writer {
|
||||
return i.o.Stdout()
|
||||
}
|
||||
|
||||
func (i *Instance) Stderr() io.Writer {
|
||||
return i.o.Stderr()
|
||||
}
|
||||
|
|
59
terminal.go
59
terminal.go
|
@ -4,6 +4,7 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
|
@ -11,10 +12,14 @@ import (
|
|||
)
|
||||
|
||||
type Terminal struct {
|
||||
cfg *Config
|
||||
state *terminal.State
|
||||
outchan chan rune
|
||||
closed int64
|
||||
cfg *Config
|
||||
state *terminal.State
|
||||
outchan chan rune
|
||||
closed int64
|
||||
stopChan chan struct{}
|
||||
kickChan chan struct{}
|
||||
wg sync.WaitGroup
|
||||
isReading bool
|
||||
}
|
||||
|
||||
func NewTerminal(cfg *Config) (*Terminal, error) {
|
||||
|
@ -23,9 +28,11 @@ func NewTerminal(cfg *Config) (*Terminal, error) {
|
|||
return nil, err
|
||||
}
|
||||
t := &Terminal{
|
||||
cfg: cfg,
|
||||
state: state,
|
||||
outchan: make(chan rune),
|
||||
cfg: cfg,
|
||||
state: state,
|
||||
kickChan: make(chan struct{}, 1),
|
||||
outchan: make(chan rune),
|
||||
stopChan: make(chan struct{}, 1),
|
||||
}
|
||||
|
||||
go t.ioloop()
|
||||
|
@ -52,11 +59,38 @@ func (t *Terminal) ReadRune() rune {
|
|||
return <-t.outchan
|
||||
}
|
||||
|
||||
func (t *Terminal) IsReading() bool {
|
||||
return t.isReading
|
||||
}
|
||||
|
||||
func (t *Terminal) KickRead() {
|
||||
select {
|
||||
case t.kickChan <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) ioloop() {
|
||||
t.wg.Add(1)
|
||||
defer t.wg.Done()
|
||||
var (
|
||||
isEscape bool
|
||||
isEscapeEx bool
|
||||
expectNextChar bool
|
||||
)
|
||||
|
||||
buf := bufio.NewReader(os.Stdin)
|
||||
isEscape := false
|
||||
isEscapeEx := false
|
||||
for {
|
||||
if !expectNextChar {
|
||||
t.isReading = false
|
||||
select {
|
||||
case <-t.kickChan:
|
||||
t.isReading = true
|
||||
case <-t.stopChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
expectNextChar = false
|
||||
r, _, err := buf.ReadRune()
|
||||
if err != nil {
|
||||
break
|
||||
|
@ -65,6 +99,7 @@ func (t *Terminal) ioloop() {
|
|||
if isEscape {
|
||||
isEscape = false
|
||||
if r == CharEscapeEx {
|
||||
expectNextChar = true
|
||||
isEscapeEx = true
|
||||
continue
|
||||
}
|
||||
|
@ -80,7 +115,11 @@ func (t *Terminal) ioloop() {
|
|||
goto exit
|
||||
case CharEsc:
|
||||
isEscape = true
|
||||
expectNextChar = true
|
||||
case CharEnter, CharCtrlJ:
|
||||
t.outchan <- r
|
||||
default:
|
||||
expectNextChar = true
|
||||
t.outchan <- r
|
||||
}
|
||||
}
|
||||
|
@ -91,5 +130,7 @@ func (t *Terminal) Close() error {
|
|||
if atomic.SwapInt64(&t.closed, 1) != 0 {
|
||||
return nil
|
||||
}
|
||||
t.stopChan <- struct{}{}
|
||||
t.wg.Wait()
|
||||
return Restore(syscall.Stdin, t.state)
|
||||
}
|
||||
|
|
8
utils.go
8
utils.go
|
@ -22,7 +22,13 @@ func MakeRaw(fd int) (*terminal.State, error) {
|
|||
}
|
||||
|
||||
func Restore(fd int, state *terminal.State) error {
|
||||
return terminal.Restore(fd, state)
|
||||
err := terminal.Restore(fd, state)
|
||||
if err != nil {
|
||||
if err.Error() == "errno 0" {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsPrintable(key rune) bool {
|
||||
|
|
Loading…
Reference in New Issue