emoji.go (2133B)
1 // Copyright 2016 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package helpers
15
16 import (
17 "bytes"
18 "sync"
19
20 "github.com/kyokomi/emoji/v2"
21 )
22
23 var (
24 emojiInit sync.Once
25
26 emojis = make(map[string][]byte)
27
28 emojiDelim = []byte(":")
29 emojiWordDelim = []byte(" ")
30 emojiMaxSize int
31 )
32
33 // Emoji returns the emojy given a key, e.g. ":smile:", nil if not found.
34 func Emoji(key string) []byte {
35 emojiInit.Do(initEmoji)
36 return emojis[key]
37 }
38
39 // Emojify "emojifies" the input source.
40 // Note that the input byte slice will be modified if needed.
41 // See http://www.emoji-cheat-sheet.com/
42 func Emojify(source []byte) []byte {
43 emojiInit.Do(initEmoji)
44
45 start := 0
46 k := bytes.Index(source[start:], emojiDelim)
47
48 for k != -1 {
49
50 j := start + k
51
52 upper := j + emojiMaxSize
53
54 if upper > len(source) {
55 upper = len(source)
56 }
57
58 endEmoji := bytes.Index(source[j+1:upper], emojiDelim)
59 nextWordDelim := bytes.Index(source[j:upper], emojiWordDelim)
60
61 if endEmoji < 0 {
62 start++
63 } else if endEmoji == 0 || (nextWordDelim != -1 && nextWordDelim < endEmoji) {
64 start += endEmoji + 1
65 } else {
66 endKey := endEmoji + j + 2
67 emojiKey := source[j:endKey]
68
69 if emoji, ok := emojis[string(emojiKey)]; ok {
70 source = append(source[:j], append(emoji, source[endKey:]...)...)
71 }
72
73 start += endEmoji
74 }
75
76 if start >= len(source) {
77 break
78 }
79
80 k = bytes.Index(source[start:], emojiDelim)
81 }
82
83 return source
84 }
85
86 func initEmoji() {
87 emojiMap := emoji.CodeMap()
88
89 for k, v := range emojiMap {
90 emojis[k] = []byte(v)
91
92 if len(k) > emojiMaxSize {
93 emojiMaxSize = len(k)
94 }
95 }
96 }