on main help sign in
fix(noninteractive): always print newline after output
2fd5ab2Christian Rocha
internal/app/app.go+15−7
@@ -101,8 +101,8 @@ func (app *App) Config() *config.Config {
101 return app.config
101 return app.config
102}
102}
103
103
104−// RunNonInteractive handles the execution flow when a prompt is provided via
104+// RunNonInteractive runs the application in non-interactive mode with the
105−// CLI flag.
105+// given prompt, printing to stdout.
106func (app *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) error {
106func (app *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool) error {
107 slog.Info("Running in non-interactive mode")
107 slog.Info("Running in non-interactive mode")
108
108
@@ -125,7 +125,7 @@ func (app *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool
125 defer stopSpinner()
125 defer stopSpinner()
126
126
127 const maxPromptLengthForTitle = 100
127 const maxPromptLengthForTitle = 100
128− titlePrefix := "Non-interactive: "
128+ const titlePrefix = "Non-interactive: "
129 var titleSuffix string
129 var titleSuffix string
130
130
131 if len(prompt) > maxPromptLengthForTitle {
131 if len(prompt) > maxPromptLengthForTitle {
@@ -165,11 +165,19 @@ func (app *App) RunNonInteractive(ctx context.Context, prompt string, quiet bool
165 messageEvents := app.Messages.Subscribe(ctx)
165 messageEvents := app.Messages.Subscribe(ctx)
166 messageReadBytes := make(map[string]int)
166 messageReadBytes := make(map[string]int)
167
167
168+ defer func() {
168− defer fmt.Printf(ansi.ResetProgressBar)
169+ _, _ = fmt.Printf(ansi.ResetProgressBar)
170+
171+ // Always print a newline at the end. If output is a TTY this will
172+ // prevent the prompt from overwriting the last line of output.
173+ _, _ = fmt.Print('\n')
174+ }()
175+
169 for {
176 for {
170− // HACK: add it again on every iteration so it doesn't get hidden by
177+ // HACK: Reinitialize the terminal progress bar on every iteration so
171− // the terminal due to inactivity.
178+ // it doesn't get hidden by the terminal due to inactivity.
172− fmt.Printf(ansi.SetIndeterminateProgressBar)
179+ _, _ = fmt.Printf(ansi.SetIndeterminateProgressBar)
180+
173 select {
181 select {
174 case result := <-done:
182 case result := <-done:
175 stopSpinner()
183 stopSpinner()
internal/cmd/run.go+6−1
@@ -48,7 +48,12 @@ crush run -q "Generate a README for this project"
48 return fmt.Errorf("no prompt provided")
48 return fmt.Errorf("no prompt provided")
49 }
49 }
50
50
51− // Run non-interactive flow using the App method
51+ // TODO: Make this work when redirected to something other than stdout.
52+ // For example:
53+ // crush run "Do something fancy" > output.txt
54+ // echo "Do something fancy" | crush run > output.txt
55+ //
56+ // TODO: We currently need to press ^c twice to cancel. Fix that.
52 return app.RunNonInteractive(cmd.Context(), prompt, quiet)
57 return app.RunNonInteractive(cmd.Context(), prompt, quiet)
53 },
58 },
54}
59}