github.com/coveo/gotemplate@v2.7.7+incompatible/collections/string_util.go (about) 1 package collections 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "unicode" 8 "unicode/utf8" 9 10 "github.com/Masterminds/sprig" 11 "github.com/coveo/gotemplate/errors" 12 ) 13 14 var must = errors.Must 15 16 // CenterString returns string s centered within width 17 func CenterString(s string, width int) string { 18 l := utf8.RuneCountInString(s) 19 if l > width { 20 return s 21 } 22 left := (width - l) / 2 23 right := width - left - l 24 return fmt.Sprintf("%[2]*[1]s%[4]s%[3]*[1]s", "", left, right, s) 25 } 26 27 // WrapString wraps long string according to the supplied width 28 func WrapString(s string, width int) string { 29 lines := strings.Split(s, "\n") 30 result := make([]string, 0, len(lines)) 31 32 for i := range lines { 33 words := strings.Fields(strings.TrimRight(lines[i], "\t ")) 34 start, length := 0, 0 35 for j := range words { 36 if length > 0 && length+len(words[j]) > width { 37 result = append(result, strings.Join(words[start:j], " ")) 38 start, length = j, 0 39 } 40 length += len(words[j]) 41 if j-start > 0 { 42 length++ 43 } 44 } 45 result = append(result, strings.Join(words[start:len(words)], " ")) 46 } 47 48 return strings.Join(result, "\n") 49 } 50 51 // Interface2string returns the string representation of any interface. 52 func Interface2string(str interface{}) string { 53 switch str := str.(type) { 54 case string: 55 return str 56 default: 57 return fmt.Sprintf("%v", str) 58 } 59 } 60 61 // Concat returns a string with all string representation of object concatenated without space. 62 func Concat(objects ...interface{}) string { 63 var result string 64 for _, object := range objects { 65 result += fmt.Sprint(object) 66 } 67 return result 68 } 69 70 // ToStrings converts the supplied parameter into an array of string. 71 var ToStrings = sprig.GenericFuncMap()["toStrings"].(func(interface{}) []string) 72 73 // ToInterfaces converts an array of strings into an array of interfaces 74 func ToInterfaces(values ...string) []interface{} { 75 result := make([]interface{}, len(values)) 76 for i := range values { 77 result[i] = values[i] 78 } 79 return result 80 } 81 82 // SplitLines return a list of interface object for each line in the supplied content. 83 func SplitLines(content interface{}) []interface{} { 84 content = Interface2string(content) 85 split := strings.Split(strings.TrimSuffix(content.(string), "\n"), "\n") 86 result := make([]interface{}, len(split)) 87 for i := range split { 88 result[i] = split[i] 89 } 90 return result 91 } 92 93 // JoinLines concatenate the representation of supplied arguments as a string separated by newlines. 94 func JoinLines(objects ...interface{}) string { 95 result := make([]string, len(objects)) 96 for i := range objects { 97 result[i] = fmt.Sprintf("%v", objects[i]) 98 } 99 return strings.Join(result, "\n") 100 } 101 102 // Split2 returns left and right part of a split. 103 func Split2(source, sep string) (left, right string) { 104 split := strings.SplitN(source, sep, 2) 105 left = split[0] 106 if len(split) > 1 { 107 right = split[1] 108 } 109 return 110 } 111 112 // UnIndent returns the unindented version of the supplied string only if all lines are prefixed 113 // with the same pattern of spaces. 114 func UnIndent(s string) string { 115 lines := strings.Split(s, "\n") 116 if len(lines) <= 1 { 117 return s 118 } 119 120 var spaces *string 121 for i, line := range lines { 122 if spaces == nil { 123 if strings.TrimSpace(line) == "" { 124 // We do not consider empty lines 125 continue 126 } 127 trimmed := strings.TrimLeftFunc(line, unicode.IsSpace) 128 trimmed = string(lines[i][:len(lines[i])-len(trimmed)]) 129 spaces = &trimmed 130 } 131 if !strings.HasPrefix(line, *spaces) && strings.TrimSpace(line) != "" { 132 return s 133 } 134 lines[i] = strings.TrimPrefix(line, *spaces) 135 } 136 137 return strings.Join(lines, "\n") 138 } 139 140 // Indent returns the indented version of the supplied string. 141 func Indent(s, indent string) string { 142 split := strings.Split(s, "\n") 143 for i := range split { 144 split[i] = indent + split[i] 145 } 146 return strings.Join(split, "\n") 147 } 148 149 // IndentN returns the indented version (indent as a number of spaces) of the supplied string. 150 func IndentN(s string, indent int) string { return Indent(s, strings.Repeat(" ", indent)) } 151 152 // PrettyPrintStruct returns a readable version of an object. 153 func PrettyPrintStruct(object interface{}) string { 154 var out string 155 isZero := func(x interface{}) bool { 156 return x == nil || reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface()) 157 } 158 159 val := reflect.ValueOf(object) 160 switch val.Kind() { 161 case reflect.Interface: 162 fallthrough 163 case reflect.Ptr: 164 val = val.Elem() 165 } 166 167 result := make([][2]string, 0, val.NumField()) 168 max := 0 169 for i := 0; i < val.NumField(); i++ { 170 field := val.Field(i) 171 fieldType := val.Type().Field(i) 172 173 if !field.CanInterface() { 174 continue 175 } 176 177 itf := val.Field(i).Interface() 178 if isZero(itf) { 179 continue 180 } 181 182 itf = reflect.Indirect(val.Field(i)).Interface() 183 value := strings.Split(strings.TrimSpace(UnIndent(fmt.Sprint(itf))), "\n") 184 if val.Field(i).Kind() == reflect.Struct { 185 value[0] = "\n" + IndentN(strings.Join(value, "\n"), 4) 186 } else if len(value) > 1 { 187 value[0] += " ..." 188 } 189 result = append(result, [2]string{fieldType.Name, value[0]}) 190 if len(fieldType.Name) > max { 191 max = len(fieldType.Name) 192 } 193 } 194 195 for _, entry := range result { 196 out += fmt.Sprintf("%*s = %v\n", -max, entry[0], entry[1]) 197 } 198 199 return out 200 }