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.generateConstant()
86 e.generateUnicode()
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 (e *emoji) generateConstant() {
117 c := e.Constant
118 c = strutil.Clean(c)
119 c = strings.Title(strings.ToLower(c))
120 c = strutil.RemoveSpaces(c)
121 e.Constant = c
122}
123
124func (e *emoji) generateUnicode() {
125 unicodes := []string{}
126 for _, v := range strings.Split(e.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 e.Code = 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}