Detailed changes
@@ -128,8 +128,9 @@ type LSPConfig struct {
}
type TUIOptions struct {
- CompactMode bool `json:"compact_mode,omitempty" jsonschema:"description=Enable compact mode for the TUI interface,default=false"`
- DiffMode string `json:"diff_mode,omitempty" jsonschema:"description=Diff mode for the TUI interface,enum=unified,enum=split"`
+ CompactMode bool `json:"compact_mode,omitempty" jsonschema:"description=Enable compact mode for the TUI interface,default=false"`
+ DiffMode string `json:"diff_mode,omitempty" jsonschema:"description=Diff mode for the TUI interface,enum=unified,enum=split"`
+ ReduceAnimations bool `json:"reduce_animations,omitempty" jsonschema:"description=Reduce animations in the TUI,default=false"`
// Here we can add themes later or any TUI related options
//
@@ -124,6 +124,14 @@ type anim struct {
// New creates a new anim instance with the specified width and label.
func New(opts Settings) Spinner {
+ if colorIsUnset(opts.LabelColor) {
+ opts.LabelColor = defaultLabelColor
+ }
+
+ if opts.Static {
+ return newStatic(opts.Label, opts.LabelColor)
+ }
+
// Validate settings.
if opts.Size < 1 {
opts.Size = defaultNumCyclingChars
@@ -134,13 +142,7 @@ func New(opts Settings) Spinner {
if colorIsUnset(opts.GradColorB) {
opts.GradColorB = defaultGradColorB
}
- if colorIsUnset(opts.LabelColor) {
- opts.LabelColor = defaultLabelColor
- }
- if opts.Static {
- return newStatic(opts.Label, opts.LabelColor)
- }
a := &anim{}
a.id = nextID()
a.startTime = time.Now()
@@ -321,9 +323,7 @@ func (a *anim) Width() (w int) {
}
// Init starts the animation.
-func (a *anim) Init() tea.Cmd {
- return a.Step()
-}
+func (a *anim) Init() tea.Cmd { return stepCmd(a.id) }
// Update processes animation steps (or not).
func (a *anim) Update(msg tea.Msg) (Spinner, tea.Cmd) {
@@ -348,7 +348,7 @@ func (a *anim) Update(msg tea.Msg) (Spinner, tea.Cmd) {
} else if !a.initialized.Load() && time.Since(a.startTime) >= maxBirthOffset {
a.initialized.Store(true)
}
- return a, a.Step()
+ return a, stepCmd(a.id)
default:
return a, nil
}
@@ -388,10 +388,10 @@ func (a *anim) View() string {
return b.String()
}
-// Step is a command that triggers the next step in the animation.
-func (a *anim) Step() tea.Cmd {
+// stepCmd is a command that triggers the next stepCmd in the animation.
+func stepCmd(id int) tea.Cmd {
return tea.Tick(time.Second/time.Duration(fps), func(t time.Time) tea.Msg {
- return StepMsg{id: a.id}
+ return StepMsg{id: id}
})
}
@@ -1,6 +1,7 @@
package anim
import (
+ "cmp"
"image/color"
tea "github.com/charmbracelet/bubbletea/v2"
@@ -10,18 +11,33 @@ import (
type noAnim struct {
Color color.Color
rendered string
+ id int
}
func newStatic(label string, foreground color.Color) Spinner {
a := &noAnim{Color: foreground}
a.SetLabel(label)
+ a.id = nextID()
return a
}
func (s *noAnim) SetLabel(label string) {
- s.rendered = lipgloss.NewStyle().Foreground(s.Color).Render(label + ellipsisFrames[2])
+ s.rendered = lipgloss.NewStyle().
+ Foreground(s.Color).
+ Render(cmp.Or(label, "Working") + ellipsisFrames[2])
}
-func (s noAnim) Init() tea.Cmd { return nil }
-func (s *noAnim) Update(tea.Msg) (Spinner, tea.Cmd) { return s, nil }
-func (s *noAnim) View() string { return s.rendered }
+func (s noAnim) Init() tea.Cmd { return stepCmd(s.id) }
+func (s *noAnim) View() string { return s.rendered }
+func (s *noAnim) Update(msg tea.Msg) (Spinner, tea.Cmd) {
+ switch msg := msg.(type) {
+ case StepMsg:
+ if msg.id != s.id {
+ // Reject messages that are not for this instance.
+ return s, nil
+ }
+ return s, stepCmd(s.id)
+ default:
+ return s, nil
+ }
+}
@@ -75,6 +75,7 @@ func NewMessageCmp(msg message.Message) MessageCmp {
m := &messageCmp{
message: msg,
anim: anim.New(anim.Settings{
+ Static: isReduceAnimations(),
Size: 15,
GradColorA: t.Primary,
GradColorB: t.Secondary,
@@ -425,3 +426,10 @@ func (m *assistantSectionModel) IsSectionHeader() bool {
func (m *messageCmp) ID() string {
return m.message.ID
}
+
+func isReduceAnimations() bool {
+ cfg := config.Get()
+ return cfg.Options != nil &&
+ cfg.Options.TUI != nil &&
+ cfg.Options.TUI.ReduceAnimations
+}
@@ -120,6 +120,7 @@ func NewToolCallCmp(parentMessageID string, tc message.ToolCall, permissions per
}
t := styles.CurrentTheme()
m.anim = anim.New(anim.Settings{
+ Static: isReduceAnimations(),
Size: 15,
Label: "Working",
GradColorA: t.Primary,
@@ -129,6 +130,7 @@ func NewToolCallCmp(parentMessageID string, tc message.ToolCall, permissions per
})
if m.isNested {
m.anim = anim.New(anim.Settings{
+ Static: isReduceAnimations(),
Size: 10,
GradColorA: t.Primary,
GradColorB: t.Secondary,