#!/usr/bin/env python3 # # This is a debugging tool that takes as input a bunch of different # emoji data sources, and outputs a convenient HTML table that can be # used to sanity-check the differences between these different data # sources' decisions about what names to provide to each Unicode # codepoint. import os import sys from typing import Any import orjson TOOLS_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ZULIP_PATH = os.path.dirname(TOOLS_DIR) sys.path.append(ZULIP_PATH) from tools.setup.emoji.emoji_names import EMOJI_NAME_MAPS from tools.setup.emoji.emoji_setup_utils import emoji_is_supported, get_emoji_code UNIFIED_REACTIONS_FILE = os.path.join( ZULIP_PATH, "zerver", "management", "data", "unified_reactions.json" ) EMOJI_DATA_FILE = os.path.join(ZULIP_PATH, "node_modules", "emoji-datasource-google", "emoji.json") EMOJI_CACHE = os.path.join(ZULIP_PATH, "static", "generated", "emoji") OUTPUT_FILE = os.path.join(EMOJI_CACHE, "emoji_names_table.html") # Emoji sets that we currently support. EMOJISETS = ["google", "twitter"] with open(EMOJI_DATA_FILE, "rb") as fp: EMOJI_DATA = orjson.loads(fp.read()) with open(UNIFIED_REACTIONS_FILE, "rb") as fp: UNIFIED_REACTIONS_MAP = orjson.loads(fp.read()) EMOJI_IMAGE_TEMPLATE = """ """ TABLE_ROW_TEMPLATE = """ {sorting_info} {emoji_code} {images_html} {zulip_names} {iamcal_names} {gemoji_names} {unicode_name} """ EMOJI_LISTING_TEMPLATE = """ Zulip emoji names {tbody}
Category Emoji code Images Zulip Iamcal (Slack) Gemoji (unordered) Unicode
""" TABLE_CSS = """ .emoji { height: 35px; width: 35px; position: relative; margin-top: -7px; vertical-align: middle; top: 3px; } .emoji-images { width: 200px; } table, td, th { border: 1px solid black; border-collapse: collapse; } td, th { height: 40px; text-align: center; } .google { background-image: url('sheet-google-64.png') !important; } .twitter { background-image: url('sheet-twitter-64.png') !important; } """ SORTED_CATEGORIES = [ "Smileys & Emotion", "People & Body", "Animals & Nature", "Food & Drink", "Activities", "Travel & Places", "Objects", "Symbols", "Flags", "Skin Tones", ] emoji_code_to_zulip_names: dict[str, str] = {} emoji_code_to_iamcal_names: dict[str, str] = {} emoji_code_to_gemoji_names: dict[str, str] = {} emoji_collection: dict[str, list[dict[str, Any]]] = {category: [] for category in SORTED_CATEGORIES} def generate_emoji_code_to_emoji_names_maps() -> None: # Prepare gemoji names map. reverse_unified_reactions_map: dict[str, list[str]] = {} for name in UNIFIED_REACTIONS_MAP: emoji_code = UNIFIED_REACTIONS_MAP[name] if emoji_code in reverse_unified_reactions_map: reverse_unified_reactions_map[emoji_code].append(name) else: reverse_unified_reactions_map[emoji_code] = [name] for emoji_code in reverse_unified_reactions_map: emoji_code_to_gemoji_names[emoji_code] = ", ".join( reverse_unified_reactions_map[emoji_code] ) # Prepare iamcal names map. for emoji_dict in EMOJI_DATA: emoji_code = get_emoji_code(emoji_dict) emoji_code_to_iamcal_names[emoji_code] = ", ".join(emoji_dict["short_names"]) # Prepare zulip names map. for emoji_code in EMOJI_NAME_MAPS: canonical_name = EMOJI_NAME_MAPS[emoji_code]["canonical_name"] aliases = EMOJI_NAME_MAPS[emoji_code]["aliases"] names = [canonical_name] names.extend(aliases) emoji_code_to_zulip_names[emoji_code] = ", ".join(names) def get_sorting_info(category: str, sort_order: int) -> str: return f"{category} {sort_order}" def get_images_html(emoji_code: str) -> str: images_html = "" for emojiset in EMOJISETS: images_html += EMOJI_IMAGE_TEMPLATE.format( emoji_code=emoji_code, emojiset=emojiset, ) return images_html def generate_emoji_collection() -> None: generate_emoji_code_to_emoji_names_maps() # Prepare `emoji_collection`. for emoji_dict in EMOJI_DATA: if not emoji_is_supported(emoji_dict): continue category = emoji_dict["category"] emoji_code = get_emoji_code(emoji_dict) sort_order = emoji_dict["sort_order"] emoji_collection[category].append( { "category": category, "emoji_code": emoji_code, "images_html": get_images_html(emoji_code), "gemoji_names": emoji_code_to_gemoji_names.get(emoji_code, ""), "iamcal_names": emoji_code_to_iamcal_names.get(emoji_code, ""), "zulip_names": emoji_code_to_zulip_names.get(emoji_code, ""), "unicode_name": (emoji_dict["name"] or "").lower(), "sort_order": sort_order, "sorting_info": get_sorting_info(category, sort_order), } ) # Sort `emoji_collection`. for category in SORTED_CATEGORIES: emoji_collection[category].sort(key=lambda x: x["sort_order"]) def main() -> None: generate_emoji_collection() tbody = "" for category in SORTED_CATEGORIES: for emoji_entry in emoji_collection[category]: tbody += TABLE_ROW_TEMPLATE.format(**emoji_entry) with open(OUTPUT_FILE, "w") as fp: fp.write( EMOJI_LISTING_TEMPLATE.format( tbody=tbody, table_css=TABLE_CSS, ) ) print( "Done! Open http://localhost:9991/static/generated/emoji/emoji_names_table.html " "to view(after starting the dev server)." ) if __name__ == "__main__": main()