on main help sign in
fix: tui: use KeyPressMsg instead of KeyMsg

The `tea.KeyMsg` type can match both key presses and releases, which can lead to unexpected behavior in the TUI. Use `tea.KeyPressMsg` explicitly to ensure we match only key presses.

commitbc67c13e666dd1b812679b89e5daa90973a154e7 authorAyman Bagabas <ayman.bagabas@gmail.com> dateWed 21 May 2025, 12:04 (1 year ago) parent9c4a47b
16 files changed+25−476
internal/format/spinner.go+1−1 internal/tui/components/chat/list.go−451 internal/tui/components/core/list/list.go+1−1 internal/tui/components/dialog/arguments.go+1−1 internal/tui/components/dialog/commands.go+1−1 internal/tui/components/dialog/complete.go+1−1 internal/tui/components/dialog/filepicker.go+1−1 internal/tui/components/dialog/init.go+2−2 internal/tui/components/dialog/models.go+1−1 internal/tui/components/dialog/permission.go+1−1 internal/tui/components/dialog/quit.go+1−1 internal/tui/components/dialog/session.go+1−1 internal/tui/components/dialog/theme.go+1−1 internal/tui/components/util/simple-list.go+1−1 internal/tui/page/chat.go+2−2 internal/tui/tui.go+9−9
internal/format/spinner.go+1−1
@@ -31,7 +31,7 @@ func (m spinnerModel) Init() tea.Cmd {
3131
3232func (m spinnerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
3333 switch msg := msg.(type) {
34− case tea.KeyMsg:
34+ case tea.KeyPressMsg:
3535 m.quitting = true
3636 return m, tea.Quit
3737 case spinner.TickMsg:
internal/tui/components/chat/list.go−451
@@ -2,48 +2,6 @@ package chat
22
33import "github.com/charmbracelet/bubbles/v2/key"
44
5−// import (
6−//
7−// "context"
8−// "fmt"
9−// "math"
10−//
11−// "github.com/charmbracelet/bubbles/v2/key"
12−// "github.com/charmbracelet/bubbles/v2/spinner"
13−// "github.com/charmbracelet/bubbles/v2/viewport"
14−// tea "github.com/charmbracelet/bubbletea/v2"
15−// "github.com/charmbracelet/lipgloss/v2"
16−// "github.com/opencode-ai/opencode/internal/app"
17−// "github.com/opencode-ai/opencode/internal/message"
18−// "github.com/opencode-ai/opencode/internal/pubsub"
19−// "github.com/opencode-ai/opencode/internal/session"
20−// "github.com/opencode-ai/opencode/internal/tui/components/dialog"
21−// "github.com/opencode-ai/opencode/internal/tui/styles"
22−// "github.com/opencode-ai/opencode/internal/tui/theme"
23−// "github.com/opencode-ai/opencode/internal/tui/util"
24−//
25−// )
26−//
27−// type cacheItem struct {
28−// width int
29−// content []uiMessage
30−// }
31−//
32−// type messagesCmp struct {
33−// app *app.App
34−// width, height int
35−// viewport viewport.Model
36−// session session.Session
37−// messages []message.Message
38−// uiMessages []uiMessage
39−// currentMsgID string
40−// cachedContent map[string]cacheItem
41−// spinner spinner.Model
42−// rendering bool
43−// attachments viewport.Model
44−// }
45−//
46−// type renderFinishedMsg struct{}
475type MessageKeys struct {
486 PageDown key.Binding
497 PageUp key.Binding
@@ -69,412 +27,3 @@ var messageKeys = MessageKeys{
6927 key.WithHelp("ctrl+d", "½ page down"),
7028 ),
7129}
72−
73−//
74−// func (m *messagesCmp) Init() tea.Cmd {
75−// return tea.Batch(m.viewport.Init(), m.spinner.Tick)
76−// }
77−//
78−// func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
79−// var cmds []tea.Cmd
80−// switch msg := msg.(type) {
81−// case dialog.ThemeChangedMsg:
82−// m.rerender()
83−// return m, nil
84−// case SessionSelectedMsg:
85−// if msg.ID != m.session.ID {
86−// cmd := m.SetSession(msg)
87−// return m, cmd
88−// }
89−// return m, nil
90−// case SessionClearedMsg:
91−// m.session = session.Session{}
92−// m.messages = make([]message.Message, 0)
93−// m.currentMsgID = ""
94−// m.rendering = false
95−// return m, nil
96−//
97−// case tea.KeyMsg:
98−// if key.Matches(msg, messageKeys.PageUp) || key.Matches(msg, messageKeys.PageDown) ||
99−// key.Matches(msg, messageKeys.HalfPageUp) || key.Matches(msg, messageKeys.HalfPageDown) {
100−// u, cmd := m.viewport.Update(msg)
101−// m.viewport = u
102−// cmds = append(cmds, cmd)
103−// }
104−//
105−// case renderFinishedMsg:
106−// m.rendering = false
107−// m.viewport.GotoBottom()
108−// case pubsub.Event[session.Session]:
109−// if msg.Type == pubsub.UpdatedEvent && msg.Payload.ID == m.session.ID {
110−// m.session = msg.Payload
111−// if m.session.SummaryMessageID == m.currentMsgID {
112−// delete(m.cachedContent, m.currentMsgID)
113−// m.renderView()
114−// }
115−// }
116−// case pubsub.Event[message.Message]:
117−// needsRerender := false
118−// if msg.Type == pubsub.CreatedEvent {
119−// if msg.Payload.SessionID == m.session.ID {
120−//
121−// messageExists := false
122−// for _, v := range m.messages {
123−// if v.ID == msg.Payload.ID {
124−// messageExists = true
125−// break
126−// }
127−// }
128−//
129−// if !messageExists {
130−// if len(m.messages) > 0 {
131−// lastMsgID := m.messages[len(m.messages)-1].ID
132−// delete(m.cachedContent, lastMsgID)
133−// }
134−//
135−// m.messages = append(m.messages, msg.Payload)
136−// delete(m.cachedContent, m.currentMsgID)
137−// m.currentMsgID = msg.Payload.ID
138−// needsRerender = true
139−// }
140−// }
141−// // There are tool calls from the child task
142−// for _, v := range m.messages {
143−// for _, c := range v.ToolCalls() {
144−// if c.ID == msg.Payload.SessionID {
145−// delete(m.cachedContent, v.ID)
146−// needsRerender = true
147−// }
148−// }
149−// }
150−// } else if msg.Type == pubsub.UpdatedEvent && msg.Payload.SessionID == m.session.ID {
151−// for i, v := range m.messages {
152−// if v.ID == msg.Payload.ID {
153−// m.messages[i] = msg.Payload
154−// delete(m.cachedContent, msg.Payload.ID)
155−// needsRerender = true
156−// break
157−// }
158−// }
159−// }
160−// if needsRerender {
161−// m.renderView()
162−// if len(m.messages) > 0 {
163−// if (msg.Type == pubsub.CreatedEvent) ||
164−// (msg.Type == pubsub.UpdatedEvent && msg.Payload.ID == m.messages[len(m.messages)-1].ID) {
165−// m.viewport.GotoBottom()
166−// }
167−// }
168−// }
169−// }
170−//
171−// spinner, cmd := m.spinner.Update(msg)
172−// m.spinner = spinner
173−// cmds = append(cmds, cmd)
174−// return m, tea.Batch(cmds...)
175−// }
176−//
177−// func (m *messagesCmp) IsAgentWorking() bool {
178−// return m.app.CoderAgent.IsSessionBusy(m.session.ID)
179−// }
180−//
181−// func formatTimeDifference(unixTime1, unixTime2 int64) string {
182−// diffSeconds := float64(math.Abs(float64(unixTime2 - unixTime1)))
183−//
184−// if diffSeconds < 60 {
185−// return fmt.Sprintf("%.1fs", diffSeconds)
186−// }
187−//
188−// minutes := int(diffSeconds / 60)
189−// seconds := int(diffSeconds) % 60
190−// return fmt.Sprintf("%dm%ds", minutes, seconds)
191−// }
192−//
193−// func (m *messagesCmp) renderView() {
194−// m.uiMessages = make([]uiMessage, 0)
195−// pos := 0
196−// baseStyle := styles.BaseStyle()
197−//
198−// if m.width == 0 {
199−// return
200−// }
201−// for inx, msg := range m.messages {
202−// switch msg.Role {
203−// case message.User:
204−// if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
205−// m.uiMessages = append(m.uiMessages, cache.content...)
206−// continue
207−// }
208−// userMsg := renderUserMessage(
209−// msg,
210−// msg.ID == m.currentMsgID,
211−// m.width,
212−// pos,
213−// )
214−// m.uiMessages = append(m.uiMessages, userMsg)
215−// m.cachedContent[msg.ID] = cacheItem{
216−// width: m.width,
217−// content: []uiMessage{userMsg},
218−// }
219−// pos += userMsg.height + 1 // + 1 for spacing
220−// case message.Assistant:
221−// if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
222−// m.uiMessages = append(m.uiMessages, cache.content...)
223−// continue
224−// }
225−// isSummary := m.session.SummaryMessageID == msg.ID
226−//
227−// assistantMessages := renderAssistantMessage(
228−// msg,
229−// inx,
230−// m.messages,
231−// m.app.Messages,
232−// m.currentMsgID,
233−// isSummary,
234−// m.width,
235−// pos,
236−// )
237−// for _, msg := range assistantMessages {
238−// m.uiMessages = append(m.uiMessages, msg)
239−// pos += msg.height + 1 // + 1 for spacing
240−// }
241−// m.cachedContent[msg.ID] = cacheItem{
242−// width: m.width,
243−// content: assistantMessages,
244−// }
245−// }
246−// }
247−//
248−// messages := make([]string, 0)
249−// for _, v := range m.uiMessages {
250−// messages = append(messages, lipgloss.JoinVertical(lipgloss.Left, v.content),
251−// baseStyle.
252−// Width(m.width).
253−// Render(
254−// "",
255−// ),
256−// )
257−// }
258−//
259−// m.viewport.SetContent(
260−// baseStyle.
261−// Width(m.width).
262−// Render(
263−// lipgloss.JoinVertical(
264−// lipgloss.Top,
265−// messages...,
266−// ),
267−// ),
268−// )
269−// }
270−//
271−// func (m *messagesCmp) View() string {
272−// baseStyle := styles.BaseStyle()
273−//
274−// if m.rendering {
275−// return baseStyle.
276−// Width(m.width).
277−// Render(
278−// lipgloss.JoinVertical(
279−// lipgloss.Top,
280−// "Loading...",
281−// m.working(),
282−// m.help(),
283−// ),
284−// )
285−// }
286−// if len(m.messages) == 0 {
287−// content := baseStyle.
288−// Width(m.width).
289−// Height(m.height - 1).
290−// Render(
291−// initialScreen(),
292−// )
293−//
294−// return baseStyle.
295−// Width(m.width).
296−// Render(
297−// lipgloss.JoinVertical(
298−// lipgloss.Top,
299−// content,
300−// "",
301−// m.help(),
302−// ),
303−// )
304−// }
305−//
306−// return baseStyle.
307−// Width(m.width).
308−// Render(
309−// lipgloss.JoinVertical(
310−// lipgloss.Top,
311−// m.viewport.View(),
312−// m.working(),
313−// m.help(),
314−// ),
315−// )
316−// }
317−//
318−// func hasToolsWithoutResponse(messages []message.Message) bool {
319−// toolCalls := make([]message.ToolCall, 0)
320−// toolResults := make([]message.ToolResult, 0)
321−// for _, m := range messages {
322−// toolCalls = append(toolCalls, m.ToolCalls()...)
323−// toolResults = append(toolResults, m.ToolResults()...)
324−// }
325−//
326−// for _, v := range toolCalls {
327−// found := false
328−// for _, r := range toolResults {
329−// if v.ID == r.ToolCallID {
330−// found = true
331−// break
332−// }
333−// }
334−// if !found && v.Finished {
335−// return true
336−// }
337−// }
338−// return false
339−// }
340−//
341−// func hasUnfinishedToolCalls(messages []message.Message) bool {
342−// toolCalls := make([]message.ToolCall, 0)
343−// for _, m := range messages {
344−// toolCalls = append(toolCalls, m.ToolCalls()...)
345−// }
346−// for _, v := range toolCalls {
347−// if !v.Finished {
348−// return true
349−// }
350−// }
351−// return false
352−// }
353−//
354−// func (m *messagesCmp) working() string {
355−// text := ""
356−// if m.IsAgentWorking() && len(m.messages) > 0 {
357−// t := theme.CurrentTheme()
358−// baseStyle := styles.BaseStyle()
359−//
360−// task := "Thinking..."
361−// lastMessage := m.messages[len(m.messages)-1]
362−// if hasToolsWithoutResponse(m.messages) {
363−// task = "Waiting for tool response..."
364−// } else if hasUnfinishedToolCalls(m.messages) {
365−// task = "Building tool call..."
366−// } else if !lastMessage.IsFinished() {
367−// task = "Generating..."
368−// }
369−// if task != "" {
370−// text += baseStyle.
371−// Width(m.width).
372−// Foreground(t.Primary()).
373−// Bold(true).
374−// Render(fmt.Sprintf("%s %s ", m.spinner.View(), task))
375−// }
376−// }
377−// return text
378−// }
379−//
380−// func (m *messagesCmp) help() string {
381−// t := theme.CurrentTheme()
382−// baseStyle := styles.BaseStyle()
383−//
384−// text := ""
385−//
386−// if m.app.CoderAgent.IsBusy() {
387−// text += lipgloss.JoinHorizontal(
388−// lipgloss.Left,
389−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
390−// baseStyle.Foreground(t.Text()).Bold(true).Render("esc"),
391−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to exit cancel"),
392−// )
393−// } else {
394−// text += lipgloss.JoinHorizontal(
395−// lipgloss.Left,
396−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
397−// baseStyle.Foreground(t.Text()).Bold(true).Render("enter"),
398−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to send the message,"),
399−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" write"),
400−// baseStyle.Foreground(t.Text()).Bold(true).Render(" \\"),
401−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" and enter to add a new line"),
402−// )
403−// }
404−// return baseStyle.
405−// Width(m.width).
406−// Render(text)
407−// }
408−//
409−// func (m *messagesCmp) rerender() {
410−// for _, msg := range m.messages {
411−// delete(m.cachedContent, msg.ID)
412−// }
413−// m.renderView()
414−// }
415−//
416−// func (m *messagesCmp) SetSize(width, height int) tea.Cmd {
417−// if m.width == width && m.height == height {
418−// return nil
419−// }
420−// m.width = width
421−// m.height = height
422−// m.viewport.SetWidth(width)
423−// m.viewport.SetHeight(height - 2)
424−// m.attachments.SetWidth(width + 40)
425−// m.attachments.SetHeight(3)
426−// m.rerender()
427−// return nil
428−// }
429−//
430−// func (m *messagesCmp) GetSize() (int, int) {
431−// return m.width, m.height
432−// }
433−//
434−// func (m *messagesCmp) SetSession(session session.Session) tea.Cmd {
435−// if m.session.ID == session.ID {
436−// return nil
437−// }
438−// m.session = session
439−// messages, err := m.app.Messages.List(context.Background(), session.ID)
440−// if err != nil {
441−// return util.ReportError(err)
442−// }
443−// m.messages = messages
444−// if len(m.messages) > 0 {
445−// m.currentMsgID = m.messages[len(m.messages)-1].ID
446−// }
447−// delete(m.cachedContent, m.currentMsgID)
448−// m.rendering = true
449−// return func() tea.Msg {
450−// m.renderView()
451−// return renderFinishedMsg{}
452−// }
453−// }
454−//
455−// func (m *messagesCmp) BindingKeys() []key.Binding {
456−// return []key.Binding{
457−// m.viewport.KeyMap.PageDown,
458−// m.viewport.KeyMap.PageUp,
459−// m.viewport.KeyMap.HalfPageUp,
460−// m.viewport.KeyMap.HalfPageDown,
461−// }
462−// }
463−//
464−// func NewMessagesCmp(app *app.App) util.Model {
465−// s := spinner.New()
466−// s.Spinner = spinner.Pulse
467−// vp := viewport.New()
468−// attachmets := viewport.New()
469−// vp.KeyMap.PageUp = messageKeys.PageUp
470−// vp.KeyMap.PageDown = messageKeys.PageDown
471−// vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp
472−// vp.KeyMap.HalfPageDown = messageKeys.HalfPageDown
473−// return &messagesCmp{
474−// app: app,
475−// cachedContent: make(map[string]cacheItem),
476−// viewport: vp,
477−// spinner: s,
478−// attachments: attachmets,
479−// }
480−// }
internal/tui/components/core/list/list.go+1−1
@@ -117,7 +117,7 @@ func (m *model) Init() tea.Cmd {
117117func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
118118 var cmds []tea.Cmd
119119 switch msg := msg.(type) {
120− case tea.KeyMsg:
120+ case tea.KeyPressMsg:
121121 switch {
122122 case key.Matches(msg, m.keymap.Down) || key.Matches(msg, m.keymap.NDown):
123123 if m.reverse {
internal/tui/components/dialog/arguments.go+1−1
@@ -118,7 +118,7 @@ func (m MultiArgumentsDialogCmp) Init() tea.Cmd {
118118func (m MultiArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
119119 var cmds []tea.Cmd
120120 switch msg := msg.(type) {
121− case tea.KeyMsg:
121+ case tea.KeyPressMsg:
122122 switch {
123123 case key.Matches(msg, key.NewBinding(key.WithKeys("esc"))):
124124 return m, util.CmdHandler(CloseMultiArgumentsDialogMsg{
internal/tui/components/dialog/commands.go+1−1
@@ -90,7 +90,7 @@ func (c *commandDialogCmp) Init() tea.Cmd {
9090func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9191 var cmds []tea.Cmd
9292 switch msg := msg.(type) {
93− case tea.KeyMsg:
93+ case tea.KeyPressMsg:
9494 switch {
9595 case key.Matches(msg, commandKeys.Enter):
9696 selectedItem, idx := c.listView.GetSelectedItem()
internal/tui/components/dialog/complete.go+1−1
@@ -136,7 +136,7 @@ func (c *completionDialogCmp) close() tea.Cmd {
136136func (c *completionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
137137 var cmds []tea.Cmd
138138 switch msg := msg.(type) {
139− case tea.KeyMsg:
139+ case tea.KeyPressMsg:
140140 if c.pseudoSearchTextArea.Focused() {
141141
142142 if !key.Matches(msg, completionDialogKeys.Complete) {
internal/tui/components/dialog/filepicker.go+1−1
@@ -126,7 +126,7 @@ func (f *filepickerCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
126126 f.viewport.SetHeight(22)
127127 f.cursor = 0
128128 f.getCurrentFileBelowCursor()
129− case tea.KeyMsg:
129+ case tea.KeyPressMsg:
130130 if f.cwd.Focused() {
131131 f.cwd, cmd = f.cwd.Update(msg)
132132 }
internal/tui/components/dialog/init.go+2−2
@@ -70,7 +70,7 @@ func (m InitDialogCmp) Init() tea.Cmd {
7070// Update implements tea.Model.
7171func (m InitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7272 switch msg := msg.(type) {
73− case tea.KeyMsg:
73+ case tea.KeyPressMsg:
7474 switch {
7575 case key.Matches(msg, key.NewBinding(key.WithKeys("esc"))):
7676 return m, util.CmdHandler(CloseInitDialogMsg{Initialize: false})
@@ -95,7 +95,7 @@ func (m InitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9595func (m InitDialogCmp) View() string {
9696 t := theme.CurrentTheme()
9797 baseStyle := styles.BaseStyle()
98−
98+
9999 // Calculate width needed for content
100100 maxWidth := 60 // Width for explanation text
101101
internal/tui/components/dialog/models.go+1−1
@@ -111,7 +111,7 @@ func (m *modelDialogCmp) Init() tea.Cmd {
111111
112112func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
113113 switch msg := msg.(type) {
114− case tea.KeyMsg:
114+ case tea.KeyPressMsg:
115115 switch {
116116 case key.Matches(msg, modelKeys.Up) || key.Matches(msg, modelKeys.K):
117117 m.moveSelectionUp()
internal/tui/components/dialog/permission.go+1−1
@@ -107,7 +107,7 @@ func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
107107 cmds = append(cmds, cmd)
108108 p.markdownCache = make(map[string]string)
109109 p.diffCache = make(map[string]string)
110− case tea.KeyMsg:
110+ case tea.KeyPressMsg:
111111 switch {
112112 case key.Matches(msg, permissionsKeys.Right) || key.Matches(msg, permissionsKeys.Tab):
113113 p.selectedOption = (p.selectedOption + 1) % 3
internal/tui/components/dialog/quit.go+1−1
@@ -62,7 +62,7 @@ func (q *quitDialogCmp) Init() tea.Cmd {
6262
6363func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
6464 switch msg := msg.(type) {
65− case tea.KeyMsg:
65+ case tea.KeyPressMsg:
6666 switch {
6767 case key.Matches(msg, helpKeys.LeftRight) || key.Matches(msg, helpKeys.Tab):
6868 q.selectedNo = !q.selectedNo
internal/tui/components/dialog/session.go+1−1
@@ -77,7 +77,7 @@ func (s *sessionDialogCmp) Init() tea.Cmd {
7777
7878func (s *sessionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7979 switch msg := msg.(type) {
80− case tea.KeyMsg:
80+ case tea.KeyPressMsg:
8181 switch {
8282 case key.Matches(msg, sessionKeys.Up) || key.Matches(msg, sessionKeys.K):
8383 if s.selectedIdx > 0 {
internal/tui/components/dialog/theme.go+1−1
@@ -86,7 +86,7 @@ func (t *themeDialogCmp) Init() tea.Cmd {
8686
8787func (t *themeDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
8888 switch msg := msg.(type) {
89− case tea.KeyMsg:
89+ case tea.KeyPressMsg:
9090 switch {
9191 case key.Matches(msg, themeKeys.Up) || key.Matches(msg, themeKeys.K):
9292 if t.selectedIdx > 0 {
internal/tui/components/util/simple-list.go+1−1
@@ -66,7 +66,7 @@ func (c *simpleListCmp[T]) Init() tea.Cmd {
6666
6767func (c *simpleListCmp[T]) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
6868 switch msg := msg.(type) {
69− case tea.KeyMsg:
69+ case tea.KeyPressMsg:
7070 switch {
7171 case key.Matches(msg, simpleListKeys.Up) || (c.useAlphaNumericKeys && key.Matches(msg, simpleListKeys.UpAlpha)):
7272 if c.selectedIdx > 0 {
internal/tui/page/chat.go+2−2
@@ -102,7 +102,7 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
102102 }
103103 }
104104 p.session = msg
105− case tea.KeyMsg:
105+ case tea.KeyPressMsg:
106106 switch {
107107 case key.Matches(msg, keyMap.ShowCompletionDialog):
108108 p.showCompletionDialog = true
@@ -128,7 +128,7 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
128128 cmds = append(cmds, contextCmd)
129129
130130 // Doesn't forward event if enter key is pressed
131− if keyMsg, ok := msg.(tea.KeyMsg); ok {
131+ if keyMsg, ok := msg.(tea.KeyPressMsg); ok {
132132 if keyMsg.String() == "enter" {
133133 return p, tea.Batch(cmds...)
134134 }
internal/tui/tui.go+9−9
@@ -448,7 +448,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
448448 }
449449 return a, nil
450450
451− case tea.KeyMsg:
451+ case tea.KeyPressMsg:
452452 // If multi-arguments dialog is open, let it handle the key press first
453453 if a.showMultiArgumentsDialog {
454454 args, cmd := a.multiArgumentsDialog.Update(msg)
@@ -588,7 +588,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
588588 a.filepicker = f.(dialog.FilepickerCmp)
589589 cmds = append(cmds, filepickerCmd)
590590 // Only block key messages send all other messages down
591− if _, ok := msg.(tea.KeyMsg); ok {
591+ if _, ok := msg.(tea.KeyPressMsg); ok {
592592 return a, tea.Batch(cmds...)
593593 }
594594 }
@@ -598,7 +598,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
598598 a.quit = q.(dialog.QuitDialog)
599599 cmds = append(cmds, quitCmd)
600600 // Only block key messages send all other messages down
601− if _, ok := msg.(tea.KeyMsg); ok {
601+ if _, ok := msg.(tea.KeyPressMsg); ok {
602602 return a, tea.Batch(cmds...)
603603 }
604604 }
@@ -607,7 +607,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
607607 a.permissions = d.(dialog.PermissionDialogCmp)
608608 cmds = append(cmds, permissionsCmd)
609609 // Only block key messages send all other messages down
610− if _, ok := msg.(tea.KeyMsg); ok {
610+ if _, ok := msg.(tea.KeyPressMsg); ok {
611611 return a, tea.Batch(cmds...)
612612 }
613613 }
@@ -617,7 +617,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
617617 a.sessionDialog = d.(dialog.SessionDialog)
618618 cmds = append(cmds, sessionCmd)
619619 // Only block key messages send all other messages down
620− if _, ok := msg.(tea.KeyMsg); ok {
620+ if _, ok := msg.(tea.KeyPressMsg); ok {
621621 return a, tea.Batch(cmds...)
622622 }
623623 }
@@ -627,7 +627,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
627627 a.commandDialog = d.(dialog.CommandDialog)
628628 cmds = append(cmds, commandCmd)
629629 // Only block key messages send all other messages down
630− if _, ok := msg.(tea.KeyMsg); ok {
630+ if _, ok := msg.(tea.KeyPressMsg); ok {
631631 return a, tea.Batch(cmds...)
632632 }
633633 }
@@ -637,7 +637,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
637637 a.modelDialog = d.(dialog.ModelDialog)
638638 cmds = append(cmds, modelCmd)
639639 // Only block key messages send all other messages down
640− if _, ok := msg.(tea.KeyMsg); ok {
640+ if _, ok := msg.(tea.KeyPressMsg); ok {
641641 return a, tea.Batch(cmds...)
642642 }
643643 }
@@ -647,7 +647,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
647647 a.initDialog = d.(dialog.InitDialogCmp)
648648 cmds = append(cmds, initCmd)
649649 // Only block key messages send all other messages down
650− if _, ok := msg.(tea.KeyMsg); ok {
650+ if _, ok := msg.(tea.KeyPressMsg); ok {
651651 return a, tea.Batch(cmds...)
652652 }
653653 }
@@ -657,7 +657,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
657657 a.themeDialog = d.(dialog.ThemeDialog)
658658 cmds = append(cmds, themeCmd)
659659 // Only block key messages send all other messages down
660− if _, ok := msg.(tea.KeyMsg); ok {
660+ if _, ok := msg.(tea.KeyPressMsg); ok {
661661 return a, tea.Batch(cmds...)
662662 }
663663 }