mirror of https://github.com/zulip/zulip.git
markdown: Add support for a pretty syntax for message links.
Links to zulip messages can now be written as `#**channel_name > topic_name @ message_id**.` The `message_id` is replaced with `💬` in the rendered message. Fixes part of #31920
This commit is contained in:
parent
65c9b249b7
commit
000cc7bcde
|
@ -194,6 +194,31 @@ def get_compiled_stream_topic_link_regex() -> Pattern[str]:
|
|||
)
|
||||
|
||||
|
||||
STREAM_TOPIC_MESSAGE_LINK_REGEX = rf"""
|
||||
{BEFORE_MENTION_ALLOWED_REGEX} # Start after whitespace or specified chars
|
||||
\#\*\* # and after hash sign followed by double asterisks
|
||||
(?P<stream_name>[^\*>]+) # stream name can contain anything except >
|
||||
> # > acts as separator
|
||||
(?P<topic_name>[^\*]+) # topic name can contain anything
|
||||
@
|
||||
(?P<message_id>\d+) # message id
|
||||
\*\* # ends by double asterisks
|
||||
"""
|
||||
|
||||
|
||||
@lru_cache(None)
|
||||
def get_compiled_stream_topic_message_link_regex() -> Pattern[str]:
|
||||
# Not using verbose_compile as it adds ^(.*?) and
|
||||
# (.*?)$ which cause extra overhead of matching
|
||||
# pattern which is not required.
|
||||
# With new InlineProcessor these extra patterns
|
||||
# are not required.
|
||||
return re.compile(
|
||||
STREAM_TOPIC_MESSAGE_LINK_REGEX,
|
||||
re.DOTALL | re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(None)
|
||||
def get_web_link_regex() -> Pattern[str]:
|
||||
# We create this one time, but not at startup. So the
|
||||
|
@ -2041,6 +2066,29 @@ class StreamTopicPattern(StreamTopicMessageProcessor):
|
|||
return el, m.start(), m.end()
|
||||
|
||||
|
||||
class StreamTopicMessagePattern(StreamTopicMessageProcessor):
|
||||
@override
|
||||
def handleMatch( # type: ignore[override] # https://github.com/python/mypy/issues/10197
|
||||
self, m: Match[str], data: str
|
||||
) -> tuple[Element | str | None, int | None, int | None]:
|
||||
stream_name = m.group("stream_name")
|
||||
topic_name = m.group("topic_name")
|
||||
message_id = m.group("message_id")
|
||||
|
||||
stream_id = self.find_stream_id(stream_name)
|
||||
if stream_id is None or topic_name is None:
|
||||
return None, None, None
|
||||
el = Element("a")
|
||||
el.set("class", "message-link")
|
||||
stream_url = encode_stream(stream_id, stream_name)
|
||||
topic_url = hash_util_encode(topic_name)
|
||||
link = f"/#narrow/channel/{stream_url}/topic/{topic_url}/near/{message_id}"
|
||||
el.set("href", link)
|
||||
text = f"#{stream_name} > {topic_name} @ 💬"
|
||||
el.text = markdown.util.AtomicString(text)
|
||||
return el, m.start(), m.end()
|
||||
|
||||
|
||||
def possible_linked_stream_names(content: str) -> set[str]:
|
||||
return {
|
||||
*re.findall(STREAM_LINK_REGEX, content, re.VERBOSE),
|
||||
|
@ -2305,6 +2353,11 @@ class ZulipMarkdown(markdown.Markdown):
|
|||
)
|
||||
reg.register(UserMentionPattern(mention.MENTIONS_RE, self), "usermention", 95)
|
||||
reg.register(Tex(TEX_RE, self), "tex", 90)
|
||||
reg.register(
|
||||
StreamTopicMessagePattern(get_compiled_stream_topic_message_link_regex(), self),
|
||||
"stream_topic_message",
|
||||
89,
|
||||
)
|
||||
reg.register(StreamTopicPattern(get_compiled_stream_topic_link_regex(), self), "topic", 87)
|
||||
reg.register(StreamPattern(get_compiled_stream_link_regex(), self), "stream", 85)
|
||||
reg.register(Timestamp(TIMESTAMP_RE), "timestamp", 75)
|
||||
|
|
|
@ -3108,6 +3108,28 @@ class MarkdownStreamMentionTests(ZulipTestCase):
|
|||
".</p>",
|
||||
)
|
||||
|
||||
def test_message_id_multiple(self) -> None:
|
||||
denmark = get_stream("Denmark", get_realm("zulip"))
|
||||
sender_user_profile = self.example_user("othello")
|
||||
msg = Message(
|
||||
sender=sender_user_profile,
|
||||
sending_client=get_client("test"),
|
||||
realm=sender_user_profile.realm,
|
||||
)
|
||||
content = "As mentioned in #**Denmark>danish@123** and #**Denmark>danish@456**."
|
||||
self.assertEqual(
|
||||
render_message_markdown(msg, content).rendered_content,
|
||||
"<p>As mentioned in "
|
||||
f'<a class="message-link" '
|
||||
f'href="/#narrow/channel/{denmark.id}-{denmark.name}/topic/danish/near/123">'
|
||||
f"#Denmark > danish @ 💬</a>"
|
||||
" and "
|
||||
f'<a class="message-link" '
|
||||
f'href="/#narrow/channel/{denmark.id}-{denmark.name}/topic/danish/near/456">'
|
||||
f"#Denmark > danish @ 💬</a>"
|
||||
".</p>",
|
||||
)
|
||||
|
||||
def test_possible_stream_names(self) -> None:
|
||||
content = """#**test here**
|
||||
This mentions #**Denmark** too.
|
||||
|
|
Loading…
Reference in New Issue