aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrygve Aaberge <trygveaa@gmail.com>2023-08-21 19:25:03 +0200
committerTrygve Aaberge <trygveaa@gmail.com>2024-02-18 11:32:54 +0100
commitfed3a064a788b94f1c0b420bf276c158f8197ddf (patch)
treee2da384f076e579185e1dfb1c640b2e768bcc7b3
parent9453d1771232882ca111ff53ca3bf343fccbb62a (diff)
downloadwee-slack-fed3a064a788b94f1c0b420bf276c158f8197ddf.tar.gz
Support rendering emoji unicode characters
-rw-r--r--slack/config.py17
-rw-r--r--slack/register.py2
-rw-r--r--slack/shared.py2
-rw-r--r--slack/slack_emoji.py64
-rw-r--r--slack/slack_message.py19
-rw-r--r--slack/weechat_config.py4
6 files changed, 103 insertions, 5 deletions
diff --git a/slack/config.py b/slack/config.py
index a3b01ce..864ac18 100644
--- a/slack/config.py
+++ b/slack/config.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import Optional
+from typing import TYPE_CHECKING, Optional
import weechat
@@ -17,6 +17,9 @@ from slack.weechat_config import (
WeeChatSection,
)
+if TYPE_CHECKING:
+ from typing_extensions import Literal
+
class SlackConfigSectionColor:
def __init__(self, weechat_config: WeeChatConfig):
@@ -136,6 +139,16 @@ class SlackConfigSectionLook:
"*",
)
+ self.render_emoji_as: WeeChatOption[
+ Literal["emoji", "name", "both"]
+ ] = WeeChatOption(
+ self._section,
+ "render_emoji_as",
+ "show emojis as: emoji = the emoji unicode character, name = the emoji name, both = both the emoji name and the emoji character",
+ "emoji",
+ string_values=["emoji", "name", "both"],
+ )
+
self.typing_status_nicks = WeeChatOption(
self._section,
"typing_status_nicks",
@@ -221,7 +234,7 @@ class SlackConfigSectionWorkspace:
default_value: WeeChatOptionType,
min_value: Optional[int] = None,
max_value: Optional[int] = None,
- string_values: Optional[str] = None,
+ string_values: Optional[list[WeeChatOptionType]] = None,
) -> WeeChatOption[WeeChatOptionType]:
if self._workspace_name:
option_name = f"{self._workspace_name}.{name}"
diff --git a/slack/register.py b/slack/register.py
index 7eab789..d77163b 100644
--- a/slack/register.py
+++ b/slack/register.py
@@ -6,6 +6,7 @@ from slack.commands import register_commands
from slack.config import SlackConfig
from slack.shared import shared
from slack.slack_conversation import get_conversation_from_buffer_pointer
+from slack.slack_emoji import load_standard_emojis
from slack.task import run_async, sleep
from slack.util import get_callback_name, with_color
@@ -105,6 +106,7 @@ def register():
"",
):
shared.weechat_version = int(weechat.info_get("version_number", "") or 0)
+ shared.standard_emojis = load_standard_emojis()
shared.workspaces = {}
shared.config = SlackConfig()
shared.config.config_read()
diff --git a/slack/shared.py b/slack/shared.py
index 8dbac1a..600723b 100644
--- a/slack/shared.py
+++ b/slack/shared.py
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Callable, Dict, List, Union
if TYPE_CHECKING:
from slack.config import SlackConfig
from slack.error import UncaughtError
+ from slack.slack_emoji import Emoji
from slack.slack_workspace import SlackWorkspace
from slack.task import Future, Task
@@ -24,6 +25,7 @@ class Shared:
self.workspaces: Dict[str, SlackWorkspace] = {}
self.config: SlackConfig
self.uncaught_errors: List[UncaughtError] = []
+ self.standard_emojis: Dict[str, Emoji]
shared = Shared()
diff --git a/slack/slack_emoji.py b/slack/slack_emoji.py
new file mode 100644
index 0000000..e2b9b11
--- /dev/null
+++ b/slack/slack_emoji.py
@@ -0,0 +1,64 @@
+from __future__ import annotations
+
+import json
+import os
+from typing import TYPE_CHECKING, Any, Dict
+
+import weechat
+
+from slack.error import store_and_format_exception
+from slack.log import print_error
+
+if TYPE_CHECKING:
+ from typing_extensions import NotRequired, TypedDict
+else:
+ TypedDict = Any
+
+
+class EmojiSkinVariation(TypedDict):
+ name: str
+ unicode: str
+
+
+class Emoji(TypedDict):
+ aliasOf: NotRequired[str]
+ name: str
+ skinVariations: NotRequired[Dict[str, EmojiSkinVariation]]
+ unicode: str
+
+
+def load_standard_emojis() -> Dict[str, Emoji]:
+ weechat_dir = weechat.info_get("weechat_data_dir", "") or weechat.info_get(
+ "weechat_dir", ""
+ )
+ weechat_sharedir = weechat.info_get("weechat_sharedir", "")
+ local_weemoji, global_weemoji = (
+ f"{path}/weemoji.json" for path in (weechat_dir, weechat_sharedir)
+ )
+ path = (
+ global_weemoji
+ if os.path.exists(global_weemoji) and not os.path.exists(local_weemoji)
+ else local_weemoji
+ )
+ if not os.path.exists(path):
+ return {}
+
+ try:
+ with open(path) as f:
+ emojis: Dict[str, Emoji] = json.loads(f.read())
+
+ emojis_skin_tones: Dict[str, Emoji] = {
+ skin_tone["name"]: {
+ "name": skin_tone["name"],
+ "unicode": skin_tone["unicode"],
+ }
+ for emoji in emojis.values()
+ if "skinVariations" in emoji
+ for skin_tone in emoji["skinVariations"].values()
+ }
+
+ emojis.update(emojis_skin_tones)
+ return emojis
+ except Exception as e:
+ print_error(f"couldn't read weemoji.json: {store_and_format_exception(e)}")
+ return {}
diff --git a/slack/slack_message.py b/slack/slack_message.py
index d1d29fe..ab72582 100644
--- a/slack/slack_message.py
+++ b/slack/slack_message.py
@@ -16,6 +16,7 @@ from slack.util import with_color
if TYPE_CHECKING:
from slack_api.slack_conversations_history import SlackMessage as SlackMessageDict
from slack_api.slack_conversations_history import SlackMessageReaction
+ from typing_extensions import assert_never
from slack.slack_conversation import SlackConversation
from slack.slack_workspace import SlackWorkspace
@@ -321,6 +322,22 @@ class SlackMessage:
return re_mention.sub(unfurl_ref, message)
+ def _get_emoji(self, emoji_name: str) -> str:
+ emoji_name_with_colons = f":{emoji_name}:"
+ if shared.config.look.render_emoji_as.value == "name":
+ return emoji_name_with_colons
+
+ emoji_item = shared.standard_emojis.get(emoji_name)
+ if emoji_item is None:
+ return emoji_name_with_colons
+
+ if shared.config.look.render_emoji_as.value == "emoji":
+ return emoji_item["unicode"]
+ elif shared.config.look.render_emoji_as.value == "both":
+ return f"{emoji_item['unicode']}({emoji_name_with_colons})"
+ else:
+ assert_never(shared.config.look.render_emoji_as.value)
+
async def _create_reaction_string(self, reaction: SlackMessageReaction) -> str:
if shared.config.look.display_reaction_nicks.value:
# TODO: initialize_items?
@@ -332,7 +349,7 @@ class SlackMessage:
else:
users_str = len(reaction["users"])
- reaction_string = f":{reaction['name']}:{users_str}"
+ reaction_string = f"{self._get_emoji(reaction['name'])}{users_str}"
if self.workspace.my_user.id in reaction["users"]:
return with_color(
diff --git a/slack/weechat_config.py b/slack/weechat_config.py
index 78b36a1..6eab089 100644
--- a/slack/weechat_config.py
+++ b/slack/weechat_config.py
@@ -77,7 +77,7 @@ class WeeChatOption(Generic[WeeChatOptionType]):
default_value: WeeChatOptionType
min_value: Optional[int] = None
max_value: Optional[int] = None
- string_values: Optional[str] = None
+ string_values: Optional[list[WeeChatOptionType]] = None
parent_option: Union[WeeChatOption[WeeChatOptionType], str, None] = None
callback_change: Optional[
Callable[[WeeChatOption[WeeChatOptionType], bool], None]
@@ -174,7 +174,7 @@ class WeeChatOption(Generic[WeeChatOptionType]):
name,
self.weechat_type,
self.description,
- self.string_values or "",
+ "|".join(str(x) for x in self.string_values or []),
self.min_value or -(2**31),
self.max_value or 2**31 - 1,
default_value,