github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/helpers/emoji.go (about)

     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  }