fix: wait for read-loop to finish before spawning child process

This commit is contained in:
Christian Muehlhaeuser 2022-09-27 09:01:29 +02:00
parent 93c63f07aa
commit b1c9d80603
2 changed files with 39 additions and 29 deletions

10
tea.go
View File

@ -292,13 +292,7 @@ func (p *Program) StartReturningModel() (Model, error) {
waitForGoroutines = func(withReadLoop bool) { waitForGoroutines = func(withReadLoop bool) {
if withReadLoop { if withReadLoop {
select { p.waitForReadLoop()
case <-p.readLoopDone:
case <-time.After(500 * time.Millisecond):
// The read loop hangs, which means the input
// cancelReader's cancel function has returned true even
// though it was not able to cancel the read.
}
} }
<-cmdLoopDone <-cmdLoopDone
<-resizeLoopDone <-resizeLoopDone
@ -712,6 +706,8 @@ func (p *Program) DisableMouseAllMotion() {
func (p *Program) ReleaseTerminal() error { func (p *Program) ReleaseTerminal() error {
p.ignoreSignals = true p.ignoreSignals = true
p.cancelInput() p.cancelInput()
p.waitForReadLoop()
p.altScreenWasActive = p.altScreenActive p.altScreenWasActive = p.altScreenActive
if p.altScreenActive { if p.altScreenActive {
p.ExitAltScreen() p.ExitAltScreen()

58
tty.go
View File

@ -3,6 +3,7 @@ package tea
import ( import (
"errors" "errors"
"io" "io"
"time"
"github.com/muesli/cancelreader" "github.com/muesli/cancelreader"
) )
@ -48,33 +49,46 @@ func (p *Program) initCancelReader() error {
} }
p.readLoopDone = make(chan struct{}) p.readLoopDone = make(chan struct{})
go func() { go p.eventLoop()
defer close(p.readLoopDone)
for {
if p.ctx.Err() != nil {
return
}
msgs, err := readInputs(p.cancelReader)
if err != nil {
if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
p.errs <- err
}
return
}
for _, msg := range msgs {
p.msgs <- msg
}
}
}()
return nil return nil
} }
func (p *Program) eventLoop() {
defer close(p.readLoopDone)
for {
if p.ctx.Err() != nil {
return
}
msgs, err := readInputs(p.cancelReader)
if err != nil {
if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
p.errs <- err
}
return
}
for _, msg := range msgs {
p.msgs <- msg
}
}
}
// cancelInput cancels the input reader. // cancelInput cancels the input reader.
func (p *Program) cancelInput() { func (p *Program) cancelInput() {
p.cancelReader.Cancel() p.cancelReader.Cancel()
} }
// waitForReadLoop waits for the cancelReader to finish its read loop.
func (p *Program) waitForReadLoop() {
select {
case <-p.readLoopDone:
case <-time.After(500 * time.Millisecond):
// The read loop hangs, which means the input
// cancelReader's cancel function has returned true even
// though it was not able to cancel the read.
}
}