| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- package tea
- import (
- "errors"
- "fmt"
- "io"
- "time"
- "github.com/charmbracelet/x/term"
- "github.com/muesli/cancelreader"
- )
- func (p *Program) initTerminal() error {
- if err := p.initInput(); err != nil {
- return err
- }
- p.renderer.hideCursor()
- return nil
- }
- // restoreTerminalState restores the terminal to the state prior to running the
- // Bubble Tea program.
- func (p *Program) restoreTerminalState() error {
- if p.renderer != nil {
- p.renderer.disableBracketedPaste()
- p.renderer.showCursor()
- p.disableMouse()
- if p.renderer.altScreen() {
- p.renderer.exitAltScreen()
- // give the terminal a moment to catch up
- time.Sleep(time.Millisecond * 10) //nolint:gomnd
- }
- }
- return p.restoreInput()
- }
- // restoreInput restores the tty input to its original state.
- func (p *Program) restoreInput() error {
- if p.ttyInput != nil && p.previousTtyInputState != nil {
- if err := term.Restore(p.ttyInput.Fd(), p.previousTtyInputState); err != nil {
- return fmt.Errorf("error restoring console: %w", err)
- }
- }
- if p.ttyOutput != nil && p.previousOutputState != nil {
- if err := term.Restore(p.ttyOutput.Fd(), p.previousOutputState); err != nil {
- return fmt.Errorf("error restoring console: %w", err)
- }
- }
- return nil
- }
- // initCancelReader (re)commences reading inputs.
- func (p *Program) initCancelReader() error {
- var err error
- p.cancelReader, err = newInputReader(p.input)
- if err != nil {
- return fmt.Errorf("error creating cancelreader: %w", err)
- }
- p.readLoopDone = make(chan struct{})
- go p.readLoop()
- return nil
- }
- func (p *Program) readLoop() {
- defer close(p.readLoopDone)
- err := readInputs(p.ctx, p.msgs, p.cancelReader)
- if !errors.Is(err, io.EOF) && !errors.Is(err, cancelreader.ErrCanceled) {
- select {
- case <-p.ctx.Done():
- case p.errs <- err:
- }
- }
- }
- // waitForReadLoop waits for the cancelReader to finish its read loop.
- func (p *Program) waitForReadLoop() {
- select {
- case <-p.readLoopDone:
- case <-time.After(500 * time.Millisecond): //nolint:gomnd
- // 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.
- }
- }
- // checkResize detects the current size of the output and informs the program
- // via a WindowSizeMsg.
- func (p *Program) checkResize() {
- if p.ttyOutput == nil {
- // can't query window size
- return
- }
- w, h, err := term.GetSize(p.ttyOutput.Fd())
- if err != nil {
- select {
- case <-p.ctx.Done():
- case p.errs <- err:
- }
- return
- }
- p.Send(WindowSizeMsg{
- Width: w,
- Height: h,
- })
- }
|