From 787867bea87222cfa523654347378085b2275c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Tue, 19 May 2026 19:02:33 +0200 Subject: [PATCH] tui: Fix URL clicks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7a30d0db3b47 added URL opening for terminals where mouse tracking prevents native link handling. That worked by treating a mouse release at the same cell as the initial click as a plain click, then opening any URL at that position. That made link activation depend on the terminal and Bubble Tea delivering a matching MouseReleaseMsg after MouseClickMsg. With the current event stream, plain clicks can reach handleMouseClick without a reliable release event, so the URL detector still found links but the OpenURLMsg path was never reached. Open URLs from the left-click handler after higher-priority message controls have been checked, and cover that event path with a regression test. Signed-off-by: Paweł Gronowski --- pkg/tui/components/messages/messages.go | 4 ++++ pkg/tui/components/messages/messages_test.go | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pkg/tui/components/messages/messages.go b/pkg/tui/components/messages/messages.go index 38e125e07..2e6ffc1ba 100644 --- a/pkg/tui/components/messages/messages.go +++ b/pkg/tui/components/messages/messages.go @@ -330,6 +330,10 @@ func (m *model) handleMouseClick(msg tea.MouseClickMsg) (layout.Model, tea.Cmd) } } + if url := m.urlAt(line, col); url != "" { + return m, core.CmdHandler(messages.OpenURLMsg{URL: url}) + } + clickCount := m.selection.detectClickType(line, col) switch clickCount { diff --git a/pkg/tui/components/messages/messages_test.go b/pkg/tui/components/messages/messages_test.go index eb05ecea7..0af86fc6b 100644 --- a/pkg/tui/components/messages/messages_test.go +++ b/pkg/tui/components/messages/messages_test.go @@ -39,6 +39,22 @@ func TestViewDoesNotWrapWideLines(t *testing.T) { } } +func TestMouseClickOnURLOpensURL(t *testing.T) { + t.Parallel() + + m := NewScrollableView(80, 24, &service.SessionState{}).(*model) + m.renderedLines = []string{"visit https://example.com for more"} + m.totalHeight = len(m.renderedLines) + m.renderDirty = false + + _, cmd := m.handleMouseClick(tea.MouseClickMsg{X: 10, Y: 0, Button: tea.MouseLeft}) + require.NotNil(t, cmd) + + msg, ok := cmd().(tuimessages.OpenURLMsg) + require.True(t, ok) + assert.Equal(t, "https://example.com", msg.URL) +} + func TestLoadFromSessionIncludesReasoningContent(t *testing.T) { t.Parallel()