pingo.go 2.9 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. p pingo.Model
  20. }
  21. type timingMsg time.Time
  22. var (
  23. // footer styles
  24. titleStyle = lipgloss.NewStyle().
  25. Align(lipgloss.Center). // implies consumer functions will apply a width
  26. Italic(true).
  27. Faint(true)
  28. // footer style
  29. footerStyle = lipgloss.NewStyle().
  30. Align(lipgloss.Center). // implies consumer functions will apply a width
  31. Italic(true).
  32. Faint(true)
  33. )
  34. func (m md) Init() tea.Cmd {
  35. return tea.Tick(100*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) })
  36. }
  37. func (m md) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  38. var cmds []tea.Cmd
  39. var cmd tea.Cmd
  40. switch msg := msg.(type) {
  41. case tea.WindowSizeMsg:
  42. m.p.Width = msg.Width
  43. m.p.Height = msg.Height - m.getVerticalMargin() - 1
  44. if m.viewport.Width() == 0 && m.viewport.Height() == 0 {
  45. m.viewport = viewport.New(
  46. viewport.WithHeight(msg.Height-m.getVerticalMargin()),
  47. viewport.WithWidth(msg.Width),
  48. )
  49. }
  50. m.viewport.SetHeight(msg.Height - m.getVerticalMargin())
  51. m.viewport.SetWidth(msg.Width)
  52. m.viewport.YPosition = 1
  53. case tea.KeyPressMsg:
  54. k := msg.String()
  55. if k == "ctrl+c" {
  56. return m, tea.Quit
  57. }
  58. case timingMsg:
  59. cmd = tea.Tick(100*time.Millisecond, func(t time.Time) tea.Msg { return timingMsg(t) })
  60. cmds = append(cmds, cmd, m.p.Poll())
  61. }
  62. m.viewport.SetContent(m.p.View().Content)
  63. m.viewport, cmd = m.viewport.Update(msg)
  64. cmds = append(cmds, cmd)
  65. model, cmd := m.p.Update(msg)
  66. m.p = model.(pingo.Model)
  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.InitialModel(hosts, 20, 10, *chartHeight)})
  94. if _, err := p.Run(); err != nil {
  95. fmt.Printf("Alas, there's been an error: %v", err)
  96. os.Exit(1)
  97. }
  98. }