github.com/greenboxal/deis@v1.12.1/pkg/prettyprint/colorizer.go (about)

     1  // Package prettyprint contains tools for formatting text.
     2  package prettyprint
     3  
     4  import (
     5  	"bytes"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  	"text/template"
    10  )
    11  
    12  // Colors contains a map of the standard ANSI color codes.
    13  //
    14  // There are four variants:
    15  // 	- Bare color names (Red, Black) color the characters.
    16  // 	- Bold color names add bolding to the characters.
    17  // 	- Under color names add underlining to the characters.
    18  // 	- Hi color names add highlighting (background colors).
    19  //
    20  // These can be used within `text/template` to provide colors. The convenience
    21  // function `Colorize()` provides this feature.
    22  var Colors = map[string]string{
    23  	"Default":     "\033[0m",
    24  	"Black":       "\033[0;30m",
    25  	"Red":         "\033[0;31m",
    26  	"Green":       "\033[0;32m",
    27  	"Yellow":      "\033[0;33m",
    28  	"Blue":        "\033[0;34m",
    29  	"Purple":      "\033[0;35m",
    30  	"Cyan":        "\033[0;36m",
    31  	"White":       "\033[0;37m",
    32  	"BoldBlack":   "\033[1;30m",
    33  	"BoldRed":     "\033[1;31m",
    34  	"BoldGreen":   "\033[1;32m",
    35  	"BoldYellow":  "\033[1;33m",
    36  	"BoldBlue":    "\033[1;34m",
    37  	"BoldPurple":  "\033[1;35m",
    38  	"BoldCyan":    "\033[1;36m",
    39  	"BoldWhite":   "\033[1;37m",
    40  	"UnderBlack":  "\033[4;30m",
    41  	"UnderRed":    "\033[4;31m",
    42  	"UnderGreen":  "\033[4;32m",
    43  	"UnderYellow": "\033[4;33m",
    44  	"UnderBlue":   "\033[4;34m",
    45  	"UnderPurple": "\033[4;35m",
    46  	"UnderCyan":   "\033[4;36m",
    47  	"UnderWhite":  "\033[4;37m",
    48  	"HiBlack":     "\033[30m",
    49  	"HiRed":       "\033[31m",
    50  	"HiGreen":     "\033[32m",
    51  	"HiYellow":    "\033[33m",
    52  	"HiBlue":      "\033[34m",
    53  	"HiPurple":    "\033[35m",
    54  	"HiCyan":      "\033[36m",
    55  	"HiWhite":     "\033[37m",
    56  	"Deis1":       "\033[31m● \033[34m▴ \033[32m■\033[0m",
    57  	"Deis2":       "\033[32m■ \033[31m● \033[34m▴\033[0m",
    58  	"Deis3":       "\033[34m▴ \033[32m■ \033[31m●\033[0m",
    59  	"Deis":        "\033[31m● \033[34m▴ \033[32m■\n\033[32m■ \033[31m● \033[34m▴\n\033[34m▴ \033[32m■ \033[31m●\n",
    60  }
    61  
    62  // DeisIfy returns a pretty-printed deis logo along with the corresponding message
    63  func DeisIfy(msg string) string {
    64  	var t = struct {
    65  		Msg string
    66  		C   map[string]string
    67  	}{
    68  		Msg: msg,
    69  		C:   Colors,
    70  	}
    71  	tpl := "{{.C.Deis1}}\n{{.C.Deis2}} {{.Msg}}\n{{.C.Deis3}}\n"
    72  	var buf bytes.Buffer
    73  	template.Must(template.New("deis").Parse(tpl)).Execute(&buf, t)
    74  	return buf.String()
    75  }
    76  
    77  // Logo returns a colorized Deis logo with no space for text.
    78  func Logo() string {
    79  	return Colorize("{{.Deis}}")
    80  }
    81  
    82  // NoColor strips colors from the template.
    83  //
    84  // NoColor provides support for non-color ANSI terminals. It can be used
    85  // as an alternative to Colorize when it is detected that the terminal does
    86  // not support colors.
    87  func NoColor(msg string) string {
    88  	empties := make(map[string]string, len(Colors))
    89  	for k := range Colors {
    90  		empties[k] = ""
    91  	}
    92  	return colorize(msg, empties)
    93  }
    94  
    95  // Colorize makes it easy to add colors to ANSI terminal output.
    96  //
    97  // This takes any of the colors defined in the Colors map. Colors are rendered
    98  // through the `text/template` system, so you may use pipes and functions as
    99  // well.
   100  //
   101  // Example:
   102  //	Colorize("{{.Red}}ERROR:{{.Default}} Something happened.")
   103  func Colorize(msg string) string {
   104  	return colorize(msg, Colors)
   105  }
   106  
   107  // ColorizeVars provides template rendering with color support.
   108  //
   109  // The template is given a datum with two objects: `.V` and `.C`. `.V` contains
   110  // the `vars` passed into the function. `.C` contains the color map.
   111  //
   112  // Assuming `vars` contains a member named `Msg`, a template can be constructed
   113  // like this:
   114  //	{{.C.Red}}Message:{{.C.Default}} .V.Msg
   115  func ColorizeVars(msg string, vars interface{}) string {
   116  	var t = struct {
   117  		V interface{}
   118  		C map[string]string
   119  	}{
   120  		V: vars,
   121  		C: Colors,
   122  	}
   123  	return colorize(msg, t)
   124  }
   125  
   126  func colorize(msg string, vars interface{}) string {
   127  	tpl, err := template.New(msg).Parse(msg)
   128  	// If the template's not valid, we just ignore and return.
   129  	if err != nil {
   130  		return msg
   131  	}
   132  	var buf bytes.Buffer
   133  	if err := tpl.Execute(&buf, vars); err != nil {
   134  		return msg
   135  	}
   136  
   137  	return buf.String()
   138  }
   139  
   140  // Overwrite sends a line that will be replaced by a subsequent overwrite.
   141  //
   142  // Example:
   143  // 	Overwrite("foo")
   144  // 	Overwrite("bar")
   145  //
   146  // The above will print "foo" and then immediately replace it with "var".
   147  //
   148  // (Interpretation of \r is left to the shell.)
   149  func Overwrite(msg string) string {
   150  	lm := len(msg)
   151  	if lm >= 80 {
   152  		return msg + "\r"
   153  	}
   154  	pad := 80 - len(msg)
   155  	return msg + strings.Repeat(" ", pad) + "\r"
   156  
   157  }
   158  
   159  // Overwritef formats a string and then returns an overwrite line.
   160  //
   161  // See `Overwrite` for details.
   162  func Overwritef(msg string, args ...interface{}) string {
   163  	return Overwrite(fmt.Sprintf(msg, args...))
   164  }
   165  
   166  // PrettyTabs formats a map with with alligned keys and values.
   167  //
   168  // Example:
   169  // test := map[string]string {
   170  //    "test": "testing",
   171  //    "foo": "bar",
   172  //  }
   173  //
   174  // Prettytabs(test, 5)
   175  //
   176  // This will return a formatted string.
   177  // The previous example would return:
   178  // foo      bar
   179  // test     testing
   180  func PrettyTabs(msg map[string]string, spaces int) string {
   181  	// find the longest key so we know how much padding to use
   182  	max := 0
   183  	for key := range msg {
   184  		if len(key) > max {
   185  			max = len(key)
   186  		}
   187  	}
   188  	max += spaces
   189  
   190  	// sort the map keys so we can print them alphabetically
   191  	var keys []string
   192  	for k := range msg {
   193  		keys = append(keys, k)
   194  	}
   195  	sort.Strings(keys)
   196  
   197  	var output string
   198  	for _, k := range keys {
   199  		output += fmt.Sprintf("%s%s%s\n", k, strings.Repeat(" ", max-len(k)), msg[k])
   200  	}
   201  	return output
   202  }