diff --git a/examples/debounce/main.go b/examples/debounce/main.go new file mode 100644 index 0000000..834f521 --- /dev/null +++ b/examples/debounce/main.go @@ -0,0 +1,66 @@ +package main + +// This example illustrates how to debounce commands. +// +// When the user presses a key we increment the "tag" value on the model and, +// after a short delay, we include that tag value in the message produced +// by the Tick command. +// +// In a subsequent Update, if the tag in the Msg matches current tag on the +// model's state we know that the debouncing is complete and we can proceeed as +// normal. If not, we simply ignore the inbound message. + +import ( + "fmt" + "os" + "time" + + tea "github.com/charmbracelet/bubbletea" +) + +const debounceDuration = time.Second + +type exitMsg int + +type model struct { + tag int +} + +func (m model) Init() tea.Cmd { + return nil +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + // Increment the tag on the model... + m.tag++ + return m, tea.Tick(debounceDuration, func(_ time.Time) tea.Msg { + // ...and include a copy of that tag value in the message. + return exitMsg(m.tag) + }) + case exitMsg: + // If the tag in the message doesn't match the tag on the model then we + // know that this message was not the last one sent and another is on + // the way. If that's the case we know, we can ignore this message. + // Otherwise, the debounce timeout has passed and this message is a + // valid debounced one. + if int(msg) == m.tag { + return m, tea.Quit + } + } + + return m, nil +} + +func (m model) View() string { + return fmt.Sprintf("Key presses: %d", m.tag) + + "\nTo exit press any key, then wait for one second without pressing anything." +} + +func main() { + if err := tea.NewProgram(model{}).Start(); err != nil { + fmt.Println("uh oh:", err) + os.Exit(1) + } +}