| // colorstring provides functions for colorizing strings for terminal |
| // output. |
| package colorstring |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "regexp" |
| "strings" |
| ) |
| |
| // Color colorizes your strings using the default settings. |
| // |
| // Strings given to Color should use the syntax `[color]` to specify the |
| // color for text following. For example: `[blue]Hello` will return "Hello" |
| // in blue. See DefaultColors for all the supported colors and attributes. |
| // |
| // If an unrecognized color is given, it is ignored and assumed to be part |
| // of the string. For example: `[hi]world` will result in "[hi]world". |
| // |
| // A color reset is appended to the end of every string. This will reset |
| // the color of following strings when you output this text to the same |
| // terminal session. |
| // |
| // If you want to customize any of this behavior, use the Colorize struct. |
| func Color(v string) string { |
| return def.Color(v) |
| } |
| |
| // ColorPrefix returns the color sequence that prefixes the given text. |
| // |
| // This is useful when wrapping text if you want to inherit the color |
| // of the wrapped text. For example, "[green]foo" will return "[green]". |
| // If there is no color sequence, then this will return "". |
| func ColorPrefix(v string) string { |
| return def.ColorPrefix(v) |
| } |
| |
| // Colorize colorizes your strings, giving you the ability to customize |
| // some of the colorization process. |
| // |
| // The options in Colorize can be set to customize colorization. If you're |
| // only interested in the defaults, just use the top Color function directly, |
| // which creates a default Colorize. |
| type Colorize struct { |
| // Colors maps a color string to the code for that color. The code |
| // is a string so that you can use more complex colors to set foreground, |
| // background, attributes, etc. For example, "boldblue" might be |
| // "1;34" |
| Colors map[string]string |
| |
| // If true, color attributes will be ignored. This is useful if you're |
| // outputting to a location that doesn't support colors and you just |
| // want the strings returned. |
| Disable bool |
| |
| // Reset, if true, will reset the color after each colorization by |
| // adding a reset code at the end. |
| Reset bool |
| } |
| |
| // Color colorizes a string according to the settings setup in the struct. |
| // |
| // For more details on the syntax, see the top-level Color function. |
| func (c *Colorize) Color(v string) string { |
| matches := parseRe.FindAllStringIndex(v, -1) |
| if len(matches) == 0 { |
| return v |
| } |
| |
| result := new(bytes.Buffer) |
| colored := false |
| m := []int{0, 0} |
| for _, nm := range matches { |
| // Write the text in between this match and the last |
| result.WriteString(v[m[1]:nm[0]]) |
| m = nm |
| |
| var replace string |
| if code, ok := c.Colors[v[m[0]+1:m[1]-1]]; ok { |
| colored = true |
| |
| if !c.Disable { |
| replace = fmt.Sprintf("\033[%sm", code) |
| } |
| } else { |
| replace = v[m[0]:m[1]] |
| } |
| |
| result.WriteString(replace) |
| } |
| result.WriteString(v[m[1]:]) |
| |
| if colored && c.Reset && !c.Disable { |
| // Write the clear byte at the end |
| result.WriteString("\033[0m") |
| } |
| |
| return result.String() |
| } |
| |
| // ColorPrefix returns the first color sequence that exists in this string. |
| // |
| // For example: "[green]foo" would return "[green]". If no color sequence |
| // exists, then "" is returned. This is especially useful when wrapping |
| // colored texts to inherit the color of the wrapped text. |
| func (c *Colorize) ColorPrefix(v string) string { |
| return prefixRe.FindString(strings.TrimSpace(v)) |
| } |
| |
| // DefaultColors are the default colors used when colorizing. |
| // |
| // If the color is surrounded in underscores, such as "_blue_", then that |
| // color will be used for the background color. |
| var DefaultColors map[string]string |
| |
| func init() { |
| DefaultColors = map[string]string{ |
| // Default foreground/background colors |
| "default": "39", |
| "_default_": "49", |
| |
| // Foreground colors |
| "black": "30", |
| "red": "31", |
| "green": "32", |
| "yellow": "33", |
| "blue": "34", |
| "magenta": "35", |
| "cyan": "36", |
| "light_gray": "37", |
| "dark_gray": "90", |
| "light_red": "91", |
| "light_green": "92", |
| "light_yellow": "93", |
| "light_blue": "94", |
| "light_magenta": "95", |
| "light_cyan": "96", |
| "white": "97", |
| |
| // Background colors |
| "_black_": "40", |
| "_red_": "41", |
| "_green_": "42", |
| "_yellow_": "43", |
| "_blue_": "44", |
| "_magenta_": "45", |
| "_cyan_": "46", |
| "_light_gray_": "47", |
| "_dark_gray_": "100", |
| "_light_red_": "101", |
| "_light_green_": "102", |
| "_light_yellow_": "103", |
| "_light_blue_": "104", |
| "_light_magenta_": "105", |
| "_light_cyan_": "106", |
| "_white_": "107", |
| |
| // Attributes |
| "bold": "1", |
| "dim": "2", |
| "underline": "4", |
| "blink_slow": "5", |
| "blink_fast": "6", |
| "invert": "7", |
| "hidden": "8", |
| |
| // Reset to reset everything to their defaults |
| "reset": "0", |
| "reset_bold": "21", |
| } |
| |
| def = Colorize{ |
| Colors: DefaultColors, |
| Reset: true, |
| } |
| } |
| |
| var def Colorize |
| var parseReRaw = `\[[a-z0-9_-]+\]` |
| var parseRe = regexp.MustCompile(`(?i)` + parseReRaw) |
| var prefixRe = regexp.MustCompile(`^(?i)(` + parseReRaw + `)+`) |
| |
| // Print is a convenience wrapper for fmt.Print with support for color codes. |
| // |
| // Print formats using the default formats for its operands and writes to |
| // standard output with support for color codes. Spaces are added between |
| // operands when neither is a string. It returns the number of bytes written |
| // and any write error encountered. |
| func Print(a string) (n int, err error) { |
| return fmt.Print(Color(a)) |
| } |
| |
| // Println is a convenience wrapper for fmt.Println with support for color |
| // codes. |
| // |
| // Println formats using the default formats for its operands and writes to |
| // standard output with support for color codes. Spaces are always added |
| // between operands and a newline is appended. It returns the number of bytes |
| // written and any write error encountered. |
| func Println(a string) (n int, err error) { |
| return fmt.Println(Color(a)) |
| } |
| |
| // Printf is a convenience wrapper for fmt.Printf with support for color codes. |
| // |
| // Printf formats according to a format specifier and writes to standard output |
| // with support for color codes. It returns the number of bytes written and any |
| // write error encountered. |
| func Printf(format string, a ...interface{}) (n int, err error) { |
| return fmt.Printf(Color(format), a...) |
| } |
| |
| // Fprint is a convenience wrapper for fmt.Fprint with support for color codes. |
| // |
| // Fprint formats using the default formats for its operands and writes to w |
| // with support for color codes. Spaces are added between operands when neither |
| // is a string. It returns the number of bytes written and any write error |
| // encountered. |
| func Fprint(w io.Writer, a string) (n int, err error) { |
| return fmt.Fprint(w, Color(a)) |
| } |
| |
| // Fprintln is a convenience wrapper for fmt.Fprintln with support for color |
| // codes. |
| // |
| // Fprintln formats using the default formats for its operands and writes to w |
| // with support for color codes. Spaces are always added between operands and a |
| // newline is appended. It returns the number of bytes written and any write |
| // error encountered. |
| func Fprintln(w io.Writer, a string) (n int, err error) { |
| return fmt.Fprintln(w, Color(a)) |
| } |
| |
| // Fprintf is a convenience wrapper for fmt.Fprintf with support for color |
| // codes. |
| // |
| // Fprintf formats according to a format specifier and writes to w with support |
| // for color codes. It returns the number of bytes written and any write error |
| // encountered. |
| func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { |
| return fmt.Fprintf(w, Color(format), a...) |
| } |