From 6383d66a58eaa0583a71d04c908d0270269512b5 Mon Sep 17 00:00:00 2001 From: Sushmey Date: Thu, 30 Mar 2023 13:38:06 +0530 Subject: [PATCH] views/keys/hotkeys: Add key to copy message content Adding a key to copy message content which can be then pasted. Implemented using preexisting `copy_to_clipboard` function Fixes #546 --- docs/hotkeys.md | 1 + tests/ui_tools/test_popups.py | 23 ++++++++++++++++++----- zulipterminal/config/keys.py | 6 ++++++ zulipterminal/ui_tools/views.py | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/docs/hotkeys.md b/docs/hotkeys.md index db4972036f..e7e164b31b 100644 --- a/docs/hotkeys.md +++ b/docs/hotkeys.md @@ -62,6 +62,7 @@ |View current message in browser (from message information)|v| |Show/hide full rendered message (from message information)|f| |Show/hide full raw message (from message information)|r| +|Copy message content to clipboard|C| ## Stream list actions |Command|Key Combination| diff --git a/tests/ui_tools/test_popups.py b/tests/ui_tools/test_popups.py index 3205a13d52..68762dbf5c 100644 --- a/tests/ui_tools/test_popups.py +++ b/tests/ui_tools/test_popups.py @@ -1001,6 +1001,18 @@ def test_keypress_full_raw_message( time_mentions=list(), ) + @pytest.mark.parametrize("key", keys_for_command("COPY_MESSAGE")) + def test_keypress_copy_message( + self, key: str, widget_size: Callable[[Widget], urwid_Size] + ) -> None: + size = widget_size(self.msg_info_view) + + self.msg_info_view.keypress(size, key) + + self.controller.copy_to_clipboard.assert_called_once_with( + self.msg_info_view.msg["content"], "Message Content" + ) + @pytest.mark.parametrize( "key", {*keys_for_command("GO_BACK"), *keys_for_command("MSG_INFO")} ) @@ -1027,13 +1039,14 @@ def test_keypress_view_in_browser( assert self.controller.open_in_browser.called def test_height_noreactions(self) -> None: - expected_height = 8 - # 6 = 1 (date & time) +1 (sender's name) +1 (sender's email) - # +1 (display group header) + expected_height = 9 + # 9 = 1 (date & time) +1 (sender's name) +1 (sender's email) # +1 (whitespace column) + # +1 (display group header) # +1 (view message in browser) # +1 (full rendered message) # +1 (full raw message) + # +1 (copy message content) assert self.msg_info_view.height == expected_height # FIXME This is the same parametrize as MessageBox:test_reactions_view @@ -1101,9 +1114,9 @@ def test_height_reactions( OrderedDict(), list(), ) - # 12 = 7 labels + 2 blank lines + 1 'Reactions' (category) + # 15 = 8 labels + 2 blank lines + 1 'Reactions' (category) # + 4 reactions (excluding 'Message Links'). - expected_height = 14 + expected_height = 15 assert self.msg_info_view.height == expected_height @pytest.mark.parametrize( diff --git a/zulipterminal/config/keys.py b/zulipterminal/config/keys.py index 62482b6c58..3fa73e12d8 100644 --- a/zulipterminal/config/keys.py +++ b/zulipterminal/config/keys.py @@ -396,6 +396,12 @@ class KeyBinding(TypedDict): 'help_text': 'Show/hide full raw message (from message information)', 'key_category': 'msg_actions', }), + ('COPY_MESSAGE', { + 'keys': ['C'], + 'help_text': + 'Copy message content to clipboard', + 'key_category': 'msg_actions', + }), ]) # fmt: on diff --git a/zulipterminal/ui_tools/views.py b/zulipterminal/ui_tools/views.py index 8f6ad15de4..9204950c2e 100644 --- a/zulipterminal/ui_tools/views.py +++ b/zulipterminal/ui_tools/views.py @@ -1530,6 +1530,9 @@ def __init__( full_raw_message_keys = "[{}]".format( ", ".join(map(str, keys_for_command("FULL_RAW_MESSAGE"))) ) + copy_message_keys = "[{}]".format( + ", ".join(map(str, keys_for_command("COPY_MESSAGE"))) + ) msg_info = [ ( "", @@ -1548,6 +1551,7 @@ def __init__( ("Open in web browser", view_in_browser_keys), ("Full rendered message", full_rendered_message_keys), ("Full raw message", full_raw_message_keys), + ("Copy message", copy_message_keys), ], ) msg_info.append(viewing_actions) @@ -1678,6 +1682,17 @@ def keypress(self, size: urwid_Size, key: str) -> str: time_mentions=self.time_mentions, ) return key + elif is_command_key("COPY_MESSAGE", key): + rendered_content, *_ = MessageBox.transform_content( + self.msg["content"], self.controller.model.server_url + ) + content = [] + for word in rendered_content[1]: + if isinstance(word, tuple): # if msg content has markup + content.append(word[1]) + else: + content.append(word) + self.controller.copy_to_clipboard("".join(content), "Message Content") return super().keypress(size, key)