// A simple TUI application that charts latency times to specified hosts. // // i.e, change the address title to red so long as there is a single -1 in // the display buffer, and a toast notification (???) if a display buffer is // entirely composed of -1 package main import ( "flag" "fmt" "os" "pingo" "time" "charm.land/bubbles/v2/viewport" tea "charm.land/bubbletea/v2" "charm.land/lipgloss/v2" ) type md struct { viewport viewport.Model speed time.Duration p pingo.Model } type timingMsg time.Time var ( // footer styles titleStyle = lipgloss.NewStyle(). Align(lipgloss.Center). // implies consumer functions will apply a width Italic(true). Faint(true) // footer style footerStyle = lipgloss.NewStyle(). Align(lipgloss.Center). // implies consumer functions will apply a width Italic(true). Faint(true) ) func (m md) Init() tea.Cmd { return tea.Tick(m.speed*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) }) } func (m md) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd var cmd tea.Cmd switch msg := msg.(type) { case tea.WindowSizeMsg: m.p.Width = msg.Width m.p.Height = msg.Height - m.getVerticalMargin() - 1 if m.viewport.Width() == 0 && m.viewport.Height() == 0 { m.viewport = viewport.New( viewport.WithHeight(msg.Height-m.getVerticalMargin()), viewport.WithWidth(msg.Width), ) } m.viewport.SetHeight(msg.Height - m.getVerticalMargin()) m.viewport.SetWidth(msg.Width) m.viewport.YPosition = 1 case tea.KeyPressMsg: k := msg.String() if k == "ctrl+c" { return m, tea.Quit } case timingMsg: cmd = tea.Tick(m.speed*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) }) cmds = append(cmds, tea.Sequence(m.p.Poll(), cmd)) } m.viewport.SetContent(m.p.View().Content) m.viewport, cmd = m.viewport.Update(msg) cmds = append(cmds, cmd) model, cmd := m.p.Update(msg) m.p = model.(pingo.Model) cmds = append(cmds, cmd) return m, tea.Batch(cmds...) } func (m md) View() tea.View { m.viewport.SetContent(m.p.View().Content) content := fmt.Sprintf("%s%s\n%s", m.header(), m.viewport.View(), m.footer()) var v tea.View v.SetContent(content) v.AltScreen = true return v } func (m md) header() string { return titleStyle.Width(m.viewport.Width()).Render("pingo v0") } func (m md) footer() string { return footerStyle.Width(m.viewport.Width()).Render("j/k: down/up\t|\tctrl+c: quit") } func (m md) getVerticalMargin() int { return lipgloss.Height(m.header() + m.footer()) } func main() { speed := flag.Int("s", 80, "the speed with which the UI runs") chartHeight := flag.Int("h", 0, "the height of the latency chart. set to 0 to render charts full screen.") flag.Parse() hosts := flag.Args() if len(hosts) == 0 { fmt.Println("Must specify hosts!") return } p := tea.NewProgram(md{p: pingo.InitialModel(hosts, 20, 10, *chartHeight), speed: time.Duration(*speed)}) if _, err := p.Run(); err != nil { fmt.Printf("Alas, there's been an error: %v", err) os.Exit(1) } }