You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate-emoji.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Copyright 2015 Kenneth Shaw
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. //go:build ignore
  6. // +build ignore
  7. package main
  8. import (
  9. "flag"
  10. "fmt"
  11. "go/format"
  12. "io"
  13. "log"
  14. "net/http"
  15. "os"
  16. "regexp"
  17. "sort"
  18. "strconv"
  19. "strings"
  20. "unicode/utf8"
  21. "code.gitea.io/gitea/modules/json"
  22. )
  23. const (
  24. gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
  25. maxUnicodeVersion = 12
  26. )
  27. var (
  28. flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
  29. )
  30. // Gemoji is a set of emoji data.
  31. type Gemoji []Emoji
  32. // Emoji represents a single emoji and associated data.
  33. type Emoji struct {
  34. Emoji string `json:"emoji"`
  35. Description string `json:"description,omitempty"`
  36. Aliases []string `json:"aliases"`
  37. UnicodeVersion string `json:"unicode_version,omitempty"`
  38. SkinTones bool `json:"skin_tones,omitempty"`
  39. }
  40. // Don't include some fields in JSON
  41. func (e Emoji) MarshalJSON() ([]byte, error) {
  42. type emoji Emoji
  43. x := emoji(e)
  44. x.UnicodeVersion = ""
  45. x.Description = ""
  46. x.SkinTones = false
  47. return json.Marshal(x)
  48. }
  49. func main() {
  50. var err error
  51. flag.Parse()
  52. // generate data
  53. buf, err := generate()
  54. if err != nil {
  55. log.Fatal(err)
  56. }
  57. // write
  58. err = os.WriteFile(*flagOut, buf, 0644)
  59. if err != nil {
  60. log.Fatal(err)
  61. }
  62. }
  63. var replacer = strings.NewReplacer(
  64. "main.Gemoji", "Gemoji",
  65. "main.Emoji", "\n",
  66. "}}", "},\n}",
  67. ", Description:", ", ",
  68. ", Aliases:", ", ",
  69. ", UnicodeVersion:", ", ",
  70. ", SkinTones:", ", ",
  71. )
  72. var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
  73. func generate() ([]byte, error) {
  74. var err error
  75. // load gemoji data
  76. res, err := http.Get(gemojiURL)
  77. if err != nil {
  78. return nil, err
  79. }
  80. defer res.Body.Close()
  81. // read all
  82. body, err := io.ReadAll(res.Body)
  83. if err != nil {
  84. return nil, err
  85. }
  86. // unmarshal
  87. var data Gemoji
  88. err = json.Unmarshal(body, &data)
  89. if err != nil {
  90. return nil, err
  91. }
  92. var skinTones = make(map[string]string)
  93. skinTones["\U0001f3fb"] = "Light Skin Tone"
  94. skinTones["\U0001f3fc"] = "Medium-Light Skin Tone"
  95. skinTones["\U0001f3fd"] = "Medium Skin Tone"
  96. skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone"
  97. skinTones["\U0001f3ff"] = "Dark Skin Tone"
  98. var tmp Gemoji
  99. //filter out emoji that require greater than max unicode version
  100. for i := range data {
  101. val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64)
  102. if int(val) <= maxUnicodeVersion {
  103. tmp = append(tmp, data[i])
  104. }
  105. }
  106. data = tmp
  107. sort.Slice(data, func(i, j int) bool {
  108. return data[i].Aliases[0] < data[j].Aliases[0]
  109. })
  110. aliasMap := make(map[string]int, len(data))
  111. for i, e := range data {
  112. if e.Emoji == "" || len(e.Aliases) == 0 {
  113. continue
  114. }
  115. for _, a := range e.Aliases {
  116. if a == "" {
  117. continue
  118. }
  119. aliasMap[a] = i
  120. }
  121. }
  122. // gitea customizations
  123. i, ok := aliasMap["tada"]
  124. if ok {
  125. data[i].Aliases = append(data[i].Aliases, "hooray")
  126. }
  127. i, ok = aliasMap["laughing"]
  128. if ok {
  129. data[i].Aliases = append(data[i].Aliases, "laugh")
  130. }
  131. // write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet)
  132. file, _ := json.Marshal(data)
  133. _ = os.WriteFile("assets/emoji.json", file, 0644)
  134. // Add skin tones to emoji that support it
  135. var (
  136. s []string
  137. newEmoji string
  138. newDescription string
  139. newData Emoji
  140. )
  141. for i := range data {
  142. if data[i].SkinTones {
  143. for k, v := range skinTones {
  144. s = strings.Split(data[i].Emoji, "")
  145. if utf8.RuneCountInString(data[i].Emoji) == 1 {
  146. s = append(s, k)
  147. } else {
  148. // insert into slice after first element because all emoji that support skin tones
  149. // have that modifier placed at this spot
  150. s = append(s, "")
  151. copy(s[2:], s[1:])
  152. s[1] = k
  153. }
  154. newEmoji = strings.Join(s, "")
  155. newDescription = data[i].Description + ": " + v
  156. newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_")
  157. newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false}
  158. data = append(data, newData)
  159. }
  160. }
  161. }
  162. // add header
  163. str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))
  164. // change the format of the unicode string
  165. str = emojiRE.ReplaceAllStringFunc(str, func(s string) string {
  166. var err error
  167. s, err = strconv.Unquote(s[len("{Emoji:"):])
  168. if err != nil {
  169. panic(err)
  170. }
  171. return "{" + strconv.QuoteToASCII(s)
  172. })
  173. // format
  174. return format.Source([]byte(str))
  175. }
  176. const hdr = `
  177. // Copyright 2020 The Gitea Authors. All rights reserved.
  178. // Use of this source code is governed by a MIT-style
  179. // license that can be found in the LICENSE file.
  180. package emoji
  181. // Code generated by gen.go. DO NOT EDIT.
  182. // Sourced from %s
  183. //
  184. var GemojiData = %#v
  185. `