Pause spinner ticks when not refreshing.
All checks were successful
Build & Test / Main (push) Successful in 59s

Also, add a quick-and-dirty model for displaying basic performance
stats, currently just the number of calls to the root Update() and
View() methods.
This commit is contained in:
Sam Fredrickson 2024-03-22 21:12:14 -07:00
parent c4dde38d23
commit 270534c0d5
4 changed files with 74 additions and 18 deletions

View File

@ -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)
}

View File

@ -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 {
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

42
tui/perf/perf.go Normal file
View File

@ -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)
}

View File

@ -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
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
}