Use context.Context and Cancel function
This commit is contained in:
parent
536e34532a
commit
d7dd5f9548
50
prompt.go
50
prompt.go
@ -2,6 +2,7 @@ package prompt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -29,6 +30,8 @@ type Prompt struct {
|
|||||||
keyBindings []KeyBind
|
keyBindings []KeyBind
|
||||||
ASCIICodeBindings []ASCIICodeBind
|
ASCIICodeBindings []ASCIICodeBind
|
||||||
keyBindMode KeyBindMode
|
keyBindMode KeyBindMode
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec is the struct contains user input context.
|
// Exec is the struct contains user input context.
|
||||||
@ -53,27 +56,23 @@ func (p *Prompt) Run() {
|
|||||||
|
|
||||||
p.renderer.Render(p.buf, p.completion)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
|
|
||||||
bufCh := make(chan []byte, 128)
|
bufchan := make(chan []byte, 128)
|
||||||
stopReadBufCh := make(chan struct{})
|
go p.readBuffer(p.ctx, bufchan)
|
||||||
go p.readBuffer(bufCh, stopReadBufCh)
|
|
||||||
|
|
||||||
exitCh := make(chan int)
|
exitCh := make(chan int)
|
||||||
winSizeCh := make(chan *WinSize)
|
winchan := make(chan *WinSize)
|
||||||
stopHandleSignalCh := make(chan struct{})
|
go p.handleSignals(p.ctx, p.cancel, winchan)
|
||||||
go p.handleSignals(exitCh, winSizeCh, stopHandleSignalCh)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case b := <-bufCh:
|
case b := <-bufchan:
|
||||||
if shouldExit, e := p.feed(b); shouldExit {
|
if shouldExit, e := p.feed(b); shouldExit {
|
||||||
p.renderer.BreakLine(p.buf)
|
p.renderer.BreakLine(p.buf)
|
||||||
stopReadBufCh <- struct{}{}
|
p.cancel()
|
||||||
stopHandleSignalCh <- struct{}{}
|
|
||||||
return
|
return
|
||||||
} else if e != nil {
|
} else if e != nil {
|
||||||
// Stop goroutine to run readBuffer function
|
// Stop goroutine to run readBuffer function
|
||||||
stopReadBufCh <- struct{}{}
|
p.cancel()
|
||||||
stopHandleSignalCh <- struct{}{}
|
|
||||||
|
|
||||||
// Unset raw mode
|
// Unset raw mode
|
||||||
// Reset to Blocking mode because returned EAGAIN when still set non-blocking mode.
|
// Reset to Blocking mode because returned EAGAIN when still set non-blocking mode.
|
||||||
@ -85,13 +84,16 @@ func (p *Prompt) Run() {
|
|||||||
|
|
||||||
// Set raw mode
|
// Set raw mode
|
||||||
p.in.Setup()
|
p.in.Setup()
|
||||||
go p.readBuffer(bufCh, stopReadBufCh)
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
go p.handleSignals(exitCh, winSizeCh, stopHandleSignalCh)
|
p.ctx = ctx
|
||||||
|
p.cancel = cancel
|
||||||
|
go p.readBuffer(p.ctx, bufchan)
|
||||||
|
go p.handleSignals(p.ctx, p.cancel, winchan)
|
||||||
} else {
|
} else {
|
||||||
p.completion.Update(*p.buf.Document())
|
p.completion.Update(*p.buf.Document())
|
||||||
p.renderer.Render(p.buf, p.completion)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
}
|
}
|
||||||
case w := <-winSizeCh:
|
case w := <-winchan:
|
||||||
p.renderer.UpdateWinSize(w)
|
p.renderer.UpdateWinSize(w)
|
||||||
p.renderer.Render(p.buf, p.completion)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
case code := <-exitCh:
|
case code := <-exitCh:
|
||||||
@ -233,20 +235,17 @@ func (p *Prompt) Input() string {
|
|||||||
defer p.tearDown()
|
defer p.tearDown()
|
||||||
|
|
||||||
p.renderer.Render(p.buf, p.completion)
|
p.renderer.Render(p.buf, p.completion)
|
||||||
bufCh := make(chan []byte, 128)
|
bufchan := make(chan []byte, 128)
|
||||||
stopReadBufCh := make(chan struct{})
|
go p.readBuffer(p.ctx, bufchan)
|
||||||
go p.readBuffer(bufCh, stopReadBufCh)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case b := <-bufCh:
|
case b := <-bufchan:
|
||||||
if shouldExit, e := p.feed(b); shouldExit {
|
if shouldExit, e := p.feed(b); shouldExit {
|
||||||
p.renderer.BreakLine(p.buf)
|
p.renderer.BreakLine(p.buf)
|
||||||
stopReadBufCh <- struct{}{}
|
p.cancel()
|
||||||
return ""
|
return ""
|
||||||
} else if e != nil {
|
} else if e != nil {
|
||||||
// Stop goroutine to run readBuffer function
|
|
||||||
stopReadBufCh <- struct{}{}
|
|
||||||
return e.input
|
return e.input
|
||||||
} else {
|
} else {
|
||||||
p.completion.Update(*p.buf.Document())
|
p.completion.Update(*p.buf.Document())
|
||||||
@ -258,11 +257,11 @@ func (p *Prompt) Input() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
|
func (p *Prompt) readBuffer(ctx context.Context, bufCh chan []byte) {
|
||||||
log.Printf("[INFO] readBuffer start")
|
log.Printf("[INFO] readBuffer start")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stopCh:
|
case <-ctx.Done():
|
||||||
log.Print("[INFO] stop readBuffer")
|
log.Print("[INFO] stop readBuffer")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
@ -278,9 +277,14 @@ func (p *Prompt) setUp() {
|
|||||||
p.in.Setup()
|
p.in.Setup()
|
||||||
p.renderer.Setup()
|
p.renderer.Setup()
|
||||||
p.renderer.UpdateWinSize(p.in.GetWinSize())
|
p.renderer.UpdateWinSize(p.in.GetWinSize())
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
p.ctx = ctx
|
||||||
|
p.cancel = cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Prompt) tearDown() {
|
func (p *Prompt) tearDown() {
|
||||||
|
p.cancel()
|
||||||
p.in.TearDown()
|
p.in.TearDown()
|
||||||
p.renderer.TearDown()
|
p.renderer.TearDown()
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,18 @@
|
|||||||
package prompt
|
package prompt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) {
|
func (p *Prompt) handleSignals(ctx context.Context, cancel context.CancelFunc, winSizeCh chan *WinSize) {
|
||||||
in := p.in
|
in := p.in
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigchan := make(chan os.Signal, 1)
|
||||||
signal.Notify(
|
signal.Notify(
|
||||||
sigCh,
|
sigchan,
|
||||||
syscall.SIGINT,
|
syscall.SIGINT,
|
||||||
syscall.SIGTERM,
|
syscall.SIGTERM,
|
||||||
syscall.SIGQUIT,
|
syscall.SIGQUIT,
|
||||||
@ -22,22 +23,22 @@ func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop ch
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-ctx.Done():
|
||||||
log.Println("[INFO] stop handleSignals")
|
log.Println("[INFO] stop handleSignals")
|
||||||
return
|
return
|
||||||
case s := <-sigCh:
|
case s := <-sigchan:
|
||||||
switch s {
|
switch s {
|
||||||
case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
|
case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
|
||||||
log.Println("[SIGNAL] Catch SIGINT")
|
log.Println("[SIGNAL] Catch SIGINT")
|
||||||
exitCh <- 0
|
cancel()
|
||||||
|
|
||||||
case syscall.SIGTERM: // kill -SIGTERM XXXX
|
case syscall.SIGTERM: // kill -SIGTERM XXXX
|
||||||
log.Println("[SIGNAL] Catch SIGTERM")
|
log.Println("[SIGNAL] Catch SIGTERM")
|
||||||
exitCh <- 1
|
cancel()
|
||||||
|
|
||||||
case syscall.SIGQUIT: // kill -SIGQUIT XXXX
|
case syscall.SIGQUIT: // kill -SIGQUIT XXXX
|
||||||
log.Println("[SIGNAL] Catch SIGQUIT")
|
log.Println("[SIGNAL] Catch SIGQUIT")
|
||||||
exitCh <- 0
|
cancel()
|
||||||
|
|
||||||
case syscall.SIGWINCH:
|
case syscall.SIGWINCH:
|
||||||
log.Println("[SIGNAL] Catch SIGWINCH")
|
log.Println("[SIGNAL] Catch SIGWINCH")
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
package prompt
|
package prompt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) {
|
func (p *Prompt) handleSignals(tx context.Context, cancel context.CancelFunc, winSizeCh chan *WinSize) {
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(
|
signal.Notify(
|
||||||
sigCh,
|
sigCh,
|
||||||
@ -20,23 +21,18 @@ func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop ch
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-ctx.Done():
|
||||||
log.Println("[INFO] stop handleSignals")
|
|
||||||
return
|
return
|
||||||
case s := <-sigCh:
|
case s := <-sigCh:
|
||||||
switch s {
|
switch s {
|
||||||
|
|
||||||
case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
|
case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
|
||||||
log.Println("[SIGNAL] Catch SIGINT")
|
cancel()
|
||||||
exitCh <- 0
|
|
||||||
|
|
||||||
case syscall.SIGTERM: // kill -SIGTERM XXXX
|
case syscall.SIGTERM: // kill -SIGTERM XXXX
|
||||||
log.Println("[SIGNAL] Catch SIGTERM")
|
log.Println("[SIGNAL] Catch SIGTERM")
|
||||||
exitCh <- 1
|
|
||||||
|
|
||||||
case syscall.SIGQUIT: // kill -SIGQUIT XXXX
|
case syscall.SIGQUIT: // kill -SIGQUIT XXXX
|
||||||
log.Println("[SIGNAL] Catch SIGQUIT")
|
cancel()
|
||||||
exitCh <- 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user