1package message 2 3import ( 4 "fmt" 5) 6 7const ( 8 // Reset resets the color 9 Reset = "\033[0m" 10 11 // Bold makes the following text bold 12 Bold = "\033[1m" 13 14 // Dim dims the following text 15 Dim = "\033[2m" 16 17 // Italic makes the following text italic 18 Italic = "\033[3m" 19 20 // Underline underlines the following text 21 Underline = "\033[4m" 22 23 // Blink blinks the following text 24 Blink = "\033[5m" 25 26 // Invert inverts the following text 27 Invert = "\033[7m" 28 29 // Newline 30 Newline = "\r\n" 31 32 // BEL 33 Bel = "\007" 34) 35 36// Interface for Styles 37type Style interface { 38 String() string 39 Format(string) string 40} 41 42// General hardcoded style, mostly used as a crutch until we flesh out the 43// framework to support backgrounds etc. 44type style string 45 46func (c style) String() string { 47 return string(c) 48} 49 50func (c style) Format(s string) string { 51 return c.String() + s + Reset 52} 53 54// 256 color type, for terminals who support it 55type Color256 uint8 56 57// String version of this color 58func (c Color256) String() string { 59 return fmt.Sprintf("38;05;%d", c) 60} 61 62// Return formatted string with this color 63func (c Color256) Format(s string) string { 64 return "\033[" + c.String() + "m" + s + Reset 65} 66 67func Color256Palette(colors ...uint8) *Palette { 68 size := len(colors) 69 p := make([]Style, 0, size) 70 for _, color := range colors { 71 p = append(p, Color256(color)) 72 } 73 return &Palette{ 74 colors: p, 75 size: size, 76 } 77} 78 79// No color, used for mono theme 80type Color0 struct{} 81 82// No-op for Color0 83func (c Color0) String() string { 84 return "" 85} 86 87// No-op for Color0 88func (c Color0) Format(s string) string { 89 return s 90} 91 92// Container for a collection of colors 93type Palette struct { 94 colors []Style 95 size int 96} 97 98// Get a color by index, overflows are looped around. 99func (p Palette) Get(i int) Style { 100 if p.size == 1 { 101 return p.colors[0] 102 } 103 return p.colors[i%(p.size-1)] 104} 105 106func (p Palette) Len() int { 107 return p.size 108} 109 110func (p Palette) String() string { 111 r := "" 112 for _, c := range p.colors { 113 r += c.Format("X") 114 } 115 return r 116} 117 118// Collection of settings for chat 119type Theme struct { 120 id string 121 sys Style 122 pm Style 123 highlight Style 124 names *Palette 125 useID bool 126} 127 128func (theme Theme) ID() string { 129 return theme.id 130} 131 132// Colorize name string given some index 133func (theme Theme) ColorName(u *User) string { 134 var name string 135 if theme.useID { 136 name = u.ID() 137 } else { 138 name = u.Name() 139 } 140 if theme.names == nil { 141 return name 142 } 143 144 return theme.names.Get(u.colorIdx).Format(name) 145} 146 147// Colorize the PM string 148func (theme Theme) ColorPM(s string) string { 149 if theme.pm == nil { 150 return s 151 } 152 153 return theme.pm.Format(s) 154} 155 156// Colorize the Sys message 157func (theme Theme) ColorSys(s string) string { 158 if theme.sys == nil { 159 return s 160 } 161 162 return theme.sys.Format(s) 163} 164 165// Highlight a matched string, usually name 166func (theme Theme) Highlight(s string) string { 167 if theme.highlight == nil { 168 return s 169 } 170 return theme.highlight.Format(s) 171} 172 173// Timestamp colorizes the timestamp. 174func (theme Theme) Timestamp(s string) string { 175 if theme.sys == nil { 176 return s 177 } 178 return theme.sys.Format(s) 179} 180 181// List of initialzied themes 182var Themes []Theme 183 184// Default theme to use 185var DefaultTheme *Theme 186 187// MonoTheme is a simple theme without colors, useful for testing and bots. 188var MonoTheme *Theme 189 190func allColors256() *Palette { 191 colors := []uint8{} 192 var i uint8 193 for i = 0; i < 255; i++ { 194 colors = append(colors, i) 195 } 196 return Color256Palette(colors...) 197} 198 199func readableColors256() *Palette { 200 colors := []uint8{} 201 var i uint8 202 for i = 0; i < 255; i++ { 203 if i == 0 || i == 7 || i == 8 || i == 15 || i == 16 || i == 17 || i > 230 { 204 // Skip 31 Shades of Grey, and one hyperintelligent shade of blue. 205 continue 206 } 207 colors = append(colors, i) 208 } 209 return Color256Palette(colors...) 210} 211 212func init() { 213 Themes = []Theme{ 214 { 215 id: "colors", 216 names: readableColors256(), 217 sys: Color256(245), // Grey 218 pm: Color256(7), // White 219 highlight: style(Bold + "\033[48;5;11m\033[38;5;16m"), // Yellow highlight 220 }, 221 { 222 id: "solarized", 223 names: Color256Palette(1, 2, 3, 4, 5, 6, 7, 9, 13), 224 sys: Color256(11), // Yellow 225 pm: Color256(15), // White 226 highlight: style(Bold + "\033[48;5;3m\033[38;5;94m"), // Orange highlight 227 }, 228 { 229 id: "hacker", 230 names: Color256Palette(82), // Green 231 sys: Color256(22), // Another green 232 pm: Color256(28), // More green, slightly lighter 233 highlight: style(Bold + "\033[48;5;22m\033[38;5;46m"), // Green on dark green 234 }, 235 { 236 id: "mono", 237 useID: true, 238 }, 239 } 240 241 DefaultTheme = &Themes[0] 242 MonoTheme = &Themes[3] 243 244 /* Some debug helpers for your convenience: 245 246 // Debug for palettes 247 printPalette(allColors256()) 248 249 // Debug for themes 250 for _, t := range Themes { 251 printTheme(t) 252 } 253 254 */ 255} 256 257func printTheme(t Theme) { 258 fmt.Println("Printing theme:", t.ID()) 259 if t.names != nil { 260 for i, color := range t.names.colors { 261 fmt.Printf("%s ", color.Format(fmt.Sprintf("name%d", i))) 262 } 263 fmt.Println("") 264 } 265 fmt.Println(t.ColorSys("SystemMsg")) 266 fmt.Println(t.ColorPM("PrivateMsg")) 267 fmt.Println(t.Highlight("Highlight")) 268 fmt.Println("") 269} 270 271func printPalette(p *Palette) { 272 for i, color := range p.colors { 273 fmt.Printf("%d\t%s\n", i, color.Format(color.String()+" ")) 274 } 275} 276