package tui import ( "context" "sync" tea "charm.land/bubbletea/v2" ) type tuiObservations struct { mu sync.Mutex ctx context.Context cancel context.CancelFunc workers sync.WaitGroup closed bool } // Register before returning the command, so exit also owns a refresh that the // command loop has not yet scheduled. Results are buffered independently of it. func (m *Model) observationCmd(fn func(context.Context) tea.Msg) tea.Cmd { if m.observations == nil { m.observations = &tuiObservations{} } m.observations.mu.Lock() if m.observations.closed { m.observations.mu.Unlock() return nil } if m.observations.ctx == nil { m.observations.ctx, m.observations.cancel = context.WithCancel(context.Background()) } ctx := m.observations.ctx m.observations.workers.Add(1) m.observations.mu.Unlock() result := make(chan tea.Msg, 1) go func() { defer m.observations.workers.Done() result <- fn(ctx) }() return func() tea.Msg { return <-result } } func (m *Model) cancelObservations() { if m.observations == nil { m.observations = &tuiObservations{} } m.observations.mu.Lock() m.observations.closed = true if m.observations.cancel != nil { m.observations.cancel() } m.observations.mu.Unlock() } func (m *Model) stopObservations() { m.cancelObservations() m.observations.workers.Wait() }