diff --git a/internal/agent/agent.go b/internal/agent/agent.go index 7e682460fffd0a781886fe29691558dd6da48049..deba2d1941641a8f3dc572467eb7176248f2b01c 100644 --- a/internal/agent/agent.go +++ b/internal/agent/agent.go @@ -286,7 +286,7 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy // Strip leading newline from initial text content. This is is // particularly important in non-interactive mode where leading // newlines are very visible. - if len(currentAssistant.Parts) == 0 && strings.HasPrefix(text, "\n") { + if len(currentAssistant.Parts) == 0 { text = strings.TrimPrefix(text, "\n") } diff --git a/internal/app/app.go b/internal/app/app.go index 0957de2422b1f25dd08780c06ed73f2543b64c98..fef0fa1639c8f2ded4176141aca04e93f520ca16 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "log/slog" + "os" "sync" "time" @@ -27,7 +28,11 @@ import ( "github.com/charmbracelet/crush/internal/permission" "github.com/charmbracelet/crush/internal/pubsub" "github.com/charmbracelet/crush/internal/session" + "github.com/charmbracelet/crush/internal/tui/components/anim" + "github.com/charmbracelet/crush/internal/tui/styles" + "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/exp/charmtone" ) type App struct { @@ -114,7 +119,25 @@ func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt var spinner *format.Spinner if !quiet { - spinner = format.NewSpinner(ctx, cancel, "Generating") + t := styles.CurrentTheme() + + // Detect background color to set the appropriate color for the + // spinner's 'Generating...' text. Without this, that text would be + // unreadable in light terminals. + hasDarkBG := true + if f, ok := output.(*os.File); ok { + hasDarkBG = lipgloss.HasDarkBackground(os.Stdin, f) + } + defaultFG := lipgloss.LightDark(hasDarkBG)(charmtone.Pepper, t.FgBase) + + spinner = format.NewSpinner(ctx, cancel, anim.Settings{ + Size: 10, + Label: "Generating", + LabelColor: defaultFG, + GradColorA: t.Primary, + GradColorB: t.Secondary, + CycleColors: true, + }) spinner.Start() } diff --git a/internal/format/spinner.go b/internal/format/spinner.go index d1d9805f4b7bd511270316c4b1f0dafdfe9401b3..c557f203f8deb835501260233246942b07cff4ba 100644 --- a/internal/format/spinner.go +++ b/internal/format/spinner.go @@ -8,7 +8,6 @@ import ( tea "github.com/charmbracelet/bubbletea/v2" "github.com/charmbracelet/crush/internal/tui/components/anim" - "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/x/ansi" ) @@ -42,28 +41,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // NewSpinner creates a new spinner with the given message -func NewSpinner(ctx context.Context, cancel context.CancelFunc, message string) *Spinner { - t := styles.CurrentTheme() - model := model{ - anim: anim.New(anim.Settings{ - Size: 10, - Label: message, - LabelColor: t.FgBase, - GradColorA: t.Primary, - GradColorB: t.Secondary, - CycleColors: true, - }), +func NewSpinner(ctx context.Context, cancel context.CancelFunc, animSettings anim.Settings) *Spinner { + m := model{ + anim: anim.New(animSettings), cancel: cancel, } - prog := tea.NewProgram( - model, - tea.WithOutput(os.Stderr), - tea.WithContext(ctx), - ) + p := tea.NewProgram(m, tea.WithOutput(os.Stderr), tea.WithContext(ctx)) return &Spinner{ - prog: prog, + prog: p, done: make(chan struct{}, 1), } }