diff --git a/moonmath.go b/moonmath.go index 98ff08b..ae09603 100644 --- a/moonmath.go +++ b/moonmath.go @@ -9,11 +9,13 @@ import ( "code.humancabbage.net/sam/moonmath/config" "code.humancabbage.net/sam/moonmath/tui" "github.com/alecthomas/kong" + tea "github.com/charmbracelet/bubbletea" ) var CLI struct { Asset []string `short:"a" default:"BTC" help:"Asset(s) to project."` ConfigFile string `short:"c" help:"Path to YAML configuration file."` + Perf bool `help:"Display internal performance stats."` } func main() { @@ -30,7 +32,11 @@ func main() { asset := coindesk.Asset(strings.ToUpper(CLI.Asset[i])) assets = append(assets, asset) } - p := tui.New(assets, allCfg) + m := tui.New(assets, allCfg, CLI.Perf) + p := tea.NewProgram(m, + tea.WithAltScreen(), + tea.WithFPS(30), + ) if _, err := p.Run(); err != nil { fail(err) } diff --git a/tui/asset/asset.go b/tui/asset/asset.go index b8a3c1a..ec98ee0 100644 --- a/tui/asset/asset.go +++ b/tui/asset/asset.go @@ -108,11 +108,16 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { switch msg := msg.inner.(type) { case refresh: m.refreshing = true - return m, func() tea.Msg { - // TODO: log errors - _ = m.math.Refresh(context.TODO()) - return Msg{m.math.Asset, m.math} - } + return m, tea.Batch( + func() tea.Msg { + return m.indicator.Tick() + }, + func() tea.Msg { + // TODO: log errors + _ = m.math.Refresh(context.TODO()) + return Msg{m.math.Asset, m.math} + }, + ) case moon.Math: m.math = msg refillProperties(&m) @@ -135,6 +140,9 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { return m, nil } case spinner.TickMsg: + if !m.refreshing { + return m, nil + } var cmd tea.Cmd m.indicator, cmd = m.indicator.Update(msg) return m, cmd diff --git a/tui/perf/perf.go b/tui/perf/perf.go new file mode 100644 index 0000000..2b3b6de --- /dev/null +++ b/tui/perf/perf.go @@ -0,0 +1,42 @@ +package perf + +import ( + "fmt" + "sync/atomic" + + tea "github.com/charmbracelet/bubbletea" +) + +type Model struct { + updates *atomic.Int64 + views *atomic.Int64 +} + +func New() (m Model) { + m.updates = new(atomic.Int64) + m.views = new(atomic.Int64) + return +} + +func (m Model) Init() tea.Cmd { + return nil +} + +func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { + return m, nil +} + +func (m Model) View() string { + updates := m.updates.Load() + views := m.views.Load() + s := fmt.Sprintf("updates: %d\tviews: %d", updates, views) + return s +} + +func (m Model) AddUpdate() { + m.updates.Add(1) +} + +func (m Model) AddView() { + m.views.Add(1) +} diff --git a/tui/tui.go b/tui/tui.go index 6d651e1..0e6146b 100644 --- a/tui/tui.go +++ b/tui/tui.go @@ -6,25 +6,20 @@ import ( "code.humancabbage.net/sam/moonmath/coindesk" "code.humancabbage.net/sam/moonmath/config" "code.humancabbage.net/sam/moonmath/tui/asset" + "code.humancabbage.net/sam/moonmath/tui/perf" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) type Model struct { - assets []asset.Model + assets []asset.Model + stats perf.Model + displayStats bool } -func New(assets []coindesk.Asset, cfg config.All) (p *tea.Program) { - model := newModel(assets, cfg) - p = tea.NewProgram( - model, - tea.WithAltScreen(), - tea.WithFPS(30), - ) - return -} - -func newModel(assets []coindesk.Asset, cfg config.All) (m Model) { +func New(assets []coindesk.Asset, cfg config.All, displayStats bool) (m Model) { + m.stats = perf.New() + m.displayStats = displayStats // construct models for each asset, but don't filter out dupes seen := map[coindesk.Asset]struct{}{} for _, a := range assets { @@ -52,6 +47,7 @@ func (m Model) Init() tea.Cmd { } func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + m.stats.AddUpdate() switch msg := msg.(type) { // handle keys for quitting case tea.KeyMsg: @@ -78,11 +74,15 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m Model) View() string { + m.stats.AddView() var ss []string for i := range m.assets { s := m.assets[i].View() ss = append(ss, s) } + if m.displayStats { + ss = append(ss, m.stats.View()) + } r := lipgloss.JoinVertical(lipgloss.Center, ss...) return r }