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()