github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/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 }