Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions pkg/action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,10 @@ func DiffHeader(breadcrumb []string, target string, color bool) string {
}

// 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.
// followed by the turn's instance name in bold. The chip is white rather than the
// run log's indigo root color, so the banner reads as "this is the diff" and not
// more run output. It is the anchor the eye lands on, so turn boundaries stand out
// in a long batch. Callers put the separating blank line above the header block.
func diffTurnBanner(root, turn string, color bool) string {
if color {
return diffColorInvert + diffColorRoot + diffColorBold + " ≡ " + root + " ≡ " + diffColorReset +
Expand All @@ -184,18 +185,20 @@ func diffTurnBanner(root, turn string, color bool) string {
// diffHandoffChain renders the submodule hand-off lines beneath a turn banner:
// one "▸ parent › child" per descent step from the turn down to the leaf, the
// run log's nested-dispatch form — no root chip, so headers inside a turn read
// lighter. The marker and parent share the worker teal so the hand-off reads as
// one legible breadcrumb unit rather than fading into the diff; the child, the
// step that matters, stays bold. Empty when the breadcrumb stops at the turn.
// lighter. The child — the module that produced the diff — is an inverted light-
// gray chip: a filled anchor so the breadcrumb stands out against the diff, one
// step below the white turn chip, and in neither the log's indigo nor teal so it
// never reads as more run output. The marker and parent stay muted context.
// Empty when the breadcrumb stops at the turn.
func diffHandoffChain(segs []string, color bool) string {
var b strings.Builder
for i := 1; i+1 < len(segs); i++ {
parent, child := segs[i], segs[i+1]
if color {
b.WriteString(diffColorWorker + "▸ " + parent + " › " + diffColorReset +
diffColorBold + child + diffColorReset + "\n")
b.WriteString(diffColorMuted + "▸ " + parent + " › " + diffColorReset +
diffColorInvert + diffColorSub + " " + child + " " + diffColorReset + "\n")
} else {
b.WriteString("▸ " + parent + " › " + child + "\n")
b.WriteString("▸ " + parent + " › [" + child + "]\n")
}
}
return b.String()
Expand Down
6 changes: 3 additions & 3 deletions pkg/action/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const (
diffColorGreen = "\033[32m"
diffColorCyan = "\033[36m"
diffColorInvert = "\033[7m"
diffColorMuted = "\033[38;5;244m" // mid gray — matches the log handler's muted tone
diffColorRoot = "\033[38;5;61m" // muted indigo — the orchestrator chip (log's root color)
diffColorWorker = "\033[38;5;66m" // slate teal — the hand-off marker (log's worker color)
diffColorMuted = "\033[38;5;244m" // mid gray — the hand-off marker, parent context, and target line
diffColorRoot = "\033[38;5;231m" // white — the turn chip, top of the diff header
diffColorSub = "\033[38;5;250m" // light gray — the submodule chip, one step below the turn
)

// printDiff computes a unified diff between old and new content and hands it to
Expand Down
10 changes: 5 additions & 5 deletions pkg/action/diff_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestDiffHeader_SubmoduleGetsRootFreeHandoff(t *testing.T) {
// root and item, then a "▸ item › submodule" hand-off with no root chip.
got := DiffHeader([]string{"bulk-deploy-k8s", "deploy-k8s-2", "autocert"}, "acme/cluster-2 (main)", false)
want := "\n[≡ bulk-deploy-k8s ≡] deploy-k8s-2\n" +
"▸ deploy-k8s-2 › autocert\n" +
"▸ deploy-k8s-2 › [autocert]\n" +
"acme/cluster-2 (main)\n"
if got != want {
t.Errorf("got %q, want %q", got, want)
Expand All @@ -44,8 +44,8 @@ func TestDiffHeader_ColorTurnBannerAndHandoff(t *testing.T) {
want := "\n" +
diffColorInvert + diffColorRoot + diffColorBold + " ≡ deps-bump ≡ " + diffColorReset +
" " + diffColorBold + "service-a" + diffColorReset + "\n" +
diffColorWorker + "▸ service-a › " + diffColorReset +
diffColorBold + "autocert" + diffColorReset + "\n" +
diffColorMuted + "▸ service-a › " + diffColorReset +
diffColorInvert + diffColorSub + " autocert " + diffColorReset + "\n" +
diffColorMuted + "acme/service-a" + diffColorReset + "\n"
if got != want {
t.Errorf("got %q, want %q", got, want)
Expand Down Expand Up @@ -106,15 +106,15 @@ func TestDiffCollector_BannerOncePerTurnHandoffPerSubmodule(t *testing.T) {
t.Errorf("expected deploy-1 named 3 times, got %d:\n%s", n, out)
}
for _, want := range []string{
"▸ deploy-1 › autocert", "▸ deploy-1 › ingress", "▸ deploy-2 › autocert",
"▸ deploy-1 › [autocert]", "▸ deploy-1 › [ingress]", "▸ deploy-2 › [autocert]",
} {
if !strings.Contains(out, want) {
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") {
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)
}
}
Loading