From 6c6e8eef3593e2295c625bb0bf23a1700cea49ee Mon Sep 17 00:00:00 2001 From: Rick Liu Date: Thu, 23 Jul 2026 23:58:41 +0100 Subject: [PATCH] fix(diff): separate every bulk header block with a blank line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inside a turn, a submodule's "▸ parent › child" hand-off (and a bare target change) printed glued to the end of the diff above it — only the turn banner was set off by a blank line. So a breadcrumb sitting between two diffs got lost in the surrounding diff text. Lead every header block with a blank line, not just the turn banner: move the separator out of diffTurnBanner and into the callers (DiffCollector.Print and DiffHeader), emitted whenever a new header block starts. The rendered header bytes are otherwise unchanged, so full mode and the single-module path are unaffected. Co-Authored-By: Claude Opus 4.8 --- pkg/action/action.go | 21 +++++++++++++-------- pkg/action/diff_header_test.go | 5 +++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/action/action.go b/pkg/action/action.go index 627ad0e..5b5fd7e 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -100,6 +100,12 @@ func (c *DiffCollector) Print(w io.Writer) { if len(segs) > 1 { turn := segs[0] + "\x00" + segs[1] + // A blank line sets every header block apart from the diff above it, so + // a breadcrumb sitting between two diffs stays visible — not just the + // turn banner, but a submodule hand-off or a bare target change too. + if i == 0 || key != lastKey { + fmt.Fprint(w, "\n") + } if i == 0 || turn != lastTurn { fmt.Fprint(w, diffTurnBanner(segs[0], segs[1], color)) } @@ -132,7 +138,7 @@ func (c *DiffCollector) Print(w io.Writer) { func DiffHeader(breadcrumb []string, target string, color bool) string { segs := nonEmptySegs(breadcrumb) if len(segs) > 1 { - return diffTurnBanner(segs[0], segs[1], color) + + return "\n" + diffTurnBanner(segs[0], segs[1], color) + diffHandoffChain(segs, color) + diffTargetLine(target, color) } @@ -163,17 +169,16 @@ func DiffHeader(breadcrumb []string, target string, color bool) string { return b.String() } -// diffTurnBanner heads one bulk turn: a leading blank line, then the root module -// as an inverted "≡ … ≡" chip (mirroring the log's root section header) followed -// by the turn's instance name in bold. This is the anchor the eye lands on, so -// turn boundaries stand out in a long batch. +// diffTurnBanner heads one bulk turn: the root module as an inverted "≡ … ≡" chip +// (mirroring the log's root section header) followed by the turn's instance name +// in bold. This is the anchor the eye lands on, so turn boundaries stand out in a +// long batch. Callers put the separating blank line above the whole header block. func diffTurnBanner(root, turn string, color bool) string { if color { - return "\n" + - diffColorInvert + diffColorRoot + diffColorBold + " ≡ " + root + " ≡ " + diffColorReset + + return diffColorInvert + diffColorRoot + diffColorBold + " ≡ " + root + " ≡ " + diffColorReset + " " + diffColorBold + turn + diffColorReset + "\n" } - return "\n[≡ " + root + " ≡] " + turn + "\n" + return "[≡ " + root + " ≡] " + turn + "\n" } // diffHandoffChain renders the submodule hand-off lines beneath a turn banner: diff --git a/pkg/action/diff_header_test.go b/pkg/action/diff_header_test.go index 66f1ed1..3834521 100644 --- a/pkg/action/diff_header_test.go +++ b/pkg/action/diff_header_test.go @@ -113,4 +113,9 @@ func TestDiffCollector_BannerOncePerTurnHandoffPerSubmodule(t *testing.T) { t.Errorf("expected hand-off %q, got:\n%s", want, out) } } + // Every header block is set off from the diff above it by a blank line, so a + // breadcrumb between two diffs stays visible — the within-turn submodule too. + if !strings.Contains(out, "\n\n▸ deploy-1 › ingress") { + t.Errorf("expected a blank line before the within-turn submodule header, got:\n%s", out) + } }