package clifmt import ( "fmt" "regexp" "strings" ) var titleIndex = 0 var alignOffset = 40 var defaultPrinter = fmt.Printf // Warn returns a red warning ASCII sign. If a string is given // as argument, it will print it after the warning sign func Warn(s ...string) string { if len(s) == 0 { return Color(31, "/!\\") } return fmt.Sprintf("%s %s", Warn(), s[0]) } // Info returns a blue info ASCII sign. If a string is given // as argument, it will print it after the info sign func Info(s ...string) string { if len(s) == 0 { return Color(34, "(!)") } return fmt.Sprintf("%s %s", Info(), s[0]) } // Title prints a formatted title (auto-indexed from local counted) func Title(s string) { titleIndex++ defaultPrinter("\n%s |%d| %s %s\n", Color(33, ">>", false), titleIndex, s, Color(33, "<<", false)) } // Align prints strings with space padding to align line ends (fixed width) // also crops the content to add '...' at the end if too long (must have a space // at the end) func Align(s string) { // 1. replace tabs with 4 spaces tabs := strings.Split(strings.Trim(s, " \t"), "\t") s = strings.Join(tabs, " ") // 2. get real size size := DisplaySize(s) offset := alignOffset if size > alignOffset-2 { for i := len(s) - 1; i > 0; i-- { // find when real size is right under next := fmt.Sprintf("%s\033[0m… ", s[0:i]) if DisplaySize(next) <= alignOffset { s = next size = DisplaySize(s) break } } } // 3. print string defaultPrinter("%s", s) // 4. print trailing spaces for i := size; i < offset; i++ { defaultPrinter(" ") } } var re = regexp.MustCompile(`(?m)\[(?:\d+;)*\d+m`) var reDots = regexp.MustCompile(`(?m)…`) // DisplaySize returns the real size escaping special characters func DisplaySize(s string) int { // 1. get actual size size := len(s) // 2. get all terminal coloring matches matches := re.FindAllString(s, -1) for _, m := range matches { size -= len(m) } // 3. Remove unicode character (len of 3 instead of 1) matches = reDots.FindAllString(s, -1) for _, m := range matches { size -= len(m) size++ } return size }