-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathtext.go
106 lines (92 loc) · 2.73 KB
/
text.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Package text is a set of utility functions for text processing and outputting to the terminal.
package text
import (
"fmt"
"regexp"
"strings"
"time"
"unicode"
"github.com/muesli/reflow/ansi"
"github.com/muesli/reflow/truncate"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
const (
ellipsis = "..."
minWidthForEllipsis = len(ellipsis) + 2
)
var indentRE = regexp.MustCompile(`(?m)^`)
// Indent returns a copy of the string s with indent prefixed to it, will apply indent
// to each line of the string.
func Indent(s, indent string) string {
if len(strings.TrimSpace(s)) == 0 {
return s
}
return indentRE.ReplaceAllLiteralString(s, indent)
}
// DisplayWidth calculates what the rendered width of string s will be.
func DisplayWidth(s string) int {
return ansi.PrintableRuneWidth(s)
}
// Truncate returns a copy of the string s that has been shortened to fit the maximum display width.
func Truncate(maxWidth int, s string) string {
w := DisplayWidth(s)
if w <= maxWidth {
return s
}
tail := ""
if maxWidth >= minWidthForEllipsis {
tail = ellipsis
}
r := truncate.StringWithTail(s, uint(maxWidth), tail)
if DisplayWidth(r) < maxWidth {
r += " "
}
return r
}
// Pluralize returns a concatenated string with num and the plural form of thing if necessary.
func Pluralize(num int, thing string) string {
if num == 1 {
return fmt.Sprintf("%d %s", num, thing)
}
return fmt.Sprintf("%d %ss", num, thing)
}
func fmtDuration(amount int, unit string) string {
return fmt.Sprintf("about %s ago", Pluralize(amount, unit))
}
// RelativeTimeAgo returns a human readable string of the time duration between a and b that is estimated
// to the nearest unit of time.
func RelativeTimeAgo(a, b time.Time) string {
ago := a.Sub(b)
if ago < time.Minute {
return "less than a minute ago"
}
if ago < time.Hour {
return fmtDuration(int(ago.Minutes()), "minute")
}
if ago < 24*time.Hour {
return fmtDuration(int(ago.Hours()), "hour")
}
if ago < 30*24*time.Hour {
return fmtDuration(int(ago.Hours())/24, "day")
}
if ago < 365*24*time.Hour {
return fmtDuration(int(ago.Hours())/24/30, "month")
}
return fmtDuration(int(ago.Hours()/24/365), "year")
}
// RemoveDiacritics returns the input value without "diacritics", or accent marks.
func RemoveDiacritics(value string) string {
// Mn = "Mark, nonspacing" unicode character category
removeMnTransfomer := runes.Remove(runes.In(unicode.Mn))
// 1. Decompose the text into characters and diacritical marks
// 2. Remove the diacriticals marks
// 3. Recompose the text
t := transform.Chain(norm.NFD, removeMnTransfomer, norm.NFC)
normalized, _, err := transform.String(t, value)
if err != nil {
return value
}
return normalized
}