From 65d2cde63ce34f5cf5b8a69ac394603f192dc30a Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 11 Oct 2026 19:19:15 +0200 Subject: [PATCH] Slow blink progress pulse, add verb label and brick color Gate the icon frame on a 450ms wall-clock interval so the bloom pulses at a calm pace regardless of file throughput. Show "checking"/"fixing" next to the icon and color it in the terracotta brand orange. --- blink/internal/reporter/progress.go | 43 +++++++++++++++++++++-------- blink/main.go | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/blink/internal/reporter/progress.go b/blink/internal/reporter/progress.go index 010067d9f7..9767a2013e 100644 --- a/blink/internal/reporter/progress.go +++ b/blink/internal/reporter/progress.go @@ -5,26 +5,38 @@ import ( "os" "strings" "sync" + "time" ) +// pulseInterval is the minimum wall-clock gap between icon frames, so the bloom +// pulses at a calm pace regardless of how fast files are processed. +const pulseInterval = 450 * time.Millisecond + // Progress is an ECS-style progress bar rendered on a terminal. It is a no-op // when the writer is not a terminal (piped output, CI), so scripts stay clean. type Progress struct { - w *os.File - width int - active bool - total int - cur int - frame int - mu sync.Mutex + w *os.File + width int + active bool + label string + total int + cur int + frame int + lastTick time.Time + mu sync.Mutex } // iconFrames is a pulsing bloom that grows from a dot to a star and back, advanced one step per render. var iconFrames = []string{"·", "∘", "○", "◯", "✦", "✧", "✦", "◯", "○", "∘"} // NewProgress returns a progress bar; it only draws when w is a terminal. -func NewProgress(w *os.File) *Progress { - p := &Progress{w: w, width: 28} +// fix selects the verb shown next to the icon: "fixing" when writing, else "checking". +func NewProgress(w *os.File, fix bool) *Progress { + label := "checking" + if fix { + label = "fixing" + } + p := &Progress{w: w, width: 28, label: label} if _, ok := winsize(w); ok { p.active = true } @@ -71,11 +83,20 @@ func (p *Progress) Finish() { _, _ = fmt.Fprintf(p.w, "\r%s\r", strings.Repeat(" ", p.width+24)) } +// brickOrange wraps s in Claude's terracotta foreground color (truecolor ANSI). +func brickOrange(s string) string { + return "\x1b[38;2;215;119;87m" + s + "\x1b[0m" +} + func (p *Progress) render() { if p.total <= 0 { return } + now := time.Now() + if now.Sub(p.lastTick) >= pulseInterval { + p.frame++ + p.lastTick = now + } icon := iconFrames[p.frame%len(iconFrames)] - p.frame++ - _, _ = fmt.Fprintf(p.w, "\r %s", icon) + _, _ = fmt.Fprintf(p.w, "\r %s %s..", brickOrange(icon), p.label) } diff --git a/blink/main.go b/blink/main.go index b3397cb204..19a18ec154 100644 --- a/blink/main.go +++ b/blink/main.go @@ -80,7 +80,7 @@ func run(args []string) int { cfg.WithPaths(paths...) start := time.Now() - progress := reporter.NewProgress(os.Stderr) + progress := reporter.NewProgress(os.Stderr, fix) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop()