package tui import ( "strings" "github.com/charmbracelet/lipgloss" ) // Responsive breakpoints const ( widthCompact = 60 // mobile / Termux widthMedium = 100 // tablet ) // boxOverhead is the horizontal chars consumed by BorderStyle (border 2 + padding 4) const boxOverhead = 6 // wrapFooter wraps a footer string into multiple lines that fit availW. // Words are split on double-space separators (" ") and grouped greedily. // Returns the wrapped string with "\n" line breaks. func wrapFooter(text string, availW int) string { if availW < 1 { availW = 1 } if lipgloss.Width(text) <= availW { return text } words := strings.Split(text, " ") var lines []string var current strings.Builder for _, word := range words { word = strings.TrimSpace(word) if word == "" { continue } if current.Len() == 0 { current.WriteString(word) } else if current.Len()+2+lipgloss.Width(word) <= availW { current.WriteString(" ") current.WriteString(word) } else { lines = append(lines, current.String()) current.Reset() current.WriteString(word) } } if current.Len() > 0 { lines = append(lines, current.String()) } return strings.Join(lines, "\n") } // adaptiveSidePad returns horizontal padding based on terminal width. // wide: 6, medium: 3, compact: 1 func adaptiveSidePad(termWidth int) int { switch { case termWidth < widthCompact: return 1 case termWidth < widthMedium: return 3 default: return 6 } } // clampWidth clamps a target box width to fit within the terminal. // Reserves boxOverhead for border+padding. Enforces a minimum of 20. func clampWidth(target, termWidth int) int { maxW := termWidth - boxOverhead if maxW < 20 { maxW = 20 } if target > maxW { return maxW } if target < 20 { return 20 } return target } // truncateStr truncates a string to maxLen with an ellipsis character. func truncateStr(s string, maxLen int) string { if maxLen < 1 { return "" } if lipgloss.Width(s) <= maxLen { return s } if maxLen <= 1 { return "…" } runes := []rune(s) var result []rune resultW := 0 for _, r := range runes { rw := lipgloss.Width(string(r)) if resultW+rw > maxLen-1 { break } result = append(result, r) resultW += rw } return string(result) + "…" } // Exported wrappers for testing // WrapFooter wraps a footer string into multiple lines that fit availW func WrapFooter(text string, availW int) string { return wrapFooter(text, availW) } // ClampWidth clamps a target box width to fit within the terminal func ClampWidth(target, termWidth int) int { return clampWidth(target, termWidth) } // TruncateStr truncates a string to maxLen with an ellipsis character func TruncateStr(s string, maxLen int) string { return truncateStr(s, maxLen) }