// Package emoji terminal output. package emoji import ( "bytes" "errors" "fmt" "io" "regexp" "unicode" ) //go:generate generateEmojiCodeMap -pkg emoji -o emoji_codemap.go // Replace Padding character for emoji. var ( ReplacePadding = " " ) // CodeMap gets the underlying map of emoji. func CodeMap() map[string]string { return emojiCode() } // RevCodeMap gets the underlying map of emoji. func RevCodeMap() map[string][]string { return emojiRevCode() } func AliasList(shortCode string) []string { return emojiRevCode()[emojiCode()[shortCode]] } // HasAlias flags if the given `shortCode` has multiple aliases with other // codes. func HasAlias(shortCode string) bool { return len(AliasList(shortCode)) > 1 } // NormalizeShortCode normalizes a given `shortCode` to a deterministic alias. func NormalizeShortCode(shortCode string) string { shortLists := AliasList(shortCode) if len(shortLists) == 0 { return shortCode } return shortLists[0] } // regular expression that matches :flag-[countrycode]: var flagRegexp = regexp.MustCompile(":flag-([a-z]{2}):") // Emojize Converts the string passed as an argument to a emoji. For unsupported emoji, the string passed as an argument is returned as is. func Emojize(x string) string { str, ok := emojiCode()[x] if ok { return str + ReplacePadding } if match := flagRegexp.FindStringSubmatch(x); len(match) == 2 { return regionalIndicator(match[1][0]) + regionalIndicator(match[1][1]) } return x } // regionalIndicator maps a lowercase letter to a unicode regional indicator func regionalIndicator(i byte) string { return string('\U0001F1E6' + rune(i) - 'a') } func replaceEmoji(input *bytes.Buffer) string { emoji := bytes.NewBufferString(":") for { i, _, err := input.ReadRune() if err != nil { // not replace return emoji.String() } if i == ':' && emoji.Len() == 1 { return emoji.String() + replaceEmoji(input) } emoji.WriteRune(i) switch { case unicode.IsSpace(i): return emoji.String() case i == ':': return Emojize(emoji.String()) } } } func compile(x string) string { if x == "" { return "" } input := bytes.NewBufferString(x) output := bytes.NewBufferString("") for { i, _, err := input.ReadRune() if err != nil { break } switch i { default: output.WriteRune(i) case ':': output.WriteString(replaceEmoji(input)) } } return output.String() } // Print is fmt.Print which supports emoji func Print(a ...interface{}) (int, error) { return fmt.Print(compile(fmt.Sprint(a...))) } // Println is fmt.Println which supports emoji func Println(a ...interface{}) (int, error) { return fmt.Println(compile(fmt.Sprint(a...))) } // Printf is fmt.Printf which supports emoji func Printf(format string, a ...interface{}) (int, error) { return fmt.Print(compile(fmt.Sprintf(format, a...))) } // Fprint is fmt.Fprint which supports emoji func Fprint(w io.Writer, a ...interface{}) (int, error) { return fmt.Fprint(w, compile(fmt.Sprint(a...))) } // Fprintln is fmt.Fprintln which supports emoji func Fprintln(w io.Writer, a ...interface{}) (int, error) { return fmt.Fprintln(w, compile(fmt.Sprint(a...))) } // Fprintf is fmt.Fprintf which supports emoji func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) { return fmt.Fprint(w, compile(fmt.Sprintf(format, a...))) } // Sprint is fmt.Sprint which supports emoji func Sprint(a ...interface{}) string { return compile(fmt.Sprint(a...)) } // Sprintf is fmt.Sprintf which supports emoji func Sprintf(format string, a ...interface{}) string { return compile(fmt.Sprintf(format, a...)) } // Errorf is fmt.Errorf which supports emoji func Errorf(format string, a ...interface{}) error { return errors.New(compile(Sprintf(format, a...))) }