...
1
2 package text
3
4 import (
5 "fmt"
6 "regexp"
7 "strings"
8 "time"
9 "unicode"
10
11 "github.com/charmbracelet/lipgloss"
12 "github.com/muesli/reflow/truncate"
13 "golang.org/x/text/runes"
14 "golang.org/x/text/transform"
15 "golang.org/x/text/unicode/norm"
16 )
17
18 const (
19 ellipsis = "..."
20 minWidthForEllipsis = len(ellipsis) + 2
21 )
22
23 var indentRE = regexp.MustCompile(`(?m)^`)
24
25
26
27 func Indent(s, indent string) string {
28 if len(strings.TrimSpace(s)) == 0 {
29 return s
30 }
31 return indentRE.ReplaceAllLiteralString(s, indent)
32 }
33
34
35 func DisplayWidth(s string) int {
36 return lipgloss.Width(s)
37 }
38
39
40 func Truncate(maxWidth int, s string) string {
41 w := DisplayWidth(s)
42 if w <= maxWidth {
43 return s
44 }
45 tail := ""
46 if maxWidth >= minWidthForEllipsis {
47 tail = ellipsis
48 }
49 r := truncate.StringWithTail(s, uint(maxWidth), tail)
50 if DisplayWidth(r) < maxWidth {
51 r += " "
52 }
53 return r
54 }
55
56
57
58 func PadRight(maxWidth int, s string) string {
59 if padWidth := maxWidth - DisplayWidth(s); padWidth > 0 {
60 s += strings.Repeat(" ", padWidth)
61 }
62 return s
63 }
64
65
66 func Pluralize(num int, thing string) string {
67 if num == 1 {
68 return fmt.Sprintf("%d %s", num, thing)
69 }
70 return fmt.Sprintf("%d %ss", num, thing)
71 }
72
73 func fmtDuration(amount int, unit string) string {
74 return fmt.Sprintf("about %s ago", Pluralize(amount, unit))
75 }
76
77
78
79 func RelativeTimeAgo(a, b time.Time) string {
80 ago := a.Sub(b)
81
82 if ago < time.Minute {
83 return "less than a minute ago"
84 }
85 if ago < time.Hour {
86 return fmtDuration(int(ago.Minutes()), "minute")
87 }
88 if ago < 24*time.Hour {
89 return fmtDuration(int(ago.Hours()), "hour")
90 }
91 if ago < 30*24*time.Hour {
92 return fmtDuration(int(ago.Hours())/24, "day")
93 }
94 if ago < 365*24*time.Hour {
95 return fmtDuration(int(ago.Hours())/24/30, "month")
96 }
97
98 return fmtDuration(int(ago.Hours()/24/365), "year")
99 }
100
101
102 func RemoveDiacritics(value string) string {
103
104 removeMnTransfomer := runes.Remove(runes.In(unicode.Mn))
105
106
107
108
109 t := transform.Chain(norm.NFD, removeMnTransfomer, norm.NFC)
110 normalized, _, err := transform.String(t, value)
111 if err != nil {
112 return value
113 }
114 return normalized
115 }
116
View as plain text