...

Source file src/github.com/jedib0t/go-pretty/v6/text/transformer.go

Documentation: github.com/jedib0t/go-pretty/v6/text

     1  package text
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  // Transformer related constants
    13  const (
    14  	unixTimeMinMilliseconds = int64(10000000000)
    15  	unixTimeMinMicroseconds = unixTimeMinMilliseconds * 1000
    16  	unixTimeMinNanoSeconds  = unixTimeMinMicroseconds * 1000
    17  )
    18  
    19  // Transformer related variables
    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, // strfmt.DateTime.String()'s default layout
    31  		rfc3339Micro,
    32  		time.RFC3339Nano,
    33  	}
    34  )
    35  
    36  // Transformer helps format the contents of an object to the user's liking.
    37  type Transformer func(val interface{}) string
    38  
    39  // NewNumberTransformer returns a number Transformer that:
    40  //   * transforms the number as directed by 'format' (ex.: %.2f)
    41  //   * colors negative values Red
    42  //   * colors positive values Green
    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  // NewJSONTransformer returns a Transformer that can format a JSON string or an
   134  // object into pretty-indented JSON-strings.
   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  // NewTimeTransformer returns a Transformer that can format a timestamp (a
   150  // time.Time) into a well-defined time format defined using the provided layout
   151  // (ex.: time.RFC3339).
   152  //
   153  // If a non-nil location value is provided, the time will be localized to that
   154  // location (use time.Local to get localized timestamps).
   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  			// cycle through some supported layouts to see if the string form
   162  			// of the object matches any of these layouts
   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  // NewUnixTimeTransformer returns a Transformer that can format a unix-timestamp
   175  // into a well-defined time format as defined by 'layout'. This can handle
   176  // unix-time in Seconds, MilliSeconds, Microseconds and Nanoseconds.
   177  //
   178  // If a non-nil location value is provided, the time will be localized to that
   179  // location (use time.Local to get localized timestamps).
   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  // NewURLTransformer returns a Transformer that can format and pretty print a string
   196  // that contains a URL (the text is underlined and colored Blue).
   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