From b1c9d8060380b33858db912089472d377b05e827 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 27 Sep 2022 09:01:29 +0200 Subject: [PATCH] fix: wait for read-loop to finish before spawning child process --- tea.go | 10 +++------- tty.go | 58 ++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/tea.go b/tea.go index 23d8cb7..e13559b 100644 --- a/tea.go +++ b/tea.go @@ -292,13 +292,7 @@ func (p *Program) StartReturningModel() (Model, error) { waitForGoroutines = func(withReadLoop bool) { if withReadLoop { - 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. - } + p.waitForReadLoop() } <-cmdLoopDone <-resizeLoopDone @@ -712,6 +706,8 @@ func (p *Program) DisableMouseAllMotion() { func (p *Program) ReleaseTerminal() error { p.ignoreSignals = true p.cancelInput() + p.waitForReadLoop() + p.altScreenWasActive = p.altScreenActive if p.altScreenActive { p.ExitAltScreen() diff --git a/tty.go b/tty.go index 5259638..a36aa68 100644 --- a/tty.go +++ b/tty.go @@ -3,6 +3,7 @@ package tea import ( "errors" "io" + "time" "github.com/muesli/cancelreader" ) @@ -48,33 +49,46 @@ func (p *Program) initCancelReader() error { } p.readLoopDone = make(chan struct{}) - go func() { - 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 - } - } - }() + go p.eventLoop() 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. func (p *Program) cancelInput() { 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. + } +}