handleCommands runs commands in a goroutine and sends the result to the program's message channel.
(cmds chan Cmd)
| 698 | // handleCommands runs commands in a goroutine and sends the result to the |
| 699 | // program's message channel. |
| 700 | func (p *Program) handleCommands(cmds chan Cmd) chan struct{} { |
| 701 | ch := make(chan struct{}) |
| 702 | |
| 703 | go func() { |
| 704 | defer close(ch) |
| 705 | |
| 706 | for { |
| 707 | select { |
| 708 | case <-p.ctx.Done(): |
| 709 | return |
| 710 | |
| 711 | case cmd := <-cmds: |
| 712 | if cmd == nil { |
| 713 | continue |
| 714 | } |
| 715 | |
| 716 | // Don't wait on these goroutines, otherwise the shutdown |
| 717 | // latency would get too large as a Cmd can run for some time |
| 718 | // (e.g. tick commands that sleep for half a second). It's not |
| 719 | // possible to cancel them so we'll have to leak the goroutine |
| 720 | // until Cmd returns. |
| 721 | go func() { |
| 722 | // Recover from panics. |
| 723 | if !p.disableCatchPanics { |
| 724 | defer func() { |
| 725 | if r := recover(); r != nil { |
| 726 | p.recoverFromPanic(r) |
| 727 | } |
| 728 | }() |
| 729 | } |
| 730 | |
| 731 | msg := cmd() // this can be long. |
| 732 | p.Send(msg) |
| 733 | }() |
| 734 | } |
| 735 | } |
| 736 | }() |
| 737 | |
| 738 | return ch |
| 739 | } |
| 740 | |
| 741 | // eventLoop is the central message loop. It receives and handles the default |
| 742 | // Bubble Tea messages, update the model and triggers redraws. |
no test coverage detected