diff --git a/signals_unix.go b/signals_unix.go index ef9ed9a3ad..bcc5926bef 100644 --- a/signals_unix.go +++ b/signals_unix.go @@ -8,8 +8,6 @@ import ( "os" "os/signal" "syscall" - - "golang.org/x/term" ) // listenForResize sends messages (or errors) when the terminal resizes. @@ -31,15 +29,6 @@ func listenForResize(ctx context.Context, output *os.File, msgs chan Msg, errs c case <-sig: } - w, h, err := term.GetSize(int(output.Fd())) - if err != nil { - errs <- err - } - - select { - case <-ctx.Done(): - return - case msgs <- WindowSizeMsg{w, h}: - } + checkResize(ctx, output, msgs, errs) } } diff --git a/tea.go b/tea.go index ccb0c50ffd..e38fe03627 100644 --- a/tea.go +++ b/tea.go @@ -310,17 +310,7 @@ func (p *Program) StartReturningModel() (Model, error) { if f, ok := p.output.TTY().(*os.File); ok && isatty.IsTerminal(f.Fd()) { // Get the initial terminal size and send it to the program. - go func() { - w, h, err := term.GetSize(int(f.Fd())) - if err != nil { - p.errs <- err - } - - select { - case <-p.ctx.Done(): - case p.msgs <- WindowSizeMsg{w, h}: - } - }() + go checkResize(p.ctx, f, p.msgs, p.errs) // Listen for window resizes. go listenForResize(p.ctx, f, p.msgs, p.errs, resizeLoopDone) @@ -451,7 +441,10 @@ func (p *Program) Start() error { // If the program is not running this this will be a no-op, so it's safe to // send messages if the program is unstarted, or has exited. func (p *Program) Send(msg Msg) { - p.msgs <- msg + select { + case <-p.ctx.Done(): + case p.msgs <- msg: + } } // Quit is a convenience function for quitting Bubble Tea programs. Use it @@ -525,11 +518,35 @@ func (p *Program) RestoreTerminal() error { p.EnterAltScreen() } - go p.Send(repaintMsg{}) + go func() { + // If the output is a terminal, it may have been resized while + // another process was at the foreground, in which case we may not + // have received SIGWINCH. Detect any size change now and + // propagate the new size as needed. + if f, ok := p.output.TTY().(*os.File); ok && isatty.IsTerminal(f.Fd()) { + checkResize(p.ctx, f, p.msgs, p.errs) + } + p.Send(repaintMsg{}) + }() return nil } +// checkResize detects the current size of the output and informs +// the program via a WindowSizeMsg. +func checkResize(ctx context.Context, output *os.File, msgs chan Msg, errs chan error) { + w, h, err := term.GetSize(int(output.Fd())) + if err != nil { + errs <- err + return + } + + select { + case <-ctx.Done(): + case msgs <- WindowSizeMsg{w, h}: + } +} + // Println prints above the Program. This output is unmanaged by the program // and will persist across renders by the Program. //