Skip to content

Commit a3f97d5

Browse files
authored
Merge pull request #1949 from dgageot/board/when-running-inside-tmux-there-s-no-visi-12a66d94
Animate window title while working for tmux activity detection
2 parents 3876aea + 4058fa0 commit a3f97d5

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

pkg/tui/components/spinner/spinner.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ var defaultMessages = []string{
6969

7070
func New(mode Mode, dotsStyle lipgloss.Style) Spinner {
7171
// Pre-render all spinner frames for fast lookup during render
72-
styledFrames := make([]string, len(spinnerChars))
73-
for i, char := range spinnerChars {
72+
styledFrames := make([]string, len(frames))
73+
for i, char := range frames {
7474
styledFrames[i] = dotsStyle.Render(char)
7575
}
7676

@@ -136,7 +136,13 @@ func (s *spinner) Stop() {
136136
s.animSub.Stop()
137137
}
138138

139-
var spinnerChars = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
139+
// frames contains the braille spinner characters used for animation.
140+
var frames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
141+
142+
// Frame returns the spinner character for the given animation frame.
143+
func Frame(index int) string {
144+
return frames[index%len(frames)]
145+
}
140146

141147
// lightStyles maps distance from light position to style (0=brightest, 1=bright, 2=dim, 3+=dimmest).
142148
var lightStyles = []lipgloss.Style{

pkg/tui/tui.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ type appModel struct {
9595
// Working state indicator (resize handle spinner)
9696
workingSpinner spinner.Spinner
9797

98+
// animFrame is the current animation frame, used to rotate the window
99+
// title spinner so that tmux can detect pane activity.
100+
animFrame int
101+
98102
// Window state
99103
wWidth, wHeight int
100104
width, height int
@@ -445,6 +449,8 @@ func (m *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
445449
m.workingSpinner = model.(spinner.Spinner)
446450
cmds = append(cmds, cmd)
447451
}
452+
// Track frame for window-title spinner (tmux activity detection)
453+
m.animFrame = msg.Frame
448454
// Forward frame to tab bar for running indicator animation
449455
m.tabBar.SetAnimFrame(msg.Frame)
450456
if animation.HasActive() {
@@ -1992,11 +1998,17 @@ func (m *appModel) View() tea.View {
19921998
}
19931999

19942000
// windowTitle returns the terminal window title.
2001+
// When the agent is working, a rotating spinner character is prepended so that
2002+
// terminal multiplexers (tmux) can detect activity in the pane.
19952003
func (m *appModel) windowTitle() string {
2004+
title := "cagent"
19962005
if sessionTitle := m.sessionState.SessionTitle(); sessionTitle != "" {
1997-
return sessionTitle + " - cagent"
2006+
title = sessionTitle + " - cagent"
2007+
}
2008+
if m.chatPage.IsWorking() {
2009+
title = spinner.Frame(m.animFrame) + " " + title
19982010
}
1999-
return "cagent"
2011+
return title
20002012
}
20012013

20022014
// cleanupAll cleans up all sessions, editors, and resources.

0 commit comments

Comments
 (0)