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}