all repos — emoji @ v0.0.4

A minimalistic emoji package for Go (golang)

internal/generator/emoji.go (view raw)

  1package main
  2
  3import (
  4	"fmt"
  5	"regexp"
  6	"strconv"
  7	"strings"
  8
  9	emojipkg "github.com/enescakir/emoji"
 10	"github.com/enescakir/emoji/internal/strutil"
 11)
 12
 13var (
 14	emojiRegex = regexp.MustCompile(`^(?m)(?P<code>[A-Z\d ]+[A-Z\d])\s+;\s+(fully-qualified|component)\s+#\s+.+\s+E\d+\.\d+ (?P<name>.+)$`)
 15	toneRegex  = regexp.MustCompile(`:\s.*tone,?`)
 16)
 17
 18type groups struct {
 19	Groups []*group
 20}
 21
 22func (g *groups) Append(grpName string) *group {
 23	// fmt.Printf("group: %v\n", grpName)
 24	grp := group{Name: grpName}
 25	g.Groups = append(g.Groups, &grp)
 26
 27	return &grp
 28}
 29
 30type group struct {
 31	Name      string
 32	Subgroups []*subgroup
 33}
 34
 35func (g *group) Append(subgrpName string) *subgroup {
 36	// fmt.Printf("subgroup: %v\n", subgrpName)
 37	subgrp := subgroup{Name: subgrpName, Emojis: make(map[string][]emoji)}
 38	g.Subgroups = append(g.Subgroups, &subgrp)
 39
 40	return &subgrp
 41}
 42
 43type subgroup struct {
 44	Name      string
 45	Emojis    map[string][]emoji
 46	Constants []string
 47}
 48
 49func (s *subgroup) Append(e emoji) {
 50	// fmt.Printf("emoji: %v\n", e)
 51	if _, ok := s.Emojis[e.Constant]; ok {
 52		s.Emojis[e.Constant] = append(s.Emojis[e.Constant], e)
 53	} else {
 54		s.Emojis[e.Constant] = []emoji{e}
 55		s.Constants = append(s.Constants, e.Constant)
 56	}
 57}
 58
 59type emoji struct {
 60	Name     string
 61	Constant string
 62	Code     string
 63	Tones    []string
 64}
 65
 66func (e *emoji) String() string {
 67	return fmt.Sprintf("name:%v, constant:%v, code:%v, tones: %v\n", e.Name, e.Constant, e.Code, e.Tones)
 68}
 69
 70func newEmoji(line string) *emoji {
 71	matches := emojiRegex.FindStringSubmatch(line)
 72	if len(matches) < 4 {
 73		return nil
 74	}
 75	code := matches[1]
 76	name := matches[3]
 77
 78	e := emoji{
 79		Name:     name,
 80		Constant: name,
 81		Code:     code,
 82		Tones:    []string{},
 83	}
 84	e.extractAttr()
 85	e.Constant = generateConstant(e.Constant)
 86	e.Code = generateUnicode(e.Code)
 87
 88	return &e
 89}
 90
 91func (e *emoji) extractAttr() {
 92	parts := strings.Split(e.Constant, ":")
 93	if len(parts) < 2 {
 94		// no attributes
 95		return
 96	}
 97	c := parts[0]
 98	attrs := strings.Split(parts[1], ",")
 99	for _, attr := range attrs {
100		switch {
101		case strings.Contains(attr, "tone"):
102			e.Tones = append(e.Tones, attr)
103		case strings.Contains(attr, "beard"):
104			fallthrough
105		case strings.Contains(attr, "hair"):
106			c += " with " + attr
107		case strings.HasPrefix(c, "flag"):
108			c += " for " + attr
109		default:
110			c += " " + attr
111		}
112	}
113	e.Constant = c
114}
115
116func generateConstant(c string) string {
117	c = strutil.Clean(c)
118	c = strings.Title(strings.ToLower(c))
119	c = strutil.RemoveSpaces(c)
120
121	return c
122}
123
124func generateUnicode(code string) string {
125	unicodes := []string{}
126	for _, v := range strings.Split(code, " ") {
127		u, err := strconv.ParseInt(v, 16, 32)
128		if err != nil {
129			panic(fmt.Errorf("unknown unicode: %v", v))
130		}
131		unicodes = append(unicodes, string(u))
132	}
133
134	return strings.Join(unicodes, "")
135}
136
137func defaultTone(basic, toned string) string {
138	toneInd := strings.IndexRune(toned, []rune(emojipkg.TonePlaceholder)[0])
139	for i, ch := range basic {
140		if i != toneInd {
141			continue
142		}
143		if ch == '\ufe0f' {
144			return "\ufe0f"
145		}
146		break
147	}
148
149	return ""
150}
151
152func replaceTones(code string) string {
153	for _, tone := range []emojipkg.Tone{
154		emojipkg.Light,
155		emojipkg.MediumLight,
156		emojipkg.Medium,
157		emojipkg.MediumDark,
158		emojipkg.Dark,
159	} {
160		code = strings.ReplaceAll(code, tone.String(), emojipkg.TonePlaceholder)
161	}
162
163	return code
164}