@@ -120,6 +120,8 @@ to assist developers in writing, debugging, and understanding code directly from
tea.WithAltScreen(),
tea.WithKeyReleases(),
tea.WithUniformKeyLayout(),
+ tea.WithMouseCellMotion(), // Use cell motion instead of all motion to reduce event flooding
+ tea.WithFilter(tui.MouseEventFilter), // Filter mouse events based on focus state
)
// Setup the subscriptions, this will send services events to the TUI
@@ -7,6 +7,7 @@ import (
"runtime"
"slices"
"strings"
+ "time"
"unicode"
"github.com/charmbracelet/bubbles/v2/key"
@@ -30,6 +31,8 @@ type FileCompletionItem struct {
Path string // The file path
}
+type CompletionDebounceMsg struct{}
+
type editorCmp struct {
width int
height int
@@ -46,6 +49,9 @@ type editorCmp struct {
currentQuery string
completionsStartIndex int
isCompletionsOpen bool
+
+ // Debouncing for completions
+ debounceTimer *time.Timer
}
var DeleteKeyMaps = DeleteAttachmentKeyMaps{
@@ -141,6 +147,22 @@ func (m *editorCmp) send() tea.Cmd {
)
}
+// debouncedCompletionFilter creates a debounced command for filtering completions
+func (m *editorCmp) debouncedCompletionFilter() tea.Cmd {
+ // Cancel existing timer if any
+ if m.debounceTimer != nil {
+ m.debounceTimer.Stop()
+ }
+
+ // Create new timer for debouncing
+ m.debounceTimer = time.NewTimer(150 * time.Millisecond)
+
+ return func() tea.Msg {
+ <-m.debounceTimer.C
+ return CompletionDebounceMsg{}
+ }
+}
+
func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
@@ -160,6 +182,18 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.isCompletionsOpen = false
m.currentQuery = ""
m.completionsStartIndex = 0
+ // Cancel any pending debounce timer
+ if m.debounceTimer != nil {
+ m.debounceTimer.Stop()
+ m.debounceTimer = nil
+ }
+ case CompletionDebounceMsg:
+ // Handle debounced completion filtering
+ if m.isCompletionsOpen {
+ return m, util.CmdHandler(completions.FilterCompletionsMsg{
+ Query: m.currentQuery,
+ })
+ }
case completions.SelectCompletionMsg:
if !m.isCompletionsOpen {
return m, nil
@@ -196,9 +230,8 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case msg.String() == "backspace" && m.isCompletionsOpen:
if len(m.currentQuery) > 0 {
m.currentQuery = m.currentQuery[:len(m.currentQuery)-1]
- cmds = append(cmds, util.CmdHandler(completions.FilterCompletionsMsg{
- Query: m.currentQuery,
- }))
+ // Use debounced filtering instead of immediate filtering
+ cmds = append(cmds, m.debouncedCompletionFilter())
} else {
m.isCompletionsOpen = false
m.currentQuery = ""
@@ -208,9 +241,8 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
default:
if m.isCompletionsOpen {
m.currentQuery += msg.String()
- cmds = append(cmds, util.CmdHandler(completions.FilterCompletionsMsg{
- Query: m.currentQuery,
- }))
+ // Use debounced filtering instead of immediate filtering
+ cmds = append(cmds, m.debouncedCompletionFilter())
}
}
if key.Matches(msg, DeleteKeyMaps.AttachmentDeleteMode) {
@@ -258,6 +290,7 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}
}
+
m.textarea, cmd = m.textarea.Update(msg)
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
@@ -355,6 +388,11 @@ func (m *editorCmp) startCompletions() tea.Msg {
// Blur implements Container.
func (c *editorCmp) Blur() tea.Cmd {
c.textarea.Blur()
+ // Clean up debounce timer when losing focus
+ if c.debounceTimer != nil {
+ c.debounceTimer.Stop()
+ c.debounceTimer = nil
+ }
return nil
}
@@ -39,6 +39,7 @@ type (
type ChatPage interface {
util.Model
layout.Help
+ IsChatFocused() bool
}
type chatPage struct {
@@ -415,3 +416,8 @@ func NewChatPage(app *app.App) ChatPage {
header: header.New(app.LSPClients),
}
}
+
+// IsChatFocused returns whether the chat messages are focused (true) or editor is focused (false)
+func (p *chatPage) IsChatFocused() bool {
+ return p.chatFocused
+}
@@ -31,6 +31,29 @@ import (
"github.com/charmbracelet/lipgloss/v2"
)
+// MouseEventFilter filters mouse events based on the current focus state
+// This is used with tea.WithFilter to prevent mouse scroll events from
+// interfering with typing performance in the editor
+func MouseEventFilter(m tea.Model, msg tea.Msg) tea.Msg {
+ // Only filter mouse events
+ switch msg.(type) {
+ case tea.MouseWheelMsg, tea.MouseMotionMsg:
+ // Check if we have an appModel and if editor is focused
+ if appModel, ok := m.(*appModel); ok {
+ if appModel.currentPage == chat.ChatPageID {
+ if chatPage, ok := appModel.pages[appModel.currentPage].(chat.ChatPage); ok {
+ // If editor is focused (not chatFocused), filter out mouse wheel/motion events
+ if !chatPage.IsChatFocused() {
+ return nil // Filter out the event
+ }
+ }
+ }
+ }
+ }
+ // Allow all other events to pass through
+ return msg
+}
+
// appModel represents the main application model that manages pages, dialogs, and UI state.
type appModel struct {
wWidth, wHeight int // Window dimensions
@@ -82,9 +105,6 @@ func (a appModel) Init() tea.Cmd {
return nil
})
- // Enable mouse support.
- cmds = append(cmds, tea.EnableMouseAllMotion)
-
return tea.Batch(cmds...)
}