From bbe3d3f284e88cbb57ec2d6526b3550f56b7e7f7 Mon Sep 17 00:00:00 2001 From: tw93 Date: Fri, 27 Feb 2026 10:07:44 +0800 Subject: [PATCH] fix(status): keep compact header single-line on tight widths --- cmd/status/view.go | 38 +++++++++++++++++++++++++------------- cmd/status/view_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/cmd/status/view.go b/cmd/status/view.go index a534028..514473f 100644 --- a/cmd/status/view.go +++ b/cmd/status/view.go @@ -167,27 +167,39 @@ func renderHeader(m MetricsSnapshot, errMsg string, animFrame int, termWidth int if m.Hardware.RefreshRate != "" { infoParts = append(infoParts, m.Hardware.RefreshRate) } + optionalInfoParts := []string{} if !compactHeader && m.Hardware.OSVersion != "" { - infoParts = append(infoParts, m.Hardware.OSVersion) + optionalInfoParts = append(optionalInfoParts, m.Hardware.OSVersion) } if !compactHeader && m.Uptime != "" { - infoParts = append(infoParts, subtleStyle.Render("up "+m.Uptime)) + optionalInfoParts = append(optionalInfoParts, subtleStyle.Render("up "+m.Uptime)) } headLeft := title + " " + scoreText - baseLines := wrapToWidth(headLeft, termWidth) - headerLines := append([]string{}, baseLines...) - if len(infoParts) > 0 { - headRight := strings.Join(infoParts, " · ") - combined := headLeft + " " + headRight - if lipgloss.Width(combined) <= termWidth { - headerLines = wrapToWidth(combined, termWidth) - } else { - wrappedRight := wrapToWidth(headRight, termWidth) - headerLines = append(baseLines, wrappedRight...) + headerLine := headLeft + if termWidth > 0 && lipgloss.Width(headerLine) > termWidth { + headerLine = wrapToWidth(headLeft, termWidth)[0] + } + if termWidth > 0 { + allParts := append(append([]string{}, infoParts...), optionalInfoParts...) + if len(allParts) > 0 { + combined := headLeft + " " + strings.Join(allParts, " · ") + if lipgloss.Width(combined) <= termWidth { + headerLine = combined + } else { + // When width is tight, drop lower-priority tail (OS and uptime) as a group. + fitParts := append([]string{}, infoParts...) + for len(fitParts) > 0 { + candidate := headLeft + " " + strings.Join(fitParts, " · ") + if lipgloss.Width(candidate) <= termWidth { + headerLine = candidate + break + } + fitParts = fitParts[:len(fitParts)-1] + } + } } } - headerLine := lipgloss.JoinVertical(lipgloss.Left, headerLines...) // Show cat unless hidden - render mole centered below header var mole string diff --git a/cmd/status/view_test.go b/cmd/status/view_test.go index 6dc06d4..beb99f3 100644 --- a/cmd/status/view_test.go +++ b/cmd/status/view_test.go @@ -982,6 +982,34 @@ func TestRenderHeaderHidesOSAndUptimeOnNarrowWidth(t *testing.T) { } } +func TestRenderHeaderDropsLowPriorityInfoToStaySingleLine(t *testing.T) { + m := MetricsSnapshot{ + HealthScore: 90, + Hardware: HardwareInfo{ + Model: "MacBook Pro", + CPUModel: "Apple M2 Pro", + TotalRAM: "32.0 GB", + DiskSize: "460.4 GB", + RefreshRate: "60Hz", + OSVersion: "macOS 26.3", + }, + GPU: []GPUStatus{{CoreCount: 19}}, + Uptime: "9d 13h", + } + + header, _ := renderHeader(m, "", 0, 100, true) + plain := stripANSI(header) + if strings.Contains(plain, "\n") { + t.Fatalf("renderHeader() should stay single line when trimming low-priority fields, got %q", plain) + } + if strings.Contains(plain, "macOS 26.3") { + t.Fatalf("renderHeader() should drop os version when width is tight, got %q", plain) + } + if strings.Contains(plain, "up 9d 13h") { + t.Fatalf("renderHeader() should drop uptime when width is tight, got %q", plain) + } +} + func TestRenderCardWrapsOnNarrowWidth(t *testing.T) { card := cardData{ icon: iconCPU,