1
0

pingo.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // A simple TUI application that charts latency times to specified hosts.
  2. //
  3. // i.e, change the address title to red so long as there is a single -1 in
  4. // the display buffer, and a toast notification (???) if a display buffer is
  5. // entirely composed of -1
  6. package main
  7. import (
  8. "flag"
  9. "fmt"
  10. "os"
  11. "pingo"
  12. "time"
  13. "charm.land/bubbles/v2/viewport"
  14. tea "charm.land/bubbletea/v2"
  15. "charm.land/lipgloss/v2"
  16. )
  17. type md struct {
  18. viewport viewport.Model
  19. speed time.Duration
  20. p pingo.Peak
  21. }
  22. type timingMsg time.Time
  23. var (
  24. // footer styles
  25. titleStyle = lipgloss.NewStyle().
  26. Align(lipgloss.Center). // implies consumer functions will apply a width
  27. Italic(true).
  28. Faint(true)
  29. // footer style
  30. footerStyle = lipgloss.NewStyle().
  31. Align(lipgloss.Center). // implies consumer functions will apply a width
  32. Italic(true).
  33. Faint(true)
  34. )
  35. func (m md) Init() tea.Cmd {
  36. return tea.Tick(m.speed*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) })
  37. }
  38. func (m md) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  39. var cmds []tea.Cmd
  40. var cmd tea.Cmd
  41. switch msg := msg.(type) {
  42. case tea.WindowSizeMsg:
  43. m.p.Width = msg.Width
  44. m.p.Height = msg.Height - m.getVerticalMargin() - 1
  45. if m.viewport.Width() == 0 && m.viewport.Height() == 0 {
  46. m.viewport = viewport.New(
  47. viewport.WithHeight(msg.Height-m.getVerticalMargin()),
  48. viewport.WithWidth(msg.Width),
  49. )
  50. }
  51. m.viewport.SetHeight(msg.Height - m.getVerticalMargin())
  52. m.viewport.SetWidth(msg.Width)
  53. m.viewport.YPosition = 1
  54. case tea.KeyPressMsg:
  55. k := msg.String()
  56. if k == "ctrl+c" {
  57. return m, tea.Quit
  58. }
  59. case timingMsg:
  60. cmd = tea.Tick(m.speed*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) })
  61. cmds = append(cmds, tea.Sequence(m.p.Poll(), cmd))
  62. }
  63. m.viewport.SetContent(m.p.View().Content)
  64. m.viewport, cmd = m.viewport.Update(msg)
  65. cmds = append(cmds, cmd)
  66. m.p, cmd = m.p.Update(msg)
  67. cmds = append(cmds, cmd)
  68. return m, tea.Batch(cmds...)
  69. }
  70. func (m md) View() tea.View {
  71. m.viewport.SetContent(m.p.View().Content)
  72. content := fmt.Sprintf("%s%s\n%s", m.header(), m.viewport.View(), m.footer())
  73. var v tea.View
  74. v.SetContent(content)
  75. v.AltScreen = true
  76. return v
  77. }
  78. func (m md) header() string { return titleStyle.Width(m.viewport.Width()).Render("pingo v0") }
  79. func (m md) footer() string {
  80. return footerStyle.Width(m.viewport.Width()).Render("j/k: down/up\t|\tctrl+c: quit")
  81. }
  82. func (m md) getVerticalMargin() int { return lipgloss.Height(m.header() + m.footer()) }
  83. func main() {
  84. speed := flag.Int("s", 80, "the speed with which the UI runs")
  85. chartHeight := flag.Int("h", 0,
  86. "the height of the latency chart. set to 0 to render charts full screen.")
  87. flag.Parse()
  88. hosts := flag.Args()
  89. if len(hosts) == 0 {
  90. fmt.Println("Must specify hosts!")
  91. return
  92. }
  93. p := tea.NewProgram(md{p: pingo.InitialPeakBubble(hosts, 20, 10, *chartHeight), speed: time.Duration(*speed)})
  94. if _, err := p.Run(); err != nil {
  95. fmt.Printf("Alas, there's been an error: %v", err)
  96. os.Exit(1)
  97. }
  98. }