Jelajahi Sumber

Implemented tui viewport and tick based timing

arianagiroux 3 minggu lalu
induk
melakukan
accd7b6ea1
2 mengubah file dengan 88 tambahan dan 38 penghapusan
  1. 80 36
      internal/tui/tui.go
  2. 8 2
      main.go

+ 80 - 36
internal/tui/tui.go

@@ -2,23 +2,31 @@ package tui
 
 import (
 	"fmt"
+	"time"
 
 	"github.com/NimbleMarkets/ntcharts/linechart/streamlinechart"
+	"github.com/charmbracelet/bubbles/viewport"
 	tea "github.com/charmbracelet/bubbletea"
 	"github.com/charmbracelet/lipgloss"
 )
 
 // Bubbletea model
 type Model struct {
-	width     int
-	Addresses []Address // as defined in internal/tui/types.go
+	width       int
+	Addresses   []Address // as defined in internal/tui/types.go
+	viewport    viewport.Model
+	UpdateSpeed time.Duration
 }
 
-func InitialModel(addresses []string) Model {
+func InitialModel(addresses []string, speed time.Duration) Model {
 	var model Model
+	model.viewport = viewport.New(0, 0)
+	model.viewport.MouseWheelEnabled = true
+	model.UpdateSpeed = speed
+
 	for _, address := range addresses {
 		var addr Address
-		addr.max_results = 999
+		addr.max_results = 80
 		addr.Address = address
 		model.Addresses = append(model.Addresses, addr)
 	}
@@ -26,29 +34,18 @@ func InitialModel(addresses []string) Model {
 }
 
 func (m Model) Init() tea.Cmd {
-	return m.Poll
+	return m.Tick()
 }
 
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
-	switch msg := msg.(type) {
-	// if case is KeyMsg (keypress)
-	case tea.WindowSizeMsg:
-		m.width = msg.Width
-		for i, address := range m.Addresses {
-			address.max_results = m.width
-			m.Addresses[i] = address
-		}
+type tickMsg time.Time
 
-	case tea.KeyMsg:
-		return m, tea.Quit
-
-	case pollMsg:
-		m.Poll()
-	}
-	return m, m.Poll
+func (m Model) Tick() tea.Cmd {
+	return tea.Tick(time.Millisecond*m.UpdateSpeed, func(t time.Time) tea.Msg {
+		return tickMsg(t)
+	})
 }
 
-func (m Model) View() string {
+func (m Model) content() string {
 	var headerStyle = lipgloss.NewStyle().
 		Bold(true).
 		Italic(true)
@@ -57,28 +54,74 @@ func (m Model) View() string {
 		Width(m.width).
 		Align(lipgloss.Center)
 
-	output := "Results:\n\n"
-	for _, address := range m.Addresses {
+	var footerStyle = lipgloss.NewStyle().
+		Width(m.width).
+		Align(lipgloss.Center).
+		Italic(true).
+		Faint(true)
 
+	output := "\n"
+	for _, address := range m.Addresses {
 		if len(address.results) == 0 {
-			output = output + fmt.Sprintf("%s\tloading...\n\n", headerStyle.Render(address.Address))
+			output = output + fmt.Sprintf("\n%s\tloading...\n\n", headerStyle.Render(address.Address))
 		} else {
-			output = output + fmt.Sprintf("%s\n\n", blockStyle.Render(headerStyle.Render(address.Address)))
-
-			if m.width > 0 {
-				// Linechart
-				slc := streamlinechart.New(m.width, 10)
-				for _, v := range address.results {
-					slc.Push(v)
-				}
-				slc.Draw()
-				output = output + fmt.Sprintf("%s\n\n", slc.View())
+			output = output + fmt.Sprintf("\n%s\n\n", blockStyle.Render(headerStyle.Render(address.Address)))
+
+			// Linechart
+			slc := streamlinechart.New(m.width, 7)
+			for _, v := range address.results {
+				slc.Push(v)
 			}
+			slc.Draw()
+			output = output + blockStyle.Render(fmt.Sprintf("\n%s\n", slc.View()))
 		}
 	}
 
+	output = output + footerStyle.Render("\n--------\npingo v0\n")
+
 	return output
 }
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	var cmd tea.Cmd
+	var cmds []tea.Cmd
+
+	switch msg := msg.(type) {
+	// if case is KeyMsg (keypress)
+	case tea.WindowSizeMsg:
+		m.width = msg.Width
+		for i, address := range m.Addresses {
+			address.max_results = m.width
+			m.Addresses[i] = address
+		}
+		m.viewport.Height = msg.Height
+		m.viewport.Width = msg.Width
+		// m.viewport.YPosition = 0
+
+	case tea.KeyMsg:
+		if k := msg.String(); k == "j" { // scroll down
+			m.viewport.HalfViewDown()
+		} else if k == "k" { // scroll up
+			m.viewport.HalfViewUp()
+		} else {
+			return m, tea.Quit
+		}
+
+	case tickMsg:
+		cmds = append(cmds, m.Tick())
+		cmds = append(cmds, m.Poll)
+	}
+
+	m.viewport, cmd = m.viewport.Update(msg)
+	m.viewport.SetContent(m.content())
+	cmds = append(cmds, cmd)
+	// cmds = append(cmds, m.Poll)
+
+	return m, tea.Batch(cmds...)
+}
+
+func (m Model) View() string {
+	return fmt.Sprintf("\n%s\n", m.viewport.View())
+}
 
 // A wrapper for the underlying [tui.Address.Poll] function. For each address in
 // [tui.Model.Addresses], run its respective Poll function and update [tui.Model]
@@ -87,7 +130,8 @@ func (m Model) View() string {
 func (m Model) Poll() tea.Msg {
 	for i, element := range m.Addresses {
 		element.Poll()
+		// element.results = append(element.results, -1)
 		m.Addresses[i] = element
 	}
-	return true
+	return nil
 }

+ 8 - 2
main.go

@@ -5,11 +5,13 @@ import (
 	"fmt"
 	"os"
 	"pingo/internal/tui"
+	"time"
 
 	tea "github.com/charmbracelet/bubbletea"
 )
 
 func main() {
+	speed := flag.Int("s", 80, "the speed with which the UI runs")
 	flag.Parse()
 	hosts := flag.Args()
 
@@ -19,10 +21,14 @@ func main() {
 	}
 	var model = tui.InitialModel( // TODO(argv) set args via argv
 		// []string{"doesntresolve.comdoasdf", "google.ca"},
-		hosts,
+		hosts, time.Duration(*speed),
+	)
+
+	p := tea.NewProgram(model,
+		tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer"
+		// tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
 	)
 
-	p := tea.NewProgram(model)
 	if _, err := p.Run(); err != nil {
 		fmt.Printf("Alas, there's been an error: %v", err)
 		os.Exit(1)