diff --git a/README.md b/README.md index 34a4b48..59ad945 100644 --- a/README.md +++ b/README.md @@ -308,16 +308,17 @@ if summary.HasFailures() { That shape works well in ordinary Go CLIs, Mage targets, Cobra/Fang commands, and small Go helpers invoked from tools like `make`, `just`, or `task`. `laslig` stays responsible for rendering, while the caller stays responsible for process control. Callers can also disable grouped failed-test, skipped-test, package-error, or captured-output sections when they want a tighter stream. -`gotestout` also supports one spinner-only live activity footer for active test -streams. The footer defaults to `auto`, which means styled human terminal -output gets one transient spinner line while the stream is active, while plain, -unstyled human, and JSON output stay stable and non-transient. Callers can -force that footer on with `gotestout.ActivityOn` for demos or disable it +`gotestout` also supports one live transient activity block for active test +streams. The activity view defaults to `auto`, which means styled human +terminal output gets one transient spinner-led block while the stream is +active, while plain, unstyled human, and JSON output stay stable and +non-transient. Callers can force that block on with `gotestout.ActivityOn` for +demos or disable it entirely with `gotestout.ActivityOff`. This repository dogfoods that pattern in [`magefiles/magefile.go`](./magefiles/magefile.go): `mage test` runs `go test -json ./...`, renders compact package and failure output through `gotestout`, and still returns a normal Mage error on failure. The focused runnable example for that package lives in [`examples/gotestout/main.go`](./examples/gotestout/main.go). -The separate Mage-facing example in [`examples/magecheck/main.go`](./examples/magecheck/main.go) shows the same passing task-runner path with `gotestout`'s live activity footer enabled while the test stream is active. +The separate Mage-facing example in [`examples/magecheck/main.go`](./examples/magecheck/main.go) shows the same passing task-runner path with `gotestout`'s live activity block enabled while the test stream is active. Common ways to try that surface locally: @@ -329,7 +330,7 @@ mage test The focused `gotestout` GIF and example command intentionally include passing, skipped, and failing test events plus one package build failure. The separate `magecheck` GIF shows the passing task-runner path with the live activity -footer active during the running stream. That keeps the README honest about +block active during the running stream. That keeps the README honest about both the success path and the failure path. Future `gotestout` work is about smarter summaries, not basic @@ -357,7 +358,7 @@ go run ./examples/all --format human --style always mage test ``` -`mage demo` is the normal paced walkthrough entrypoint. `mage test` is the real Mage-facing `gotestout` dogfood path. The `magecheck` focused example demonstrates the live activity footer during the running test stream. The `go run` forms above show the focused per-item examples directly, while `go run ./examples/all` renders the aggregate example without the paced demo wrapper. +`mage demo` is the normal paced walkthrough entrypoint. `mage test` is the real Mage-facing `gotestout` dogfood path. The `magecheck` focused example demonstrates the live activity block during the running test stream. The `go run` forms above show the focused per-item examples directly, while `go run ./examples/all` renders the aggregate example without the paced demo wrapper. The README GIFs are generated from the focused VHS tapes under [`docs/vhs/`](./docs/vhs). `mage vhs` renders all tracked tapes so the README stays aligned with the runnable examples. diff --git a/docs/vhs/codeblock.gif b/docs/vhs/codeblock.gif index 376f917..cbd9325 100644 Binary files a/docs/vhs/codeblock.gif and b/docs/vhs/codeblock.gif differ diff --git a/docs/vhs/demo.gif b/docs/vhs/demo.gif index aac82c7..4db1655 100644 Binary files a/docs/vhs/demo.gif and b/docs/vhs/demo.gif differ diff --git a/docs/vhs/gotestout.gif b/docs/vhs/gotestout.gif index 18b831a..57f8fae 100644 Binary files a/docs/vhs/gotestout.gif and b/docs/vhs/gotestout.gif differ diff --git a/docs/vhs/kv.gif b/docs/vhs/kv.gif index 30be6fa..9bed0b5 100644 Binary files a/docs/vhs/kv.gif and b/docs/vhs/kv.gif differ diff --git a/docs/vhs/list.gif b/docs/vhs/list.gif index cdf235d..4939f1e 100644 Binary files a/docs/vhs/list.gif and b/docs/vhs/list.gif differ diff --git a/docs/vhs/logblock.gif b/docs/vhs/logblock.gif index 6f39113..7093e98 100644 Binary files a/docs/vhs/logblock.gif and b/docs/vhs/logblock.gif differ diff --git a/docs/vhs/magecheck.gif b/docs/vhs/magecheck.gif index baf47f9..c7bebe9 100644 Binary files a/docs/vhs/magecheck.gif and b/docs/vhs/magecheck.gif differ diff --git a/docs/vhs/markdown.gif b/docs/vhs/markdown.gif index 3af0b6f..517cc8c 100644 Binary files a/docs/vhs/markdown.gif and b/docs/vhs/markdown.gif differ diff --git a/docs/vhs/notice.gif b/docs/vhs/notice.gif index 09a35a9..ae78936 100644 Binary files a/docs/vhs/notice.gif and b/docs/vhs/notice.gif differ diff --git a/docs/vhs/panel.gif b/docs/vhs/panel.gif index 347d69a..6ee6f0f 100644 Binary files a/docs/vhs/panel.gif and b/docs/vhs/panel.gif differ diff --git a/docs/vhs/paragraph.gif b/docs/vhs/paragraph.gif index 8894a8e..7cd287c 100644 Binary files a/docs/vhs/paragraph.gif and b/docs/vhs/paragraph.gif differ diff --git a/docs/vhs/record.gif b/docs/vhs/record.gif index 5062374..b88c78a 100644 Binary files a/docs/vhs/record.gif and b/docs/vhs/record.gif differ diff --git a/docs/vhs/section.gif b/docs/vhs/section.gif index d115baf..4745a0d 100644 Binary files a/docs/vhs/section.gif and b/docs/vhs/section.gif differ diff --git a/docs/vhs/spinner.gif b/docs/vhs/spinner.gif index 56043f9..914e170 100644 Binary files a/docs/vhs/spinner.gif and b/docs/vhs/spinner.gif differ diff --git a/docs/vhs/statusline.gif b/docs/vhs/statusline.gif index a15c0fd..0cc9fa2 100644 Binary files a/docs/vhs/statusline.gif and b/docs/vhs/statusline.gif differ diff --git a/docs/vhs/table.gif b/docs/vhs/table.gif index 382b662..94505e9 100644 Binary files a/docs/vhs/table.gif and b/docs/vhs/table.gif differ diff --git a/examples/all/testdata/TestRunArgsHumanStyledGolden.golden b/examples/all/testdata/TestRunArgsHumanStyledGolden.golden index cdb1383..83f9fe6 100644 --- a/examples/all/testdata/TestRunArgsHumanStyledGolden.golden +++ b/examples/all/testdata/TestRunArgsHumanStyledGolden.golden @@ -171,7 +171,7 @@ gotestout Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control. - This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active. + This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active. INFO Mixed fixture demo The example command itself is expected to exit successfully so you can inspect the output shape. @@ -217,7 +217,7 @@ gotestout + Mage Use gotestout inside Mage or small Go helpers behind make, just, or task when you want caller-owned process control with a readable test stream. - The preview below matches this repository's mage check and mage test shape, including the live gotestout activity footer while the test stream is still active. + The preview below matches this repository's mage check and mage test shape, including the live gotestout activity block while the test stream is still active. Build diff --git a/examples/all/testdata/TestRunArgsPlainGolden.golden b/examples/all/testdata/TestRunArgsPlainGolden.golden index 1ce11c6..6233b36 100644 --- a/examples/all/testdata/TestRunArgsPlainGolden.golden +++ b/examples/all/testdata/TestRunArgsPlainGolden.golden @@ -156,7 +156,7 @@ gotestout Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control. - This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active. + This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active. [INFO] Mixed fixture demo The example command itself is expected to exit successfully so you can inspect the output shape. @@ -202,7 +202,7 @@ gotestout + Mage Use gotestout inside Mage or small Go helpers behind make, just, or task when you want caller-owned process control with a readable test stream. - The preview below matches this repository's mage check and mage test shape, including the live gotestout activity footer while the test stream is still active. + The preview below matches this repository's mage check and mage test shape, including the live gotestout activity block while the test stream is still active. Build diff --git a/examples/gotestout/testdata/TestRunArgsPlainGolden.golden b/examples/gotestout/testdata/TestRunArgsPlainGolden.golden index ad95d67..684a18e 100644 --- a/examples/gotestout/testdata/TestRunArgsPlainGolden.golden +++ b/examples/gotestout/testdata/TestRunArgsPlainGolden.golden @@ -3,7 +3,7 @@ gotestout Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control. - This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active. + This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active. [INFO] Mixed fixture demo The example command itself is expected to exit successfully so you can inspect the output shape. diff --git a/gotestout/activity.go b/gotestout/activity.go index e0923aa..f0b727f 100644 --- a/gotestout/activity.go +++ b/gotestout/activity.go @@ -30,6 +30,7 @@ type activityState struct { pkgsPassed int pkgsFailed int pkgsSkipped int + height int shown bool stopCh chan struct{} doneCh chan struct{} @@ -70,6 +71,7 @@ func (r *Renderer) stopActivity() error { stopCh := activity.stopCh doneCh := activity.doneCh shown := activity.shown + height := activity.height err := activity.err r.writeMu.Unlock() @@ -82,7 +84,7 @@ func (r *Renderer) stopActivity() error { if shown { r.writeMu.Lock() - if _, clearErr := io.WriteString(r.out, activityClearLine); err == nil && clearErr != nil { + if _, clearErr := io.WriteString(r.out, clearActivityBlock(height)); err == nil && clearErr != nil { err = fmt.Errorf("clear activity footer: %w", clearErr) } r.writeMu.Unlock() @@ -221,10 +223,16 @@ func (r *Renderer) tickActivity(advance bool) error { if advance { r.activity.frame = (r.activity.frame + 1) % len(r.activity.frames) } - if _, err := io.WriteString(r.out, activityClearLine+r.renderActivityLineLocked()); err != nil { + block, height := r.renderActivityBlockLocked() + output := block + if r.activity.shown { + output = clearActivityBlock(r.activity.height) + output + } + if _, err := io.WriteString(r.out, output); err != nil { r.activity.err = fmt.Errorf("write activity footer: %w", err) return r.activity.err } + r.activity.height = height r.activity.shown = true return nil } @@ -233,10 +241,11 @@ func (r *Renderer) clearActivityLocked() error { if r.activity == nil || !r.activity.shown { return nil } - if _, err := io.WriteString(r.out, activityClearLine); err != nil { + if _, err := io.WriteString(r.out, clearActivityBlock(r.activity.height)); err != nil { r.activity.err = fmt.Errorf("clear activity footer: %w", err) return r.activity.err } + r.activity.height = 0 r.activity.shown = false return nil } @@ -248,50 +257,148 @@ func (r *Renderer) redrawActivityLocked() error { } return nil } - if _, err := io.WriteString(r.out, activityClearLine+r.renderActivityLineLocked()); err != nil { + block, height := r.renderActivityBlockLocked() + if _, err := io.WriteString(r.out, block); err != nil { r.activity.err = fmt.Errorf("redraw activity footer: %w", err) return r.activity.err } + r.activity.height = height r.activity.shown = true return nil } -func (r *Renderer) renderActivityLineLocked() string { +func (r *Renderer) renderActivityBlockLocked() (string, int) { frame := r.activity.frames[r.activity.frame%len(r.activity.frames)] - subject := r.activity.currentPkg - if r.activity.currentTest != "" { - subject += " :: " + r.activity.currentTest - } - text := strings.TrimSpace(r.activity.text) if text == "" { text = "Running go test -json" } - details := []string{ - fmt.Sprintf("tests: %d/%d/%d", r.activity.testsPassed, r.activity.testsFailed, r.activity.testsSkipped), - fmt.Sprintf("pkgs: %d/%d/%d", r.activity.pkgsPassed, r.activity.pkgsFailed, r.activity.pkgsSkipped), - formatActivityElapsed(time.Since(r.activity.startedAt)), + lines := []string{} + lines = append(lines, r.renderActivityHeaderLines(frame, text)...) + + subject := strings.TrimSpace(r.activity.currentPkg) + if subject != "" && strings.TrimSpace(r.activity.currentTest) != "" { + subject += " :: " + strings.TrimSpace(r.activity.currentTest) } if subject != "" { - details = append([]string{"current: " + subject}, details...) + lines = append(lines, r.renderActivityValueLines("- ", subject, r.theme.Identifier)...) + } + + if pkg := strings.TrimSpace(r.activity.currentPkg); pkg != "" { + lines = append(lines, r.renderActivityFieldLines("package", pkg, r.theme.Identifier)...) + } + if test := strings.TrimSpace(r.activity.currentTest); test != "" { + lines = append(lines, r.renderActivityFieldLines("test", test, r.theme.Identifier)...) + } + lines = append(lines, r.renderActivityCountsLines( + "tests", + r.activity.testsPassed, + r.activity.testsFailed, + r.activity.testsSkipped, + )...) + lines = append(lines, r.renderActivityCountsLines( + "packages", + r.activity.pkgsPassed, + r.activity.pkgsFailed, + r.activity.pkgsSkipped, + )...) + lines = append(lines, r.renderActivityFieldLines("elapsed", formatActivityElapsed(time.Since(r.activity.startedAt)), r.theme.Muted)...) + return strings.Join(lines, "\n"), len(lines) +} + +func clearActivityBlock(height int) string { + if height <= 0 { + return activityClearLine } - lineText := text + " " + strings.Join(details, " ") - if r.mode.Width > 0 { - textWidth := r.mode.Width - lipgloss.Width(frame) - 1 - if textWidth < 0 { - textWidth = 0 + var builder strings.Builder + builder.WriteString(activityClearLine) + for i := 1; i < height; i++ { + builder.WriteString("\x1b[1A") + builder.WriteString(activityClearLine) + } + return builder.String() +} + +func (r *Renderer) renderActivityHeaderLines(frame string, text string) []string { + lines := wrapActivityText(text, r.activityContentWidth(lipgloss.Width(frame)+1)) + if len(lines) == 0 { + lines = []string{""} + } + + rendered := make([]string, 0, len(lines)) + for index, line := range lines { + if index == 0 { + rendered = append(rendered, lipgloss.JoinHorizontal( + lipgloss.Top, + r.theme.Identifier.Render(frame), + " ", + r.theme.Value.Render(line), + )) + continue } - lineText = truncateActivityText(lineText, textWidth) + rendered = append(rendered, strings.Repeat(" ", lipgloss.Width(frame)+1)+r.theme.Value.Render(line)) } + return rendered +} + +func (r *Renderer) renderActivityValueLines(prefix string, value string, style lipgloss.Style) []string { + return renderWrappedStyledValueLines(prefix, "", value, style, style, r.activityContentWidth(lipgloss.Width(prefix))) +} + +func (r *Renderer) renderActivityFieldLines(label string, value string, style lipgloss.Style) []string { + prefixPlain := " " + label + ": " + prefixStyled := " " + r.theme.Label.Render(label+":") + " " + return renderWrappedStyledValueLines(prefixPlain, prefixStyled, value, style, style, r.activityContentWidth(lipgloss.Width(prefixPlain))) +} + +func (r *Renderer) renderActivityCountsLines(label string, passed int, failed int, skipped int) []string { + prefixPlain := " " + label + ": " + prefixStyled := " " + r.theme.Label.Render(label+":") + " " + plainValue := fmt.Sprintf("%d pass, %d fail, %d skip", passed, failed, skipped) + valueWidth := r.activityContentWidth(lipgloss.Width(prefixPlain)) + lines := wrapActivityText(plainValue, valueWidth) + if len(lines) == 0 { + lines = []string{""} + } + + rendered := make([]string, 0, len(lines)) + for index, line := range lines { + prefix := strings.Repeat(" ", lipgloss.Width(prefixPlain)) + if index == 0 { + prefix = prefixStyled + } + rendered = append(rendered, prefix+r.renderActivityCountsValue(line)) + } + return rendered +} + +func (r *Renderer) renderActivityCountsValue(value string) string { + if r.mode.Format != laslig.FormatHuman { + return value + } + + passStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575")) + failStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("160")) + skipStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("214")) - return lipgloss.JoinHorizontal( - lipgloss.Top, - r.theme.Identifier.Render(frame), - " ", - r.theme.Value.Render(lineText), - ) + replaced := value + replaced = strings.ReplaceAll(replaced, " pass", " "+passStyle.Render("pass")) + replaced = strings.ReplaceAll(replaced, " fail", " "+failStyle.Render("fail")) + replaced = strings.ReplaceAll(replaced, " skip", " "+skipStyle.Render("skip")) + return r.theme.Value.Render(replaced) +} + +func (r *Renderer) activityContentWidth(prefixWidth int) int { + if r.mode.Width <= 0 { + return 0 + } + width := r.mode.Width - prefixWidth + if width < 1 { + return 1 + } + return width } func activityFrames(style laslig.SpinnerStyle) []string { @@ -316,28 +423,66 @@ func formatActivityElapsed(elapsed time.Duration) string { return elapsed.Round(time.Second).String() } -func truncateActivityText(value string, width int) string { - if width <= 0 { - return "" +func wrapActivityText(value string, width int) []string { + trimmed := strings.TrimSpace(value) + if trimmed == "" { + return nil } - if lipgloss.Width(value) <= width { - return value + if width <= 0 || lipgloss.Width(trimmed) <= width { + return []string{trimmed} } - const ellipsis = "…" - if width == 1 { - return ellipsis + lines := []string{} + remaining := trimmed + for strings.TrimSpace(remaining) != "" { + lines = append(lines, sliceVisibleWidth(remaining, width)) + if len(lines[len(lines)-1]) >= len(remaining) { + break + } + remaining = strings.TrimLeft(remaining[len(lines[len(lines)-1]):], " ") + } + return lines +} + +func sliceVisibleWidth(value string, width int) string { + if width <= 0 { + return value } var builder strings.Builder for _, r := range value { candidate := builder.String() + string(r) - if lipgloss.Width(candidate+ellipsis) > width { + if lipgloss.Width(candidate) > width { break } builder.WriteRune(r) } - return strings.TrimRight(builder.String(), " ") + ellipsis + if builder.Len() == 0 { + return value + } + return builder.String() +} + +func renderWrappedStyledValueLines(prefixPlain string, prefixStyled string, value string, firstStyle lipgloss.Style, continuationStyle lipgloss.Style, width int) []string { + if prefixStyled == "" { + prefixStyled = prefixPlain + } + lines := wrapActivityText(value, width) + if len(lines) == 0 { + lines = []string{""} + } + + rendered := make([]string, 0, len(lines)) + for index, line := range lines { + prefix := strings.Repeat(" ", lipgloss.Width(prefixPlain)) + style := continuationStyle + if index == 0 { + prefix = prefixStyled + style = firstStyle + } + rendered = append(rendered, prefix+style.Render(line)) + } + return rendered } func writerIsTerminal(out io.Writer) bool { diff --git a/gotestout/doc.go b/gotestout/doc.go index 474f9f2..c11084a 100644 --- a/gotestout/doc.go +++ b/gotestout/doc.go @@ -4,12 +4,12 @@ // The package focuses on parsing and rendering the event stream itself. It does // not execute commands or own process lifecycle. Callers are expected to wire // exec.Command, Mage, or another runner to an io.Reader that yields go test -// events. Options allow compact or detailed views, a spinner-only live -// activity footer with auto/on/off modes for styled human output, and grouped -// failed-test, skipped-test, package-error, or captured-output sections that -// callers can disable when they want a tighter summary. In JSON mode, Render -// re-emits the raw go test events while still returning summary counts, and it -// skips the grouped human/plain summary blocks and transient activity footer. +// events. Options allow compact or detailed views, one transient live activity +// block with auto/on/off modes for styled human output, and grouped failed- +// test, skipped-test, package-error, or captured-output sections that callers +// can disable when they want a tighter summary. In JSON mode, Render re-emits +// the raw go test events while still returning summary counts, and it skips the +// grouped human/plain summary blocks and transient activity block. // This makes the package a good fit for Mage targets such as `mage test`, // ordinary Go CLI commands, and small Go helpers invoked from tools such as // `make`, `just`, or `task`. diff --git a/gotestout/renderer_test.go b/gotestout/renderer_test.go index c963d14..e84952a 100644 --- a/gotestout/renderer_test.go +++ b/gotestout/renderer_test.go @@ -244,13 +244,19 @@ func TestRenderHumanStyledActivityOn(t *testing.T) { if !strings.Contains(plain, "Running go test -json") { t.Fatalf("Render() output missing activity text:\n%s", plain) } - if !strings.Contains(plain, "tests: 1/1/1") { + if !strings.Contains(plain, "package: example/pkg") { + t.Fatalf("Render() output missing package field:\n%s", plain) + } + if !strings.Contains(plain, "tests: 1 pass, 1 fail, 1 skip") { t.Fatalf("Render() output missing live test counts:\n%s", plain) } + if !strings.Contains(plain, "packages: 0 pass, 1 fail, 0 skip") { + t.Fatalf("Render() output missing live package counts:\n%s", plain) + } } // TestRenderPlainActivityOnNoFooter verifies plain output never emits the live -// activity footer even when callers force activity on. +// activity block even when callers force activity on. func TestRenderPlainActivityOnNoFooter(t *testing.T) { var buf bytes.Buffer _, err := Render(&buf, strings.NewReader(sampleStream), Options{ diff --git a/gotestout/types.go b/gotestout/types.go index 0c998a1..75ab131 100644 --- a/gotestout/types.go +++ b/gotestout/types.go @@ -128,18 +128,18 @@ type Options struct { Activity ActivityOptions } -// ActivityMode controls whether gotestout renders one live activity footer +// ActivityMode controls whether gotestout renders one live activity block // while a test stream is still running. type ActivityMode string const ( - // ActivityAuto enables the activity footer only for styled human terminal + // ActivityAuto enables the activity block only for styled human terminal // output where transient redraws are appropriate. ActivityAuto ActivityMode = "auto" - // ActivityOn forces the activity footer for styled human output even when + // ActivityOn forces the activity block for styled human output even when // the writer is not a terminal, which is useful for demos and tests. ActivityOn ActivityMode = "on" - // ActivityOff disables the activity footer completely. + // ActivityOff disables the activity block completely. ActivityOff ActivityMode = "off" ) @@ -153,19 +153,19 @@ func (m ActivityMode) Valid() bool { } } -// ActivityOptions configures the optional live activity footer shown while a +// ActivityOptions configures the optional live activity block shown while a // go test stream is still running. // -// The footer is spinner-only. It is transient in styled human output and is -// suppressed entirely in plain, unstyled human, and JSON modes. +// The block is transient in styled human output and is suppressed entirely in +// plain, unstyled human, and JSON modes. type ActivityOptions struct { - // Mode selects whether the footer is enabled automatically, forced on for + // Mode selects whether the activity block is enabled automatically, forced on for // styled human output, or disabled entirely. The default is auto. Mode ActivityMode - // SpinnerStyle selects the built-in spinner frame set used when the footer + // SpinnerStyle selects the built-in spinner frame set used when the block // is visible. The default is laslig.DefaultSpinnerStyle(). SpinnerStyle laslig.SpinnerStyle - // Delay waits this long before showing the footer, which helps avoid + // Delay waits this long before showing the block, which helps avoid // flicker on very short test runs. The default is 750ms. Delay time.Duration // Text overrides the leading activity label. The default is diff --git a/internal/examples/render.go b/internal/examples/render.go index e391761..3c3d933 100644 --- a/internal/examples/render.go +++ b/internal/examples/render.go @@ -318,7 +318,7 @@ func RenderGotestout(out io.Writer, printer *laslig.Printer) error { } if err := printer.Paragraph(laslig.Paragraph{ Body: "Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control.", - Footer: "This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active.", + Footer: "This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active.", }); err != nil { return fmt.Errorf("render gotestout intro: %w", err) } @@ -360,7 +360,7 @@ func RenderMageCheckPreview(out io.Writer, printer *laslig.Printer) error { } if err := printer.Paragraph(laslig.Paragraph{ Body: "Use gotestout inside Mage or small Go helpers behind make, just, or task when you want caller-owned process control with a readable test stream.", - Footer: "The preview below matches this repository's mage check and mage test shape, including the live gotestout activity footer while the test stream is still active.", + Footer: "The preview below matches this repository's mage check and mage test shape, including the live gotestout activity block while the test stream is still active.", }); err != nil { return fmt.Errorf("render mage preview intro: %w", err) } diff --git a/internal/examples/testdata/TestRenderAllHumanStyledGolden.golden b/internal/examples/testdata/TestRenderAllHumanStyledGolden.golden index b3759e1..f7ed59b 100644 --- a/internal/examples/testdata/TestRenderAllHumanStyledGolden.golden +++ b/internal/examples/testdata/TestRenderAllHumanStyledGolden.golden @@ -199,8 +199,7 @@ gotestout This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals - show gotestout's live activity footer while the stream is still - active. + show gotestout's live activity block while the stream is still active. INFO Mixed fixture demo The example command itself is expected to exit successfully so you can @@ -250,7 +249,7 @@ gotestout + Mage stream. The preview below matches this repository's mage check and mage test - shape, including the live gotestout activity footer while the test + shape, including the live gotestout activity block while the test stream is still active. diff --git a/internal/examples/testdata/TestRunAllPlainGolden.golden b/internal/examples/testdata/TestRunAllPlainGolden.golden index 1ce11c6..6233b36 100644 --- a/internal/examples/testdata/TestRunAllPlainGolden.golden +++ b/internal/examples/testdata/TestRunAllPlainGolden.golden @@ -156,7 +156,7 @@ gotestout Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control. - This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active. + This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active. [INFO] Mixed fixture demo The example command itself is expected to exit successfully so you can inspect the output shape. @@ -202,7 +202,7 @@ gotestout + Mage Use gotestout inside Mage or small Go helpers behind make, just, or task when you want caller-owned process control with a readable test stream. - The preview below matches this repository's mage check and mage test shape, including the live gotestout activity footer while the test stream is still active. + The preview below matches this repository's mage check and mage test shape, including the live gotestout activity block while the test stream is still active. Build diff --git a/internal/examples/testdata/TestRunFocusedPlainGolden/gotestout.golden b/internal/examples/testdata/TestRunFocusedPlainGolden/gotestout.golden index ad95d67..684a18e 100644 --- a/internal/examples/testdata/TestRunFocusedPlainGolden/gotestout.golden +++ b/internal/examples/testdata/TestRunFocusedPlainGolden/gotestout.golden @@ -3,7 +3,7 @@ gotestout Use gotestout for attractive, structured go test output when your task runner, CLI command, or Go helper behind make/just should keep owning process control. - This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity footer while the stream is still active. + This focused example intentionally mixes passing, skipped, and failing test events plus one package build failure, and styled human terminals show gotestout's live activity block while the stream is still active. [INFO] Mixed fixture demo The example command itself is expected to exit successfully so you can inspect the output shape. diff --git a/internal/examples/testdata/TestRunFocusedPlainGolden/magecheck.golden b/internal/examples/testdata/TestRunFocusedPlainGolden/magecheck.golden index 5aec203..2fc3e20 100644 --- a/internal/examples/testdata/TestRunFocusedPlainGolden/magecheck.golden +++ b/internal/examples/testdata/TestRunFocusedPlainGolden/magecheck.golden @@ -3,7 +3,7 @@ gotestout + Mage Use gotestout inside Mage or small Go helpers behind make, just, or task when you want caller-owned process control with a readable test stream. - The preview below matches this repository's mage check and mage test shape, including the live gotestout activity footer while the test stream is still active. + The preview below matches this repository's mage check and mage test shape, including the live gotestout activity block while the test stream is still active. Build