all repos — emoji @ v0.0.4

A minimalistic emoji package for Go (golang)

emoji.go (view raw)

  1package emoji
  2
  3import (
  4	"fmt"
  5	"html"
  6	"strings"
  7)
  8
  9// Base attributes
 10const (
 11	unicodeFlagBaseIndex = 127397
 12	TonePlaceholder      = "@"
 13)
 14
 15// Skin tone colors
 16const (
 17	Default     Tone = ""
 18	Light       Tone = "\U0001F3FB"
 19	MediumLight Tone = "\U0001F3FC"
 20	Medium      Tone = "\U0001F3FD"
 21	MediumDark  Tone = "\U0001F3FE"
 22	Dark        Tone = "\U0001F3FF"
 23)
 24
 25// Emoji defines an emoji object with no skin variations.
 26type Emoji string
 27
 28// String returns string representation of the simple emoji.
 29func (e Emoji) String() string {
 30	return string(e)
 31}
 32
 33// EmojiWithTone defines an emoji object that has skin tone options.
 34type EmojiWithTone struct {
 35	oneTonedCode string
 36	twoTonedCode string
 37	defaultTone  Tone
 38}
 39
 40// newEmojiWithTone constructs a new emoji object that has skin tone options.
 41func newEmojiWithTone(codes ...string) EmojiWithTone {
 42	if len(codes) == 0 {
 43		return EmojiWithTone{}
 44	}
 45
 46	one := codes[0]
 47	two := codes[0]
 48
 49	if len(codes) > 1 {
 50		two = codes[1]
 51	}
 52
 53	return EmojiWithTone{
 54		oneTonedCode: one,
 55		twoTonedCode: two,
 56	}
 57}
 58
 59// withDefaultTone sets default tone for an emoji and returns it.
 60func (e EmojiWithTone) withDefaultTone(tone string) EmojiWithTone {
 61	e.defaultTone = Tone(tone)
 62
 63	return e
 64}
 65
 66// String returns string representation of the emoji with default skin tone.
 67func (e EmojiWithTone) String() string {
 68	return strings.ReplaceAll(e.oneTonedCode, TonePlaceholder, e.defaultTone.String())
 69}
 70
 71// Tone returns string representation of the emoji with given skin tone.
 72func (e EmojiWithTone) Tone(tones ...Tone) string {
 73	// if no tone given, return with default skin tone
 74	if len(tones) == 0 {
 75		return e.String()
 76	}
 77
 78	str := e.twoTonedCode
 79	replaceCount := 1
 80
 81	// if one tone given or emoji doesn't have twoTonedCode, use oneTonedCode
 82	// Also, replace all with one tone
 83	if len(tones) == 1 {
 84		str = e.oneTonedCode
 85		replaceCount = -1
 86	}
 87
 88	// replace tone one by one
 89	for _, t := range tones {
 90		// use emoji's default tone
 91		if t == Default {
 92			t = e.defaultTone
 93		}
 94
 95		str = strings.Replace(str, TonePlaceholder, t.String(), replaceCount)
 96	}
 97
 98	return str
 99}
100
101// Tone defines skin tone options for emojis.
102type Tone string
103
104// String returns string representation of the skin tone.
105func (t Tone) String() string {
106	return string(t)
107}
108
109// CountryFlag returns a country flag emoji from given country code.
110// Full list of country codes: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
111func CountryFlag(code string) (Emoji, error) {
112	if len(code) != 2 {
113		return "", fmt.Errorf("not valid country code: %q", code)
114	}
115
116	code = strings.ToUpper(code)
117	flag := countryCodeLetter(code[0]) + countryCodeLetter(code[1])
118
119	return Emoji(flag), nil
120}
121
122// countryCodeLetter shifts given letter byte as unicodeFlagBaseIndex and changes encoding.
123func countryCodeLetter(l byte) string {
124	shifted := unicodeFlagBaseIndex + int(l)
125
126	return html.UnescapeString(fmt.Sprintf("&#%v;", shifted))
127}