gitea源码

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