diff --git a/examples/event-logger/main.go b/examples/event-logger/main.go new file mode 100644 index 0000000..5f9a6bc --- /dev/null +++ b/examples/event-logger/main.go @@ -0,0 +1,158 @@ +package main + +// An event logger that displays tea window-size, key, and mouse events. + +import ( + "fmt" + "log" + "time" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/dustin/go-humanize" +) + +var ( + typeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) + msgStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#DDDDDD")) + timeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FF06B7")) + tooltipStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#333333")) +) + +func main() { + p := tea.NewProgram(&model{lastEvent: time.Now()}, + tea.WithAltScreen(), + tea.WithMouseAllMotion(), + ) + if _, err := p.Run(); err != nil { + log.Fatal(err) + } +} + +type event struct { + timestamp time.Time + msg tea.Msg +} + +type model struct { + width int + height int + + lastEvent time.Time + lastMouseEvent tea.MouseEvent + + events []event +} + +func (m *model) Init() tea.Cmd { + return tick +} + +func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c": + return m, tea.Quit + } + + case tea.MouseMsg: + m.lastMouseEvent = tea.MouseEvent(msg) + + if m.lastMouseEvent.Type == tea.MouseMotion { + // don't log motion events as it becomes spamy + return m, nil + } + + case tea.WindowSizeMsg: + m.width = msg.Width + m.height = msg.Height + + case tickMsg: + return m, tick + } + + m.lastEvent = time.Now() + m.events = append(m.events, event{ + timestamp: time.Now(), + msg: msg, + }) + + return m, nil +} + +func (m model) View() string { + if m.width == 0 || m.height == 0 { + return "" + } + + h := m.height - 3 + evs := m.events + if m.height > 0 && len(evs) > h { + evs = evs[len(evs)-h:] + } + + var s string + for _, event := range evs { + s += fmt.Sprintf("[%s] %s\n", + timeStyle.Render(event.timestamp.Format("15:04:05")), + msgView(event.msg), + ) + } + + lastEvent := fmt.Sprintf("Waiting for event... (last %s)", humanize.Time(m.lastEvent)) + cursor := fmt.Sprintf("X: %d, Y: %d", m.lastMouseEvent.X, m.lastMouseEvent.Y) + + return fmt.Sprintf("%s\n%s%s\n%s", + lipgloss.NewStyle().Height(h+1).Render(s), + lipgloss.NewStyle().Width(m.width-16).Render(lastEvent), + lipgloss.NewStyle().Width(16).Align(lipgloss.Right).Render(cursor), + tooltipStyle.Render("Press Ctrl+C to quit"), + ) +} + +func msgView(msg tea.Msg) string { + switch ev := msg.(type) { + case tea.KeyMsg: + return fmt.Sprintf("%s %s", + typeStyle.Render("KeyMsg"), + msgStyle.Render( + fmt.Sprintf("%s (alt: %t)", + ev.String(), + ev.Alt, + ), + ), + ) + case tea.MouseMsg: + return fmt.Sprintf("%s %s", + typeStyle.Render("MouseMsg"), + msgStyle.Render( + fmt.Sprintf("X: %d, Y: %d, type: %s", + ev.X, + ev.Y, + tea.MouseEvent(ev), + ), + ), + ) + case tea.WindowSizeMsg: + return fmt.Sprintf("%s %s", + typeStyle.Render("WindowSizeMsg"), + msgStyle.Render( + fmt.Sprintf("%d x %d", + ev.Width, + ev.Height, + ), + ), + ) + + default: + return "Unknown event" + } +} + +type tickMsg time.Time + +func tick() tea.Msg { + time.Sleep(time.Second) + return tickMsg{} +} diff --git a/examples/go.mod b/examples/go.mod index 042b22f..06cd96f 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -7,6 +7,7 @@ require ( github.com/charmbracelet/bubbletea v0.22.0 github.com/charmbracelet/glamour v0.5.0 github.com/charmbracelet/lipgloss v0.6.0 + github.com/dustin/go-humanize v1.0.0 github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 github.com/lucasb-eyer/go-colorful v1.2.0 github.com/mattn/go-isatty v0.0.16 diff --git a/examples/go.sum b/examples/go.sum index 65731b4..17f8c7e 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,6 +22,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 h1:VRIbnDWRmAh5yBdz+J6yFMF5vso1It6vn+WmM/5l7MA= github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776/go.mod h1:9wvnDu3YOfxzWM9Cst40msBF1C2UdQgDv962oTxSuMs= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=