71 lines
1.6 KiB
Go
71 lines
1.6 KiB
Go
|
|
package text
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"math"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Pluralize returns "1 issue" or "2 issues" depending on count.
|
||
|
|
// It applies a simple "s" suffix rule.
|
||
|
|
func Pluralize(count int, singular string) string {
|
||
|
|
if count == 1 {
|
||
|
|
return fmt.Sprintf("%d %s", count, singular)
|
||
|
|
}
|
||
|
|
return fmt.Sprintf("%d %ss", count, singular)
|
||
|
|
}
|
||
|
|
|
||
|
|
// FuzzyAgo returns a human-friendly relative time string like "just now",
|
||
|
|
// "2 minutes ago", "3 hours ago", etc.
|
||
|
|
func FuzzyAgo(t time.Time) string {
|
||
|
|
d := time.Since(t)
|
||
|
|
|
||
|
|
if d < time.Minute {
|
||
|
|
return "just now"
|
||
|
|
}
|
||
|
|
|
||
|
|
minutes := int(math.Floor(d.Minutes()))
|
||
|
|
if minutes < 60 {
|
||
|
|
return fmt.Sprintf("%s ago", Pluralize(minutes, "minute"))
|
||
|
|
}
|
||
|
|
|
||
|
|
hours := int(math.Floor(d.Hours()))
|
||
|
|
if hours < 24 {
|
||
|
|
return fmt.Sprintf("%s ago", Pluralize(hours, "hour"))
|
||
|
|
}
|
||
|
|
|
||
|
|
days := hours / 24
|
||
|
|
if days < 30 {
|
||
|
|
return fmt.Sprintf("%s ago", Pluralize(days, "day"))
|
||
|
|
}
|
||
|
|
|
||
|
|
months := days / 30
|
||
|
|
if months < 12 {
|
||
|
|
return fmt.Sprintf("%s ago", Pluralize(months, "month"))
|
||
|
|
}
|
||
|
|
|
||
|
|
years := months / 12
|
||
|
|
return fmt.Sprintf("%s ago", Pluralize(years, "year"))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Truncate shortens text to maxWidth, replacing the end with "..." if it exceeds
|
||
|
|
// the limit. If maxWidth is less than or equal to 3, the result is just "...".
|
||
|
|
func Truncate(text string, maxWidth int) string {
|
||
|
|
if len(text) <= maxWidth {
|
||
|
|
return text
|
||
|
|
}
|
||
|
|
if maxWidth <= 3 {
|
||
|
|
return "..."[:maxWidth]
|
||
|
|
}
|
||
|
|
return text[:maxWidth-3] + "..."
|
||
|
|
}
|
||
|
|
|
||
|
|
// FormatDate returns a human-friendly relative time for TTY output, or an
|
||
|
|
// RFC3339 timestamp for piped output.
|
||
|
|
func FormatDate(t time.Time, isTTY bool) string {
|
||
|
|
if isTTY {
|
||
|
|
return FuzzyAgo(t)
|
||
|
|
}
|
||
|
|
return t.Format(time.RFC3339)
|
||
|
|
}
|