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  }