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