From 9e99c1d54eec2ab49a1a6a749bec1def8d182927 Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Sat, 21 Oct 2023 22:54:35 +0200 Subject: Support completing @nicks in current buffer Adds all known nicks in the current buffer with an @ prefix to the nicks completion. Disables the API search based nick completion for now until it's working properly. It currently doesn't have any context of which conversation/thread you are in, so you often get other nicks than the one you want to complete first. Additionally, it doesn't work with OAuth tokens. --- slack/commands.py | 30 +++++++++++++++++++++++++++--- slack/slack_buffer.py | 18 +++++++++++++++++- slack/slack_conversation.py | 18 +++++++++++++++++- slack/slack_thread.py | 20 +++++++++++++++++++- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/slack/commands.py b/slack/commands.py index 67c214a..f9dcec2 100644 --- a/slack/commands.py +++ b/slack/commands.py @@ -448,6 +448,23 @@ def completion_irc_channels_cb( return weechat.WEECHAT_RC_OK +def completion_nicks_cb( + data: str, completion_item: str, buffer: str, completion: str +) -> int: + slack_buffer = shared.buffers.get(buffer) + if slack_buffer is None: + return weechat.WEECHAT_RC_OK + + for user in slack_buffer.members: + weechat.completion_list_add( + completion, + f"@{user.nick(only_nick=True)}", + 1, + weechat.WEECHAT_LIST_POS_SORT, + ) + return weechat.WEECHAT_RC_OK + + def completion_thread_hashes_cb( data: str, completion_item: str, buffer: str, completion: str ) -> int: @@ -577,9 +594,10 @@ def register_commands(): weechat.hook_command_run( "/input set_unread_current_buffer", get_callback_name(buffer_set_unread_cb), "" ) - weechat.hook_command_run( - "/input complete_*", get_callback_name(input_complete_cb), "" - ) + # Disable until working properly + # weechat.hook_command_run( + # "/input complete_*", get_callback_name(input_complete_cb), "" + # ) weechat.hook_completion( "slack_workspaces", "Slack workspaces (internal names)", @@ -598,6 +616,12 @@ def register_commands(): get_callback_name(completion_irc_channels_cb), "", ) + weechat.hook_completion( + "nicks", + "nicks in the current Slack buffer", + get_callback_name(completion_nicks_cb), + "", + ) weechat.hook_completion( "threads", "complete thread ids for slack", diff --git a/slack/slack_buffer.py b/slack/slack_buffer.py index a3155e6..addd2be 100644 --- a/slack/slack_buffer.py +++ b/slack/slack_buffer.py @@ -4,13 +4,24 @@ import re import time from abc import ABC, abstractmethod from contextlib import contextmanager -from typing import TYPE_CHECKING, Dict, List, Mapping, Match, Optional, Set, Tuple +from typing import ( + TYPE_CHECKING, + Dict, + Generator, + List, + Mapping, + Match, + 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.slack_user import SlackUser from slack.task import gather, run_async from slack.util import get_callback_name, htmlescape @@ -194,6 +205,11 @@ class SlackBuffer(ABC): def context(self) -> Literal["conversation", "thread"]: raise NotImplementedError() + @property + @abstractmethod + def members(self) -> Generator[SlackUser, None, None]: + raise NotImplementedError() + @property @abstractmethod def messages(self) -> Mapping[SlackTs, SlackMessage]: diff --git a/slack/slack_conversation.py b/slack/slack_conversation.py index e415dd4..a7a6928 100644 --- a/slack/slack_conversation.py +++ b/slack/slack_conversation.py @@ -2,7 +2,17 @@ from __future__ import annotations import hashlib from collections import OrderedDict -from typing import TYPE_CHECKING, Dict, List, Mapping, NoReturn, Optional, Tuple, Union +from typing import ( + TYPE_CHECKING, + Dict, + Generator, + List, + Mapping, + NoReturn, + Optional, + Tuple, + Union, +) import weechat @@ -156,6 +166,12 @@ class SlackConversation(SlackBuffer): def context(self) -> Literal["conversation", "thread"]: return "conversation" + @property + def members(self) -> Generator[SlackUser, None, None]: + for user_or_bot in self._nicklist: + if isinstance(user_or_bot, SlackUser): + yield user_or_bot + @property def messages(self) -> Mapping[SlackTs, SlackMessage]: return self._messages diff --git a/slack/slack_thread.py b/slack/slack_thread.py index 8033ff1..3a96789 100644 --- a/slack/slack_thread.py +++ b/slack/slack_thread.py @@ -1,10 +1,12 @@ from __future__ import annotations from itertools import chain -from typing import TYPE_CHECKING, Dict, Mapping, Optional, Tuple +from typing import TYPE_CHECKING, Dict, Generator, Mapping, Optional, Set, Tuple +from slack.log import print_exception_once from slack.slack_buffer import SlackBuffer from slack.slack_message import SlackMessage, SlackTs +from slack.slack_user import SlackUser from slack.task import gather if TYPE_CHECKING: @@ -18,6 +20,7 @@ class SlackThread(SlackBuffer): def __init__(self, parent: SlackMessage) -> None: super().__init__() self.parent = parent + self._reply_users: Set[SlackUser] = set() @property def workspace(self) -> SlackWorkspace: @@ -31,6 +34,11 @@ class SlackThread(SlackBuffer): def context(self) -> Literal["conversation", "thread"]: return "thread" + @property + def members(self) -> Generator[SlackUser, None, None]: + for user in self._reply_users: + yield user + @property def messages(self) -> Mapping[SlackTs, SlackMessage]: return self.parent.replies @@ -107,6 +115,16 @@ class SlackThread(SlackBuffer): self.history_needs_refresh = False self.history_pending = False + async def print_message(self, message: SlackMessage): + await super().print_message(message) + sender_user_id = message.sender_user_id + if sender_user_id is not None: + try: + sender_user = await self.workspace.users[sender_user_id] + self._reply_users.add(sender_user) + except Exception as e: + print_exception_once(e) + async def mark_read(self): # subscriptions.thread.mark is only available for session tokens if self.workspace.token_type != "session": -- cgit