Merge pull request #111 from charmbracelet/perf-filter

Raphael Amorim created

Improve TUI performance with Bubbletea v2 event filtering

Change summary

cmd/root.go                                   |  2 +
internal/tui/components/chat/editor/editor.go |  1 
internal/tui/page/chat/chat.go                |  6 ++++
internal/tui/tui.go                           | 26 ++++++++++++++++++--
4 files changed, 32 insertions(+), 3 deletions(-)

Detailed changes

cmd/root.go 🔗

@@ -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

internal/tui/page/chat/chat.go 🔗

@@ -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
+}

internal/tui/tui.go 🔗

@@ -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...)
 }