Use STATUSLINE_WIDTH env var for reliable width detection

term.GetSize returns unreliable values when running inside Claude Code
over SSH. Replace the hardcoded statuslineWidthOffset with STATUSLINE_WIDTH
env var (set in Claude Code settings), falling back to terminal detection,
then 80 columns.
This commit is contained in:
2026-02-08 23:27:26 +01:00
parent a06aa4c549
commit 27128e2e3b
2 changed files with 16 additions and 17 deletions

26
main.go
View File

@@ -15,7 +15,7 @@ import (
"golang.org/x/term" "golang.org/x/term"
) )
const statuslineWidthOffset = 7 const defaultStatuslineWidth = 80
// TokenUsage tracks context window token consumption. // TokenUsage tracks context window token consumption.
type TokenUsage struct { type TokenUsage struct {
@@ -117,7 +117,7 @@ func run(r *bufio.Reader, w *strings.Builder) error {
rightVisible := stripANSI(right) rightVisible := stripANSI(right)
// Get terminal width // Get terminal width
termWidth := getTerminalWidth() - statuslineWidthOffset termWidth := getTerminalWidth()
// Calculate and apply padding // Calculate and apply padding
padding := calculatePadding(leftVisible, rightVisible, termWidth) padding := calculatePadding(leftVisible, rightVisible, termWidth)
@@ -212,30 +212,30 @@ func getGitInfo(cwd string) string {
return fmt.Sprintf(" git:(%s)", branch) return fmt.Sprintf(" git:(%s)", branch)
} }
// termWidthFunc returns the terminal width. // termWidthFunc returns the usable status line width.
// Tries stderr and stdin as fallbacks since stdout is typically piped // Checks STATUSLINE_WIDTH env var first (set in Claude Code settings),
// when Claude Code captures the status line output. // then tries terminal detection on stderr/stdin/stdout, then falls back
// to defaultStatuslineWidth.
// Replaced in tests to avoid depending on a real TTY. // Replaced in tests to avoid depending on a real TTY.
var termWidthFunc = func() (int, error) { var termWidthFunc = func() (int, error) {
if sw := os.Getenv("STATUSLINE_WIDTH"); sw != "" {
var w int
if _, err := fmt.Sscanf(sw, "%d", &w); err == nil && w > 0 {
return w, nil
}
}
for _, fd := range []uintptr{os.Stderr.Fd(), os.Stdin.Fd(), os.Stdout.Fd()} { for _, fd := range []uintptr{os.Stderr.Fd(), os.Stdin.Fd(), os.Stdout.Fd()} {
if width, _, err := term.GetSize(int(fd)); err == nil { if width, _, err := term.GetSize(int(fd)); err == nil {
return width, nil return width, nil
} }
} }
// Fall back to COLUMNS env var
if cols := os.Getenv("COLUMNS"); cols != "" {
var w int
if _, err := fmt.Sscanf(cols, "%d", &w); err == nil && w > 0 {
return w, nil
}
}
return 0, errors.New("no terminal detected") return 0, errors.New("no terminal detected")
} }
func getTerminalWidth() int { func getTerminalWidth() int {
width, err := termWidthFunc() width, err := termWidthFunc()
if err != nil { if err != nil {
return 80 return defaultStatuslineWidth
} }
return width return width
} }

View File

@@ -756,10 +756,9 @@ func TestTokenUsage_ZeroValues(t *testing.T) {
} }
} }
func TestStatuslineWidthOffset_Constant(t *testing.T) { func TestDefaultStatuslineWidth_Constant(t *testing.T) {
// Verify the constant is defined and reasonable if defaultStatuslineWidth < 40 || defaultStatuslineWidth > 300 {
if statuslineWidthOffset <= 0 || statuslineWidthOffset > 20 { t.Errorf("defaultStatuslineWidth = %d, expected between 40 and 300", defaultStatuslineWidth)
t.Errorf("statuslineWidthOffset = %d, expected between 1 and 20", statuslineWidthOffset)
} }
} }