1 package text
2
3 import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "strconv"
8 "strings"
9 "time"
10 )
11
12
13 const (
14 unixTimeMinMilliseconds = int64(10000000000)
15 unixTimeMinMicroseconds = unixTimeMinMilliseconds * 1000
16 unixTimeMinNanoSeconds = unixTimeMinMicroseconds * 1000
17 )
18
19
20 var (
21 colorsNumberPositive = Colors{FgHiGreen}
22 colorsNumberNegative = Colors{FgHiRed}
23 colorsNumberZero = Colors{}
24 colorsURL = Colors{Underline, FgBlue}
25 rfc3339Milli = "2006-01-02T15:04:05.000Z07:00"
26 rfc3339Micro = "2006-01-02T15:04:05.000000Z07:00"
27
28 possibleTimeLayouts = []string{
29 time.RFC3339,
30 rfc3339Milli,
31 rfc3339Micro,
32 time.RFC3339Nano,
33 }
34 )
35
36
37 type Transformer func(val interface{}) string
38
39
40
41
42
43 func NewNumberTransformer(format string) Transformer {
44 return func(val interface{}) string {
45 if valStr := transformInt(format, val); valStr != "" {
46 return valStr
47 }
48 if valStr := transformUint(format, val); valStr != "" {
49 return valStr
50 }
51 if valStr := transformFloat(format, val); valStr != "" {
52 return valStr
53 }
54 return fmt.Sprint(val)
55 }
56 }
57
58 func transformInt(format string, val interface{}) string {
59 transform := func(val int64) string {
60 if val < 0 {
61 return colorsNumberNegative.Sprintf("-"+format, -val)
62 }
63 if val > 0 {
64 return colorsNumberPositive.Sprintf(format, val)
65 }
66 return colorsNumberZero.Sprintf(format, val)
67 }
68
69 if number, ok := val.(int); ok {
70 return transform(int64(number))
71 }
72 if number, ok := val.(int8); ok {
73 return transform(int64(number))
74 }
75 if number, ok := val.(int16); ok {
76 return transform(int64(number))
77 }
78 if number, ok := val.(int32); ok {
79 return transform(int64(number))
80 }
81 if number, ok := val.(int64); ok {
82 return transform(int64(number))
83 }
84 return ""
85 }
86
87 func transformUint(format string, val interface{}) string {
88 transform := func(val uint64) string {
89 if val > 0 {
90 return colorsNumberPositive.Sprintf(format, val)
91 }
92 return colorsNumberZero.Sprintf(format, val)
93 }
94
95 if number, ok := val.(uint); ok {
96 return transform(uint64(number))
97 }
98 if number, ok := val.(uint8); ok {
99 return transform(uint64(number))
100 }
101 if number, ok := val.(uint16); ok {
102 return transform(uint64(number))
103 }
104 if number, ok := val.(uint32); ok {
105 return transform(uint64(number))
106 }
107 if number, ok := val.(uint64); ok {
108 return transform(uint64(number))
109 }
110 return ""
111 }
112
113 func transformFloat(format string, val interface{}) string {
114 transform := func(val float64) string {
115 if val < 0 {
116 return colorsNumberNegative.Sprintf("-"+format, -val)
117 }
118 if val > 0 {
119 return colorsNumberPositive.Sprintf(format, val)
120 }
121 return colorsNumberZero.Sprintf(format, val)
122 }
123
124 if number, ok := val.(float32); ok {
125 return transform(float64(number))
126 }
127 if number, ok := val.(float64); ok {
128 return transform(float64(number))
129 }
130 return ""
131 }
132
133
134
135 func NewJSONTransformer(prefix string, indent string) Transformer {
136 return func(val interface{}) string {
137 if valStr, ok := val.(string); ok {
138 var b bytes.Buffer
139 if err := json.Indent(&b, []byte(strings.TrimSpace(valStr)), prefix, indent); err == nil {
140 return string(b.Bytes())
141 }
142 } else if b, err := json.MarshalIndent(val, prefix, indent); err == nil {
143 return string(b)
144 }
145 return fmt.Sprintf("%#v", val)
146 }
147 }
148
149
150
151
152
153
154
155 func NewTimeTransformer(layout string, location *time.Location) Transformer {
156 return func(val interface{}) string {
157 rsp := fmt.Sprint(val)
158 if valTime, ok := val.(time.Time); ok {
159 rsp = formatTime(valTime, layout, location)
160 } else {
161
162
163 for _, possibleTimeLayout := range possibleTimeLayouts {
164 if valTime, err := time.Parse(possibleTimeLayout, rsp); err == nil {
165 rsp = formatTime(valTime, layout, location)
166 break
167 }
168 }
169 }
170 return rsp
171 }
172 }
173
174
175
176
177
178
179
180 func NewUnixTimeTransformer(layout string, location *time.Location) Transformer {
181 transformer := NewTimeTransformer(layout, location)
182
183 return func(val interface{}) string {
184 if unixTime, ok := val.(int64); ok {
185 return formatTimeUnix(unixTime, transformer)
186 } else if unixTimeStr, ok := val.(string); ok {
187 if unixTime, err := strconv.ParseInt(unixTimeStr, 10, 64); err == nil {
188 return formatTimeUnix(unixTime, transformer)
189 }
190 }
191 return fmt.Sprint(val)
192 }
193 }
194
195
196
197 func NewURLTransformer(colors ...Color) Transformer {
198 colorsToUse := colorsURL
199 if len(colors) > 0 {
200 colorsToUse = colors
201 }
202
203 return func(val interface{}) string {
204 return colorsToUse.Sprint(val)
205 }
206 }
207
208 func formatTime(t time.Time, layout string, location *time.Location) string {
209 rsp := ""
210 if t.Unix() > 0 {
211 if location != nil {
212 t = t.In(location)
213 }
214 rsp = t.Format(layout)
215 }
216 return rsp
217 }
218
219 func formatTimeUnix(unixTime int64, timeTransformer Transformer) string {
220 if unixTime >= unixTimeMinNanoSeconds {
221 unixTime = unixTime / time.Second.Nanoseconds()
222 } else if unixTime >= unixTimeMinMicroseconds {
223 unixTime = unixTime / (time.Second.Nanoseconds() / 1000)
224 } else if unixTime >= unixTimeMinMilliseconds {
225 unixTime = unixTime / (time.Second.Nanoseconds() / 1000000)
226 }
227 return timeTransformer(time.Unix(unixTime, 0))
228 }
229
View as plain text