From e6e18e50120c7c064f41be7ef1acd5a8d57b78b2 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Mon, 22 Jul 2024 14:57:15 -0400 Subject: [PATCH] feat!: use new bubbletea input api --- README.md | 2 +- filepicker/filepicker.go | 4 ++-- go.mod | 15 +++++++++------ go.sum | 18 ++++++++++++++++++ key/key.go | 4 ++-- list/list.go | 6 +++--- paginator/paginator.go | 2 +- paginator/paginator_test.go | 4 ++-- progress/progress.go | 4 ++-- table/table.go | 2 +- textarea/textarea.go | 7 +++++-- textarea/textarea_test.go | 10 +++++----- textinput/textinput.go | 9 ++++++--- viewport/viewport.go | 11 ++++------- 14 files changed, 61 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f6e4d21..b0a021f 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ var DefaultKeyMap = KeyMap{ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, DefaultKeyMap.Up): // The user pressed up diff --git a/filepicker/filepicker.go b/filepicker/filepicker.go index 9a1235a..3f06921 100644 --- a/filepicker/filepicker.go +++ b/filepicker/filepicker.go @@ -254,7 +254,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { m.Height = msg.Height - marginBottom } m.max = m.Height - 1 - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.GoToTop): m.selected = 0 @@ -463,7 +463,7 @@ func (m Model) didSelectFile(msg tea.Msg) (bool, string) { return false, "" } switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: // If the msg does not match the Select keymap then this could not have been a selection. if !key.Matches(msg, m.KeyMap.Select) { return false, "" diff --git a/go.mod b/go.mod index 4d7b1bb..6ab790b 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,10 @@ go 1.18 require ( github.com/MakeNowJust/heredoc v1.0.0 github.com/atotto/clipboard v0.1.4 - github.com/charmbracelet/bubbletea v0.26.4 + github.com/charmbracelet/bubbletea v0.26.7-0.20240722185632-e15f5e8453c6 github.com/charmbracelet/harmonica v0.2.0 - github.com/charmbracelet/lipgloss v0.11.0 - github.com/charmbracelet/x/ansi v0.1.2 + github.com/charmbracelet/lipgloss v0.12.1 + github.com/charmbracelet/x/ansi v0.1.4 github.com/dustin/go-humanize v1.0.1 github.com/lucasb-eyer/go-colorful v1.2.0 github.com/mattn/go-runewidth v0.0.15 @@ -19,9 +19,10 @@ require ( require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/x/input v0.1.0 // indirect + github.com/charmbracelet/shampoo v0.0.0-00010101000000-000000000000 // indirect + github.com/charmbracelet/x/input v0.1.3 // indirect github.com/charmbracelet/x/term v0.1.1 // indirect - github.com/charmbracelet/x/windows v0.1.0 // indirect + github.com/charmbracelet/x/windows v0.1.2 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -30,6 +31,8 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.3.8 // indirect ) + +replace github.com/charmbracelet/shampoo => ../shampoo diff --git a/go.sum b/go.sum index 41f2d1d..593303d 100644 --- a/go.sum +++ b/go.sum @@ -6,18 +6,34 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40= github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722180334-ce80c3f0df51 h1:CsaCaDqRcboCOczWOfmja+TjApzBAlzcxj3iBMxJbRs= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722180334-ce80c3f0df51/go.mod h1:UxcWwrixHinfMcAYXyEePrWDnZcnYD1DezkwwhsVDeU= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722184912-1ea337f015e5 h1:19HwiGxeFwW+7KZOF0GRpgiYg6zx0c5rdbHI7FN16lg= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722184912-1ea337f015e5/go.mod h1:UxcWwrixHinfMcAYXyEePrWDnZcnYD1DezkwwhsVDeU= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722185123-460967f9b5a4 h1:ZPnOa7i6Yyh9FIKGP4B3EGm3Asaz4AnCy9UP7UXxO48= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722185123-460967f9b5a4/go.mod h1:UxcWwrixHinfMcAYXyEePrWDnZcnYD1DezkwwhsVDeU= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722185632-e15f5e8453c6 h1:j6y5mOC7dC+1/yqOzLUaAgyTkeWNdzn8XUVMczB1bt4= +github.com/charmbracelet/bubbletea v0.26.7-0.20240722185632-e15f5e8453c6/go.mod h1:UxcWwrixHinfMcAYXyEePrWDnZcnYD1DezkwwhsVDeU= github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= +github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs= +github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8= github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY= github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= +github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= +github.com/charmbracelet/x/input v0.1.3 h1:oy4TMhyGQsYs/WWJwu1ELUMFnjiUAXwtDf048fHbCkg= +github.com/charmbracelet/x/input v0.1.3/go.mod h1:1gaCOyw1KI9e2j00j/BBZ4ErzRZqa05w0Ghn83yIhKU= github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4= github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= @@ -52,5 +68,7 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= diff --git a/key/key.go b/key/key.go index c7888fa..b6f486d 100644 --- a/key/key.go +++ b/key/key.go @@ -20,7 +20,7 @@ // // func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg := msg.(type) { -// case tea.KeyMsg: +// case tea.KeyPressMsg: // switch { // case key.Matches(msg, DefaultKeyMap.Up): // // The user pressed up @@ -129,7 +129,7 @@ type Help struct { } // Matches checks if the given KeyMsg matches the given bindings. -func Matches(k tea.KeyMsg, b ...Binding) bool { +func Matches(k tea.KeyPressMsg, b ...Binding) bool { keys := k.String() for _, binding := range b { for _, v := range binding.keys { diff --git a/list/list.go b/list/list.go index 17e6e15..8d5fb50 100644 --- a/list/list.go +++ b/list/list.go @@ -771,7 +771,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: if key.Matches(msg, m.KeyMap.ForceQuit) { return m, tea.Quit } @@ -806,7 +806,7 @@ func (m *Model) handleBrowsing(msg tea.Msg) tea.Cmd { numItems := len(m.VisibleItems()) switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { // Note: we match clear filter before quit because, by default, they're // both mapped to escape. @@ -875,7 +875,7 @@ func (m *Model) handleFiltering(msg tea.Msg) tea.Cmd { var cmds []tea.Cmd // Handle keys - if msg, ok := msg.(tea.KeyMsg); ok { + if msg, ok := msg.(tea.KeyPressMsg); ok { switch { case key.Matches(msg, m.KeyMap.CancelWhileFiltering): m.resetFiltering() diff --git a/paginator/paginator.go b/paginator/paginator.go index 82dc3ed..87e777a 100644 --- a/paginator/paginator.go +++ b/paginator/paginator.go @@ -152,7 +152,7 @@ var NewModel = New // Update is the Tea update function which binds keystrokes to pagination. func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.NextPage): m.NextPage() diff --git a/paginator/paginator_test.go b/paginator/paginator_test.go index 57f326c..1c9c18b 100644 --- a/paginator/paginator_test.go +++ b/paginator/paginator_test.go @@ -50,7 +50,7 @@ func TestPrevPage(t *testing.T) { model.SetTotalPages(tt.totalPages) model.Page = tt.page - model, _ = model.Update(tea.KeyMsg{Type: tea.KeyLeft, Alt: false, Runes: []rune{}}) + model, _ = model.Update(tea.KeyPressMsg{Sym: tea.KeyLeft}) if model.Page != tt.expected { t.Errorf("PrevPage() = %d, expected %d", model.Page, tt.expected) } @@ -75,7 +75,7 @@ func TestNextPage(t *testing.T) { model.SetTotalPages(tt.totalPages) model.Page = tt.page - model, _ = model.Update(tea.KeyMsg{Type: tea.KeyRight, Alt: false, Runes: []rune{}}) + model, _ = model.Update(tea.KeyPressMsg{Sym: tea.KeyRight}) if model.Page != tt.expected { t.Errorf("NextPage() = %d, expected %d", model.Page, tt.expected) } diff --git a/progress/progress.go b/progress/progress.go index defa981..be5b16b 100644 --- a/progress/progress.go +++ b/progress/progress.go @@ -205,8 +205,8 @@ func New(opts ...Option) Model { var NewModel = New // Init exists to satisfy the tea.Model interface. -func (m Model) Init() tea.Cmd { - return nil +func (m Model) Init() (tea.Model, tea.Cmd) { + return m, nil } // Update is used to animate the progress bar during transitions. Use diff --git a/table/table.go b/table/table.go index 3b8d3e2..97c6ce6 100644 --- a/table/table.go +++ b/table/table.go @@ -210,7 +210,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.LineUp): m.MoveUp(1) diff --git a/textarea/textarea.go b/textarea/textarea.go index 153f39e..53b2f89 100644 --- a/textarea/textarea.go +++ b/textarea/textarea.go @@ -973,7 +973,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.DeleteAfterCursor): m.col = clamp(m.col, 0, len(m.value[m.row])) @@ -1060,9 +1060,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { m.transposeLeft() default: - m.insertRunesFromUserInput(msg.Runes) + m.insertRunesFromUserInput([]rune{msg.Rune}) } + case tea.PasteMsg: + m.insertRunesFromUserInput([]rune(msg)) + case pasteMsg: m.insertRunesFromUserInput([]rune(msg)) diff --git a/textarea/textarea_test.go b/textarea/textarea_test.go index 6aab299..89ea810 100644 --- a/textarea/textarea_test.go +++ b/textarea/textarea_test.go @@ -234,7 +234,7 @@ func TestVerticalNavigationKeepsCursorHorizontalPosition(t *testing.T) { t.Fatal("Expected cursor to be on the fourth character because there are two double width runes on the first line.") } - downMsg := tea.KeyMsg{Type: tea.KeyDown, Alt: false, Runes: []rune{}} + downMsg := tea.KeyPressMsg{Sym: tea.KeyDown} textarea, _ = textarea.Update(downMsg) lineInfo = textarea.LineInfo() @@ -273,7 +273,7 @@ func TestVerticalNavigationShouldRememberPositionWhileTraversing(t *testing.T) { } // Let's go up. - upMsg := tea.KeyMsg{Type: tea.KeyUp, Alt: false, Runes: []rune{}} + upMsg := tea.KeyPressMsg{Sym: tea.KeyUp} textarea, _ = textarea.Update(upMsg) // We should be at the end of the second line. @@ -292,7 +292,7 @@ func TestVerticalNavigationShouldRememberPositionWhileTraversing(t *testing.T) { } // Let's go down, twice. - downMsg := tea.KeyMsg{Type: tea.KeyDown, Alt: false, Runes: []rune{}} + downMsg := tea.KeyPressMsg{Sym: tea.KeyDown} textarea, _ = textarea.Update(downMsg) textarea, _ = textarea.Update(downMsg) @@ -308,7 +308,7 @@ func TestVerticalNavigationShouldRememberPositionWhileTraversing(t *testing.T) { // work. textarea, _ = textarea.Update(upMsg) - leftMsg := tea.KeyMsg{Type: tea.KeyLeft, Alt: false, Runes: []rune{}} + leftMsg := tea.KeyPressMsg{Sym: tea.KeyLeft} textarea, _ = textarea.Update(leftMsg) if textarea.col != 4 || textarea.row != 1 { @@ -1716,7 +1716,7 @@ func newTextArea() Model { } func keyPress(key rune) tea.Msg { - return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{key}, Alt: false} + return tea.KeyPressMsg{Rune: key} } func sendString(m Model, str string) Model { diff --git a/textinput/textinput.go b/textinput/textinput.go index 93bc150..ceb7870 100644 --- a/textinput/textinput.go +++ b/textinput/textinput.go @@ -555,7 +555,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { } // Need to check for completion before, because key is configurable and might be double assigned - keyMsg, ok := msg.(tea.KeyMsg) + keyMsg, ok := msg.(tea.KeyPressMsg) if ok && key.Matches(keyMsg, m.KeyMap.AcceptSuggestion) { if m.canAcceptSuggestion() { m.value = append(m.value, m.matchedSuggestions[m.currentSuggestionIndex][len(m.value):]...) @@ -568,7 +568,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { oldPos := m.pos //nolint switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.DeleteWordBackward): m.deleteWordBackward() @@ -616,13 +616,16 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { m.previousSuggestion() default: // Input one or more regular characters. - m.insertRunesFromUserInput(msg.Runes) + m.insertRunesFromUserInput([]rune{msg.Rune}) } // Check again if can be completed // because value might be something that does not match the completion prefix m.updateSuggestions() + case tea.PasteMsg: + m.insertRunesFromUserInput([]rune(msg)) + case pasteMsg: m.insertRunesFromUserInput([]rune(msg)) diff --git a/viewport/viewport.go b/viewport/viewport.go index e0a4cc3..81d0d40 100644 --- a/viewport/viewport.go +++ b/viewport/viewport.go @@ -292,7 +292,7 @@ func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { - case tea.KeyMsg: + case tea.KeyPressMsg: switch { case key.Matches(msg, m.KeyMap.PageDown): lines := m.ViewDown() @@ -331,18 +331,15 @@ func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) { } } - case tea.MouseMsg: - if !m.MouseWheelEnabled || msg.Action != tea.MouseActionPress { - break - } + case tea.MouseWheelMsg: switch msg.Button { - case tea.MouseButtonWheelUp: + case tea.MouseWheelUp: lines := m.LineUp(m.MouseWheelDelta) if m.HighPerformanceRendering { cmd = ViewUp(m, lines) } - case tea.MouseButtonWheelDown: + case tea.MouseWheelDown: lines := m.LineDown(m.MouseWheelDelta) if m.HighPerformanceRendering { cmd = ViewDown(m, lines)