Skip to content
Merged
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
15 changes: 8 additions & 7 deletions cmd/vitals/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/Jason-Adam/vitals/internal/preset"
"github.com/Jason-Adam/vitals/internal/render"
"github.com/Jason-Adam/vitals/internal/stdin"
"github.com/lucasb-eyer/go-colorful"
)

// installPath is the go install target for the update command.
Expand Down Expand Up @@ -408,13 +407,15 @@ func queryLightBackground() (light bool, ok bool) {
}

// isLightColor returns true when a color's HSL lightness is >= 0.5.
// Mirrors lipgloss's unexported isDarkColor with the inverse condition.
// Uses the standard RGB-to-HSL lightness formula: L = (max + min) / 2.
func isLightColor(c color.Color) bool {
col, ok := colorful.MakeColor(c)
if !ok {
return false // can't determine — assume dark (safe default)
}
_, _, l := col.Hsl()
r, g, b, _ := c.RGBA()
rf := float64(r) / 0xffff
gf := float64(g) / 0xffff
bf := float64(b) / 0xffff
mx := max(rf, gf, bf)
mn := min(rf, gf, bf)
l := (mx + mn) / 2
return l >= 0.5
}

Expand Down
25 changes: 25 additions & 0 deletions cmd/vitals/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bytes"
"image/color"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -260,6 +261,30 @@ func TestWatchAndRender_DetectsFileChange(t *testing.T) {
}
}

func TestIsLightColor(t *testing.T) {
tests := []struct {
name string
c color.Color
want bool
}{
{"black", color.Black, false},
{"white", color.White, true},
{"dark gray", color.RGBA{R: 64, G: 64, B: 64, A: 255}, false},
{"light gray", color.RGBA{R: 192, G: 192, B: 192, A: 255}, true},
{"mid gray below threshold", color.RGBA{R: 126, G: 126, B: 126, A: 255}, false},
{"mid gray at threshold", color.RGBA{R: 128, G: 128, B: 128, A: 255}, true},
{"pure red", color.RGBA{R: 255, G: 0, B: 0, A: 255}, true},
{"dark blue", color.RGBA{R: 0, G: 0, B: 128, A: 255}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isLightColor(tt.c); got != tt.want {
t.Errorf("isLightColor(%v) = %v, want %v", tt.c, got, tt.want)
}
})
}
}

func TestFindCurrentTranscript_ReturnsNewest(t *testing.T) {
tmp := t.TempDir()
t.Setenv("HOME", tmp)
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ require (
github.com/BurntSushi/toml v1.6.0
github.com/charmbracelet/colorprofile v0.4.2
github.com/charmbracelet/x/ansi v0.11.6
github.com/charmbracelet/x/term v0.2.2
github.com/lucasb-eyer/go-colorful v1.3.0
)

require (
github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/charmbracelet/x/termios v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.11.0 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-runewidth v0.0.21 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
Expand Down
3 changes: 1 addition & 2 deletions internal/gather/gather.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/Jason-Adam/vitals/internal/git"
"github.com/Jason-Adam/vitals/internal/model"
"github.com/Jason-Adam/vitals/internal/transcript"
"github.com/charmbracelet/x/term"
)

// transcriptWidgets are the widget names that require transcript data.
Expand Down Expand Up @@ -265,7 +264,7 @@ func sessionStart(path string) string {
// (defaultTerminalWidth) when this returns 0.
func terminalWidth() int {
for _, fd := range []uintptr{os.Stdin.Fd(), os.Stderr.Fd(), os.Stdout.Fd()} {
if w, _, err := term.GetSize(fd); err == nil && w > 0 {
if w := getTermWidth(fd); w > 0 {
return w
}
}
Expand Down
7 changes: 7 additions & 0 deletions internal/gather/termsize_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !unix

package gather

// getTermWidth is a no-op on non-Unix platforms; the caller falls back
// to the COLUMNS env var.
func getTermWidth(_ uintptr) int { return 0 }
26 changes: 26 additions & 0 deletions internal/gather/termsize_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//go:build unix

package gather

import (
"syscall"
"unsafe"
)

// getTermWidth returns the terminal width for the given file descriptor
// via the TIOCGWINSZ ioctl, or 0 if the fd is not a terminal.
func getTermWidth(fd uintptr) int {
var ws struct {
Row, Col uint16
Xpixel, Ypixel uint16
}
_, _, err := syscall.Syscall(
syscall.SYS_IOCTL, fd,
syscall.TIOCGWINSZ,
uintptr(unsafe.Pointer(&ws)),
)
if err != 0 || ws.Col == 0 {
return 0
}
return int(ws.Col)
}
Loading