diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2023-08-20 12:10:28 +0200 |
---|---|---|
committer | Trygve Aaberge <trygveaa@gmail.com> | 2024-02-18 11:32:53 +0100 |
commit | b4c1ebeead35f84d50dee33a9bf6d314a84a3d86 (patch) | |
tree | 47e07e1c04d360168812d47f6dd3703eaa6456bd | |
parent | 4e38811c1a97ed4217b8cf38aa0f82816e9f8513 (diff) | |
download | wee-slack-b4c1ebeead35f84d50dee33a9bf6d314a84a3d86.tar.gz |
Support sending and receiving typing
This does not support globally showing typing from direct messages, like
the old wee-slack did, because that's not supported by WeeChats typing
plugin. It only shows typing in the current buffer.
-rw-r--r-- | slack/config.py | 14 | ||||
-rw-r--r-- | slack/register.py | 11 | ||||
-rw-r--r-- | slack/slack_conversation.py | 27 | ||||
-rw-r--r-- | slack/slack_workspace.py | 21 | ||||
-rw-r--r-- | typings/slack_rtm/slack_rtm_message.pyi | 4 | ||||
-rw-r--r-- | typings/websocket.pyi | 1 |
6 files changed, 73 insertions, 5 deletions
diff --git a/slack/config.py b/slack/config.py index e7dbbaf..890d6be 100644 --- a/slack/config.py +++ b/slack/config.py @@ -93,6 +93,20 @@ class SlackConfigSectionLook: "*", ) + self.typing_status_nicks = WeeChatOption( + self._section, + "typing_status_nicks", + 'display nicks typing on the channel in bar item "typing" (option typing.look.enabled_nicks must be enabled)', + True, + ) + + self.typing_status_self = WeeChatOption( + self._section, + "typing_status_self", + "send self typing status to channels so that other users see when you are typing a message (option typing.look.enabled_self must be enabled)", + True, + ) + weechat.hook_config( "weechat.look.nick_color_*", get_callback_name(self.config_change_nick_colors_cb), diff --git a/slack/register.py b/slack/register.py index e7628e0..7eab789 100644 --- a/slack/register.py +++ b/slack/register.py @@ -68,6 +68,16 @@ def modifier_input_text_display_with_cursor_cb( return prefix + string +def typing_self_cb(data: str, signal: str, signal_data: str) -> int: + if not shared.config.look.typing_status_self.value: + return weechat.WEECHAT_RC_OK + + conversation = get_conversation_from_buffer_pointer(signal_data) + if conversation: + conversation.typing_update_self(signal) + return weechat.WEECHAT_RC_OK + + def ws_ping_cb(data: str, remaining_calls: int) -> int: for workspace in shared.workspaces.values(): if workspace.is_connected: @@ -117,6 +127,7 @@ def register(): get_callback_name(modifier_input_text_display_with_cursor_cb), "", ) + weechat.hook_signal("typing_self_*", get_callback_name(typing_self_cb), "") weechat.hook_timer(5000, 0, 0, get_callback_name(ws_ping_cb), "") run_async(init_async()) diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py index fc53979..7c0e90f 100644 --- a/slack/slack_conversation.py +++ b/slack/slack_conversation.py @@ -46,6 +46,7 @@ class SlackConversation: self._info = info self._members: Optional[List[str]] = None self._messages: OrderedDict[SlackTs, SlackMessage] = OrderedDict() + self._typing_self_last_sent = time.time() # TODO: buffer_pointer may be accessed by buffer_switch before it's initialized self.buffer_pointer: str = "" self.is_loading = False @@ -251,6 +252,32 @@ class SlackConversation: self.buffer_pointer, "hotlist", str(message.priority.value) ) + if message.sender_user_id: + user = await self.workspace.users[message.sender_user_id] + weechat.hook_signal_send( + "typing_set_nick", + weechat.WEECHAT_HOOK_SIGNAL_STRING, + f"{self.buffer_pointer};off;{user.nick()}", + ) + + async def typing_add_user(self, user_id: str, thread_ts: Optional[str]): + if not shared.config.look.typing_status_nicks.value: + return + + if not thread_ts: + user = await self.workspace.users[user_id] + weechat.hook_signal_send( + "typing_set_nick", + weechat.WEECHAT_HOOK_SIGNAL_STRING, + f"{self.buffer_pointer};typing;{user.nick()}", + ) + + def typing_update_self(self, typing_state: str): + now = time.time() + if now - 4 > self._typing_self_last_sent: + self._typing_self_last_sent = now + self.workspace.send_typing(self.id) + def print_message(self, message: SlackMessage, rendered: str): weechat.prnt_date_tags(self.buffer_pointer, message.ts.major, "", rendered) diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py index 7e001a9..0d9405f 100644 --- a/slack/slack_workspace.py +++ b/slack/slack_workspace.py @@ -273,6 +273,12 @@ class SlackWorkspace: async def _ws_recv(self, data: SlackRtmMessage): try: + channel_id = "channel" in data and data["channel"] + if channel_id in self.open_conversations: + channel = self.open_conversations[channel_id] + else: + channel = None + if data["type"] == "message": if "subtype" in data and data["subtype"] == "message_changed": pass @@ -281,11 +287,12 @@ class SlackWorkspace: elif "subtype" in data and data["subtype"] == "message_replied": pass else: - channel_id = data["channel"] - if channel_id in self.open_conversations: - channel = self.open_conversations[channel_id] + if channel: message = SlackMessage(channel, data) await channel.add_message(message) + elif data["type"] == "user_typing": + if channel: + await channel.typing_add_user(data["user"], data.get("thread_ts")) else: weechat.prnt("", f"\t{self.name} received: {json.dumps(data)}") except Exception as e: @@ -304,6 +311,14 @@ class SlackWorkspace: print("lost connection on ping, reconnecting") run_async(self.reconnect()) + def send_typing(self, conversation_id: str): + if not self.is_connected: + raise SlackError(self, "Can't send typing when not connected") + if self._ws is None: + raise SlackError(self, "is_connected is True while _ws is None") + msg = {"type": "typing", "channel": conversation_id} + self._ws.send(json.dumps(msg)) + async def reconnect(self): self.disconnect() await self.connect() diff --git a/typings/slack_rtm/slack_rtm_message.pyi b/typings/slack_rtm/slack_rtm_message.pyi index 0f8d397..7eb50f1 100644 --- a/typings/slack_rtm/slack_rtm_message.pyi +++ b/typings/slack_rtm/slack_rtm_message.pyi @@ -8,7 +8,7 @@ from slack_api.slack_conversations_history import ( SlackMessageThreadParentSubscribed, SlackMessageWithFiles, ) -from typing_extensions import Literal, TypedDict, final +from typing_extensions import Literal, NotRequired, TypedDict, final class SlackRtmHello(TypedDict): type: Literal["hello"] @@ -81,7 +81,7 @@ class SlackMessageReplied(TypedDict): class SlackUserTyping(TypedDict): type: Literal["user_typing"] channel: str - thread_ts: str + thread_ts: NotRequired[str] id: int user: str diff --git a/typings/websocket.pyi b/typings/websocket.pyi index 0b9b769..3e5d683 100644 --- a/typings/websocket.pyi +++ b/typings/websocket.pyi @@ -51,6 +51,7 @@ class WebSocketConnectionClosedException(WebSocketException): ... class WebSocket: sock: socket + def send(self, payload: str, opcode: int = ABNF.OPCODE_TEXT) -> int: ... def ping(self, payload: str = ...) -> None: ... def recv_data( self, control_frame: bool |