diff options
Diffstat (limited to 'slack/slack_buffer.py')
-rw-r--r-- | slack/slack_buffer.py | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/slack/slack_buffer.py b/slack/slack_buffer.py index 4fa5981..7a6faee 100644 --- a/slack/slack_buffer.py +++ b/slack/slack_buffer.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re import time from abc import ABC, abstractmethod from contextlib import contextmanager @@ -7,6 +8,7 @@ from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, Set, Tuple import weechat +from slack.log import print_error from slack.shared import shared from slack.slack_message import SlackMessage, SlackTs from slack.task import run_async @@ -19,6 +21,17 @@ if TYPE_CHECKING: from slack.slack_conversation import SlackConversation from slack.slack_workspace import SlackWorkspace +MESSAGE_ID_REGEX_STRING = r"(?P<msg_id>\d+|\$[0-9a-z]{3,})" +REACTION_PREFIX_REGEX_STRING = rf"{MESSAGE_ID_REGEX_STRING}?(?P<reaction_change>\+|-)" + +EMOJI_CHAR_REGEX_STRING = "(?P<emoji_char>[\U00000080-\U0010ffff]+)" +EMOJI_NAME_REGEX_STRING = ( + ":(?P<emoji_name>[a-z0-9_+-]+(?:::skin-tone-[2-6](?:-[2-6])?)?):" +) +EMOJI_CHAR_OR_NAME_REGEX_STRING = ( + f"({EMOJI_CHAR_REGEX_STRING}|{EMOJI_NAME_REGEX_STRING})" +) + def hdata_line_ts(line_pointer: str) -> Optional[SlackTs]: data = weechat.hdata_pointer(weechat.hdata_get("line"), line_pointer, "data") @@ -311,14 +324,57 @@ class SlackBuffer(ABC): weechat.buffer_set(self.buffer_pointer, "hotlist", "-1") self.hotlist_tss.clear() + def ts_from_hash(self, ts_hash: str) -> Optional[SlackTs]: + return self.conversation.message_hashes.get_ts(ts_hash) + + def ts_from_index(self, index: int) -> Optional[SlackTs]: + lines = weechat.hdata_pointer( + weechat.hdata_get("buffer"), self.buffer_pointer, "lines" + ) + line = weechat.hdata_pointer(weechat.hdata_get("lines"), lines, "last_line") + move = -index + 1 + if move: + line = weechat.hdata_move(weechat.hdata_get("line"), line, move) + return hdata_line_ts(line) + + def ts_from_hash_or_index(self, hash_or_index: str) -> Optional[SlackTs]: + if not hash_or_index: + return self.ts_from_index(1) + elif hash_or_index.isdigit(): + return self.ts_from_index(int(hash_or_index)) + else: + return self.ts_from_hash(hash_or_index) + @abstractmethod async def post_message(self, text: str) -> None: raise NotImplementedError() + async def send_change_reaction( + self, ts: SlackTs, emoji_char: str, change_type: Literal["+", "-"] + ) -> None: + emoji = shared.standard_emojis_inverse.get(emoji_char) + emoji_name = emoji["name"] if emoji else emoji_char + await self._api.reactions_change(self.conversation, ts, emoji_name, change_type) + async def process_input(self, input_data: str): - if input_data.startswith(("//", " ")): - input_data = input_data[1:] - await self.post_message(htmlescape(input_data)) + reaction = re.match( + rf"{REACTION_PREFIX_REGEX_STRING}{EMOJI_CHAR_OR_NAME_REGEX_STRING}\s*$", + input_data, + ) + if reaction: + msg_id = reaction.group("msg_id") + ts = self.ts_from_hash_or_index(msg_id) + if ts is None: + print_error(f"No slack message found for message id or index {msg_id}") + return + emoji = reaction.group("emoji_char") or reaction.group("emoji_name") + reaction_change_type = reaction.group("reaction_change") + if reaction_change_type == "+" or reaction_change_type == "-": + await self.send_change_reaction(ts, emoji, reaction_change_type) + else: + if input_data.startswith(("//", " ")): + input_data = input_data[1:] + await self.post_message(htmlescape(input_data)) def _buffer_input_cb(self, data: str, buffer: str, input_data: str) -> int: run_async(self.process_input(input_data)) |