Skip to content

Commit fde575a

Browse files
zee-bitneiljp
authored andcommitted
bugfix: boxes/helper: Fix generation of correct quote fences.
This commit corrects generation of fences for quoted messages. The new logic for generation of quote fence is borrowed from the webapp. Fences are generated after searching for maximum length occurence of ` through regex, and wrapping the quote block with the generated fence. This allows for proper quoting of messages containing a code-block or another quote inside them. Tests added. Math & spoiler cases, and test ids, added by neiljp.
1 parent 0c3e173 commit fde575a

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

tests/helper/test_helper.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import zulipterminal.helper
44
from zulipterminal.helper import (
55
canonicalize_color, classify_unread_counts, display_error_if_present,
6-
hash_util_decode, index_messages, notify, powerset,
6+
get_unused_fence, hash_util_decode, index_messages, notify, powerset,
77
)
88

99

@@ -314,3 +314,26 @@ def test_hash_util_decode(quoted_string, expected_unquoted_string):
314314
return_value = hash_util_decode(quoted_string)
315315

316316
assert return_value == expected_unquoted_string
317+
318+
319+
@pytest.mark.parametrize('message_content, expected_fence', [
320+
('Hi `test_here`', '```'),
321+
('```quote\nZ(dot)T(dot)\n```\nempty body', '````'),
322+
('```python\ndef zulip():\n pass\n```\ncode-block', '````'),
323+
('````\ndont_know_what_this_does\n````', '`````'),
324+
('````quote\n```\ndef zulip():\n pass\n```\n````', '`````'),
325+
('```math\n\\int_a^b f(t)\\, dt = F(b) - F(a)\n```', '````'),
326+
('```spoiler Header Text\nSpoiler content\n```', '````'),
327+
], ids=[
328+
"inline_code",
329+
"block_quote",
330+
"block_code_python",
331+
"block_code",
332+
"block_code_quoted",
333+
"block_math",
334+
"block_spoiler",
335+
])
336+
def test_get_unused_fence(message_content, expected_fence):
337+
generated_fence = get_unused_fence(message_content)
338+
339+
assert generated_fence == expected_fence

zulipterminal/helper.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from collections import OrderedDict, defaultdict
66
from functools import wraps
77
from itertools import chain, combinations
8-
from re import ASCII, match
8+
from re import ASCII, MULTILINE, findall, match
99
from threading import Thread
1010
from typing import (
1111
Any, Callable, DefaultDict, Dict, FrozenSet, Iterable, List, Set, Tuple,
@@ -655,3 +655,21 @@ def hash_util_decode(string: str) -> str:
655655
# Acknowledge custom string replacements in zulip/zulip's
656656
# zerver/lib/url_encoding.py before unquote.
657657
return unquote(string.replace('.', '%'))
658+
659+
660+
def get_unused_fence(content: str) -> str:
661+
"""
662+
Generates fence for quoted-message based on regex pattern
663+
of continuous back-ticks. Referred and translated from
664+
zulip/static/shared/js/fenced_code.js.
665+
"""
666+
fence_length_regex = '^ {0,3}(`{3,})'
667+
max_length_fence = 3
668+
669+
matches = findall(fence_length_regex, content,
670+
flags=MULTILINE)
671+
if len(matches) != 0:
672+
max_length_fence = max(max_length_fence,
673+
len(max(matches, key=len)) + 1)
674+
675+
return '`' * max_length_fence

zulipterminal/ui_tools/boxes.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
STREAM_TOPIC_SEPARATOR, TIME_MENTION_MARKER,
2424
)
2525
from zulipterminal.helper import (
26-
Message, format_string, match_emoji, match_group, match_stream,
27-
match_topics, match_user,
26+
Message, format_string, get_unused_fence, match_emoji, match_group,
27+
match_stream, match_topics, match_user,
2828
)
2929
from zulipterminal.ui_tools.buttons import EditModeButton
3030
from zulipterminal.ui_tools.tables import render_table
@@ -1225,8 +1225,16 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
12251225
self.model.controller.view.middle_column.set_focus('footer')
12261226
elif is_command_key('QUOTE_REPLY', key):
12271227
self.keypress(size, 'enter')
1228-
quote = '```quote\n' + self.model.client.get_raw_message(
1229-
self.message['id'])['raw_content'] + '\n```\n'
1228+
1229+
# To correctly quote a message that contains quote/code-blocks,
1230+
# we need to fence quoted message containing ``` with ````,
1231+
# ```` with ````` and so on.
1232+
message_raw_content = self.model.client.get_raw_message(
1233+
self.message['id'])['raw_content']
1234+
fence = get_unused_fence(message_raw_content)
1235+
1236+
quote = '{0}quote\n{1}\n{0}\n'.format(fence, message_raw_content)
1237+
12301238
self.model.controller.view.write_box.msg_write_box.set_edit_text(
12311239
quote)
12321240
self.model.controller.view.write_box.msg_write_box.set_edit_pos(

0 commit comments

Comments
 (0)